Merge "msm: pil-vidc: Migrate to devm_clk_get()" into msm-3.4
diff --git a/Documentation/devicetree/bindings/pil/pil-venus.txt b/Documentation/devicetree/bindings/pil/pil-venus.txt
new file mode 100644
index 0000000..93cba32
--- /dev/null
+++ b/Documentation/devicetree/bindings/pil/pil-venus.txt
@@ -0,0 +1,28 @@
+* Qualcomm Venus Video Subsystem Peripheral Image Loader
+
+pil-venus is a peripheral image loading (PIL) driver. It is used for loading
+venus firmware images for video codec into memory and preparing the subsystem's
+processor to execute code. It is also used for shutting down the processor when
+it's not needed.
+
+Required properties:
+- compatible: "pil-venus"
+- reg: offset and length of the register set for the device. The first pair
+       corresponds to VENUS_WRAPPER, the second pair corresponds to VENUS_VBIF.
+- vdd-supply: regulator to supply venus.
+- qcom,firmware-name: Base name of the firmware image. Ex. "venus"
+- qcom,firmware-min-paddr: The lowest addr boundary for firmware image in DDR
+- qcom,firmware-max-paddr: The highest addr boundary for firmware image in DDR
+
+Example:
+        qcom,venus@fdce0000 {
+                compatible = "qcom,pil-venus";
+                reg = <0xfdce0000 0x4000>,
+                      <0xfdc80208 0x8>;
+                vdd-supply = <&gdsc_venus>;
+
+                qcom,firmware-name = "venus";
+                qcom,firmware-min-paddr = <0xF500000>;
+                qcom,firmware-max-paddr = <0xFA00000>;
+
+        };
diff --git a/arch/arm/boot/dts/msm8974-iommu.dtsi b/arch/arm/boot/dts/msm8974-iommu.dtsi
old mode 100644
new mode 100755
index 697136a..e1a0a9b
--- a/arch/arm/boot/dts/msm8974-iommu.dtsi
+++ b/arch/arm/boot/dts/msm8974-iommu.dtsi
@@ -88,4 +88,27 @@
 			qcom,iommu-ctx-name = "venus_fw";
 		};
 	};
+
+	kgsl: qcom,iommu@fdb10000 {
+		compatible = "qcom,msm-smmu-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		reg = <0xfdb10000 0x10000>;
+		vdd-supply = <&gdsc_oxili_cx>;
+		qcom,iommu-smt-size = <32>;
+
+		qcom,iommu-ctx@fdb18000 {
+			reg = <0xfdb18000 0x1000>;
+			interrupts = <0 240 0>;
+			qcom,iommu-ctx-sids = <0>;
+			qcom,iommu-ctx-name = "gfx3d_user";
+		};
+		qcom,iommu-ctx@fdb19000 {
+			reg = <0xfdb19000 0x1000>;
+			interrupts = <0 241 0>;
+			qcom,iommu-ctx-sids = <1>;
+			qcom,iommu-ctx-name = "gfx3d_priv";
+		};
+	};
 };
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 584bd11..8f8deac 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -471,4 +471,15 @@
 		compatible = "qcom,tz-log";
 		reg = <0xfe805720 0x1000>;
 	};
+
+	qcom,venus@fdce0000 {
+		compatible = "qcom,pil-venus";
+		reg = <0xfdce0000 0x4000>,
+		      <0xfdc80208 0x8>;
+		vdd-supply = <&gdsc_venus>;
+
+		qcom,firmware-name = "venus";
+		qcom,firmware-min-paddr = <0xF500000>;
+		qcom,firmware-max-paddr = <0xFA00000>;
+	};
 };
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index dd9418f..3cd06a2 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -53,6 +53,7 @@
 CONFIG_MSM_RPC_VIBRATOR=y
 CONFIG_PM8XXX_RPC_VIBRATOR=y
 CONFIG_MSM_SPM_V2=y
+CONFIG_MSM_MULTIMEDIA_USE_ION=y
 CONFIG_ARM_THUMBEE=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
@@ -250,6 +251,8 @@
 CONFIG_MSM_ACTUATOR=y
 CONFIG_OV7692=y
 CONFIG_RADIO_TAVARUA=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
 CONFIG_MSM_KGSL=y
 CONFIG_FB=y
 CONFIG_FB_MSM=y
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index b332e6b..058349a 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -53,6 +53,7 @@
 CONFIG_MSM_RPC_VIBRATOR=y
 CONFIG_PM8XXX_RPC_VIBRATOR=y
 CONFIG_MSM_SPM_V2=y
+CONFIG_MSM_MULTIMEDIA_USE_ION=y
 CONFIG_ARM_THUMBEE=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
@@ -251,6 +252,8 @@
 CONFIG_MSM_ACTUATOR=y
 CONFIG_OV7692=y
 CONFIG_RADIO_TAVARUA=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
 CONFIG_MSM_KGSL=y
 CONFIG_FB=y
 CONFIG_FB_MSM=y
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index ea4c0f6..173dcca 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -416,6 +416,8 @@
 CONFIG_ANDROID_TIMED_GPIO=y
 CONFIG_ANDROID_LOW_MEMORY_KILLER=y
 CONFIG_MSM_SSBI=y
+CONFIG_MSM_IOMMU=y
+# CONFIG_IOMMU_PGTABLES_L2 is not set
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT3_FS=y
diff --git a/arch/arm/configs/msm8660_defconfig b/arch/arm/configs/msm8660_defconfig
index 20557e5..f329c81 100644
--- a/arch/arm/configs/msm8660_defconfig
+++ b/arch/arm/configs/msm8660_defconfig
@@ -288,6 +288,8 @@
 # CONFIG_I2C_MSM is not set
 CONFIG_I2C_QUP=y
 CONFIG_I2C_SSBI=y
+CONFIG_MSM_IOMMU=y
+# CONFIG_IOMMU_PGTABLES_L2 is not set
 CONFIG_SPI=y
 CONFIG_SPI_QUP=y
 CONFIG_SPI_SPIDEV=m
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 905cb00..07bd8e6 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -47,6 +47,7 @@
 CONFIG_MSM_PIL_MSS_QDSP6V5=y
 CONFIG_MSM_PIL_MBA=y
 CONFIG_MSM_PIL_PRONTO=y
+CONFIG_MSM_PIL_VENUS=y
 CONFIG_MSM_TZ_LOG=y
 CONFIG_MSM_DIRECT_SCLK_ACCESS=y
 CONFIG_MSM_OCMEM=y
diff --git a/arch/arm/configs/msm9615_defconfig b/arch/arm/configs/msm9615_defconfig
index b4cfe4b..c9bc610 100644
--- a/arch/arm/configs/msm9615_defconfig
+++ b/arch/arm/configs/msm9615_defconfig
@@ -229,8 +229,8 @@
 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_CI13XXX_MSM=y
+CONFIG_USB_CI13XXX_MSM_HSIC=y
 CONFIG_USB_G_ANDROID=y
 CONFIG_RMNET_SMD_CTL_CHANNEL="DATA36_CNTL"
 CONFIG_RMNET_SMD_DATA_CHANNEL="DATA36"
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index d786ab7..2acf3ce 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -1906,6 +1906,13 @@
 	help
 	  Support for authenticating the video core image.
 
+config MSM_PIL_VENUS
+	tristate "VENUS (Video) Boot Support"
+	depends on MSM_PIL
+	help
+	  Support for booting and shutting down the VENUS processor (Video).
+	  Venus is the Video subsystem processor used for video codecs.
+
 config MSM_PIL_GSS
 	tristate "GSS (Coretx A5) Boot Support"
 	depends on MSM_PIL
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 7dfec38..702667b 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -79,6 +79,7 @@
 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_MSM_PIL_VENUS) += pil-venus.o
 obj-$(CONFIG_ARCH_QSD8X50) += sirc.o
 obj-$(CONFIG_ARCH_FSM9XXX) += sirc-fsm9xxx.o
 obj-$(CONFIG_MSM_FIQ_SUPPORT) += fiq_glue.o
@@ -300,6 +301,7 @@
 obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-rfkill.o msm_vibrator.o
 
 CFLAGS_msm_vibrator.o += -Idrivers/staging/android
+CFLAGS_board-9615.o += -Idrivers/usb/gadget
 
 obj-$(CONFIG_ARCH_FSM9XXX) += board-fsm9xxx.o
 
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
index 9809bdf..c9d3817 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -1615,7 +1615,7 @@
 		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()) {
+	} else if (cpu_is_msm8930() || cpu_is_msm8930aa()) {
 		enum pvs pvs_id = get_pvs();
 
 		scalable = scalable_8930;
diff --git a/arch/arm/mach-msm/board-8064-display.c b/arch/arm/mach-msm/board-8064-display.c
index 5edddb5..177e1fd 100644
--- a/arch/arm/mach-msm/board-8064-display.c
+++ b/arch/arm/mach-msm/board-8064-display.c
@@ -255,6 +255,7 @@
 #else
 	.mem_hid = MEMTYPE_EBI1,
 #endif
+	.mdp_iommu_split_domain = 1,
 };
 
 void __init apq8064_mdp_writeback(struct memtype_reserve* reserve_table)
@@ -313,7 +314,16 @@
 	.dev.platform_data = &hdmi_msm_data,
 };
 
+static char wfd_check_mdp_iommu_split_domain(void)
+{
+	return mdp_pdata.mdp_iommu_split_domain;
+}
+
 #ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
+static struct msm_wfd_platform_data wfd_pdata = {
+	.wfd_check_mdp_iommu_split = wfd_check_mdp_iommu_split_domain,
+};
+
 static struct platform_device wfd_panel_device = {
 	.name = "wfd_panel",
 	.id = 0,
@@ -323,6 +333,7 @@
 static struct platform_device wfd_device = {
 	.name          = "msm_wfd",
 	.id            = -1,
+	.dev.platform_data = &wfd_pdata,
 };
 #endif
 
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index 7175123f..f727852 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -256,7 +256,7 @@
 VREG_CONSUMERS(EXT_3P3V) = {
 	REGULATOR_SUPPLY("ext_3p3v",		NULL),
 	REGULATOR_SUPPLY("vdd_io",		"spi0.2"),
-	REGULATOR_SUPPLY("mhl_ext_3p3v",	"msm_otg"),
+	REGULATOR_SUPPLY("mhl_usb_hs_switch",	"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"),
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index a574139..f884631 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -2970,6 +2970,7 @@
 {
 	apq8064_common_init();
 	ethernet_init();
+	msm_rotator_set_split_iommu_domain();
 	platform_add_devices(rumi3_devices, ARRAY_SIZE(rumi3_devices));
 	spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
 }
@@ -2982,10 +2983,12 @@
 	if (machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
 		machine_is_mpq8064_dtv()) {
 		enable_avc_i2c_bus();
+		msm_rotator_set_split_iommu_domain();
 		platform_add_devices(mpq_devices, ARRAY_SIZE(mpq_devices));
 		mpq8064_pcie_init();
 	} else {
 		ethernet_init();
+		msm_rotator_set_split_iommu_domain();
 		platform_add_devices(cdp_devices, ARRAY_SIZE(cdp_devices));
 		spi_register_board_info(spi_board_info,
 						ARRAY_SIZE(spi_board_info));
diff --git a/arch/arm/mach-msm/board-8930-display.c b/arch/arm/mach-msm/board-8930-display.c
index 8a837d6..739dc85 100644
--- a/arch/arm/mach-msm/board-8930-display.c
+++ b/arch/arm/mach-msm/board-8930-display.c
@@ -429,6 +429,7 @@
 #else
 	.mem_hid = MEMTYPE_EBI1,
 #endif
+	.mdp_iommu_split_domain = 0,
 };
 
 void __init msm8930_mdp_writeback(struct memtype_reserve* reserve_table)
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index e6a13b1..5abb9f8 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -98,10 +98,7 @@
 };
 
 /* 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),
-};
+static struct pm8xxx_mpp_init pm8038_mpps[] __initdata = {};
 
 void __init msm8930_pm8038_gpio_mpp_init(void)
 {
diff --git a/arch/arm/mach-msm/board-8960-display.c b/arch/arm/mach-msm/board-8960-display.c
index c1017a9..20e9d2b 100644
--- a/arch/arm/mach-msm/board-8960-display.c
+++ b/arch/arm/mach-msm/board-8960-display.c
@@ -595,6 +595,7 @@
 	.mem_hid = MEMTYPE_EBI1,
 #endif
 	.cont_splash_enabled = 0x01,
+	.mdp_iommu_split_domain = 0,
 };
 
 void __init msm8960_mdp_writeback(struct memtype_reserve* reserve_table)
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index 7181990..a312e2b 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -52,6 +52,7 @@
 #include "pm.h"
 #include "pm-boot.h"
 #include <mach/gpiomux.h>
+#include "ci13xxx_udc.h"
 
 #ifdef CONFIG_ION_MSM
 #define MSM_ION_AUDIO_SIZE	0xAF000
@@ -762,10 +763,21 @@
 	.core_clk_always_on_workaround = true,
 };
 
-static struct msm_hsic_peripheral_platform_data msm_hsic_peripheral_pdata = {
+
+static struct ci13xxx_platform_data msm_peripheral_pdata = {
+	.usb_core_id = 0,
+};
+
+static struct msm_hsic_peripheral_platform_data
+			msm_hsic_peripheral_pdata_private = {
 	.core_clk_always_on_workaround = true,
 };
 
+static struct ci13xxx_platform_data msm_hsic_peripheral_pdata = {
+	.usb_core_id = 1,
+	.prv_data = &msm_hsic_peripheral_pdata_private,
+};
+
 #define PID_MAGIC_ID		0x71432909
 #define SERIAL_NUM_MAGIC_ID	0x61945374
 #define SERIAL_NUMBER_LENGTH	127
@@ -864,6 +876,7 @@
 	&msm_device_hsic_host,
 	&msm_device_usb_bam,
 	&msm_android_usb_device,
+	&msm_android_usb_hsic_device,
 	&msm9615_device_uart_gsbi4,
 	&msm9615_device_ext_2p95v_vreg,
 	&msm9615_device_ssbi_pmic1,
@@ -959,6 +972,8 @@
 {
 	struct android_usb_platform_data *android_pdata =
 				msm_android_usb_device.dev.platform_data;
+	struct android_usb_platform_data *android_hsic_pdata =
+				msm_android_usb_hsic_device.dev.platform_data;
 
 	msm9615_device_init();
 	msm9615_init_gpiomux();
@@ -976,6 +991,8 @@
 
 	msm_device_otg.dev.platform_data = &msm_otg_pdata;
 	msm_otg_pdata.phy_init_seq = shelby_phy_init_seq;
+	msm_device_gadget_peripheral.dev.platform_data =
+		&msm_peripheral_pdata;
 	msm_device_hsic_peripheral.dev.platform_data =
 		&msm_hsic_peripheral_pdata;
 	msm_device_usb_bam.dev.platform_data = &msm_usb_bam_pdata;
@@ -988,8 +1005,12 @@
 	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;
+	android_hsic_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);
diff --git a/arch/arm/mach-msm/board-msm7627a-camera.c b/arch/arm/mach-msm/board-msm7627a-camera.c
index 3ab5ba0..57684f9 100644
--- a/arch/arm/mach-msm/board-msm7627a-camera.c
+++ b/arch/arm/mach-msm/board-msm7627a-camera.c
@@ -292,6 +292,14 @@
 	.gpio_conf = &gpio_conf_ov8825,
 };
 
+static struct msm_actuator_info msm_act_main_cam_3_info = {
+	.board_info     = &msm_act_main_cam_i2c_info,
+	.cam_name   = MSM_ACTUATOR_MAIN_CAM_3,
+	.bus_id         = MSM_GSBI0_QUP_I2C_BUS_ID,
+	.vcm_pwd        = GPIO_SKU3_CAM_5MP_CAM_DRIVER_PWDN,
+	.vcm_enable     = 0,
+};
+
 static struct msm_camera_sensor_info msm_camera_sensor_ov8825_data = {
 	.sensor_name    = "ov8825",
 	.sensor_reset_enable    = 1,
@@ -303,6 +311,8 @@
 	.sensor_platform_info = &sensor_board_info_ov8825,
 	.csi_if = 1,
 	.camera_type = BACK_CAMERA_2D,
+	.sensor_type = BAYER_SENSOR,
+	.actuator_info = &msm_act_main_cam_3_info,
 };
 
 #ifdef CONFIG_MT9E013
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 7fd07af..1b21c23 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -9788,6 +9788,7 @@
 #else
 	.mem_hid = MEMTYPE_EBI1,
 #endif
+	.mdp_iommu_split_domain = 0,
 };
 
 static void __init reserve_mdp_memory(void)
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index fc91232..f99e5de8 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -5141,7 +5141,8 @@
 	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("ref_clk",	tsif_ref_clk.c,	"msm_tspp.0"),
+	CLK_LOOKUP("iface_clk",		tsif_p_clk.c,		"msm_tspp.0"),
 	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"),
@@ -5450,7 +5451,6 @@
 	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"),
@@ -5483,6 +5483,8 @@
 	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("ref_clk",	tsif_ref_clk.c,	"msm_tspp.0"),
+	CLK_LOOKUP("iface_clk",		tsif_p_clk.c,		"msm_tspp.0"),
 	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"),
@@ -6115,7 +6117,7 @@
 
 	if (cpu_is_apq8064())
 		rmwreg(0x019FECFF, MAXI_EN5_REG, 0x01FFEFFF);
-	if (cpu_is_msm8930() || cpu_is_msm8627())
+	if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627())
 		rmwreg(0x000004FF, MAXI_EN5_REG, 0x00000FFF);
 	if (cpu_is_msm8627())
 		rmwreg(0x000003C7, SAXI_EN_REG,  0x00003FFF);
@@ -6151,7 +6153,8 @@
 		rmwreg(0x80FF0000, DSI2_PIXEL_CC_REG, 0xE0FF0010);
 		rmwreg(0x80FF0000, JPEGD_CC_REG,      0xE0FF0010);
 	}
-	if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8627())
+	if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
+	    cpu_is_msm8627())
 		rmwreg(0x80FF0000, TV_CC_REG,         0xE1FFC010);
 
 	if (cpu_is_msm8960()) {
@@ -6243,7 +6246,7 @@
 	 * Program PLL15 to 900MHz with ref clk = 27MHz and
 	 * only enable PLL main output.
 	 */
-	if (cpu_is_msm8930() || cpu_is_msm8627()) {
+	if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627()) {
 		pll15_config.l = 0x21 | BVAL(31, 7, 0x600);
 		pll15_config.m = 0x1;
 		pll15_config.n = 0x3;
@@ -6257,7 +6260,7 @@
 {
 	if (cpu_is_apq8064()) {
 		vdd_sr2_pll.set_vdd = set_vdd_sr2_pll_8064;
-	} else if (cpu_is_msm8930() || cpu_is_msm8627()) {
+	} else if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627()) {
 		vdd_dig.set_vdd = set_vdd_dig_8930;
 		vdd_sr2_pll.set_vdd = set_vdd_sr2_pll_8930;
 	}
@@ -6287,7 +6290,7 @@
 	 * Change the freq tables and voltage requirements for
 	 * clocks which differ between 8960 and 8930.
 	 */
-	if (cpu_is_msm8930() || cpu_is_msm8627()) {
+	if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627()) {
 		gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8930;
 
 		memcpy(gfx3d_clk.c.fmax, fmax_gfx3d_8930,
@@ -6332,7 +6335,8 @@
 		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() || cpu_is_msm8627())
+	if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
+	    cpu_is_msm8627())
 		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);
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 2660d5e..6c9a566 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -3775,6 +3775,18 @@
 	},
 };
 
+static struct branch_clk oxilicx_axi_clk = {
+	.cbcr_reg = OXILICX_AXI_CBCR,
+	.parent = &axi_clk_src.c,
+	.has_sibling = 1,
+	.base = &virt_bases[MMSS_BASE],
+	.c = {
+		.dbg_name = "oxilicx_axi_clk",
+		.ops = &clk_ops_branch,
+		CLK_INIT(oxilicx_axi_clk.c),
+	},
+};
+
 static struct branch_clk oxili_gfx3d_clk = {
 	.cbcr_reg = OXILI_GFX3D_CBCR,
 	.has_sibling = 1,
@@ -3783,6 +3795,7 @@
 		.dbg_name = "oxili_gfx3d_clk",
 		.ops = &clk_ops_branch,
 		CLK_INIT(oxili_gfx3d_clk.c),
+		.depends = &oxilicx_axi_clk.c,
 	},
 };
 
@@ -3797,18 +3810,6 @@
 	},
 };
 
-static struct branch_clk oxilicx_axi_clk = {
-	.cbcr_reg = OXILICX_AXI_CBCR,
-	.parent = &axi_clk_src.c,
-	.has_sibling = 1,
-	.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
@@ -4744,12 +4745,19 @@
 	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, "mdp.0"),
-	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("core_clk", oxili_gfx3d_clk.c, "fdb00000.qcom,kgsl-3d0"),
+	CLK_LOOKUP("iface_clk", oxilicx_ahb_clk.c, "fdb00000.qcom,kgsl-3d0"),
+	CLK_LOOKUP("core_clk", oxilicx_axi_clk.c, "fdb10000.qcom,iommu"),
+	CLK_LOOKUP("iface_clk", oxilicx_ahb_clk.c, "fdb10000.qcom,iommu"),
 	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, ""),
+	CLK_LOOKUP("src_clk",  vcodec0_clk_src.c, "fdce0000.qcom,venus"),
+	CLK_LOOKUP("core_clk", venus0_vcodec0_clk.c, "fdce0000.qcom,venus"),
+	CLK_LOOKUP("iface_clk",  venus0_ahb_clk.c, "fdce0000.qcom,venus"),
+	CLK_LOOKUP("bus_clk",  venus0_axi_clk.c, "fdce0000.qcom,venus"),
+	CLK_LOOKUP("mem_clk",  venus0_ocmemnoc_clk.c, "fdce0000.qcom,venus"),
+
 
 	/* LPASS clocks */
 	CLK_LOOKUP("core_clk", audio_core_slimbus_core_clk.c, "fe12f000.slim"),
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 614785e..069d738 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -2596,15 +2596,15 @@
 		.name = "jpegd_dst",
 		.domain = CAMERA_DOMAIN,
 	},
-	/* Rotator */
+	/* Rotator src*/
 	{
 		.name = "rot_src",
-		.domain = ROTATOR_DOMAIN,
+		.domain = ROTATOR_SRC_DOMAIN,
 	},
-	/* Rotator */
+	/* Rotator dst */
 	{
 		.name = "rot_dst",
-		.domain = ROTATOR_DOMAIN,
+		.domain = ROTATOR_DST_DOMAIN,
 	},
 	/* Video */
 	{
@@ -2660,18 +2660,36 @@
 		},
 };
 
-static struct mem_pool apq8064_display_pools[] =  {
+static struct mem_pool apq8064_display_read_pools[] =  {
 	[GEN_POOL] =
-	/* One address space for display */
+	/* One address space for display reads */
 		{
 			.paddr	= SZ_128K,
 			.size	= SZ_2G - SZ_128K,
 		},
 };
 
-static struct mem_pool apq8064_rotator_pools[] =  {
+static struct mem_pool apq8064_display_write_pools[] =  {
 	[GEN_POOL] =
-	/* One address space for rotator */
+	/* One address space for display writes */
+		{
+			.paddr	= SZ_128K,
+			.size	= SZ_2G - SZ_128K,
+		},
+};
+
+static struct mem_pool apq8064_rotator_src_pools[] =  {
+	[GEN_POOL] =
+	/* One address space for rotator src */
+		{
+			.paddr	= SZ_128K,
+			.size	= SZ_2G - SZ_128K,
+		},
+};
+
+static struct mem_pool apq8064_rotator_dst_pools[] =  {
+	[GEN_POOL] =
+	/* One address space for rotator dst */
 		{
 			.paddr	= SZ_128K,
 			.size	= SZ_2G - SZ_128K,
@@ -2687,13 +2705,21 @@
 			.iova_pools = apq8064_camera_pools,
 			.npools = ARRAY_SIZE(apq8064_camera_pools),
 		},
-		[DISPLAY_DOMAIN] = {
-			.iova_pools = apq8064_display_pools,
-			.npools = ARRAY_SIZE(apq8064_display_pools),
+		[DISPLAY_READ_DOMAIN] = {
+			.iova_pools = apq8064_display_read_pools,
+			.npools = ARRAY_SIZE(apq8064_display_read_pools),
 		},
-		[ROTATOR_DOMAIN] = {
-			.iova_pools = apq8064_rotator_pools,
-			.npools = ARRAY_SIZE(apq8064_rotator_pools),
+		[DISPLAY_WRITE_DOMAIN] = {
+			.iova_pools = apq8064_display_write_pools,
+			.npools = ARRAY_SIZE(apq8064_display_write_pools),
+		},
+		[ROTATOR_SRC_DOMAIN] = {
+			.iova_pools = apq8064_rotator_src_pools,
+			.npools = ARRAY_SIZE(apq8064_rotator_src_pools),
+		},
+		[ROTATOR_DST_DOMAIN] = {
+			.iova_pools = apq8064_rotator_dst_pools,
+			.npools = ARRAY_SIZE(apq8064_rotator_dst_pools),
 		},
 };
 
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index 3212364..a36e7d7 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -767,12 +767,12 @@
 	/* Rotator */
 	{
 		.name = "rot_src",
-		.domain = ROTATOR_DOMAIN,
+		.domain = ROTATOR_SRC_DOMAIN,
 	},
 	/* Rotator */
 	{
 		.name = "rot_dst",
-		.domain = ROTATOR_DOMAIN,
+		.domain = ROTATOR_SRC_DOMAIN,
 	},
 	/* Video */
 	{
@@ -828,18 +828,18 @@
 		},
 };
 
-static struct mem_pool msm8930_display_pools[] =  {
+static struct mem_pool msm8930_display_read_pools[] =  {
 	[GEN_POOL] =
-	/* One address space for display */
+	/* One address space for display reads */
 		{
 			.paddr	= SZ_128K,
 			.size	= SZ_2G - SZ_128K,
 		},
 };
 
-static struct mem_pool msm8930_rotator_pools[] =  {
+static struct mem_pool msm8930_rotator_src_pools[] =  {
 	[GEN_POOL] =
-	/* One address space for rotator */
+	/* One address space for rotator src */
 		{
 			.paddr	= SZ_128K,
 			.size	= SZ_2G - SZ_128K,
@@ -855,13 +855,13 @@
 			.iova_pools = msm8930_camera_pools,
 			.npools = ARRAY_SIZE(msm8930_camera_pools),
 		},
-		[DISPLAY_DOMAIN] = {
-			.iova_pools = msm8930_display_pools,
-			.npools = ARRAY_SIZE(msm8930_display_pools),
+		[DISPLAY_READ_DOMAIN] = {
+			.iova_pools = msm8930_display_read_pools,
+			.npools = ARRAY_SIZE(msm8930_display_read_pools),
 		},
-		[ROTATOR_DOMAIN] = {
-			.iova_pools = msm8930_rotator_pools,
-			.npools = ARRAY_SIZE(msm8930_rotator_pools),
+		[ROTATOR_SRC_DOMAIN] = {
+			.iova_pools = msm8930_rotator_src_pools,
+			.npools = ARRAY_SIZE(msm8930_rotator_src_pools),
 		},
 };
 
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 369e826..7d93fe7 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -2291,6 +2291,11 @@
 		.platform_data = &rotator_pdata,
 	},
 };
+
+void __init msm_rotator_set_split_iommu_domain(void)
+{
+	rotator_pdata.rot_iommu_split_domain = 1;
+}
 #endif
 
 #define MIPI_DSI_HW_BASE        0x04700000
@@ -3643,12 +3648,12 @@
 	/* Rotator */
 	{
 		.name = "rot_src",
-		.domain = ROTATOR_DOMAIN,
+		.domain = ROTATOR_SRC_DOMAIN,
 	},
 	/* Rotator */
 	{
 		.name = "rot_dst",
-		.domain = ROTATOR_DOMAIN,
+		.domain = ROTATOR_SRC_DOMAIN,
 	},
 	/* Video */
 	{
@@ -3704,18 +3709,18 @@
 		},
 };
 
-static struct mem_pool msm8960_display_pools[] =  {
+static struct mem_pool msm8960_display_read_pools[] =  {
 	[GEN_POOL] =
-	/* One address space for display */
+	/* One address space for display reads */
 		{
 			.paddr	= SZ_128K,
 			.size	= SZ_2G - SZ_128K,
 		},
 };
 
-static struct mem_pool msm8960_rotator_pools[] =  {
+static struct mem_pool msm8960_rotator_src_pools[] =  {
 	[GEN_POOL] =
-	/* One address space for rotator */
+	/* One address space for rotator src */
 		{
 			.paddr	= SZ_128K,
 			.size	= SZ_2G - SZ_128K,
@@ -3731,13 +3736,13 @@
 			.iova_pools = msm8960_camera_pools,
 			.npools = ARRAY_SIZE(msm8960_camera_pools),
 		},
-		[DISPLAY_DOMAIN] = {
-			.iova_pools = msm8960_display_pools,
-			.npools = ARRAY_SIZE(msm8960_display_pools),
+		[DISPLAY_READ_DOMAIN] = {
+			.iova_pools = msm8960_display_read_pools,
+			.npools = ARRAY_SIZE(msm8960_display_read_pools),
 		},
-		[ROTATOR_DOMAIN] = {
-			.iova_pools = msm8960_rotator_pools,
-			.npools = ARRAY_SIZE(msm8960_rotator_pools),
+		[ROTATOR_SRC_DOMAIN] = {
+			.iova_pools = msm8960_rotator_src_pools,
+			.npools = ARRAY_SIZE(msm8960_rotator_src_pools),
 		},
 };
 
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index 06d8653..9c2b26a 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -1348,7 +1348,9 @@
 	return 0;
 }
 
-struct android_usb_platform_data msm_android_usb_pdata;
+struct android_usb_platform_data msm_android_usb_pdata = {
+	.usb_core_id = 0,
+};
 
 struct platform_device msm_android_usb_device = {
 	.name	= "android_usb",
@@ -1358,6 +1360,19 @@
 	},
 };
 
+struct android_usb_platform_data msm_android_usb_hsic_pdata  = {
+	.usb_core_id = 1,
+};
+
+struct platform_device msm_android_usb_hsic_device = {
+	.name	= "android_usb_hsic",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &msm_android_usb_hsic_pdata,
+	},
+};
+
+
 void __init msm9615_device_init(void)
 {
 	msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
@@ -1365,6 +1380,8 @@
 	BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
 	msm_android_usb_pdata.swfi_latency =
 		msm_rpmrs_levels[0].latency_us;
+	msm_android_usb_hsic_pdata.swfi_latency =
+		msm_rpmrs_levels[0].latency_us;
 
 }
 
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index 43c5f88..2ced412 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -1561,7 +1561,7 @@
 #ifdef CONFIG_MSM_BUS_SCALING
 	.bus_scale_table = &rotator_bus_scale_pdata,
 #endif
-
+	.rot_iommu_split_domain = 0,
 };
 
 struct platform_device msm_rotator_device = {
@@ -3014,12 +3014,12 @@
 	/* Rotator */
 	{
 		.name = "rot_src",
-		.domain = ROTATOR_DOMAIN,
+		.domain = ROTATOR_SRC_DOMAIN,
 	},
 	/* Rotator */
 	{
 		.name = "rot_dst",
-		.domain = ROTATOR_DOMAIN,
+		.domain = ROTATOR_SRC_DOMAIN,
 	},
 	/* Video */
 	{
@@ -3102,11 +3102,11 @@
 			.iova_pools = msm8660_camera_pools,
 			.npools = ARRAY_SIZE(msm8660_camera_pools),
 		},
-		[DISPLAY_DOMAIN] = {
+		[DISPLAY_READ_DOMAIN] = {
 			.iova_pools = msm8660_display_pools,
 			.npools = ARRAY_SIZE(msm8660_display_pools),
 		},
-		[ROTATOR_DOMAIN] = {
+		[ROTATOR_SRC_DOMAIN] = {
 			.iova_pools = msm8660_rotator_pools,
 			.npools = ARRAY_SIZE(msm8660_rotator_pools),
 		},
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index e9911cf..045dfb9 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -27,6 +27,7 @@
 void __init msm9615_init_irq(void);
 void __init msm_rotator_update_bus_vectors(unsigned int xres,
 	unsigned int yres);
+void __init msm_rotator_set_split_iommu_domain(void);
 
 extern struct platform_device asoc_msm_pcm;
 extern struct platform_device asoc_msm_dai0;
@@ -113,6 +114,7 @@
 
 extern struct platform_device msm_device_otg;
 extern struct platform_device msm_android_usb_device;
+extern struct platform_device msm_android_usb_hsic_device;
 extern struct platform_device msm_device_hsic_peripheral;
 extern struct platform_device msm8960_device_otg;
 extern struct platform_device msm8960_device_gadget_peripheral;
diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c
index 4e488d7..e5dca00 100644
--- a/arch/arm/mach-msm/dma.c
+++ b/arch/arm/mach-msm/dma.c
@@ -74,7 +74,6 @@
 };
 
 static void msm_dmov_clock_work(struct work_struct *);
-static int msm_dmov_clk_toggle(int, int);
 
 #ifdef CONFIG_ARCH_MSM8X60
 
@@ -232,40 +231,40 @@
 #define PRINT_FLOW(format, args...) \
 	MSM_DMOV_DPRINTF(MSM_DMOV_PRINT_FLOW, format, args);
 
-static int msm_dmov_clk_toggle(int adm, int on)
+static int msm_dmov_clk_on(int adm)
 {
-	int ret = 0;
+	int ret;
 
-	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;
-			}
+	ret = clk_prepare_enable(dmov_conf[adm].clk);
+	if (ret)
+		return ret;
+	if (dmov_conf[adm].pclk) {
+		ret = clk_prepare_enable(dmov_conf[adm].pclk);
+		if (ret) {
+			clk_disable_unprepare(dmov_conf[adm].clk);
+			return ret;
 		}
-		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:
+	if (dmov_conf[adm].ebiclk) {
+		ret = clk_prepare_enable(dmov_conf[adm].ebiclk);
+		if (ret) {
+			if (dmov_conf[adm].pclk)
+				clk_disable_unprepare(dmov_conf[adm].pclk);
+			clk_disable_unprepare(dmov_conf[adm].clk);
+		}
+	}
 	return ret;
 }
 
+static void msm_dmov_clk_off(int adm)
+{
+	if (dmov_conf[adm].ebiclk)
+		clk_disable_unprepare(dmov_conf[adm].ebiclk);
+	if (dmov_conf[adm].pclk)
+		clk_disable_unprepare(dmov_conf[adm].pclk);
+	clk_disable_unprepare(dmov_conf[adm].clk);
+}
+
 static void msm_dmov_clock_work(struct work_struct *work)
 {
 	struct msm_dmov_conf *conf =
@@ -274,7 +273,7 @@
 	mutex_lock(&conf->lock);
 	if (conf->clk_ctl == CLK_TO_BE_DIS) {
 		BUG_ON(conf->channel_active);
-		msm_dmov_clk_toggle(adm, 0);
+		msm_dmov_clk_off(adm);
 		conf->clk_ctl = CLK_DIS;
 	}
 	mutex_unlock(&conf->lock);
@@ -321,7 +320,7 @@
 
 	mutex_lock(&dmov_conf[adm].lock);
 	if (dmov_conf[adm].clk_ctl == CLK_DIS) {
-		status = msm_dmov_clk_toggle(adm, 1);
+		status = msm_dmov_clk_on(adm);
 		if (status != 0)
 			goto error;
 	}
@@ -588,7 +587,7 @@
 	mutex_lock(&dmov_conf[adm].lock);
 	if (dmov_conf[adm].clk_ctl == CLK_TO_BE_DIS) {
 		BUG_ON(dmov_conf[adm].channel_active);
-		msm_dmov_clk_toggle(adm, 0);
+		msm_dmov_clk_off(adm);
 		dmov_conf[adm].clk_ctl = CLK_DIS;
 	}
 	mutex_unlock(&dmov_conf[adm].lock);
@@ -726,7 +725,7 @@
 		PRINT_ERROR("Requesting ADM%d clocks failed\n", adm);
 		goto out_irq;
 	}
-	ret = msm_dmov_clk_toggle(adm, 1);
+	ret = msm_dmov_clk_on(adm);
 	if (ret) {
 		PRINT_ERROR("Enabling ADM%d clocks failed\n", adm);
 		goto out_irq;
@@ -743,7 +742,7 @@
 		     DMOV_REG(DMOV_RSLT_CONF(i), adm));
 	}
 	wmb();
-	msm_dmov_clk_toggle(adm, 0);
+	msm_dmov_clk_off(adm);
 	return ret;
 out_irq:
 	free_irq(dmov_conf[adm].irq, NULL);
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 1aa3814..198cd38 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -401,6 +401,7 @@
 	u32 ov1_wb_size;  /* overlay1 writeback size */
 	u32 mem_hid;
 	char cont_splash_enabled;
+	char mdp_iommu_split_domain;
 };
 
 
@@ -466,6 +467,10 @@
 	int *gpio;
 };
 
+struct msm_wfd_platform_data {
+	char (*wfd_check_mdp_iommu_split)(void);
+};
+
 #define PANEL_NAME_MAX_LEN 50
 struct msm_fb_platform_data {
 	int (*detect_client)(const char *name);
diff --git a/arch/arm/mach-msm/include/mach/gpio.h b/arch/arm/mach-msm/include/mach/gpio.h
index 1d32003..a0bcd2b 100644
--- a/arch/arm/mach-msm/include/mach/gpio.h
+++ b/arch/arm/mach-msm/include/mach/gpio.h
@@ -162,17 +162,24 @@
 	TLMM_HDRV_SDC3_CLK,
 	TLMM_HDRV_SDC3_CMD,
 	TLMM_HDRV_SDC3_DATA,
+	TLMM_HDRV_SDC2_CLK,
+	TLMM_HDRV_SDC2_CMD,
+	TLMM_HDRV_SDC2_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_CLK = 0,
+	TLMM_PULL_SDC4_CMD,
 	TLMM_PULL_SDC4_DATA,
 	TLMM_PULL_SDC3_CLK,
 	TLMM_PULL_SDC3_CMD,
 	TLMM_PULL_SDC3_DATA,
+	TLMM_PULL_SDC2_CLK,
+	TLMM_PULL_SDC2_CMD,
+	TLMM_PULL_SDC2_DATA,
 	TLMM_PULL_SDC1_CLK,
 	TLMM_PULL_SDC1_CMD,
 	TLMM_PULL_SDC1_DATA,
diff --git a/arch/arm/mach-msm/include/mach/iommu_domains.h b/arch/arm/mach-msm/include/mach/iommu_domains.h
index 1a3a022..1d538f2 100644
--- a/arch/arm/mach-msm/include/mach/iommu_domains.h
+++ b/arch/arm/mach-msm/include/mach/iommu_domains.h
@@ -18,8 +18,10 @@
 enum {
 	VIDEO_DOMAIN,
 	CAMERA_DOMAIN,
-	DISPLAY_DOMAIN,
-	ROTATOR_DOMAIN,
+	DISPLAY_READ_DOMAIN,
+	DISPLAY_WRITE_DOMAIN,
+	ROTATOR_SRC_DOMAIN,
+	ROTATOR_DST_DOMAIN,
 	MAX_DOMAINS
 };
 
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index 6b4ce2a..15aebcd 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -73,6 +73,7 @@
 	MSM_CPU_7X25AB,
 	MSM_CPU_8064,
 	MSM_CPU_8930,
+	MSM_CPU_8930AA,
 	MSM_CPU_7X27AA,
 	MSM_CPU_9615,
 	MSM_CPU_8974,
@@ -262,6 +263,15 @@
 #endif
 }
 
+static inline int cpu_is_msm8930aa(void)
+{
+#ifdef CONFIG_ARCH_MSM8930
+	return read_msm_cpu_type() == MSM_CPU_8930AA;
+#else
+	return 0;
+#endif
+}
+
 static inline int cpu_is_msm8627(void)
 {
 /* 8930 and 8627 will share the same CONFIG_ARCH type unless otherwise needed */
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
index e92b5c5..42f0438 100644
--- a/arch/arm/mach-msm/iommu_domains.c
+++ b/arch/arm/mach-msm/iommu_domains.c
@@ -400,6 +400,9 @@
 	struct iommu_domains_pdata *p  = pdev->dev.platform_data;
 	int i, j;
 
+	if (!msm_use_iommu())
+		return -ENODEV;
+
 	if (!p)
 		return -ENODEV;
 
diff --git a/arch/arm/mach-msm/modem-8960.c b/arch/arm/mach-msm/modem-8960.c
index 1132be2..fd7b7b5 100644
--- a/arch/arm/mach-msm/modem-8960.c
+++ b/arch/arm/mach-msm/modem-8960.c
@@ -281,8 +281,8 @@
 {
 	int ret;
 
-	if (!cpu_is_msm8960() && !cpu_is_msm8930() && !cpu_is_msm9615() &&
-	    !cpu_is_msm8627())
+	if (!cpu_is_msm8960() && !cpu_is_msm8930() && !cpu_is_msm8930aa() &&
+	    !cpu_is_msm9615() && !cpu_is_msm8627())
 		return -ENODEV;
 
 	ret = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET,
diff --git a/arch/arm/mach-msm/msm_xo.c b/arch/arm/mach-msm/msm_xo.c
index fb01427..9825ce5 100644
--- a/arch/arm/mach-msm/msm_xo.c
+++ b/arch/arm/mach-msm/msm_xo.c
@@ -234,8 +234,8 @@
 	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() ||
-			       cpu_is_msm8627();
+			       cpu_is_msm8930() || cpu_is_msm8930aa() ||
+			       cpu_is_msm9615() || cpu_is_msm8627();
 
 	if (xo_voter->mode == mode)
 		return 0;
diff --git a/arch/arm/mach-msm/pil-venus.c b/arch/arm/mach-msm/pil-venus.c
new file mode 100644
index 0000000..6a0aeaa
--- /dev/null
+++ b/arch/arm/mach-msm/pil-venus.c
@@ -0,0 +1,464 @@
+/* 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/iommu.h>
+#include <linux/iopoll.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+
+#include <asm/page.h>
+#include <asm/sizes.h>
+
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+
+#include "peripheral-loader.h"
+#include "scm-pas.h"
+
+/* VENUS WRAPPER registers */
+#define VENUS_WRAPPER_CLOCK_CONFIG			0x4
+#define VENUS_WRAPPER_VBIF_SS_SEC_CPA_START_ADDR	0x1018
+#define VENUS_WRAPPER_VBIF_SS_SEC_CPA_END_ADDR		0x101C
+#define VENUS_WRAPPER_VBIF_SS_SEC_FW_START_ADDR		0x1020
+#define VENUS_WRAPPER_VBIF_SS_SEC_FW_END_ADDR		0x1024
+#define VENUS_WRAPPER_CPU_CLOCK_CONFIG			0x2000
+#define VENUS_WRAPPER_SW_RESET				0x3000
+
+/* VENUS VBIF registers */
+#define VENUS_VBIF_AXI_HALT_CTRL0			0x0
+#define VENUS_VBIF_AXI_HALT_CTRL0_HALT_REQ		BIT(0)
+
+#define VENUS_VBIF_AXI_HALT_CTRL1			0x4
+#define VENUS_VBIF_AXI_HALT_CTRL1_HALT_ACK		BIT(0)
+#define VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US		500000
+
+/* PIL proxy vote timeout */
+#define VENUS_PROXY_TIMEOUT				10000
+
+/* Poll interval in uS */
+#define POLL_INTERVAL_US				50
+
+static const char * const clk_names[] = {
+	"core_clk",
+	"iface_clk",
+	"bus_clk",
+	"mem_clk",
+};
+
+struct venus_data {
+	void __iomem *venus_wrapper_base;
+	void __iomem *venus_vbif_base;
+	struct pil_device *pil;
+	struct regulator *gdsc;
+	phys_addr_t start_addr;
+	struct clk *clks[ARRAY_SIZE(clk_names)];
+	struct device *iommu_fw_ctx;
+	struct iommu_domain *iommu_fw_domain;
+	int venus_domain_num;
+	bool is_booted;
+	u32 fw_sz;
+	u32 fw_min_paddr;
+	u32 fw_max_paddr;
+};
+
+static int venus_register_domain(u32 fw_max_sz)
+{
+	struct msm_iova_partition venus_fw_partition = {
+		.start = 0,
+		.size = fw_max_sz,
+	};
+	struct msm_iova_layout venus_fw_layout = {
+		.partitions = &venus_fw_partition,
+		.npartitions = 1,
+		.client_name = "pil_venus",
+		.domain_flags = 0,
+	};
+
+	return msm_register_domain(&venus_fw_layout);
+}
+
+/* Get venus clocks and set rates for rate-settable clocks */
+static int venus_clock_setup(struct device *dev)
+{
+	struct venus_data *drv = dev_get_drvdata(dev);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(drv->clks); i++) {
+		drv->clks[i] = devm_clk_get(dev, clk_names[i]);
+		if (IS_ERR(drv->clks[i])) {
+			dev_err(dev, "failed to get %s\n",
+				clk_names[i]);
+			return PTR_ERR(drv->clks[i]);
+		}
+		/* Make sure rate-settable clocks' rates are set */
+		if (clk_get_rate(drv->clks[i]) == 0)
+			clk_set_rate(drv->clks[i],
+				     clk_round_rate(drv->clks[i], 0));
+	}
+
+	return 0;
+}
+
+static int venus_clock_prepare_enable(struct device *dev)
+{
+	struct venus_data *drv = dev_get_drvdata(dev);
+	int rc, i;
+
+	for (i = 0; i < ARRAY_SIZE(drv->clks); i++) {
+		rc = clk_prepare_enable(drv->clks[i]);
+		if (rc) {
+			dev_err(dev, "failed to enable %s\n",
+				clk_names[i]);
+			for (i--; i >= 0; i--)
+				clk_disable_unprepare(drv->clks[i]);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+static void venus_clock_disable_unprepare(struct device *dev)
+{
+	struct venus_data *drv = dev_get_drvdata(dev);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(drv->clks); i++)
+		clk_disable_unprepare(drv->clks[i]);
+}
+
+static int pil_venus_make_proxy_vote(struct pil_desc *pil)
+{
+	struct venus_data *drv = dev_get_drvdata(pil->dev);
+	int rc;
+
+	/*
+	 * Clocks need to be proxy voted to be able to pass control
+	 * of clocks from PIL driver to the Venus driver. But GDSC
+	 * needs to be turned on before clocks can be turned on. So
+	 * enable the GDSC here.
+	 */
+	rc = regulator_enable(drv->gdsc);
+	if (rc) {
+		dev_err(pil->dev, "GDSC enable failed\n");
+		return rc;
+	}
+
+	rc = venus_clock_prepare_enable(pil->dev);
+	if (rc)
+		regulator_disable(drv->gdsc);
+
+	return rc;
+}
+
+static void pil_venus_remove_proxy_vote(struct pil_desc *pil)
+{
+	struct venus_data *drv = dev_get_drvdata(pil->dev);
+
+	venus_clock_disable_unprepare(pil->dev);
+
+	/* Disable GDSC */
+	regulator_disable(drv->gdsc);
+}
+
+static int pil_venus_init_image(struct pil_desc *pil, const u8 *metadata,
+		size_t size)
+{
+	const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
+	struct venus_data *drv = dev_get_drvdata(pil->dev);
+
+	drv->start_addr = ehdr->e_entry;
+
+	if (drv->start_addr < drv->fw_min_paddr ||
+	    drv->start_addr >= drv->fw_max_paddr) {
+		dev_err(pil->dev, "fw start addr is not within valid range\n");
+		return -EINVAL;
+	}
+
+	drv->fw_sz = drv->fw_max_paddr - drv->start_addr;
+
+	return 0;
+}
+
+static int pil_venus_reset(struct pil_desc *pil)
+{
+	int rc;
+	struct venus_data *drv = dev_get_drvdata(pil->dev);
+	void __iomem *wrapper_base = drv->venus_wrapper_base;
+	phys_addr_t pa = drv->start_addr;
+	unsigned long iova;
+
+	/*
+	 * GDSC needs to remain on till Venus is shutdown. So, enable
+	 * the GDSC here again to make sure it remains on beyond the
+	 * expiry of the proxy vote timer.
+	 */
+	rc = regulator_enable(drv->gdsc);
+	if (rc) {
+		dev_err(pil->dev, "GDSC enable failed\n");
+		return rc;
+	}
+
+	/* Program CPA start and end address */
+	writel_relaxed(0, wrapper_base +
+			VENUS_WRAPPER_VBIF_SS_SEC_CPA_START_ADDR);
+	writel_relaxed(drv->fw_sz, wrapper_base +
+			VENUS_WRAPPER_VBIF_SS_SEC_CPA_END_ADDR);
+
+	/* Program FW start and end address */
+	writel_relaxed(0, wrapper_base +
+			VENUS_WRAPPER_VBIF_SS_SEC_FW_START_ADDR);
+	writel_relaxed(drv->fw_sz, wrapper_base +
+			VENUS_WRAPPER_VBIF_SS_SEC_FW_END_ADDR);
+
+	rc = iommu_attach_device(drv->iommu_fw_domain, drv->iommu_fw_ctx);
+	if (rc) {
+		dev_err(pil->dev, "venus fw iommu attach failed\n");
+		goto err_iommu_attach;
+	}
+
+	/* Enable all Venus internal clocks */
+	writel_relaxed(0, wrapper_base + VENUS_WRAPPER_CLOCK_CONFIG);
+	writel_relaxed(0, wrapper_base + VENUS_WRAPPER_CPU_CLOCK_CONFIG);
+
+	/* Make sure clocks are enabled */
+	mb();
+
+	/*
+	 * Need to wait 10 cycles of internal clocks before bringing ARM9
+	 * out of reset.
+	 */
+	udelay(1);
+
+	/* Map virtual addr space 0 - fw_sz to firmware physical addr space */
+	rc = msm_iommu_map_contig_buffer(pa, drv->venus_domain_num, 0,
+					 drv->fw_sz, SZ_4K, 0, &iova);
+
+	if (rc || (iova != 0)) {
+		dev_err(pil->dev, "Failed to setup IOMMU\n");
+		goto err_iommu_map;
+	}
+
+	/* Bring Arm9 out of reset */
+	writel_relaxed(0, wrapper_base + VENUS_WRAPPER_SW_RESET);
+
+	drv->is_booted = 1;
+
+	return 0;
+
+err_iommu_map:
+	iommu_detach_device(drv->iommu_fw_domain, drv->iommu_fw_ctx);
+
+err_iommu_attach:
+	regulator_disable(drv->gdsc);
+
+	return rc;
+}
+
+static int pil_venus_shutdown(struct pil_desc *pil)
+{
+	struct venus_data *drv = dev_get_drvdata(pil->dev);
+	void __iomem *vbif_base = drv->venus_vbif_base;
+	void __iomem *wrapper_base = drv->venus_wrapper_base;
+	u32 reg;
+	int rc;
+
+	if (!drv->is_booted)
+		return 0;
+
+	venus_clock_prepare_enable(pil->dev);
+
+	/* Halt AXI and AXI OCMEM VBIF Access */
+	reg = readl_relaxed(vbif_base + VENUS_VBIF_AXI_HALT_CTRL0);
+	reg |= VENUS_VBIF_AXI_HALT_CTRL0_HALT_REQ;
+	writel_relaxed(reg, vbif_base + VENUS_VBIF_AXI_HALT_CTRL0);
+
+	/* Request for AXI bus port halt */
+	rc = readl_poll_timeout(vbif_base + VENUS_VBIF_AXI_HALT_CTRL1,
+			reg, reg & VENUS_VBIF_AXI_HALT_CTRL1_HALT_ACK,
+			POLL_INTERVAL_US,
+			VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US);
+	if (rc)
+		dev_err(pil->dev, "Port halt timeout\n");
+
+	/* Assert the reset to ARM9 */
+	reg = readl_relaxed(wrapper_base + VENUS_WRAPPER_SW_RESET);
+	reg |= BIT(4);
+	writel_relaxed(reg, wrapper_base + VENUS_WRAPPER_SW_RESET);
+
+	/* Make sure reset is asserted before the mapping is removed */
+	mb();
+
+	msm_iommu_unmap_contig_buffer(0, drv->venus_domain_num,
+				      0, drv->fw_sz);
+
+	iommu_detach_device(drv->iommu_fw_domain, drv->iommu_fw_ctx);
+
+	venus_clock_disable_unprepare(pil->dev);
+
+	regulator_disable(drv->gdsc);
+
+	drv->is_booted = 0;
+
+	return 0;
+}
+
+static struct pil_reset_ops pil_venus_ops = {
+	.init_image = pil_venus_init_image,
+	.auth_and_reset = pil_venus_reset,
+	.shutdown = pil_venus_shutdown,
+	.proxy_vote = pil_venus_make_proxy_vote,
+	.proxy_unvote = pil_venus_remove_proxy_vote,
+};
+
+static int __devinit pil_venus_probe(struct platform_device *pdev)
+{
+	struct venus_data *drv;
+	struct resource *res;
+	struct pil_desc *desc;
+	int rc;
+
+	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->venus_wrapper_base = devm_ioremap(&pdev->dev, res->start,
+					resource_size(res));
+	if (!drv->venus_wrapper_base)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res)
+		return -EINVAL;
+
+	drv->venus_vbif_base = devm_ioremap(&pdev->dev, res->start,
+					resource_size(res));
+	if (!drv->venus_vbif_base)
+		return -ENOMEM;
+
+	drv->gdsc = devm_regulator_get(&pdev->dev, "vdd");
+	if (IS_ERR(drv->gdsc)) {
+		dev_err(&pdev->dev, "Failed to get Venus GDSC\n");
+		return -ENODEV;
+	}
+
+	rc = venus_clock_setup(&pdev->dev);
+	if (rc)
+		return rc;
+
+	drv->iommu_fw_ctx  = msm_iommu_get_ctx("venus_fw");
+	if (!drv->iommu_fw_ctx) {
+		dev_err(&pdev->dev, "No iommu fw context found\n");
+		return -ENODEV;
+	}
+
+	/* Get fw address boundaries */
+	rc = of_property_read_u32(pdev->dev.of_node,
+				  "qcom,firmware-max-paddr",
+				  &drv->fw_max_paddr);
+	if (rc) {
+		dev_err(&pdev->dev, "Failed to get fw max paddr\n");
+		return rc;
+	}
+
+	rc = of_property_read_u32(pdev->dev.of_node,
+				  "qcom,firmware-min-paddr",
+				  &drv->fw_min_paddr);
+	if (rc) {
+		dev_err(&pdev->dev, "Failed to get fw min paddr\n");
+		return rc;
+	}
+
+	if (drv->fw_max_paddr <= drv->fw_min_paddr) {
+		dev_err(&pdev->dev, "Invalid fw max paddr or min paddr\n");
+		return -EINVAL;
+	}
+
+	drv->venus_domain_num =
+		venus_register_domain(drv->fw_max_paddr - drv->fw_min_paddr);
+	if (drv->venus_domain_num < 0) {
+		dev_err(&pdev->dev, "Venus fw iommu domain register failed\n");
+		return -ENODEV;
+	}
+
+	drv->iommu_fw_domain = msm_get_iommu_domain(drv->venus_domain_num);
+	if (!drv->iommu_fw_domain) {
+		dev_err(&pdev->dev, "No iommu fw domain found\n");
+		return -ENODEV;
+	}
+
+	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+
+	rc = of_property_read_string(pdev->dev.of_node, "qcom,firmware-name",
+				      &desc->name);
+	if (rc)
+		return rc;
+
+	desc->dev = &pdev->dev;
+	desc->owner = THIS_MODULE;
+	desc->proxy_timeout = VENUS_PROXY_TIMEOUT;
+
+	/* TODO: need to add secure boot when the support is available */
+	desc->ops = &pil_venus_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_venus_remove(struct platform_device *pdev)
+{
+	struct venus_data *drv = platform_get_drvdata(pdev);
+	msm_pil_unregister(drv->pil);
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id msm_pil_venus_match[] = {
+	{.compatible = "qcom,pil-venus"},
+	{}
+};
+#endif
+
+static struct platform_driver pil_venus_driver = {
+	.probe = pil_venus_probe,
+	.remove = __devexit_p(pil_venus_remove),
+	.driver = {
+		.name = "pil_venus",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(msm_pil_venus_match),
+	},
+};
+
+module_platform_driver(pil_venus_driver);
+
+MODULE_DESCRIPTION("Support for booting VENUS processors");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index 428b998..48a236f 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -142,8 +142,8 @@
 	if (machine_is_msm8974_sim())
 		return krait_release_secondary_sim(0xf9088000, cpu);
 
-	if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_apq8064() ||
-	    cpu_is_msm8627())
+	if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
+	    cpu_is_apq8064() || cpu_is_msm8627())
 		return krait_release_secondary(0x02088000, cpu);
 
 	WARN(1, "unknown CPU case in release_secondary\n");
diff --git a/arch/arm/mach-msm/qdsp5/adsp.c b/arch/arm/mach-msm/qdsp5/adsp.c
index b485058..eee7e37 100644
--- a/arch/arm/mach-msm/qdsp5/adsp.c
+++ b/arch/arm/mach-msm/qdsp5/adsp.c
@@ -1262,7 +1262,7 @@
 			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);
+		INIT_HLIST_HEAD(&mod->ion_regions);
 		mod->pdev.name = adsp_info.module[i].pdev_name;
 		mod->pdev.id = -1;
 		adsp_info.id_to_module[i] = mod;
diff --git a/arch/arm/mach-msm/qdsp5/adsp.h b/arch/arm/mach-msm/qdsp5/adsp.h
index 0f16111..06e2f22 100644
--- a/arch/arm/mach-msm/qdsp5/adsp.h
+++ b/arch/arm/mach-msm/qdsp5/adsp.h
@@ -20,12 +20,16 @@
 
 #include <linux/types.h>
 #include <linux/msm_adsp.h>
+#include <linux/ion.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,
+int adsp_ion_do_cache_op(struct msm_adsp_module *module, void *addr,
+			void *paddr, unsigned long len,
+			unsigned long offset, int cmd);
+int adsp_ion_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);
@@ -276,8 +280,8 @@
 	struct clk *clk;
 	int open_count;
 
-	struct mutex pmem_regions_lock;
-	struct hlist_head pmem_regions;
+	struct mutex ion_regions_lock;
+	struct hlist_head ion_regions;
 	int (*verify_cmd) (struct msm_adsp_module*, unsigned int, void *,
 			   size_t);
 	int (*patch_event) (struct msm_adsp_module*, struct adsp_event *);
diff --git a/arch/arm/mach-msm/qdsp5/adsp_driver.c b/arch/arm/mach-msm/qdsp5/adsp_driver.c
index 6860d84..9d261ae 100644
--- a/arch/arm/mach-msm/qdsp5/adsp_driver.c
+++ b/arch/arm/mach-msm/qdsp5/adsp_driver.c
@@ -1,7 +1,7 @@
 /* arch/arm/mach-msm/qdsp5/adsp_driver.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: Iliyan Malchev <ibm@android.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -23,25 +23,27 @@
 #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 {
+struct adsp_ion_info {
 	int fd;
 	void *vaddr;
 };
 
-struct adsp_pmem_region {
+struct adsp_ion_region {
 	struct hlist_node list;
 	void *vaddr;
 	unsigned long paddr;
 	unsigned long kvaddr;
 	unsigned long len;
+	unsigned long ion_flag;
 	struct file *file;
+	struct ion_handle *handle;
+	struct ion_client *client;
+	int fd;
 };
 
 struct adsp_device {
@@ -90,14 +92,14 @@
 	res;							\
 })
 
-static int adsp_pmem_check(struct msm_adsp_module *module,
+static int adsp_ion_check(struct msm_adsp_module *module,
 		void *vaddr, unsigned long len)
 {
-	struct adsp_pmem_region *region_elt;
+	struct adsp_ion_region *region_elt;
 	struct hlist_node *node;
-	struct adsp_pmem_region t = { .vaddr = vaddr, .len = len };
+	struct adsp_ion_region t = { .vaddr = vaddr, .len = len };
 
-	hlist_for_each_entry(region_elt, node, &module->pmem_regions, list) {
+	hlist_for_each_entry(region_elt, node, &module->ion_regions, list) {
 		if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
 		    OVERLAPS(region_elt, &t)) {
 			MM_ERR("module %s:"
@@ -116,58 +118,109 @@
 	return 0;
 }
 
-static int adsp_pmem_add(struct msm_adsp_module *module,
-			 struct adsp_pmem_info *info)
+static int get_ion_region_info(int fd, struct adsp_ion_region *region)
 {
-	unsigned long paddr, kvaddr, len;
-	struct file *file;
-	struct adsp_pmem_region *region;
+	unsigned long ionflag;
+	void *temp_ptr;
 	int rc = -EINVAL;
 
-	mutex_lock(&module->pmem_regions_lock);
-	region = kmalloc(sizeof(*region), GFP_KERNEL);
+	region->client = msm_ion_client_create(UINT_MAX, "Video_Client");
+	if (IS_ERR_OR_NULL(region->client)) {
+		pr_err("Unable to create ION client\n");
+		goto client_error;
+	}
+	region->handle = ion_import_dma_buf(region->client, fd);
+	if (IS_ERR_OR_NULL(region->handle)) {
+		pr_err("%s: could not get handle of the given fd\n", __func__);
+		goto import_error;
+	}
+	rc = ion_handle_get_flags(region->client, region->handle, &ionflag);
+	if (rc) {
+		pr_err("%s: could not get flags for the handle\n", __func__);
+		goto flag_error;
+	}
+	temp_ptr = ion_map_kernel(region->client, region->handle, ionflag);
+	if (IS_ERR_OR_NULL(temp_ptr)) {
+		pr_err("%s: could not get virtual address\n", __func__);
+		goto map_error;
+	}
+	region->kvaddr = (unsigned long) temp_ptr;
+	region->ion_flag = (unsigned long) ionflag;
+
+	rc = ion_phys(region->client, region->handle, &region->paddr,
+					(size_t *)(&region->len));
+	if (rc) {
+		pr_err("%s: could not get physical address\n", __func__);
+		goto ion_error;
+	}
+	return rc;
+ion_error:
+	ion_unmap_kernel(region->client, region->handle);
+map_error:
+	ion_free(region->client, region->handle);
+flag_error:
+import_error:
+	ion_client_destroy(region->client);
+client_error:
+	return -EINVAL;
+}
+
+static void free_ion_region(struct ion_client *client,
+			struct ion_handle *handle)
+{
+	ion_unmap_kernel(client, handle);
+	ion_free(client, handle);
+	ion_client_destroy(client);
+}
+
+static int adsp_ion_add(struct msm_adsp_module *module,
+			 struct adsp_ion_info *info)
+{
+	struct adsp_ion_region *region;
+	int rc = -EINVAL;
+	mutex_lock(&module->ion_regions_lock);
+	region = kmalloc(sizeof(struct adsp_ion_region), GFP_KERNEL);
 	if (!region) {
 		rc = -ENOMEM;
 		goto end;
 	}
 	INIT_HLIST_NODE(&region->list);
-	if (get_pmem_file(info->fd, &paddr, &kvaddr, &len, &file)) {
+	if (get_ion_region_info(info->fd, region)) {
 		kfree(region);
 		goto end;
 	}
 
-	rc = adsp_pmem_check(module, info->vaddr, len);
+	rc = adsp_ion_check(module, info->vaddr, region->len);
 	if (rc < 0) {
-		put_pmem_file(file);
+		free_ion_region(region->client, region->handle);
 		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);
+	region->fd = info->fd;
+	region->file = NULL;
+	MM_INFO("adsp_ion_add: module %s: fd %d, vaddr Ox%x, len %d\n",
+			module->name, region->fd, (unsigned int)region->vaddr,
+			(int)region->len);
+	hlist_add_head(&region->list, &module->ion_regions);
 end:
-	mutex_unlock(&module->pmem_regions_lock);
+	mutex_unlock(&module->ion_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)
+static int adsp_ion_lookup_vaddr(struct msm_adsp_module *module, void **addr,
+		     unsigned long len, struct adsp_ion_region **region)
 {
 	struct hlist_node *node;
 	void *vaddr = *addr;
-	struct adsp_pmem_region *region_elt;
+	struct adsp_ion_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) {
+	hlist_for_each_entry(region_elt, node, &module->ion_regions, list) {
 		if (vaddr >= region_elt->vaddr &&
 		    vaddr < region_elt->vaddr + region_elt->len &&
 		    vaddr + len <= region_elt->vaddr + region_elt->len) {
@@ -186,7 +239,7 @@
 			"multiple hits for vaddr %p, len %ld\n",
 			module->name, vaddr, len);
 		hlist_for_each_entry(region_elt, node,
-				&module->pmem_regions, list) {
+				&module->ion_regions, list) {
 			if (vaddr >= region_elt->vaddr &&
 			    vaddr < region_elt->vaddr + region_elt->len &&
 			    vaddr + len <= region_elt->vaddr + region_elt->len)
@@ -200,16 +253,37 @@
 	return *region ? 0 : -1;
 }
 
-int adsp_pmem_fixup_kvaddr(struct msm_adsp_module *module, void **addr,
+int adsp_ion_do_cache_op(struct msm_adsp_module *module,
+				void *addr, void *paddr, unsigned long len,
+				unsigned long offset, int cmd)
+{
+	struct adsp_ion_region   *region;
+	void *vaddr = addr;
+	int ret;
+	ret = adsp_ion_lookup_vaddr(module, &vaddr, len, &region);
+	if (ret) {
+		MM_ERR("not patching %s (paddr & kvaddr)," \
+			" lookup (%p, %ld) failed\n",
+			module->name, vaddr, len);
+		return ret;
+	}
+	if ((region->ion_flag == CACHED) && region->handle) {
+		len = ((((len) + 31) & (~31)) + 32);
+		ret = msm_ion_do_cache_op(region->client, region->handle,
+				(void *)paddr, len, cmd);
+	}
+	return ret;
+}
+int adsp_ion_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;
+	struct adsp_ion_region *region;
 	void *vaddr = *addr;
 	unsigned long *paddr = (unsigned long *)addr;
 	int ret;
 
-	ret = adsp_pmem_lookup_vaddr(module, addr, len, &region);
+	ret = adsp_ion_lookup_vaddr(module, addr, len, &region);
 	if (ret) {
 		MM_ERR("not patching %s (paddr & kvaddr),"
 			" lookup (%p, %ld) failed\n",
@@ -228,12 +302,12 @@
 int adsp_pmem_fixup(struct msm_adsp_module *module, void **addr,
 		    unsigned long len)
 {
-	struct adsp_pmem_region *region;
+	struct adsp_ion_region *region;
 	void *vaddr = *addr;
 	unsigned long *paddr = (unsigned long *)addr;
 	int ret;
 
-	ret = adsp_pmem_lookup_vaddr(module, addr, len, &region);
+	ret = adsp_ion_lookup_vaddr(module, addr, len, &region);
 	if (ret) {
 		MM_ERR("not patching %s, lookup (%p, %ld) failed\n",
 			module->name, vaddr, len);
@@ -281,7 +355,7 @@
 		goto end;
 	}
 
-	mutex_lock(&adev->module->pmem_regions_lock);
+	mutex_lock(&adev->module->ion_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;
@@ -291,7 +365,7 @@
 	wmb();
 	rc = msm_adsp_write(adev->module, cmd.queue, cmd_data, cmd.len);
 end:
-	mutex_unlock(&adev->module->pmem_regions_lock);
+	mutex_unlock(&adev->module->ion_regions_lock);
 
 	if (cmd.len > 256)
 		kfree(cmd_data);
@@ -309,14 +383,14 @@
 	return yes || adev->abort;
 }
 
-static int adsp_pmem_lookup_paddr(struct msm_adsp_module *module, void **addr,
-		     struct adsp_pmem_region **region)
+static int adsp_ion_lookup_paddr(struct msm_adsp_module *module, void **addr,
+		     struct adsp_ion_region **region)
 {
 	struct hlist_node *node;
 	unsigned long paddr = (unsigned long)(*addr);
-	struct adsp_pmem_region *region_elt;
+	struct adsp_ion_region *region_elt;
 
-	hlist_for_each_entry(region_elt, node, &module->pmem_regions, list) {
+	hlist_for_each_entry(region_elt, node, &module->ion_regions, list) {
 		if (paddr >= region_elt->paddr &&
 		    paddr < region_elt->paddr + region_elt->len) {
 			*region = region_elt;
@@ -328,12 +402,12 @@
 
 int adsp_pmem_paddr_fixup(struct msm_adsp_module *module, void **addr)
 {
-	struct adsp_pmem_region *region;
+	struct adsp_ion_region *region;
 	unsigned long paddr = (unsigned long)(*addr);
 	unsigned long *vaddr = (unsigned long *)addr;
 	int ret;
 
-	ret = adsp_pmem_lookup_paddr(module, addr, &region);
+	ret = adsp_ion_lookup_paddr(module, addr, &region);
 	if (ret) {
 		MM_ERR("not patching %s, paddr %p lookup failed\n",
 			module->name, vaddr);
@@ -429,20 +503,23 @@
 	return rc;
 }
 
-static int adsp_pmem_del(struct msm_adsp_module *module)
+static int adsp_ion_del(struct msm_adsp_module *module)
 {
 	struct hlist_node *node, *tmp;
-	struct adsp_pmem_region *region;
+	struct adsp_ion_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);
+	mutex_lock(&module->ion_regions_lock);
+	hlist_for_each_safe(node, tmp, &module->ion_regions) {
+		region = hlist_entry(node, struct adsp_ion_region, list);
 		hlist_del(node);
-		put_pmem_file(region->file);
+		MM_INFO("adsp_ion_del: module %s: fd %d, vaddr Ox%x, len %d\n",
+			module->name, region->fd, (unsigned int)region->vaddr,
+			(int)region->len);
+		free_ion_region(region->client, region->handle);
 		kfree(region);
 	}
-	mutex_unlock(&module->pmem_regions_lock);
-	BUG_ON(!hlist_empty(&module->pmem_regions));
+	mutex_unlock(&module->ion_regions_lock);
+	BUG_ON(!hlist_empty(&module->ion_regions));
 
 	return 0;
 }
@@ -479,10 +556,10 @@
 	}
 
 	case ADSP_IOCTL_REGISTER_PMEM: {
-		struct adsp_pmem_info info;
+		struct adsp_ion_info info;
 		if (copy_from_user(&info, (void *) arg, sizeof(info)))
 			return -EFAULT;
-		return adsp_pmem_add(adev->module, &info);
+		return adsp_ion_add(adev->module, &info);
 	}
 
 	case ADSP_IOCTL_ABORT_EVENT_READ:
@@ -491,7 +568,7 @@
 		break;
 
 	case ADSP_IOCTL_UNREGISTER_PMEM:
-		return adsp_pmem_del(adev->module);
+		return adsp_ion_del(adev->module);
 
 	default:
 		break;
@@ -510,7 +587,7 @@
 	/* clear module before putting it to avoid race with open() */
 	adev->module = NULL;
 
-	rc = adsp_pmem_del(module);
+	rc = adsp_ion_del(module);
 
 	msm_adsp_put(module);
 	return rc;
@@ -581,8 +658,8 @@
 	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);
+	INIT_HLIST_HEAD(&adev->module->ion_regions);
+	mutex_init(&adev->module->ion_regions_lock);
 
 	return 0;
 }
diff --git a/arch/arm/mach-msm/qdsp5/adsp_video_verify_cmd.c b/arch/arm/mach-msm/qdsp5/adsp_video_verify_cmd.c
index 492fa0e..af259b5 100644
--- a/arch/arm/mach-msm/qdsp5/adsp_video_verify_cmd.c
+++ b/arch/arm/mach-msm/qdsp5/adsp_video_verify_cmd.c
@@ -3,7 +3,7 @@
  * Verificion code for aDSP VDEC packets from userspace.
  *
  * Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ * 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
@@ -55,7 +55,7 @@
 	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,
+		if (adsp_ion_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,
@@ -77,6 +77,7 @@
 static int verify_vdec_pkt_cmd(struct msm_adsp_module *module,
 			       void *cmd_data, size_t cmd_size)
 {
+	void *phys_addr;
 	unsigned short cmd_id = ((unsigned short *)cmd_data)[0];
 	viddec_cmd_subframe_pkt *pkt;
 	unsigned long subframe_pkt_addr;
@@ -89,7 +90,6 @@
 	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,
@@ -102,6 +102,8 @@
 		return -1;
 
 	pkt = (viddec_cmd_subframe_pkt *)cmd_data;
+	phys_addr = high_low_short_to_ptr(pkt->subframe_packet_high,
+				pkt->subframe_packet_low);
 
 	if (pmem_fixup_high_low(&(pkt->subframe_packet_high),
 				&(pkt->subframe_packet_low),
@@ -114,16 +116,12 @@
 		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;
-		}
+	if (adsp_ion_do_cache_op(module, phys_addr, (void *)subframe_pkt_addr,
+		subframe_pkt_size*2, offset, ION_IOC_INV_CACHES)){
+		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;
@@ -241,19 +239,14 @@
 			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;
-		}
+	/*Flush the cached mem subframe packet before sending to DSP*/
+	if (adsp_ion_do_cache_op(module,  phys_addr, (void *)subframe_pkt_addr,
+		MAX_FLUSH_SIZE, offset, ION_IOC_CLEAN_CACHES)){
+		MM_ERR("Cache operation failed for" \
+			" phys addr high %x addr low %x\n",
+			pkt->subframe_packet_high, pkt->subframe_packet_low);
+		return -EINVAL;
 	}
-
 	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
index 936b7af..290a14c 100644
--- a/arch/arm/mach-msm/qdsp5/adsp_videoenc_verify_cmd.c
+++ b/arch/arm/mach-msm/qdsp5/adsp_videoenc_verify_cmd.c
@@ -3,7 +3,7 @@
  * Verificion code for aDSP VENC packets from userspace.
  *
  * Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ * 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
@@ -53,7 +53,7 @@
 	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,
+	if (adsp_ion_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,
diff --git a/arch/arm/mach-msm/qdsp5/audio_aac.c b/arch/arm/mach-msm/qdsp5/audio_aac.c
index 725819f..15e0590 100644
--- a/arch/arm/mach-msm/qdsp5/audio_aac.c
+++ b/arch/arm/mach-msm/qdsp5/audio_aac.c
@@ -31,10 +31,10 @@
 #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 <linux/ion.h>
 
 #include <mach/msm_adsp.h>
 #include <mach/iommu.h>
@@ -181,6 +181,9 @@
 	int eq_needs_commit;
 	audpp_cmd_cfg_object_params_eqalizer eq;
 	audpp_cmd_cfg_object_params_volume vol_pan;
+	struct ion_client *client;
+	struct ion_handle *input_buff_handle;
+	struct ion_handle *output_buff_handle;
 };
 
 static int auddec_dsp_config(struct audio *audio, int enable);
@@ -1508,10 +1511,11 @@
 	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);
+	ion_unmap_kernel(audio->client, audio->output_buff_handle);
+	ion_free(audio->client, audio->output_buff_handle);
+	ion_unmap_kernel(audio->client, audio->input_buff_handle);
+	ion_free(audio->client, audio->input_buff_handle);
+	ion_client_destroy(audio->client);
 	mutex_unlock(&audio->lock);
 #ifdef CONFIG_DEBUG_FS
 	if (audio->dentry)
@@ -1653,8 +1657,13 @@
 {
 	struct audio *audio = NULL;
 	int rc, dec_attrb, decid, index, offset = 0;
-	unsigned pmem_sz = DMASZ;
+	unsigned mem_sz = DMASZ;
 	struct audaac_event *e_node = NULL;
+	int len = 0;
+	unsigned long ionflag = 0;
+	ion_phys_addr_t addr = 0;
+	struct ion_handle *handle = NULL;
+	struct ion_client *client = NULL;
 #ifdef CONFIG_DEBUG_FS
 	/* 4 bytes represents decoder number, 1 byte for terminate string */
 	char name[sizeof "msm_aac_" + 5];
@@ -1696,61 +1705,92 @@
 	}
 	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);
+	client = msm_ion_client_create(UINT_MAX, "Audio_AAC_client");
+	if (IS_ERR_OR_NULL(client)) {
+		MM_ERR("Unable to create ION client\n");
 		rc = -ENOMEM;
-		iounmap(audio->map_v_write);
-		free_contiguous_memory_by_paddr(audio->phys);
-		audpp_adec_free(audio->dec_id);
-		kfree(audio);
-		goto done;
+		goto client_create_error;
 	}
-	audio->map_v_read = ioremap(audio->read_phys,
-					PCM_BUFSZ_MIN * PCM_BUF_MAX_COUNT);
+	audio->client = client;
+
+	MM_DBG("allocating mem sz = %d\n", mem_sz);
+	handle = ion_alloc(client, mem_sz, SZ_4K,
+		ION_HEAP(ION_AUDIO_HEAP_ID));
+	if (IS_ERR_OR_NULL(handle)) {
+		MM_ERR("Unable to create allocate O/P buffers\n");
+		rc = -ENOMEM;
+		goto output_buff_alloc_error;
+	}
+
+	audio->output_buff_handle = handle;
+
+	rc = ion_phys(client, handle, &addr, &len);
+	if (rc) {
+		MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+			(unsigned int) addr, (unsigned int) len);
+		goto output_buff_get_phys_error;
+	} else {
+		MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+			(unsigned int) addr, (unsigned int) len);
+	}
+	audio->phys = (int32_t)addr;
+
+	rc = ion_handle_get_flags(client, handle, &ionflag);
+	if (rc) {
+		MM_ERR("could not get flags for the handle\n");
+		goto output_buff_get_flags_error;
+	}
+
+	audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+	if (IS_ERR(audio->map_v_write)) {
+		MM_ERR("could not map write buffers,freeing instance 0x%08x\n",
+				(int)audio);
+		rc = -ENOMEM;
+		goto output_buff_map_error;
+	}
+	audio->data = audio->map_v_write;
+	MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+		audio->phys, (int)audio->data);
+
+	audio->out_dma_sz = mem_sz;
+
+	mem_sz = (PCM_BUFSZ_MIN * PCM_BUF_MAX_COUNT);
+	MM_DBG("allocating mem sz = %d\n", mem_sz);
+	handle = ion_alloc(client, mem_sz,
+			SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+	if (IS_ERR_OR_NULL(handle)) {
+		MM_ERR("Unable to create allocate I/P buffers\n");
+		rc = -ENOMEM;
+		goto input_buff_alloc_error;
+	}
+
+	audio->input_buff_handle = handle;
+
+	rc = ion_phys(client , handle, &addr, &len);
+	if (rc) {
+		MM_ERR("I/P buffers:Invalid phy: %x sz: %x\n",
+			(unsigned int) addr, (unsigned int) len);
+		goto input_buff_get_phys_error;
+	} else {
+		MM_INFO("out Got valid phy: %x sz: %x\n",
+			(unsigned int) audio->read_phys, (unsigned int) len);
+	}
+	audio->read_phys = (int32_t)addr;
+
+	rc = ion_handle_get_flags(client,
+		handle, &ionflag);
+	if (rc) {
+		MM_ERR("could not get flags for the handle\n");
+		goto input_buff_get_flags_error;
+	}
+
+	audio->map_v_read = ion_map_kernel(client,
+		handle, ionflag);
 	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;
+		goto input_buff_map_error;
 	}
 	audio->read_data = audio->map_v_read;
 	MM_DBG("read buf: phy addr 0x%08x kernel addr 0x%08x\n",
@@ -1873,10 +1913,20 @@
 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);
+	ion_unmap_kernel(client, audio->input_buff_handle);
+input_buff_map_error:
+input_buff_get_flags_error:
+input_buff_get_phys_error:
+	ion_free(client, audio->input_buff_handle);
+input_buff_alloc_error:
+	ion_unmap_kernel(client, audio->output_buff_handle);
+output_buff_map_error:
+output_buff_get_phys_error:
+output_buff_get_flags_error:
+	ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+	ion_client_destroy(client);
+client_create_error:
 	audpp_adec_free(audio->dec_id);
 	kfree(audio);
 	return rc;
diff --git a/arch/arm/mach-msm/qdsp5/audio_aac_in.c b/arch/arm/mach-msm/qdsp5/audio_aac_in.c
index 79a828a..99e10a4 100644
--- a/arch/arm/mach-msm/qdsp5/audio_aac_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_aac_in.c
@@ -32,8 +32,8 @@
 #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 <linux/ion.h>
 
 #include "audmgr.h"
 
@@ -147,6 +147,9 @@
 	int enabled;
 	int running;
 	int stopped; /* set when stopped, cleared on flush */
+	struct ion_client *client;
+	struct ion_handle *input_buff_handle;
+	struct ion_handle *output_buff_handle;
 };
 
 struct audio_frame {
@@ -1248,16 +1251,17 @@
 
 	if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) && \
 	   (audio->out_data)) {
-		iounmap(audio->map_v_write);
-		free_contiguous_memory_by_paddr(audio->out_phys);
+		ion_unmap_kernel(audio->client, audio->input_buff_handle);
+		ion_free(audio->client, audio->input_buff_handle);
 		audio->out_data = NULL;
 	}
 
 	if (audio->data) {
-		iounmap(audio->map_v_read);
-		free_contiguous_memory_by_paddr(audio->phys);
+		ion_unmap_kernel(audio->client, audio->output_buff_handle);
+		ion_free(audio->client, audio->output_buff_handle);
 		audio->data = NULL;
 	}
+	ion_client_destroy(audio->client);
 	mutex_unlock(&audio->lock);
 	return 0;
 }
@@ -1270,6 +1274,11 @@
 	int rc;
 	int encid;
 	int dma_size = 0;
+	int len = 0;
+	unsigned long ionflag = 0;
+	ion_phys_addr_t addr = 0;
+	struct ion_handle *handle = NULL;
+	struct ion_client *client = NULL;
 
 	mutex_lock(&audio->lock);
 	if (audio->opened) {
@@ -1352,52 +1361,103 @@
 	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");
+
+	client = msm_ion_client_create(UINT_MAX, "Audio_AAC_in_client");
+	if (IS_ERR_OR_NULL(client)) {
+		MM_ERR("Unable to create ION client\n");
 		rc = -ENOMEM;
-		goto evt_error;
+		goto client_create_error;
 	}
-	MM_DBG("Memory addr = 0x%8x  phy addr = 0x%8x\n",\
-		(int) audio->data, (int) audio->phys);
+	audio->client = client;
+
+	MM_DBG("allocating mem sz = %d\n", dma_size);
+	handle = ion_alloc(client, dma_size, SZ_4K,
+		ION_HEAP(ION_AUDIO_HEAP_ID));
+	if (IS_ERR_OR_NULL(handle)) {
+		MM_ERR("Unable to create allocate O/P buffers\n");
+		rc = -ENOMEM;
+		goto output_buff_alloc_error;
+	}
+
+	audio->output_buff_handle = handle;
+
+	rc = ion_phys(client , handle, &addr, &len);
+	if (rc) {
+		MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+			(unsigned int) addr, (unsigned int) len);
+		rc = -ENOMEM;
+		goto output_buff_get_phys_error;
+	} else {
+		MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+			(unsigned int) addr, (unsigned int) len);
+	}
+	audio->phys = (int32_t)addr;
+
+	rc = ion_handle_get_flags(client, handle, &ionflag);
+	if (rc) {
+		MM_ERR("could not get flags for the handle\n");
+		rc = -ENOMEM;
+		goto output_buff_get_flags_error;
+	}
+
+	audio->map_v_read = ion_map_kernel(client, handle, ionflag);
+	if (IS_ERR(audio->map_v_read)) {
+		MM_ERR("could not map read buffers,freeing instance 0x%08x\n",
+				(int)audio);
+		rc = -ENOMEM;
+		goto output_buff_map_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 write buffers\n");
+
+		MM_DBG("allocating BUFFER_SIZE  %d\n", BUFFER_SIZE);
+		handle = ion_alloc(client, BUFFER_SIZE,
+				SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+		if (IS_ERR_OR_NULL(handle)) {
+			MM_ERR("Unable to create allocate I/P 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);
+			goto input_buff_alloc_error;
 		}
 
+		audio->input_buff_handle = handle;
+
+		rc = ion_phys(client , handle, &addr, &len);
+		if (rc) {
+			MM_ERR("I/P buffers:Invalid phy: %x sz: %x\n",
+				(unsigned int) addr, (unsigned int) len);
+			rc = -ENOMEM;
+			goto input_buff_get_phys_error;
+		} else {
+			MM_INFO("Got valid phy: %x sz: %x\n",
+				(unsigned int) addr,
+				(unsigned int) len);
+		}
+		audio->out_phys = (int32_t)addr;
+
+		rc = ion_handle_get_flags(client,
+			handle, &ionflag);
+		if (rc) {
+			MM_ERR("could not get flags for the handle\n");
+			rc = -ENOMEM;
+			goto input_buff_get_flags_error;
+		}
+
+		audio->map_v_write = ion_map_kernel(client,
+			handle, ionflag);
+		if (IS_ERR(audio->map_v_write)) {
+			MM_ERR("could not map write buffers\n");
+			rc = -ENOMEM;
+			goto input_buff_map_error;
+		}
+		audio->out_data = audio->map_v_write;
+		MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+					(unsigned int)addr,
+					(unsigned int)audio->out_data);
+
 		/* Initialize buffer */
 		audio->out[0].data = audio->out_data + 0;
 		audio->out[0].addr = audio->out_phys + 0;
@@ -1419,7 +1479,19 @@
 done:
 	mutex_unlock(&audio->lock);
 	return rc;
-evt_error:
+input_buff_map_error:
+input_buff_get_flags_error:
+input_buff_get_phys_error:
+	ion_free(client, audio->input_buff_handle);
+input_buff_alloc_error:
+	ion_unmap_kernel(client, audio->output_buff_handle);
+output_buff_map_error:
+output_buff_get_phys_error:
+output_buff_get_flags_error:
+	ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+	ion_client_destroy(client);
+client_create_error:
 	msm_adsp_put(audio->audrec);
 	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
 		msm_adsp_put(audio->audpre);
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrnb.c b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
index 1a1002e..45fa045 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrnb.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
@@ -39,10 +39,10 @@
 #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/ion.h>
 
 #include <mach/msm_adsp.h>
 #include <mach/iommu.h>
@@ -179,6 +179,9 @@
 	int eq_needs_commit;
 	audpp_cmd_cfg_object_params_eqalizer eq;
 	audpp_cmd_cfg_object_params_volume vol_pan;
+	struct ion_client *client;
+	struct ion_handle *input_buff_handle;
+	struct ion_handle *output_buff_handle;
 };
 
 struct audpp_cmd_cfg_adec_params_amrnb {
@@ -784,6 +787,10 @@
 	uint16_t enable_mask;
 	int enable;
 	int prev_state;
+	unsigned long ionflag = 0;
+	ion_phys_addr_t addr = 0;
+	struct ion_handle *handle = NULL;
+	int len = 0;
 
 	MM_DBG("cmd = %d\n", cmd);
 
@@ -970,23 +977,53 @@
 			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) {
+				handle = ion_alloc(audio->client,
+					(config.buffer_size *
+					config.buffer_count),
+					SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+				if (IS_ERR_OR_NULL(handle)) {
+					MM_ERR("Unable to alloc I/P buffs\n");
+					audio->input_buff_handle = NULL;
 					rc = -ENOMEM;
 					break;
-			}
-			audio->map_v_read = ioremap(
-						audio->read_phys,
-						config.buffer_size *
-						config.buffer_count);
+				}
+
+				audio->input_buff_handle = handle;
+
+				rc = ion_phys(audio->client ,
+					handle, &addr, &len);
+				if (rc) {
+					MM_ERR("Invalid phy: %x sz: %x\n",
+						(unsigned int) addr,
+						(unsigned int) len);
+					ion_free(audio->client, handle);
+					audio->input_buff_handle = NULL;
+					rc = -ENOMEM;
+					break;
+				} else {
+					MM_INFO("Got valid phy: %x sz: %x\n",
+						(unsigned int) audio->read_phys,
+						(unsigned int) len);
+				}
+				audio->read_phys = (int32_t)addr;
+
+				rc = ion_handle_get_flags(audio->client,
+					handle, &ionflag);
+				if (rc) {
+					MM_ERR("could not get flags\n");
+					ion_free(audio->client, handle);
+					audio->input_buff_handle = NULL;
+					rc = -ENOMEM;
+					break;
+				}
+				audio->map_v_read = ion_map_kernel(
+					audio->client,
+					handle, ionflag);
 			if (IS_ERR(audio->map_v_read)) {
 				MM_ERR("failed to map read buf\n");
+				ion_free(audio->client, handle);
+				audio->input_buff_handle = NULL;
 				rc = -ENOMEM;
-				free_contiguous_memory_by_paddr(
-							audio->read_phys);
 			} else {
 				uint8_t index;
 				uint32_t offset = 0;
@@ -1295,12 +1332,13 @@
 	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);
+	ion_unmap_kernel(audio->client, audio->output_buff_handle);
+	ion_free(audio->client, audio->output_buff_handle);
+	if (audio->input_buff_handle != NULL) {
+		ion_unmap_kernel(audio->client, audio->input_buff_handle);
+		ion_free(audio->client, audio->input_buff_handle);
 	}
+	ion_client_destroy(audio->client);
 	mutex_unlock(&audio->lock);
 #ifdef CONFIG_DEBUG_FS
 	if (audio->dentry)
@@ -1439,6 +1477,12 @@
 	struct audio *audio = NULL;
 	int rc, dec_attrb, decid, i;
 	struct audamrnb_event *e_node = NULL;
+	unsigned mem_sz = DMASZ;
+	unsigned long ionflag = 0;
+	ion_phys_addr_t addr = 0;
+	struct ion_handle *handle = NULL;
+	struct ion_client *client = NULL;
+	int len = 0;
 #ifdef CONFIG_DEBUG_FS
 	/* 4 bytes represents decoder number, 1 byte for terminate string */
 	char name[sizeof "msm_amrnb_" + 5];
@@ -1482,30 +1526,50 @@
 
 	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);
+	client = msm_ion_client_create(UINT_MAX, "Audio_AMR_NB_Client");
+	if (IS_ERR_OR_NULL(client)) {
+		pr_err("Unable to create ION client\n");
 		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);
+		goto client_create_error;
 	}
+	audio->client = client;
+
+	handle = ion_alloc(client, mem_sz, SZ_4K,
+		ION_HEAP(ION_AUDIO_HEAP_ID));
+	if (IS_ERR_OR_NULL(handle)) {
+		MM_ERR("Unable to create allocate O/P buffers\n");
+		rc = -ENOMEM;
+		goto output_buff_alloc_error;
+	}
+	audio->output_buff_handle = handle;
+
+	rc = ion_phys(client, handle, &addr, &len);
+	if (rc) {
+		MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+			(unsigned int) addr, (unsigned int) len);
+		goto output_buff_get_phys_error;
+	} else {
+		MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+			(unsigned int) addr, (unsigned int) len);
+	}
+	audio->phys = (int32_t)addr;
+
+
+	rc = ion_handle_get_flags(client, handle, &ionflag);
+	if (rc) {
+		MM_ERR("could not get flags for the handle\n");
+		goto output_buff_get_flags_error;
+	}
+
+	audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+	if (IS_ERR(audio->map_v_write)) {
+		MM_ERR("could not map write buffers\n");
+		rc = -ENOMEM;
+		goto output_buff_map_error;
+	}
+	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);
@@ -1536,6 +1600,8 @@
 		goto err;
 	}
 
+	audio->input_buff_handle = NULL;
+
 	mutex_init(&audio->lock);
 	mutex_init(&audio->write_lock);
 	mutex_init(&audio->read_lock);
@@ -1590,8 +1656,14 @@
 done:
 	return rc;
 err:
-	iounmap(audio->map_v_write);
-	free_contiguous_memory_by_paddr(audio->phys);
+	ion_unmap_kernel(client, audio->output_buff_handle);
+output_buff_map_error:
+output_buff_get_phys_error:
+output_buff_get_flags_error:
+	ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+	ion_client_destroy(client);
+client_create_error:
 	audpp_adec_free(audio->dec_id);
 	kfree(audio);
 	return rc;
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c b/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
index ac2b5ca..39578c1 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
@@ -36,8 +36,8 @@
 #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 <linux/ion.h>
 
 #include "audmgr.h"
 
@@ -151,6 +151,9 @@
 	uint8_t enabled;
 	uint8_t running;
 	uint8_t stopped; /* set when stopped, cleared on flush */
+	struct ion_client *client;
+	struct ion_handle *input_buff_handle;
+
 };
 
 struct audio_frame {
@@ -1207,8 +1210,8 @@
 	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);
+		ion_unmap_kernel(audio->client, audio->input_buff_handle);
+		ion_free(audio->client, audio->input_buff_handle);
 		audio->out_data = NULL;
 	}
 	if (audio->data) {
@@ -1221,6 +1224,7 @@
 			dma_size, audio->data, audio->phys);
 		audio->data = NULL;
 	}
+	ion_client_destroy(audio->client);
 	mutex_unlock(&audio->lock);
 	return 0;
 }
@@ -1233,6 +1237,11 @@
 	int32_t rc;
 	int encid;
 	int32_t dma_size = 0;
+	int len = 0;
+	unsigned long ionflag = 0;
+	ion_phys_addr_t addr = 0;
+	struct ion_handle *handle = NULL;
+	struct ion_client *client = NULL;
 
 	mutex_lock(&audio->lock);
 	if (audio->opened) {
@@ -1320,34 +1329,60 @@
 		goto evt_error;
 	}
 
+	client = msm_ion_client_create(UINT_MAX, "Audio_AMRNB_in_client");
+	if (IS_ERR_OR_NULL(client)) {
+		MM_ERR("Unable to create ION client\n");
+		rc = -ENOMEM;
+		goto client_create_error;
+	}
+	audio->client = client;
+
 	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");
+		MM_DBG("allocating BUFFER_SIZE  %d\n", BUFFER_SIZE);
+		handle = ion_alloc(client, BUFFER_SIZE,
+				SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+		if (IS_ERR_OR_NULL(handle)) {
+			MM_ERR("Unable to create 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);
+			goto input_buff_alloc_error;
 		}
 
+		audio->input_buff_handle = handle;
+
+		rc = ion_phys(client , handle, &addr, &len);
+		if (rc) {
+			MM_ERR("I/P buffers:Invalid phy: %x sz: %x\n",
+				(unsigned int) addr, (unsigned int) len);
+			rc = -ENOMEM;
+			goto input_buff_get_phys_error;
+		} else {
+			MM_INFO("Got valid phy: %x sz: %x\n",
+				(unsigned int) addr,
+				(unsigned int) len);
+		}
+		audio->out_phys = (int32_t)addr;
+
+		rc = ion_handle_get_flags(client,
+			handle, &ionflag);
+		if (rc) {
+			MM_ERR("could not get flags for the handle\n");
+			rc = -ENOMEM;
+			goto input_buff_get_flags_error;
+		}
+
+		audio->map_v_write = ion_map_kernel(client,
+			handle, ionflag);
+		if (IS_ERR(audio->map_v_write)) {
+			MM_ERR("could not map write buffers\n");
+			rc = -ENOMEM;
+			goto input_buff_map_error;
+		}
+		audio->out_data = audio->map_v_write;
+		MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+					(unsigned int)addr,
+					(unsigned int)audio->out_data);
+
 		/* Initialize buffer */
 		audio->out[0].data = audio->out_data + 0;
 		audio->out[0].addr = audio->out_phys + 0;
@@ -1369,6 +1404,14 @@
 done:
 	mutex_unlock(&audio->lock);
 	return rc;
+input_buff_map_error:
+input_buff_get_phys_error:
+input_buff_get_flags_error:
+	ion_free(client, audio->input_buff_handle);
+input_buff_alloc_error:
+	ion_client_destroy(client);
+client_create_error:
+	dma_free_coherent(NULL, dma_size, audio->data, audio->phys);
 evt_error:
 	msm_adsp_put(audio->audrec);
 	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrwb.c b/arch/arm/mach-msm/qdsp5/audio_amrwb.c
index b85b153..66b9354 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrwb.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrwb.c
@@ -38,10 +38,10 @@
 #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/ion.h>
 
 #include <mach/msm_adsp.h>
 #include <mach/iommu.h>
@@ -180,6 +180,9 @@
 	int eq_needs_commit;
 	audpp_cmd_cfg_object_params_eqalizer eq;
 	audpp_cmd_cfg_object_params_volume vol_pan;
+	struct ion_client *client;
+	struct ion_handle *input_buff_handle;
+	struct ion_handle *output_buff_handle;
 };
 
 static int auddec_dsp_config(struct audio *audio, int enable);
@@ -773,6 +776,10 @@
 	uint16_t enable_mask;
 	int enable;
 	int prev_state;
+	unsigned long ionflag = 0;
+	ion_phys_addr_t addr = 0;
+	struct ion_handle *handle = NULL;
+	int len = 0;
 
 	MM_DBG("cmd = %d\n", cmd);
 
@@ -966,23 +973,53 @@
 		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) {
+				handle = ion_alloc(audio->client,
+					(config.buffer_size *
+					config.buffer_count),
+					SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+				if (IS_ERR_OR_NULL(handle)) {
+					MM_ERR("Unable to alloc I/P buffs\n");
+					audio->input_buff_handle = NULL;
 					rc = -ENOMEM;
 					break;
-			}
-			audio->map_v_read = ioremap(
-						audio->read_phys,
-						config.buffer_size *
-						config.buffer_count);
+				}
+
+				audio->input_buff_handle = handle;
+
+				rc = ion_phys(audio->client ,
+					handle, &addr, &len);
+				if (rc) {
+					MM_ERR("Invalid phy: %x sz: %x\n",
+						(unsigned int) addr,
+						(unsigned int) len);
+					ion_free(audio->client, handle);
+					audio->input_buff_handle = NULL;
+					rc = -ENOMEM;
+					break;
+				} else {
+					MM_INFO("Got valid phy: %x sz: %x\n",
+						(unsigned int) audio->read_phys,
+						(unsigned int) len);
+				}
+				audio->read_phys = (int32_t)addr;
+
+				rc = ion_handle_get_flags(audio->client,
+					handle, &ionflag);
+				if (rc) {
+					MM_ERR("could not get flags\n");
+					ion_free(audio->client, handle);
+					audio->input_buff_handle = NULL;
+					rc = -ENOMEM;
+					break;
+				}
+				audio->map_v_read = ion_map_kernel(
+					audio->client,
+					handle, ionflag);
 			if (IS_ERR(audio->map_v_read)) {
 				MM_ERR("failed to map mem for read buf\n");
+				ion_free(audio->client, handle);
+				audio->input_buff_handle = NULL;
 				rc = -ENOMEM;
-				free_contiguous_memory_by_paddr(
-							audio->read_phys);
 			} else {
 				uint8_t index;
 				uint32_t offset = 0;
@@ -1024,7 +1061,8 @@
 }
 
 /* Only useful in tunnel-mode */
-static int audamrwb_fsync(struct file *file, loff_t a, loff_t b, int datasync)
+static int audamrwb_fsync(struct file *file, loff_t a, loff_t b,
+	int datasync)
 {
 	struct audio *audio = file->private_data;
 	struct buffer *frame;
@@ -1363,12 +1401,13 @@
 	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);
+	ion_unmap_kernel(audio->client, audio->output_buff_handle);
+	ion_free(audio->client, audio->output_buff_handle);
+	if (audio->input_buff_handle != NULL) {
+		ion_unmap_kernel(audio->client, audio->input_buff_handle);
+		ion_free(audio->client, audio->input_buff_handle);
 	}
+	ion_client_destroy(audio->client);
 	mutex_unlock(&audio->lock);
 #ifdef CONFIG_DEBUG_FS
 	if (audio->dentry)
@@ -1509,8 +1548,14 @@
 static int audamrwb_open(struct inode *inode, struct file *file)
 {
 	struct audio *audio = NULL;
-	int rc, dec_attrb, decid, i;
+	int rc = 0, dec_attrb, decid, i;
 	struct audamrwb_event *e_node = NULL;
+	unsigned mem_sz = DMASZ;
+	unsigned long ionflag = 0;
+	ion_phys_addr_t addr = 0;
+	struct ion_handle *handle = NULL;
+	struct ion_client *client = NULL;
+	int len = 0;
 #ifdef CONFIG_DEBUG_FS
 	/* 4 bytes represents decoder number, 1 byte for terminate string */
 	char name[sizeof "msm_amrwb_" + 5];
@@ -1545,30 +1590,49 @@
 
 	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);
+	client = msm_ion_client_create(UINT_MAX, "Audio_AMR_WB_Client");
+	if (IS_ERR_OR_NULL(client)) {
+		pr_err("Unable to create ION client\n");
 		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);
+		goto client_create_error;
 	}
+	audio->client = client;
+
+	handle = ion_alloc(client, mem_sz, SZ_4K,
+		ION_HEAP(ION_AUDIO_HEAP_ID));
+	if (IS_ERR_OR_NULL(handle)) {
+		MM_ERR("Unable to create allocate O/P buffers\n");
+		goto output_buff_alloc_error;
+	}
+	audio->output_buff_handle = handle;
+
+	rc = ion_phys(client, handle, &addr, &len);
+	if (rc) {
+		MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+			(unsigned int) addr, (unsigned int) len);
+		goto output_buff_get_phys_error;
+	} else {
+		MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+			(unsigned int) addr, (unsigned int) len);
+	}
+	audio->phys = (int32_t)addr;
+
+
+	rc = ion_handle_get_flags(client, handle, &ionflag);
+	if (rc) {
+		MM_ERR("could not get flags for the handle\n");
+		goto output_buff_get_flags_error;
+	}
+
+	audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+	if (IS_ERR(audio->map_v_write)) {
+		MM_ERR("could not map write buffers\n");
+		rc = -ENOMEM;
+		goto output_buff_map_error;
+	}
+	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);
@@ -1599,6 +1663,7 @@
 		goto err;
 	}
 
+	audio->input_buff_handle = NULL;
 	mutex_init(&audio->lock);
 	mutex_init(&audio->write_lock);
 	mutex_init(&audio->read_lock);
@@ -1658,8 +1723,14 @@
 done:
 	return rc;
 err:
-	iounmap(audio->map_v_write);
-	free_contiguous_memory_by_paddr(audio->phys);
+	ion_unmap_kernel(client, audio->output_buff_handle);
+output_buff_map_error:
+output_buff_get_phys_error:
+output_buff_get_flags_error:
+	ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+	ion_client_destroy(client);
+client_create_error:
 	audpp_adec_free(audio->dec_id);
 	kfree(audio);
 	return rc;
diff --git a/arch/arm/mach-msm/qdsp5/audio_evrc.c b/arch/arm/mach-msm/qdsp5/audio_evrc.c
index 489929b..1d4148a 100644
--- a/arch/arm/mach-msm/qdsp5/audio_evrc.c
+++ b/arch/arm/mach-msm/qdsp5/audio_evrc.c
@@ -33,10 +33,10 @@
 #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/ion.h>
 
 #include <mach/msm_adsp.h>
 #include <mach/iommu.h>
@@ -175,6 +175,9 @@
 	int eq_needs_commit;
 	audpp_cmd_cfg_object_params_eqalizer eq;
 	audpp_cmd_cfg_object_params_volume vol_pan;
+	struct ion_client *client;
+	struct ion_handle *input_buff_handle;
+	struct ion_handle *output_buff_handle;
 };
 
 static int auddec_dsp_config(struct audio *audio, int enable);
@@ -770,6 +773,10 @@
 	uint16_t enable_mask;
 	int enable;
 	int prev_state;
+	unsigned long ionflag = 0;
+	ion_phys_addr_t addr = 0;
+	struct ion_handle *handle = NULL;
+	int len = 0;
 
 	MM_DBG("cmd = %d\n", cmd);
 
@@ -955,25 +962,54 @@
 				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) {
+				handle = ion_alloc(audio->client,
+					(config.buffer_size *
+					config.buffer_count),
+					SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+				if (IS_ERR_OR_NULL(handle)) {
+					MM_ERR("Unable to alloc I/P buffs\n");
+					audio->input_buff_handle = NULL;
 					rc = -ENOMEM;
 					break;
 				}
-				audio->map_v_read = ioremap(
-							audio->read_phys,
-							config.buffer_size *
-							config.buffer_count);
+
+				audio->input_buff_handle = handle;
+
+				rc = ion_phys(audio->client ,
+					handle, &addr, &len);
+				if (rc) {
+					MM_ERR("Invalid phy: %x sz: %x\n",
+						(unsigned int) addr,
+						(unsigned int) len);
+					ion_free(audio->client, handle);
+					audio->input_buff_handle = NULL;
+					rc = -ENOMEM;
+					break;
+				} else {
+					MM_INFO("Got valid phy: %x sz: %x\n",
+						(unsigned int) audio->read_phys,
+						(unsigned int) len);
+				}
+				audio->read_phys = (int32_t)addr;
+
+				rc = ion_handle_get_flags(audio->client,
+					handle, &ionflag);
+				if (rc) {
+					MM_ERR("could not get flags\n");
+					ion_free(audio->client, handle);
+					audio->input_buff_handle = NULL;
+					rc = -ENOMEM;
+					break;
+				}
+				audio->map_v_read = ion_map_kernel(
+					audio->client,
+					handle, ionflag);
 				if (IS_ERR(audio->map_v_read)) {
 					MM_ERR("failed to map mem"
 							" for read buf\n");
+					ion_free(audio->client, handle);
+					audio->input_buff_handle = NULL;
 					rc = -ENOMEM;
-					free_contiguous_memory_by_paddr(
-							audio->read_phys);
 				} else {
 					uint8_t index;
 					uint32_t offset = 0;
@@ -1287,12 +1323,13 @@
 	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);
+	ion_unmap_kernel(audio->client, audio->output_buff_handle);
+	ion_free(audio->client, audio->output_buff_handle);
+	if (audio->input_buff_handle != NULL) {
+		ion_unmap_kernel(audio->client, audio->input_buff_handle);
+		ion_free(audio->client, audio->input_buff_handle);
 	}
+	ion_client_destroy(audio->client);
 	mutex_unlock(&audio->lock);
 #ifdef CONFIG_DEBUG_FS
 	if (audio->dentry)
@@ -1431,6 +1468,13 @@
 	struct audio *audio = NULL;
 	int rc, dec_attrb, decid, i;
 	struct audevrc_event *e_node = NULL;
+	unsigned mem_sz = DMASZ;
+	unsigned long ionflag = 0;
+	ion_phys_addr_t addr = 0;
+	struct ion_handle *handle = NULL;
+	struct ion_client *client = NULL;
+	int len = 0;
+
 #ifdef CONFIG_DEBUG_FS
 	/* 4 bytes represents decoder number, 1 byte for terminate string */
 	char name[sizeof "msm_evrc_" + 5];
@@ -1473,29 +1517,50 @@
 
 	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);
+	client = msm_ion_client_create(UINT_MAX, "Audio_EVRC_Client");
+	if (IS_ERR_OR_NULL(client)) {
+		pr_err("Unable to create ION client\n");
 		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);
+		goto client_create_error;
 	}
+	audio->client = client;
+
+	handle = ion_alloc(client, mem_sz, SZ_4K,
+		ION_HEAP(ION_AUDIO_HEAP_ID));
+	if (IS_ERR_OR_NULL(handle)) {
+		MM_ERR("Unable to create allocate O/P buffers\n");
+		rc = -ENOMEM;
+		goto output_buff_alloc_error;
+	}
+	audio->output_buff_handle = handle;
+
+	rc = ion_phys(client, handle, &addr, &len);
+	if (rc) {
+		MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+			(unsigned int) addr, (unsigned int) len);
+		goto output_buff_get_phys_error;
+	} else {
+		MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+			(unsigned int) addr, (unsigned int) len);
+	}
+	audio->phys = (int32_t)addr;
+
+
+	rc = ion_handle_get_flags(client, handle, &ionflag);
+	if (rc) {
+		MM_ERR("could not get flags for the handle\n");
+		goto output_buff_get_flags_error;
+	}
+
+	audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+	if (IS_ERR(audio->map_v_write)) {
+		MM_ERR("could not map write buffers\n");
+		rc = -ENOMEM;
+		goto output_buff_map_error;
+	}
+	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);
@@ -1527,6 +1592,8 @@
 		goto err;
 	}
 
+	audio->input_buff_handle = NULL;
+
 	/* Initialize all locks of audio instance */
 	mutex_init(&audio->lock);
 	mutex_init(&audio->write_lock);
@@ -1582,8 +1649,14 @@
 done:
 	return rc;
 err:
-	iounmap(audio->map_v_write);
-	free_contiguous_memory_by_paddr(audio->phys);
+	ion_unmap_kernel(client, audio->output_buff_handle);
+output_buff_map_error:
+output_buff_get_phys_error:
+output_buff_get_flags_error:
+	ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+	ion_client_destroy(client);
+client_create_error:
 	audpp_adec_free(audio->dec_id);
 	kfree(audio);
 	return rc;
diff --git a/arch/arm/mach-msm/qdsp5/audio_evrc_in.c b/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
index e13b072..e955c4b 100644
--- a/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
@@ -33,6 +33,7 @@
 
 
 #include <linux/memory_alloc.h>
+#include <linux/ion.h>
 
 #include <asm/atomic.h>
 #include <asm/ioctls.h>
@@ -150,6 +151,9 @@
 	int enabled;
 	int running;
 	int stopped; /* set when stopped, cleared on flush */
+	struct ion_client *client;
+	struct ion_handle *input_buff_handle;
+	struct ion_handle *output_buff_handle;
 };
 
 struct audio_frame {
@@ -1003,7 +1007,8 @@
 	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
-static int audevrc_in_fsync(struct file *file,loff_t a, loff_t b, int datasync)
+static int audevrc_in_fsync(struct file *file, loff_t a, loff_t b,
+	int datasync)
 
 {
 	struct audio_evrc_in *audio = file->private_data;
@@ -1190,15 +1195,16 @@
 	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);
+		ion_unmap_kernel(audio->client, audio->input_buff_handle);
+		ion_free(audio->client, audio->input_buff_handle);
 		audio->out_data = NULL;
 	}
 	if (audio->data) {
-		iounmap(audio->map_v_read);
-		free_contiguous_memory_by_paddr(audio->phys);
+		ion_unmap_kernel(audio->client, audio->output_buff_handle);
+		ion_free(audio->client, audio->output_buff_handle);
 		audio->data = NULL;
 	}
+	ion_client_destroy(audio->client);
 	mutex_unlock(&audio->lock);
 	return 0;
 }
@@ -1211,6 +1217,11 @@
 	int rc;
 	int encid;
 	int dma_size = 0;
+	int len = 0;
+	unsigned long ionflag = 0;
+	ion_phys_addr_t addr = 0;
+	struct ion_handle *handle = NULL;
+	struct ion_client *client = NULL;
 
 	mutex_lock(&audio->lock);
 	if (audio->opened) {
@@ -1290,51 +1301,101 @@
 	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");
+	client = msm_ion_client_create(UINT_MAX, "Audio_EVRC_in_client");
+	if (IS_ERR_OR_NULL(client)) {
+		MM_ERR("Unable to create ION client\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);
+		goto client_create_error;
 	}
+	audio->client = client;
+
+	MM_DBG("allocating mem sz = %d\n", dma_size);
+	handle = ion_alloc(client, dma_size, SZ_4K,
+		ION_HEAP(ION_AUDIO_HEAP_ID));
+	if (IS_ERR_OR_NULL(handle)) {
+		MM_ERR("Unable to create allocate O/P buffers\n");
+		rc = -ENOMEM;
+		goto output_buff_alloc_error;
+	}
+
+	audio->output_buff_handle = handle;
+
+	rc = ion_phys(client , handle, &addr, &len);
+	if (rc) {
+		MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+			(unsigned int) addr, (unsigned int) len);
+		rc = -ENOMEM;
+		goto output_buff_get_phys_error;
+	} else {
+		MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+			(unsigned int) addr, (unsigned int) len);
+	}
+	audio->phys = (int32_t)addr;
+
+	rc = ion_handle_get_flags(client, handle, &ionflag);
+	if (rc) {
+		MM_ERR("could not get flags for the handle\n");
+		rc = -ENOMEM;
+		goto output_buff_get_flags_error;
+	}
+
+	audio->map_v_read = ion_map_kernel(client, handle, ionflag);
+	if (IS_ERR(audio->map_v_read)) {
+		MM_ERR("could not map read buffers,freeing instance 0x%08x\n",
+				(int)audio);
+		rc = -ENOMEM;
+		goto output_buff_map_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");
+		MM_DBG("allocating BUFFER_SIZE  %d\n", BUFFER_SIZE);
+		handle = ion_alloc(client, BUFFER_SIZE,
+				SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+		if (IS_ERR_OR_NULL(handle)) {
+			MM_ERR("Unable to create allocate I/P 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);
+			goto input_buff_alloc_error;
 		}
 
+		audio->input_buff_handle = handle;
+
+		rc = ion_phys(client , handle, &addr, &len);
+		if (rc) {
+			MM_ERR("I/P buffers:Invalid phy: %x sz: %x\n",
+				(unsigned int) addr, (unsigned int) len);
+			rc = -ENOMEM;
+			goto input_buff_alloc_error;
+		} else {
+			MM_INFO("Got valid phy: %x sz: %x\n",
+				(unsigned int) addr,
+				(unsigned int) len);
+		}
+		audio->out_phys = (int32_t)addr;
+
+		rc = ion_handle_get_flags(client,
+			handle, &ionflag);
+		if (rc) {
+			MM_ERR("could not get flags for the handle\n");
+			rc = -ENOMEM;
+			goto input_buff_alloc_error;
+		}
+
+		audio->map_v_write = ion_map_kernel(client,
+			handle, ionflag);
+		if (IS_ERR(audio->map_v_write)) {
+			MM_ERR("could not map write buffers\n");
+			rc = -ENOMEM;
+			goto input_buff_map_error;
+		}
+		audio->out_data = audio->map_v_write;
+		MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+					(unsigned int)addr,
+					(unsigned int)audio->out_data);
+
 		/* Initialize buffer */
 		audio->out[0].data = audio->out_data + 0;
 		audio->out[0].addr = audio->out_phys + 0;
@@ -1356,7 +1417,17 @@
 done:
 	mutex_unlock(&audio->lock);
 	return rc;
-evt_error:
+input_buff_map_error:
+	ion_free(client, audio->input_buff_handle);
+input_buff_alloc_error:
+	ion_unmap_kernel(client, audio->output_buff_handle);
+output_buff_map_error:
+output_buff_get_phys_error:
+output_buff_get_flags_error:
+	ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+	ion_client_destroy(client);
+client_create_error:
 	msm_adsp_put(audio->audrec);
 	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
 		msm_adsp_put(audio->audpre);
diff --git a/arch/arm/mach-msm/qdsp5/audio_lpa.c b/arch/arm/mach-msm/qdsp5/audio_lpa.c
index 8754337..14a9e57 100644
--- a/arch/arm/mach-msm/qdsp5/audio_lpa.c
+++ b/arch/arm/mach-msm/qdsp5/audio_lpa.c
@@ -37,8 +37,8 @@
 #include <linux/debugfs.h>
 #include <linux/delay.h>
 #include <linux/earlysuspend.h>
+#include <linux/ion.h>
 #include <linux/list.h>
-#include <linux/android_pmem.h>
 #include <linux/slab.h>
 #include <linux/msm_audio.h>
 
@@ -137,9 +137,9 @@
 	union msm_audio_event_payload payload;
 };
 
-struct audlpa_pmem_region {
+struct audlpa_ion_region {
 	struct list_head list;
-	struct file *file;
+	struct ion_handle *handle;
 	int fd;
 	void *vaddr;
 	unsigned long paddr;
@@ -217,9 +217,10 @@
 	struct mutex get_event_lock;
 	int event_abort;
 
-	struct list_head pmem_region_queue;
+	struct list_head ion_region_queue;
 	int buffer_count;
 	int buffer_size;
+	struct ion_client *client;
 };
 
 static int auddec_dsp_config(struct audio *audio, int enable);
@@ -227,7 +228,7 @@
 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,
+static unsigned long audlpa_ion_fixup(struct audio *audio, void *addr,
 	unsigned long len, int ref_up);
 static void audpcm_async_send_data(struct audio *audio,
 	unsigned needed);
@@ -679,7 +680,7 @@
 
 	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,
+		audlpa_ion_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
 				  drv_evt->payload.aio_buf.buf_len, 0);
 		mutex_unlock(&audio->lock);
 	}
@@ -689,94 +690,118 @@
 	return rc;
 }
 
-static int audlpa_pmem_check(struct audio *audio,
+static int audlpa_ion_check(struct audio *audio,
 		void *vaddr, unsigned long len)
 {
-	struct audlpa_pmem_region *region_elt;
-	struct audlpa_pmem_region t = { .vaddr = vaddr, .len = len };
+	struct audlpa_ion_region *region_elt;
+	struct audlpa_ion_region t = {.vaddr = vaddr, .len = len };
 
-	list_for_each_entry(region_elt, &audio->pmem_region_queue, list) {
+	list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
 		if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
 		    OVERLAPS(region_elt, &t)) {
-			MM_ERR("region (vaddr %p len %ld)"
+			MM_ERR("[%p]:region (vaddr %p len %ld)"
 				" clashes with registered region"
 				" (vaddr %p paddr %p len %ld)\n",
-				vaddr, len,
+				audio, vaddr, len,
 				region_elt->vaddr,
-				(void *)region_elt->paddr,
-				region_elt->len);
+				(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)
+static int audlpa_ion_add(struct audio *audio,
+			struct msm_audio_ion_info *info)
 {
-	unsigned long paddr, kvaddr, len;
-	struct file *file;
-	struct audlpa_pmem_region *region;
+	ion_phys_addr_t paddr;
+	size_t len;
+	unsigned long kvaddr;
+	struct audlpa_ion_region *region;
 	int rc = -EINVAL;
+	struct ion_handle *handle;
+	unsigned long ionflag;
 
-	MM_DBG("\n"); /* Macro prints the file name and function */
+	MM_ERR("\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;
+	handle = ion_import_dma_buf(audio->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 = audlpa_pmem_check(audio, info->vaddr, len);
+	rc = ion_handle_get_flags(audio->client, handle, &ionflag);
+	if (rc) {
+		pr_err("%s: could not get flags for the handle\n", __func__);
+		goto flag_error;
+	}
+	kvaddr = (unsigned long)ion_map_kernel(audio->client, handle, ionflag);
+	if (IS_ERR_OR_NULL((void *)kvaddr)) {
+		pr_err("%s: could not get virtual address\n", __func__);
+		goto map_error;
+	}
+	rc = ion_phys(audio->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) {
-		put_pmem_file(file);
-		kfree(region);
-		goto end;
+		MM_ERR("audpcm_ion_check failed\n");
+		goto ion_error;
 	}
-
+	region->handle = handle;
 	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);
+	MM_DBG("[%p]:add region paddr %lx vaddr %p, len %lu kvaddr %lx\n",
+		audio, region->paddr, region->vaddr,
+		region->len, region->kvaddr);
+	list_add_tail(&region->list, &audio->ion_region_queue);
+
+	return rc;
+
+ion_error:
+	ion_unmap_kernel(audio->client, handle);
+map_error:
+flag_error:
+	ion_free(audio->client, handle);
+import_error:
+	kfree(region);
 end:
 	return rc;
 }
 
-static int audlpa_pmem_remove(struct audio *audio,
-	struct msm_audio_pmem_info *info)
+static int audlpa_ion_remove(struct audio *audio,
+			struct msm_audio_ion_info *info)
 {
-	struct audlpa_pmem_region *region;
+	struct audlpa_ion_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->ion_region_queue) {
+		region = list_entry(ptr, struct audlpa_ion_region, list);
 
-	list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
-		region = list_entry(ptr, struct audlpa_pmem_region, list);
-
-		if ((region->fd == info->fd) &&
+		if (region != NULL && (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);
+				MM_DBG("%s[%p]:region %p in use ref_cnt %d\n",
+					__func__, audio, 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);
+			ion_unmap_kernel(audio->client, region->handle);
+			ion_free(audio->client, region->handle);
 			kfree(region);
 			rc = 0;
 			break;
@@ -786,23 +811,20 @@
 	return rc;
 }
 
-static int audlpa_pmem_lookup_vaddr(struct audio *audio, void *addr,
-		     unsigned long len, struct audlpa_pmem_region **region)
+static int audlpa_ion_lookup_vaddr(struct audio *audio, void *addr,
+			unsigned long len, struct audlpa_ion_region **region)
 {
-	struct audlpa_pmem_region *region_elt;
-
+	struct audlpa_ion_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) {
+	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
-			 * pmem buffer
+			 * ion buffer
 			 */
 
 			match_count++;
@@ -812,31 +834,33 @@
 	}
 
 	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) {
+		MM_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)
-				MM_ERR("\t%p, %ld --> %p\n", region_elt->vaddr,
+			addr < region_elt->vaddr + region_elt->len &&
+			addr + len <= region_elt->vaddr + region_elt->len)
+					MM_ERR("\t%s[%p]:%p, %ld --> %p\n",
+						__func__, audio,
+						region_elt->vaddr,
 						region_elt->len,
 						(void *)region_elt->paddr);
 		}
 	}
-
 	return *region ? 0 : -1;
 }
-
-unsigned long audlpa_pmem_fixup(struct audio *audio, void *addr,
+static unsigned long audlpa_ion_fixup(struct audio *audio, void *addr,
 		    unsigned long len, int ref_up)
 {
-	struct audlpa_pmem_region *region;
+	struct audlpa_ion_region *region;
 	unsigned long paddr;
 	int ret;
 
-	ret = audlpa_pmem_lookup_vaddr(audio, addr, len, &region);
+	ret = audlpa_ion_lookup_vaddr(audio, addr, len, &region);
 	if (ret) {
-		MM_ERR("lookup (%p, %ld) failed\n", addr, len);
+		MM_ERR("%s[%p]:lookup (%p, %ld) failed\n",
+			__func__, audio, addr, len);
 		return 0;
 	}
 	if (ref_up)
@@ -870,10 +894,9 @@
 			buf_node->buf.buf_addr, buf_node->buf.buf_len,
 			buf_node->buf.data_len);
 
-	buf_node->paddr = audlpa_pmem_fixup(
+	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 ||
@@ -1042,23 +1065,23 @@
 		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");
+	case AUDIO_REGISTER_ION: {
+		struct msm_audio_ion_info info;
+		MM_ERR("AUDIO_REGISTER_ION\n");
 			if (copy_from_user(&info, (void *) arg, sizeof(info)))
 				rc = -EFAULT;
 			else
-				rc = audlpa_pmem_add(audio, &info);
+				rc = audlpa_ion_add(audio, &info);
 			break;
 		}
 
-	case AUDIO_DEREGISTER_PMEM: {
-			struct msm_audio_pmem_info info;
-			MM_DBG("AUDIO_DEREGISTER_PMEM\n");
+	case AUDIO_DEREGISTER_ION: {
+		struct msm_audio_ion_info info;
+		MM_ERR("AUDIO_DEREGISTER_ION\n");
 			if (copy_from_user(&info, (void *) arg, sizeof(info)))
 				rc = -EFAULT;
 			else
-				rc = audlpa_pmem_remove(audio, &info);
+				rc = audlpa_ion_remove(audio, &info);
 			break;
 		}
 
@@ -1175,7 +1198,8 @@
 	return rc;
 }
 
-int audlpa_fsync(struct file *file, loff_t a, loff_t b, int datasync)
+int audlpa_fsync(struct file *file, loff_t a, loff_t b,
+	int datasync)
 {
 	struct audio *audio = file->private_data;
 
@@ -1185,21 +1209,21 @@
 	return audlpa_async_fsync(audio);
 }
 
-static void audpcm_reset_pmem_region(struct audio *audio)
+static void audpcm_reset_ion_region(struct audio *audio)
 {
-	struct audlpa_pmem_region *region;
+	struct audlpa_ion_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_for_each_safe(ptr, next, &audio->ion_region_queue) {
+		region = list_entry(ptr, struct audlpa_ion_region, list);
 		list_del(&region->list);
-		put_pmem_file(region->file);
+		ion_unmap_kernel(audio->client, region->handle);
+		ion_free(audio->client, region->handle);
 		kfree(region);
 	}
 
 	return;
 }
-
 static int audio_release(struct inode *inode, struct file *file)
 {
 	struct audio *audio = file->private_data;
@@ -1210,7 +1234,7 @@
 	if (audio->rmt_resource_released == 0)
 		rmt_put_resource(audio);
 	audpcm_async_flush(audio);
-	audpcm_reset_pmem_region(audio);
+	audpcm_reset_ion_region(audio);
 
 	msm_adsp_put(audio->audplay);
 	audpp_adec_free(audio->dec_id);
@@ -1221,16 +1245,12 @@
 	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
+	ion_client_destroy(audio->client);
 	kfree(audio);
 	return 0;
 }
@@ -1416,7 +1436,7 @@
 	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->ion_region_queue);
 	INIT_LIST_HEAD(&audio->free_event_queue);
 	INIT_LIST_HEAD(&audio->event_queue);
 	init_waitqueue_head(&audio->wait);
@@ -1456,6 +1476,14 @@
 			break;
 		}
 	}
+
+	audio->client = msm_ion_client_create(UINT_MAX, "Audio_LPA_Client");
+	if (IS_ERR_OR_NULL(audio->client)) {
+		pr_err("Unable to create ION client\n");
+		goto err;
+	}
+	MM_DBG("Ion client created\n");
+
 done:
 	return rc;
 err:
diff --git a/arch/arm/mach-msm/qdsp5/audio_mp3.c b/arch/arm/mach-msm/qdsp5/audio_mp3.c
index 9346107..427dc8f 100644
--- a/arch/arm/mach-msm/qdsp5/audio_mp3.c
+++ b/arch/arm/mach-msm/qdsp5/audio_mp3.c
@@ -31,10 +31,10 @@
 #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 <linux/ion.h>
 
 #include <mach/msm_adsp.h>
 #include <mach/iommu.h>
@@ -136,9 +136,9 @@
 	union msm_audio_event_payload payload;
 };
 
-struct audmp3_pmem_region {
+struct audmp3_ion_region {
 	struct list_head list;
-	struct file *file;
+	struct ion_handle *handle;
 	int fd;
 	void *vaddr;
 	unsigned long paddr;
@@ -241,13 +241,16 @@
 	struct mutex get_event_lock;
 	int event_abort;
 
-	struct list_head pmem_region_queue; /* protected by lock */
+	struct list_head ion_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;
+	struct ion_client *client;
+	struct ion_handle *input_buff_handle;
+	struct ion_handle *output_buff_handle;
 };
 
 static int auddec_dsp_config(struct audio *audio, int enable);
@@ -259,7 +262,7 @@
 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,
+static unsigned long audmp3_ion_fixup(struct audio *audio, void *addr,
 				unsigned long len, int ref_up);
 
 static int rmt_put_resource(struct audio *audio)
@@ -1021,7 +1024,7 @@
 	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,
+		audmp3_ion_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
 				  drv_evt->payload.aio_buf.buf_len, 0);
 		mutex_unlock(&audio->lock);
 	}
@@ -1036,13 +1039,13 @@
 	return rc;
 }
 
-static int audmp3_pmem_check(struct audio *audio,
+static int audmp3_ion_check(struct audio *audio,
 		void *vaddr, unsigned long len)
 {
-	struct audmp3_pmem_region *region_elt;
-	struct audmp3_pmem_region t = { .vaddr = vaddr, .len = len };
+	struct audmp3_ion_region *region_elt;
+	struct audmp3_ion_region t = { .vaddr = vaddr, .len = len };
 
-	list_for_each_entry(region_elt, &audio->pmem_region_queue, list) {
+	list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
 		if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
 		    OVERLAPS(region_elt, &t)) {
 			MM_ERR("region (vaddr %p len %ld)"
@@ -1059,13 +1062,17 @@
 	return 0;
 }
 
-static int audmp3_pmem_add(struct audio *audio,
-	struct msm_audio_pmem_info *info)
+static int audmp3_ion_add(struct audio *audio,
+			struct msm_audio_ion_info *info)
 {
-	unsigned long paddr, kvaddr, len;
-	struct file *file;
-	struct audmp3_pmem_region *region;
+	ion_phys_addr_t paddr;
+	size_t len;
+	unsigned long kvaddr;
+	struct audmp3_ion_region *region;
 	int rc = -EINVAL;
+	struct ion_handle *handle;
+	unsigned long ionflag;
+	void *temp_ptr;
 
 	MM_DBG("\n"); /* Macro prints the file name and function */
 	region = kmalloc(sizeof(*region), GFP_KERNEL);
@@ -1075,55 +1082,84 @@
 		goto end;
 	}
 
-	if (get_pmem_file(info->fd, &paddr, &kvaddr, &len, &file)) {
-		kfree(region);
-		goto end;
+	handle = ion_import_dma_buf(audio->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 = audmp3_pmem_check(audio, info->vaddr, len);
+	rc = ion_handle_get_flags(audio->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(audio->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(audio->client, handle, &paddr, &len);
+	if (rc) {
+		pr_err("%s: could not get physical address\n", __func__);
+		goto ion_error;
+	}
+
+	rc = audmp3_ion_check(audio, info->vaddr, len);
 	if (rc < 0) {
-		put_pmem_file(file);
-		kfree(region);
-		goto end;
+		MM_ERR("audpcm_ion_check failed\n");
+		goto ion_error;
 	}
 
+	region->handle = handle;
 	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);
+	MM_DBG("[%p]:add region paddr %lx vaddr %p, len %lu kvaddr %lx\n",
+		audio, region->paddr, region->vaddr,
+		region->len, region->kvaddr);
+	list_add_tail(&region->list, &audio->ion_region_queue);
+	return rc;
+
+ion_error:
+	ion_unmap_kernel(audio->client, handle);
+map_error:
+flag_error:
+	ion_free(audio->client, handle);
+import_error:
+	kfree(region);
 end:
 	return rc;
 }
 
-static int audmp3_pmem_remove(struct audio *audio,
-	struct msm_audio_pmem_info *info)
+static int audmp3_ion_remove(struct audio *audio,
+			struct msm_audio_ion_info *info)
 {
-	struct audmp3_pmem_region *region;
+	struct audmp3_ion_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->ion_region_queue) {
+		region = list_entry(ptr, struct audmp3_ion_region, list);
 
-	list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
-		region = list_entry(ptr, struct audmp3_pmem_region, list);
-
-		if ((region->fd == info->fd) &&
+		if (region != NULL && (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);
+				MM_DBG("%s[%p]:region %p in use ref_cnt %d\n",
+					__func__, audio, region,
+					region->ref_cnt);
 				break;
 			}
-			MM_DBG("remove region fd %d vaddr %p \n",
-					info->fd, info->vaddr);
+			MM_DBG("remove region fd %d vaddr %p\n",
+				info->fd, info->vaddr);
 			list_del(&region->list);
-			put_pmem_file(region->file);
+			ion_unmap_kernel(audio->client, region->handle);
+			ion_free(audio->client, region->handle);
 			kfree(region);
 			rc = 0;
 			break;
@@ -1133,23 +1169,20 @@
 	return rc;
 }
 
-static int audmp3_pmem_lookup_vaddr(struct audio *audio, void *addr,
-		     unsigned long len, struct audmp3_pmem_region **region)
+static int audmp3_ion_lookup_vaddr(struct audio *audio, void *addr,
+			unsigned long len, struct audmp3_ion_region **region)
 {
-	struct audmp3_pmem_region *region_elt;
-
+	struct audmp3_ion_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) {
+	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
-			 * pmem buffer
+			 * ion buffer
 			 */
 
 			match_count++;
@@ -1159,29 +1192,31 @@
 	}
 
 	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) {
+		MM_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)
-				MM_ERR("\t%p, %ld --> %p\n", region_elt->vaddr,
+			addr < region_elt->vaddr + region_elt->len &&
+			addr + len <= region_elt->vaddr + region_elt->len)
+					MM_ERR("\t%s[%p]:%p, %ld --> %p\n",
+						__func__, audio,
+						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 audmp3_ion_fixup(struct audio *audio, void *addr,
 		    unsigned long len, int ref_up)
 {
-	struct audmp3_pmem_region *region;
+	struct audmp3_ion_region *region;
 	unsigned long paddr;
 	int ret;
 
-	ret = audmp3_pmem_lookup_vaddr(audio, addr, len, &region);
+	ret = audmp3_ion_lookup_vaddr(audio, addr, len, &region);
 	if (ret) {
 		MM_ERR("lookup (%p, %ld) failed\n", addr, len);
 		return 0;
@@ -1217,7 +1252,7 @@
 			buf_node->buf.buf_addr, buf_node->buf.buf_len,
 			buf_node->buf.data_len);
 
-	buf_node->paddr = audmp3_pmem_fixup(
+	buf_node->paddr = audmp3_ion_fixup(
 		audio, buf_node->buf.buf_addr,
 		buf_node->buf.buf_len, 1);
 
@@ -1276,6 +1311,10 @@
 	uint16_t enable_mask;
 	int enable;
 	int prev_state;
+	unsigned long ionflag = 0;
+	ion_phys_addr_t addr = 0;
+	struct ion_handle *handle = NULL;
+	int len = 0;
 
 	MM_DBG("cmd = %d\n", cmd);
 
@@ -1481,25 +1520,50 @@
 				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) {
+
+				handle = ion_alloc(audio->client,
+					(config.buffer_size *
+					config.buffer_count),
+					SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+				if (IS_ERR_OR_NULL(handle)) {
+					MM_ERR("Unable to alloc I/P buffs\n");
 					rc = -ENOMEM;
 					break;
 				}
-				audio->map_v_read = ioremap(
-							audio->read_phys,
-							config.buffer_size *
-							config.buffer_count);
+
+				audio->input_buff_handle = handle;
+
+				rc = ion_phys(audio->client ,
+					handle, &addr, &len);
+				if (rc) {
+					MM_ERR("Invalid phy: %x sz: %x\n",
+						(unsigned int) addr,
+						(unsigned int) len);
+					rc = -ENOMEM;
+					break;
+				} else {
+					MM_INFO("Got valid phy: %x sz: %x\n",
+						(unsigned int) audio->read_phys,
+						(unsigned int) len);
+				}
+				audio->read_phys = (int32_t)addr;
+
+				rc = ion_handle_get_flags(audio->client,
+					handle, &ionflag);
+				if (rc) {
+					MM_ERR("could not get flags\n");
+					rc = -ENOMEM;
+					break;
+				}
+
+				audio->map_v_read = ion_map_kernel(
+					audio->client,
+					handle, ionflag);
 
 				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);
+					ion_free(audio->client, handle);
 				} else {
 					uint8_t index;
 					uint32_t offset = 0;
@@ -1539,23 +1603,23 @@
 		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");
+	case AUDIO_REGISTER_ION: {
+			struct msm_audio_ion_info info;
+			MM_DBG("AUDIO_REGISTER_ION\n");
 			if (copy_from_user(&info, (void *) arg, sizeof(info)))
 				rc = -EFAULT;
 			else
-				rc = audmp3_pmem_add(audio, &info);
+				rc = audmp3_ion_add(audio, &info);
 			break;
 		}
 
-	case AUDIO_DEREGISTER_PMEM: {
-			struct msm_audio_pmem_info info;
-			MM_DBG("AUDIO_DEREGISTER_PMEM\n");
+	case AUDIO_DEREGISTER_ION: {
+			struct msm_audio_ion_info info;
+			MM_DBG("AUDIO_DEREGISTER_ION\n");
 			if (copy_from_user(&info, (void *) arg, sizeof(info)))
 				rc = -EFAULT;
 			else
-				rc = audmp3_pmem_remove(audio, &info);
+				rc = audmp3_ion_remove(audio, &info);
 			break;
 		}
 	case AUDIO_ASYNC_WRITE:
@@ -1939,16 +2003,16 @@
 	}
 	return rc;
 }
-
-static void audmp3_reset_pmem_region(struct audio *audio)
+static void audmp3_reset_ion_region(struct audio *audio)
 {
-	struct audmp3_pmem_region *region;
+	struct audmp3_ion_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_for_each_safe(ptr, next, &audio->ion_region_queue) {
+		region = list_entry(ptr, struct audmp3_ion_region, list);
 		list_del(&region->list);
-		put_pmem_file(region->file);
+		ion_unmap_kernel(audio->client, region->handle);
+		ion_free(audio->client, region->handle);
 		kfree(region);
 	}
 
@@ -1966,7 +2030,7 @@
 		rmt_put_resource(audio);
 	audio->drv_ops.out_flush(audio);
 	audio->drv_ops.in_flush(audio);
-	audmp3_reset_pmem_region(audio);
+	audmp3_reset_ion_region(audio);
 
 	msm_adsp_put(audio->audplay);
 	audpp_adec_free(audio->dec_id);
@@ -1977,20 +2041,18 @@
 	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
+	if (!(audio->drv_status & ADRV_STATUS_AIO_INTF)) {
+		ion_unmap_kernel(audio->client, audio->output_buff_handle);
+		ion_free(audio->client, audio->output_buff_handle);
+		ion_unmap_kernel(audio->client, audio->input_buff_handle);
+		ion_free(audio->client, audio->input_buff_handle);
+	}
+	ion_client_destroy(audio->client);
 	kfree(audio);
 	return 0;
 }
@@ -2129,7 +2191,13 @@
 	struct audio *audio = NULL;
 	int rc, i, dec_attrb, decid;
 	struct audmp3_event *e_node = NULL;
-	unsigned pmem_sz = DMASZ_MAX;
+	unsigned mem_sz = DMASZ_MAX;
+	unsigned long ionflag = 0;
+	ion_phys_addr_t addr = 0;
+	struct ion_handle *handle = NULL;
+	struct ion_client *client = NULL;
+	int len = 0;
+
 #ifdef CONFIG_DEBUG_FS
 	/* 4 bytes represents decoder number, 1 byte for terminate string */
 	char name[sizeof "msm_mp3_" + 5];
@@ -2171,43 +2239,57 @@
 	}
 	audio->dec_id = decid & MSM_AUD_DECODER_MASK;
 
+	client = msm_ion_client_create(UINT_MAX, "Audio_MP3_Client");
+	if (IS_ERR_OR_NULL(client)) {
+		pr_err("Unable to create ION client\n");
+		rc = -ENOMEM;
+		goto client_create_error;
+	}
+	audio->client = client;
+
 	/* 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;
+
+		MM_DBG("memsz = %d\n", mem_sz);
+
+		handle = ion_alloc(client, mem_sz, SZ_4K,
+			ION_HEAP(ION_AUDIO_HEAP_ID));
+		if (IS_ERR_OR_NULL(handle)) {
+			MM_ERR("Unable to create allocate O/P buffers\n");
+			rc = -ENOMEM;
+			goto output_buff_alloc_error;
 		}
-		audio->out_dma_sz = pmem_sz;
+		audio->output_buff_handle = handle;
+
+		rc = ion_phys(client , handle, &addr, &len);
+		if (rc) {
+			MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+				(unsigned int) addr, (unsigned int) len);
+			goto output_buff_get_phys_error;
+		} else {
+			MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+				(unsigned int) addr, (unsigned int) len);
+		}
+		audio->phys = (int32_t)addr;
+
+
+		rc = ion_handle_get_flags(client, handle, &ionflag);
+		if (rc) {
+			MM_ERR("could not get flags for the handle\n");
+			goto output_buff_get_flags_error;
+		}
+
+		audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+		if (IS_ERR(audio->map_v_write)) {
+			MM_ERR("could not map write buffers\n");
+			rc = -ENOMEM;
+			goto output_buff_map_error;
+		}
+		audio->data = audio->map_v_write;
+		MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+			audio->phys, (int)audio->data);
+
+		audio->out_dma_sz = mem_sz;
 	}
 
 	if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK) {
@@ -2276,7 +2358,7 @@
 	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->ion_region_queue);
 	INIT_LIST_HEAD(&audio->free_event_queue);
 	INIT_LIST_HEAD(&audio->event_queue);
 	init_waitqueue_head(&audio->wait);
@@ -2315,13 +2397,18 @@
 			break;
 		}
 	}
+
 done:
 	return rc;
 err:
-	if (audio->data) {
-		iounmap(audio->map_v_write);
-		free_contiguous_memory_by_paddr(audio->phys);
-	}
+	ion_unmap_kernel(client, audio->output_buff_handle);
+output_buff_map_error:
+output_buff_get_flags_error:
+output_buff_get_phys_error:
+	ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+	ion_client_destroy(client);
+client_create_error:
 	audpp_adec_free(audio->dec_id);
 	kfree(audio);
 	return rc;
diff --git a/arch/arm/mach-msm/qdsp5/audio_mvs.c b/arch/arm/mach-msm/qdsp5/audio_mvs.c
index 9b524b4..158dd46 100644
--- a/arch/arm/mach-msm/qdsp5/audio_mvs.c
+++ b/arch/arm/mach-msm/qdsp5/audio_mvs.c
@@ -425,6 +425,8 @@
 		set_voc_mode_msg.min_rate = cpu_to_be32(audio->rate_type);
 		set_voc_mode_msg.max_rate = cpu_to_be32(audio->rate_type);
 
+		MM_DBG("audio->mvs_mode %d audio->rate_type %d\n",
+			audio->mvs_mode, audio->rate_type);
 		msm_rpc_setup_req(&set_voc_mode_msg.rpc_hdr,
 				  audio->rpc_prog,
 				  audio->rpc_ver,
@@ -923,10 +925,14 @@
 
 				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 */
+			} else if (frame_mode == MVS_FRAME_MODE_PCM_UL) {
+				/* PCM doesn'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);
@@ -1056,7 +1062,7 @@
 					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);
+					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 =
@@ -1488,7 +1494,8 @@
 	case AUDIO_GET_MVS_CONFIG: {
 		struct msm_audio_mvs_config config;
 
-		MM_DBG("IOCTL GET_MVS_CONFIG\n");
+		MM_DBG("GET_MVS_CONFIG mvs_mode %d rate_type %d\n",
+			config.mvs_mode, config.rate_type);
 
 		mutex_lock(&audio->lock);
 		config.mvs_mode = audio->mvs_mode;
diff --git a/arch/arm/mach-msm/qdsp5/audio_pcm.c b/arch/arm/mach-msm/qdsp5/audio_pcm.c
index 49c781f..880de09 100644
--- a/arch/arm/mach-msm/qdsp5/audio_pcm.c
+++ b/arch/arm/mach-msm/qdsp5/audio_pcm.c
@@ -38,7 +38,7 @@
 #include <linux/delay.h>
 #include <linux/earlysuspend.h>
 #include <linux/list.h>
-#include <linux/android_pmem.h>
+#include <linux/ion.h>
 #include <linux/slab.h>
 #include <linux/msm_audio.h>
 
@@ -134,11 +134,10 @@
 	union msm_audio_event_payload payload;
 };
 
-struct audpcm_pmem_region {
+struct audpcm_ion_region {
 	struct list_head list;
-	struct file *file;
+	struct ion_handle *handle;
 	int fd;
-	void *vaddr_ref;
 	void *vaddr;
 	unsigned long paddr;
 	unsigned long kvaddr;
@@ -222,8 +221,10 @@
 	struct mutex get_event_lock;
 	int event_abort;
 
-	struct list_head pmem_region_queue;
+	struct list_head ion_region_queue;
 	struct audpcm_drv_operations drv_ops;
+	struct ion_client *client;
+	struct ion_handle *output_buff_handle;
 };
 
 static int auddec_dsp_config(struct audio *audio, int enable);
@@ -232,7 +233,7 @@
 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,
+static unsigned long audpcm_ion_fixup(struct audio *audio, void *addr,
 	unsigned long len, int ref_up);
 
 static int rmt_put_resource(struct audio *audio)
@@ -762,7 +763,7 @@
 
 	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,
+		audpcm_ion_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
 				  drv_evt->payload.aio_buf.buf_len, 0);
 		mutex_unlock(&audio->lock);
 	}
@@ -772,104 +773,118 @@
 	return rc;
 }
 
-static int audpcm_pmem_check(struct audio *audio,
+static int audpcm_ion_check(struct audio *audio,
 		void *vaddr, unsigned long len)
 {
-	struct audpcm_pmem_region *region_elt;
-	struct audpcm_pmem_region t = { .vaddr = vaddr, .len = len };
+	struct audpcm_ion_region *region_elt;
+	struct audpcm_ion_region t = {.vaddr = vaddr, .len = len };
 
-	list_for_each_entry(region_elt, &audio->pmem_region_queue, list) {
+	list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
 		if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
 		    OVERLAPS(region_elt, &t)) {
-			MM_ERR("region (vaddr %p len %ld)"
+			MM_ERR("[%p]:region (vaddr %p len %ld)"
 				" clashes with registered region"
 				" (vaddr %p paddr %p len %ld)\n",
-				vaddr, len,
+				audio, vaddr, len,
 				region_elt->vaddr,
-				(void *)region_elt->paddr,
-				region_elt->len);
+				(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)
+static int audpcm_ion_add(struct audio *audio,
+			struct msm_audio_ion_info *info)
 {
-	unsigned long paddr, kvaddr, len;
-	struct file *file;
-	struct audpcm_pmem_region *region;
-	struct vm_area_struct *vma;
+	ion_phys_addr_t paddr;
+	size_t len;
+	unsigned long kvaddr;
+	struct audpcm_ion_region *region;
 	int rc = -EINVAL;
+	struct ion_handle *handle;
+	unsigned long ionflag;
 
-	MM_DBG("\n"); /* Macro prints the file name and function */
+	MM_ERR("\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;
+	if (!region) {
+		rc = -ENOMEM;
+		goto end;
 	}
-
-	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;
+	handle = ion_import_dma_buf(audio->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(audio->client, handle, &ionflag);
+	if (rc) {
+		pr_err("%s: could not get flags for the handle\n", __func__);
+		goto flag_error;
+	}
+	kvaddr = (unsigned long)ion_map_kernel(audio->client, handle, ionflag);
+	if (IS_ERR_OR_NULL((void *)kvaddr)) {
+		pr_err("%s: could not get virtual address\n", __func__);
+		goto map_error;
+	}
+	rc = ion_phys(audio->client, handle, &paddr, &len);
+	if (rc) {
+		pr_err("%s: could not get physical address\n", __func__);
+		goto ion_error;
+	}
+	rc = audpcm_ion_check(audio, info->vaddr, len);
+	if (rc < 0) {
+		MM_ERR("audpcm_ion_check failed\n");
+		goto ion_error;
+	}
+	region->handle = handle;
+	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);
+	MM_DBG("[%p]:add region paddr %lx vaddr %p, len %lu kvaddr %lx\n",
+		audio, region->paddr, region->vaddr,
+		region->len, region->kvaddr);
+	list_add_tail(&region->list, &audio->ion_region_queue);
+
+	return rc;
+
+ion_error:
+	ion_unmap_kernel(audio->client, handle);
+map_error:
+flag_error:
+	ion_free(audio->client, handle);
+import_error:
+	kfree(region);
+end:
 	return rc;
 }
 
-static int audpcm_pmem_remove(struct audio *audio,
-	struct msm_audio_pmem_info *info)
+static int audpcm_ion_remove(struct audio *audio,
+			struct msm_audio_ion_info *info)
 {
-	struct audpcm_pmem_region *region;
+	struct audpcm_ion_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->ion_region_queue) {
+		region = list_entry(ptr, struct audpcm_ion_region, list);
 
-	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 != NULL && (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);
+				MM_DBG("%s[%p]:region %p in use ref_cnt %d\n",
+					__func__, audio, region,
+					region->ref_cnt);
 				break;
 			}
-			MM_DBG("remove region fd %d vaddr %p \n", info->fd,
-					info->vaddr);
+			MM_DBG("remove region fd %d vaddr %p\n",
+				info->fd, info->vaddr);
 			list_del(&region->list);
-			put_pmem_file(region->file);
+			ion_unmap_kernel(audio->client, region->handle);
+			ion_free(audio->client, region->handle);
 			kfree(region);
 			rc = 0;
 			break;
@@ -879,24 +894,22 @@
 	return rc;
 }
 
-static int audpcm_pmem_lookup_vaddr(struct audio *audio, void *addr,
-		     unsigned long len, struct audpcm_pmem_region **region)
+static int audpcm_ion_lookup_vaddr(struct audio *audio, void *addr,
+			unsigned long len, struct audpcm_ion_region **region)
 {
-	struct audpcm_pmem_region *region_elt;
-
+	struct audpcm_ion_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) {
+	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
-			 * pmem buffer
+			 * ion buffer
 			 */
+
 			match_count++;
 			if (!*region)
 				*region = region_elt;
@@ -904,31 +917,33 @@
 	}
 
 	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) {
+		MM_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)
-				MM_ERR("\t%p, %ld --> %p\n", region_elt->vaddr,
+					MM_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 audpcm_pmem_fixup(struct audio *audio, void *addr,
+static unsigned long audpcm_ion_fixup(struct audio *audio, void *addr,
 		    unsigned long len, int ref_up)
 {
-	struct audpcm_pmem_region *region;
+	struct audpcm_ion_region *region;
 	unsigned long paddr;
 	int ret;
 
-	ret = audpcm_pmem_lookup_vaddr(audio, addr, len, &region);
+	ret = audpcm_ion_lookup_vaddr(audio, addr, len, &region);
 	if (ret) {
-		MM_ERR("lookup (%p, %ld) failed\n", addr, len);
+		MM_ERR("%s[%p]:lookup (%p, %ld) failed\n",
+			__func__, audio, addr, len);
 		return 0;
 	}
 	if (ref_up)
@@ -961,7 +976,7 @@
 			buf_node, dir, buf_node->buf.buf_addr,
 			buf_node->buf.buf_len, buf_node->buf.data_len);
 
-	buf_node->paddr = audpcm_pmem_fixup(
+	buf_node->paddr = audpcm_ion_fixup(
 		audio, buf_node->buf.buf_addr,
 		buf_node->buf.buf_len, 1);
 	if (dir) {
@@ -1125,23 +1140,23 @@
 		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");
+	case AUDIO_REGISTER_ION: {
+		struct msm_audio_ion_info info;
+		MM_ERR("AUDIO_REGISTER_ION\n");
 			if (copy_from_user(&info, (void *) arg, sizeof(info)))
 				rc = -EFAULT;
 			else
-				rc = audpcm_pmem_add(audio, &info);
+				rc = audpcm_ion_add(audio, &info);
 			break;
 		}
 
-	case AUDIO_DEREGISTER_PMEM: {
-			struct msm_audio_pmem_info info;
-			MM_DBG("AUDIO_DEREGISTER_PMEM\n");
+	case AUDIO_DEREGISTER_ION: {
+		struct msm_audio_ion_info info;
+		MM_ERR("AUDIO_DEREGISTER_ION\n");
 			if (copy_from_user(&info, (void *) arg, sizeof(info)))
 				rc = -EFAULT;
 			else
-				rc = audpcm_pmem_remove(audio, &info);
+				rc = audpcm_ion_remove(audio, &info);
 			break;
 		}
 
@@ -1340,15 +1355,16 @@
 	return rc;
 }
 
-static void audpcm_reset_pmem_region(struct audio *audio)
+static void audpcm_reset_ion_region(struct audio *audio)
 {
-	struct audpcm_pmem_region *region;
+	struct audpcm_ion_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_for_each_safe(ptr, next, &audio->ion_region_queue) {
+		region = list_entry(ptr, struct audpcm_ion_region, list);
 		list_del(&region->list);
-		put_pmem_file(region->file);
+		ion_unmap_kernel(audio->client, region->handle);
+		ion_free(audio->client, region->handle);
 		kfree(region);
 	}
 
@@ -1365,7 +1381,7 @@
 	if (audio->rmt_resource_released == 0)
 		rmt_put_resource(audio);
 	audio->drv_ops.out_flush(audio);
-	audpcm_reset_pmem_region(audio);
+	audpcm_reset_ion_region(audio);
 
 	msm_adsp_put(audio->audplay);
 	audpp_adec_free(audio->dec_id);
@@ -1376,16 +1392,12 @@
 	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
+	ion_client_destroy(audio->client);
 	kfree(audio);
 	return 0;
 }
@@ -1506,7 +1518,13 @@
 	struct audio *audio = NULL;
 	int rc, i, dec_attrb, decid;
 	struct audpcm_event *e_node = NULL;
-	unsigned pmem_sz = DMASZ_MAX;
+	unsigned mem_sz = DMASZ_MAX;
+	unsigned long ionflag = 0;
+	ion_phys_addr_t addr = 0;
+	struct ion_handle *handle = NULL;
+	struct ion_client *client = NULL;
+	int len = 0;
+
 
 #ifdef CONFIG_DEBUG_FS
 	/* 4 bytes represents decoder number, 1 byte for terminate string */
@@ -1543,44 +1561,57 @@
 	}
 	audio->dec_id = decid & MSM_AUD_DECODER_MASK;
 
+	client = msm_ion_client_create(UINT_MAX, "Audio_PCM_Client");
+	if (IS_ERR_OR_NULL(client)) {
+		pr_err("Unable to create ION client\n");
+		rc = -ENOMEM;
+		goto client_create_error;
+	}
+	audio->client = client;
+
 	/* 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;
+
+		MM_DBG("memsz = %d\n", mem_sz);
+
+		handle = ion_alloc(client, mem_sz, SZ_4K,
+			ION_HEAP(ION_AUDIO_HEAP_ID));
+		if (IS_ERR_OR_NULL(handle)) {
+			MM_ERR("Unable to create allocate O/P buffers\n");
+			rc = -ENOMEM;
+			goto output_buff_alloc_error;
 		}
-		audio->out_dma_sz = pmem_sz;
+		audio->output_buff_handle = handle;
+
+		rc = ion_phys(client , handle, &addr, &len);
+		if (rc) {
+			MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+				(unsigned int) addr, (unsigned int) len);
+			goto output_buff_get_phys_error;
+		} else {
+			MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+				(unsigned int) addr, (unsigned int) len);
+		}
+		audio->phys = (int32_t)addr;
+
+
+		rc = ion_handle_get_flags(client, handle, &ionflag);
+		if (rc) {
+			MM_ERR("could not get flags for the handle\n");
+			goto output_buff_get_flags_error;
+		}
+
+		audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+		if (IS_ERR(audio->map_v_write)) {
+			MM_ERR("could not map write buffers\n");
+			rc = -ENOMEM;
+			goto output_buff_map_error;
+		}
+		audio->data = audio->map_v_write;
+		MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+			audio->phys, (int)audio->data);
+
+		audio->out_dma_sz = mem_sz;
 	}
 
 	rc = audmgr_open(&audio->audmgr);
@@ -1631,7 +1662,7 @@
 	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->ion_region_queue);
 	INIT_LIST_HEAD(&audio->free_event_queue);
 	INIT_LIST_HEAD(&audio->event_queue);
 	init_waitqueue_head(&audio->wait);
@@ -1674,10 +1705,14 @@
 done:
 	return rc;
 err:
-	if (audio->data) {
-		iounmap(audio->map_v_write);
-		free_contiguous_memory_by_paddr(audio->phys);
-	}
+	ion_unmap_kernel(client, audio->output_buff_handle);
+output_buff_map_error:
+output_buff_get_flags_error:
+output_buff_get_phys_error:
+	ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+	ion_client_destroy(client);
+client_create_error:
 	audpp_adec_free(audio->dec_id);
 	MM_DBG("audio instance 0x%08x freeing\n", (int)audio);
 	kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5/audio_pcm_in.c b/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
index 851980d..716dbd2 100644
--- a/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
@@ -2,7 +2,7 @@
  *
  * pcm audio input device
  *
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, 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.
@@ -26,6 +26,7 @@
 #include <linux/kthread.h>
 #include <linux/wait.h>
 #include <linux/dma-mapping.h>
+#include <linux/ion.h>
 
 #include <linux/delay.h>
 
@@ -114,6 +115,8 @@
 	 * All the coeff should be passed from user space	    */
 	int iir_enable;
 	audpreproc_cmd_cfg_iir_tuning_filter_params iir_cfg;
+	struct ion_client *client;
+	struct ion_handle *output_buff_handle;
 };
 
 static int audpcm_in_dsp_enable(struct audio_in *audio, int enable);
@@ -764,9 +767,11 @@
 	audio->audpre = NULL;
 	audio->opened = 0;
 	if (audio->data) {
-		free_contiguous_memory((void *)audio->data);
+		ion_unmap_kernel(audio->client, audio->output_buff_handle);
+		ion_free(audio->client, audio->output_buff_handle);
 		audio->data = NULL;
 	}
+	ion_client_destroy(audio->client);
 	mutex_unlock(&audio->lock);
 	return 0;
 }
@@ -777,6 +782,11 @@
 {
 	struct audio_in *audio = &the_audio_in;
 	int rc;
+	int len = 0;
+	unsigned long ionflag = 0;
+	ion_phys_addr_t addr = 0;
+	struct ion_handle *handle = NULL;
+	struct ion_client *client = NULL;
 
 	int encid;
 	mutex_lock(&audio->lock);
@@ -827,23 +837,53 @@
 
 	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");
+	client = msm_ion_client_create(UINT_MAX, "Audio_PCM_in_client");
+	if (IS_ERR_OR_NULL(client)) {
+		MM_ERR("Unable to create ION client\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);
+		goto client_create_error;
 	}
+	audio->client = client;
+
+	MM_DBG("allocating mem sz = %d\n", DMASZ);
+	handle = ion_alloc(client, DMASZ, SZ_4K,
+		ION_HEAP(ION_AUDIO_HEAP_ID));
+	if (IS_ERR_OR_NULL(handle)) {
+		MM_ERR("Unable to create allocate O/P buffers\n");
+		rc = -ENOMEM;
+		goto output_buff_alloc_error;
+	}
+
+	audio->output_buff_handle = handle;
+
+	rc = ion_phys(client , handle, &addr, &len);
+	if (rc) {
+		MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+			(unsigned int) addr, (unsigned int) len);
+		rc = -ENOMEM;
+		goto output_buff_get_phys_error;
+	} else {
+		MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+			(unsigned int) addr, (unsigned int) len);
+	}
+	audio->phys = (int32_t)addr;
+
+	rc = ion_handle_get_flags(client, handle, &ionflag);
+	if (rc) {
+		MM_ERR("could not get flags for the handle\n");
+		rc = -ENOMEM;
+		goto output_buff_get_flags_error;
+	}
+
+	audio->data = ion_map_kernel(client, handle, ionflag);
+	if (IS_ERR(audio->data)) {
+		MM_ERR("could not map read buffers,freeing instance 0x%08x\n",
+				(int)audio);
+		rc = -ENOMEM;
+		goto output_buff_map_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;
@@ -851,7 +891,13 @@
 done:
 	mutex_unlock(&audio->lock);
 	return rc;
-evt_error:
+output_buff_map_error:
+output_buff_get_phys_error:
+output_buff_get_flags_error:
+	ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+	ion_client_destroy(client);
+client_create_error:
 	msm_adsp_put(audio->audrec);
 	msm_adsp_put(audio->audpre);
 	audpreproc_aenc_free(audio->enc_id);
diff --git a/arch/arm/mach-msm/qdsp5/audio_qcelp.c b/arch/arm/mach-msm/qdsp5/audio_qcelp.c
index f436759..dc257cd 100644
--- a/arch/arm/mach-msm/qdsp5/audio_qcelp.c
+++ b/arch/arm/mach-msm/qdsp5/audio_qcelp.c
@@ -34,10 +34,10 @@
 #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 <linux/ion.h>
 
 #include <mach/msm_adsp.h>
 #include <mach/iommu.h>
@@ -170,6 +170,9 @@
 	int eq_needs_commit;
 	audpp_cmd_cfg_object_params_eqalizer eq;
 	audpp_cmd_cfg_object_params_volume vol_pan;
+	struct ion_client *client;
+	struct ion_handle *input_buff_handle;
+	struct ion_handle *output_buff_handle;
 };
 
 static int auddec_dsp_config(struct audio *audio, int enable);
@@ -767,6 +770,10 @@
 	uint16_t enable_mask;
 	int enable;
 	int prev_state;
+	unsigned long ionflag = 0;
+	ion_phys_addr_t addr = 0;
+	struct ion_handle *handle = NULL;
+	int len = 0;
 
 	MM_DBG("cmd = %d\n", cmd);
 
@@ -956,24 +963,53 @@
 			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) {
+				handle = ion_alloc(audio->client,
+					(config.buffer_size *
+					config.buffer_count),
+					SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+				if (IS_ERR_OR_NULL(handle)) {
+					MM_ERR("Unable to alloc I/P buffs\n");
+					audio->input_buff_handle = NULL;
 					rc = -ENOMEM;
 					break;
 				}
-				audio->map_v_read = ioremap(
-							audio->read_phys,
-							config.buffer_size *
-							config.buffer_count);
+
+				audio->input_buff_handle = handle;
+
+				rc = ion_phys(audio->client ,
+					handle, &addr, &len);
+				if (rc) {
+					MM_ERR("Invalid phy: %x sz: %x\n",
+						(unsigned int) addr,
+						(unsigned int) len);
+					ion_free(audio->client, handle);
+					audio->input_buff_handle = NULL;
+					rc = -ENOMEM;
+					break;
+				} else {
+					MM_INFO("Got valid phy: %x sz: %x\n",
+						(unsigned int) audio->read_phys,
+						(unsigned int) len);
+				}
+				audio->read_phys = (int32_t)addr;
+
+				rc = ion_handle_get_flags(audio->client,
+					handle, &ionflag);
+				if (rc) {
+					MM_ERR("could not get flags\n");
+					ion_free(audio->client, handle);
+					audio->input_buff_handle = NULL;
+					rc = -ENOMEM;
+					break;
+				}
+				audio->map_v_read = ion_map_kernel(
+					audio->client,
+					handle, ionflag);
 				if (IS_ERR(audio->map_v_read)) {
 					MM_ERR("failed to map read buf\n");
+					ion_free(audio->client, handle);
+					audio->input_buff_handle = NULL;
 					rc = -ENOMEM;
-					free_contiguous_memory_by_paddr(
-							audio->read_phys);
 				} else {
 					uint8_t index;
 					uint32_t offset = 0;
@@ -1019,7 +1055,8 @@
 }
 
 /* Only useful in tunnel-mode */
-static int audqcelp_fsync(struct file *file, loff_t a, loff_t b, int datasync)
+static int audqcelp_fsync(struct file *file, loff_t a, loff_t b,
+	int datasync)
 {
 	struct audio *audio = file->private_data;
 	int rc = 0;
@@ -1287,12 +1324,13 @@
 	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);
+	ion_unmap_kernel(audio->client, audio->output_buff_handle);
+	ion_free(audio->client, audio->output_buff_handle);
+	if (audio->input_buff_handle != NULL) {
+		ion_unmap_kernel(audio->client, audio->input_buff_handle);
+		ion_free(audio->client, audio->input_buff_handle);
 	}
+	ion_client_destroy(audio->client);
 	mutex_unlock(&audio->lock);
 #ifdef CONFIG_DEBUG_FS
 	if (audio->dentry)
@@ -1431,6 +1469,12 @@
 	struct audio *audio = NULL;
 	int rc, dec_attrb, decid, i;
 	struct audqcelp_event *e_node = NULL;
+	unsigned mem_sz = DMASZ;
+	unsigned long ionflag = 0;
+	ion_phys_addr_t addr = 0;
+	struct ion_handle *handle = NULL;
+	struct ion_client *client = NULL;
+	int len = 0;
 #ifdef CONFIG_DEBUG_FS
 	/* 4 bytes represents decoder number, 1 byte for terminate string */
 	char name[sizeof "msm_qcelp_" + 5];
@@ -1471,29 +1515,50 @@
 	}
 	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);
+	client = msm_ion_client_create(UINT_MAX, "Audio_QCELP_Client");
+	if (IS_ERR_OR_NULL(client)) {
+		pr_err("Unable to create ION client\n");
 		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);
+		goto client_create_error;
 	}
+	audio->client = client;
+
+	handle = ion_alloc(client, mem_sz, SZ_4K,
+		ION_HEAP(ION_AUDIO_HEAP_ID));
+	if (IS_ERR_OR_NULL(handle)) {
+		MM_ERR("Unable to create allocate O/P buffers\n");
+		rc = -ENOMEM;
+		goto output_buff_alloc_error;
+	}
+	audio->output_buff_handle = handle;
+
+	rc = ion_phys(client, handle, &addr, &len);
+	if (rc) {
+		MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+			(unsigned int) addr, (unsigned int) len);
+		goto output_buff_get_phys_error;
+	} else {
+		MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+			(unsigned int) addr, (unsigned int) len);
+	}
+	audio->phys = (int32_t)addr;
+
+
+	rc = ion_handle_get_flags(client, handle, &ionflag);
+	if (rc) {
+		MM_ERR("could not get flags for the handle\n");
+		goto output_buff_get_flags_error;
+	}
+
+	audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+	if (IS_ERR(audio->map_v_write)) {
+		MM_ERR("could not map write buffers\n");
+		rc = -ENOMEM;
+		goto output_buff_map_error;
+	}
+	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);
@@ -1524,6 +1589,8 @@
 		goto err;
 	}
 
+	audio->input_buff_handle = NULL;
+
 	/* Initialize all locks of audio instance */
 	mutex_init(&audio->lock);
 	mutex_init(&audio->write_lock);
@@ -1580,8 +1647,14 @@
 done:
 	return rc;
 err:
-	iounmap(audio->map_v_write);
-	free_contiguous_memory_by_paddr(audio->phys);
+	ion_unmap_kernel(client, audio->output_buff_handle);
+output_buff_map_error:
+output_buff_get_phys_error:
+output_buff_get_flags_error:
+	ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+	ion_client_destroy(client);
+client_create_error:
 	audpp_adec_free(audio->dec_id);
 	kfree(audio);
 	return rc;
diff --git a/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c b/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
index 92036e5..99a169d 100644
--- a/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
@@ -33,6 +33,7 @@
 
 
 #include <linux/memory_alloc.h>
+#include <linux/ion.h>
 
 #include <asm/atomic.h>
 #include <asm/ioctls.h>
@@ -151,6 +152,9 @@
 	int enabled;
 	int running;
 	int stopped; /* set when stopped, cleared on flush */
+	struct ion_client *client;
+	struct ion_handle *input_buff_handle;
+	struct ion_handle *output_buff_handle;
 };
 
 struct audio_frame {
@@ -1004,7 +1008,8 @@
 	spin_unlock_irqrestore(&audio->dsp_lock, flags);
 }
 
-static int audqcelp_in_fsync(struct file *file, loff_t a, loff_t b, int datasync)
+static int audqcelp_in_fsync(struct file *file, loff_t a, loff_t b,
+	int datasync)
 
 {
 	struct audio_qcelp_in *audio = file->private_data;
@@ -1192,16 +1197,17 @@
 
 	if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) && \
 	   (audio->out_data)) {
-		iounmap(audio->map_v_write);
-		free_contiguous_memory_by_paddr(audio->out_phys);
+		ion_unmap_kernel(audio->client, audio->input_buff_handle);
+		ion_free(audio->client, audio->input_buff_handle);
 		audio->out_data = NULL;
 	}
 
 	if (audio->data) {
-		iounmap(audio->map_v_read);
-		free_contiguous_memory_by_paddr(audio->phys);
+		ion_unmap_kernel(audio->client, audio->output_buff_handle);
+		ion_free(audio->client, audio->output_buff_handle);
 		audio->data = NULL;
 	}
+	ion_client_destroy(audio->client);
 	mutex_unlock(&audio->lock);
 	return 0;
 }
@@ -1214,6 +1220,11 @@
 	int rc;
 	int encid;
 	int dma_size = 0;
+	int len = 0;
+	unsigned long ionflag = 0;
+	ion_phys_addr_t addr = 0;
+	struct ion_handle *handle = NULL;
+	struct ion_client *client = NULL;
 
 	mutex_lock(&audio->lock);
 	if (audio->opened) {
@@ -1293,52 +1304,101 @@
 	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");
+	client = msm_ion_client_create(UINT_MAX, "Audio_QCELP_in_client");
+	if (IS_ERR_OR_NULL(client)) {
+		MM_ERR("Unable to create ION client\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);
+		goto client_create_error;
 	}
+	audio->client = client;
+
+	MM_DBG("allocating mem sz = %d\n", dma_size);
+	handle = ion_alloc(client, dma_size, SZ_4K,
+		ION_HEAP(ION_AUDIO_HEAP_ID));
+	if (IS_ERR_OR_NULL(handle)) {
+		MM_ERR("Unable to create allocate O/P buffers\n");
+		rc = -ENOMEM;
+		goto output_buff_alloc_error;
+	}
+
+	audio->output_buff_handle = handle;
+
+	rc = ion_phys(client , handle, &addr, &len);
+	if (rc) {
+		MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+			(unsigned int) addr, (unsigned int) len);
+		rc = -ENOMEM;
+		goto output_buff_get_phys_error;
+	} else {
+		MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+			(unsigned int) addr, (unsigned int) len);
+	}
+	audio->phys = (int32_t)addr;
+
+	rc = ion_handle_get_flags(client, handle, &ionflag);
+	if (rc) {
+		MM_ERR("could not get flags for the handle\n");
+		rc = -ENOMEM;
+		goto output_buff_get_flags_error;
+	}
+
+	audio->map_v_read = ion_map_kernel(client, handle, ionflag);
+	if (IS_ERR(audio->map_v_read)) {
+		MM_ERR("could not map read buffers,freeing instance 0x%08x\n",
+				(int)audio);
+		rc = -ENOMEM;
+		goto output_buff_map_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");
+		MM_DBG("allocating BUFFER_SIZE  %d\n", BUFFER_SIZE);
+		handle = ion_alloc(client, BUFFER_SIZE,
+				SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+		if (IS_ERR_OR_NULL(handle)) {
+			MM_ERR("Unable to create allocate I/P 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);
+			goto input_buff_alloc_error;
 		}
 
+		audio->input_buff_handle = handle;
+
+		rc = ion_phys(client , handle, &addr, &len);
+		if (rc) {
+			MM_ERR("I/P buffers:Invalid phy: %x sz: %x\n",
+				(unsigned int) addr, (unsigned int) len);
+			rc = -ENOMEM;
+			goto input_buff_get_phys_error;
+		} else {
+			MM_INFO("Got valid phy: %x sz: %x\n",
+				(unsigned int) addr,
+				(unsigned int) len);
+		}
+		audio->out_phys = (int32_t)addr;
+
+		rc = ion_handle_get_flags(client,
+			handle, &ionflag);
+		if (rc) {
+			MM_ERR("could not get flags for the handle\n");
+			rc = -ENOMEM;
+			goto input_buff_get_flags_error;
+		}
+
+		audio->map_v_write = ion_map_kernel(client,
+			handle, ionflag);
+		if (IS_ERR(audio->map_v_write)) {
+			MM_ERR("could not map write buffers\n");
+			rc = -ENOMEM;
+			goto input_buff_map_error;
+		}
+		audio->out_data = audio->map_v_write;
+		MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+					(unsigned int)addr,
+					(unsigned int)audio->out_data);
+
 		/* Initialize buffer */
 		audio->out[0].data = audio->out_data + 0;
 		audio->out[0].addr = audio->out_phys + 0;
@@ -1360,7 +1420,19 @@
 done:
 	mutex_unlock(&audio->lock);
 	return rc;
-evt_error:
+input_buff_map_error:
+input_buff_get_flags_error:
+input_buff_get_phys_error:
+	ion_free(client, audio->input_buff_handle);
+input_buff_alloc_error:
+	ion_unmap_kernel(client, audio->output_buff_handle);
+output_buff_map_error:
+output_buff_get_phys_error:
+output_buff_get_flags_error:
+	ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+	ion_client_destroy(client);
+client_create_error:
 	msm_adsp_put(audio->audrec);
 	if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
 		msm_adsp_put(audio->audpre);
diff --git a/arch/arm/mach-msm/qdsp5/audio_wma.c b/arch/arm/mach-msm/qdsp5/audio_wma.c
index 162a6f1..e28e704 100644
--- a/arch/arm/mach-msm/qdsp5/audio_wma.c
+++ b/arch/arm/mach-msm/qdsp5/audio_wma.c
@@ -37,11 +37,11 @@
 #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 <linux/ion.h>
 
 #include <mach/msm_adsp.h>
 #include <mach/iommu.h>
@@ -187,6 +187,9 @@
 	int eq_needs_commit;
 	audpp_cmd_cfg_object_params_eqalizer eq;
 	audpp_cmd_cfg_object_params_volume vol_pan;
+	struct ion_client *client;
+	struct ion_handle *input_buff_handle;
+	struct ion_handle *output_buff_handle;
 };
 
 static int auddec_dsp_config(struct audio *audio, int enable);
@@ -815,6 +818,10 @@
 	uint16_t enable_mask;
 	int enable;
 	int prev_state;
+	unsigned long ionflag = 0;
+	ion_phys_addr_t addr = 0;
+	struct ion_handle *handle = NULL;
+	int len = 0;
 
 	MM_DBG("cmd = %d\n", cmd);
 
@@ -1034,24 +1041,54 @@
 				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) {
+				handle = ion_alloc(audio->client,
+					(config.buffer_size *
+					config.buffer_count),
+					SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+				if (IS_ERR_OR_NULL(handle)) {
+					MM_ERR("Unable to alloc I/P buffs\n");
+					audio->input_buff_handle = NULL;
 					rc = -ENOMEM;
 					break;
 				}
-				audio->map_v_read = ioremap(
-						audio->read_phys,
-						config.buffer_size *
-						config.buffer_count);
+
+				audio->input_buff_handle = handle;
+
+				rc = ion_phys(audio->client ,
+					handle, &addr, &len);
+				if (rc) {
+					MM_ERR("Invalid phy: %x sz: %x\n",
+						(unsigned int) addr,
+						(unsigned int) len);
+					ion_free(audio->client, handle);
+					audio->input_buff_handle = NULL;
+					rc = -ENOMEM;
+					break;
+				} else {
+					MM_INFO("Got valid phy: %x sz: %x\n",
+						(unsigned int) audio->read_phys,
+						(unsigned int) len);
+				}
+				audio->read_phys = (int32_t)addr;
+
+				rc = ion_handle_get_flags(audio->client,
+					handle, &ionflag);
+				if (rc) {
+					MM_ERR("could not get flags\n");
+					ion_free(audio->client, handle);
+					audio->input_buff_handle = NULL;
+					rc = -ENOMEM;
+					break;
+				}
+
+				audio->map_v_read = ion_map_kernel(
+					audio->client,
+					handle, ionflag);
 				if (IS_ERR(audio->map_v_read)) {
 					MM_ERR("map of read buf failed\n");
+					ion_free(audio->client, handle);
+					audio->input_buff_handle = NULL;
 					rc = -ENOMEM;
-					free_contiguous_memory_by_paddr(
-							audio->read_phys);
 				} else {
 					uint8_t index;
 					uint32_t offset = 0;
@@ -1098,7 +1135,8 @@
 }
 
 /* Only useful in tunnel-mode */
-static int audio_fsync(struct file *file, loff_t a, loff_t b, int datasync)
+static int audio_fsync(struct file *file, loff_t a, loff_t b,
+	int datasync)
 {
 	struct audio *audio = file->private_data;
 	struct buffer *frame;
@@ -1433,12 +1471,13 @@
 	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);
+	ion_unmap_kernel(audio->client, audio->output_buff_handle);
+	ion_free(audio->client, audio->output_buff_handle);
+	if (audio->input_buff_handle != NULL) {
+		ion_unmap_kernel(audio->client, audio->input_buff_handle);
+		ion_free(audio->client, audio->input_buff_handle);
 	}
+	ion_client_destroy(audio->client);
 	mutex_unlock(&audio->lock);
 #ifdef CONFIG_DEBUG_FS
 	if (audio->dentry)
@@ -1580,8 +1619,13 @@
 {
 	struct audio *audio = NULL;
 	int rc, dec_attrb, decid, i;
-	unsigned pmem_sz = DMASZ_MAX;
+	unsigned mem_sz = DMASZ_MAX;
 	struct audwma_event *e_node = NULL;
+	unsigned long ionflag = 0;
+	ion_phys_addr_t addr = 0;
+	struct ion_handle *handle = NULL;
+	struct ion_client *client = NULL;
+	int len = 0;
 #ifdef CONFIG_DEBUG_FS
 	/* 4 bytes represents decoder number, 1 byte for terminate string */
 	char name[sizeof "msm_wma_" + 5];
@@ -1624,36 +1668,52 @@
 	}
 	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;
+	client = msm_ion_client_create(UINT_MAX, "Audio_WMA_Client");
+	if (IS_ERR_OR_NULL(client)) {
+		pr_err("Unable to create ION client\n");
+		rc = -ENOMEM;
+		goto client_create_error;
 	}
-	audio->out_dma_sz = pmem_sz;
+	audio->client = client;
+
+	handle = ion_alloc(client, mem_sz, SZ_4K,
+		ION_HEAP(ION_AUDIO_HEAP_ID));
+	if (IS_ERR_OR_NULL(handle)) {
+		MM_ERR("Unable to create allocate O/P buffers\n");
+		rc = -ENOMEM;
+		goto output_buff_alloc_error;
+	}
+	audio->output_buff_handle = handle;
+
+	rc = ion_phys(client, handle, &addr, &len);
+	if (rc) {
+		MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+			(unsigned int) addr, (unsigned int) len);
+		goto output_buff_get_phys_error;
+	} else {
+		MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+			(unsigned int) addr, (unsigned int) len);
+	}
+	audio->phys = (int32_t)addr;
+
+
+	rc = ion_handle_get_flags(client, handle, &ionflag);
+	if (rc) {
+		MM_ERR("could not get flags for the handle\n");
+		goto output_buff_get_flags_error;
+	}
+
+	audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+	if (IS_ERR(audio->map_v_write)) {
+		MM_ERR("could not map write buffers\n");
+		rc = -ENOMEM;
+		goto output_buff_map_error;
+	}
+	audio->data = audio->map_v_write;
+	MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+		audio->phys, (int)audio->data);
+
+	audio->out_dma_sz = mem_sz;
 
 	if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK) {
 		rc = audmgr_open(&audio->audmgr);
@@ -1684,6 +1744,7 @@
 		goto err;
 	}
 
+	audio->input_buff_handle = NULL;
 	mutex_init(&audio->lock);
 	mutex_init(&audio->write_lock);
 	mutex_init(&audio->read_lock);
@@ -1748,8 +1809,14 @@
 done:
 	return rc;
 err:
-	iounmap(audio->map_v_write);
-	free_contiguous_memory_by_paddr(audio->phys);
+	ion_unmap_kernel(client, audio->output_buff_handle);
+output_buff_map_error:
+output_buff_get_phys_error:
+output_buff_get_flags_error:
+	ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+	ion_client_destroy(client);
+client_create_error:
 	audpp_adec_free(audio->dec_id);
 	kfree(audio);
 	return rc;
diff --git a/arch/arm/mach-msm/qdsp5/audio_wmapro.c b/arch/arm/mach-msm/qdsp5/audio_wmapro.c
index 641b1c7..87afcf0 100644
--- a/arch/arm/mach-msm/qdsp5/audio_wmapro.c
+++ b/arch/arm/mach-msm/qdsp5/audio_wmapro.c
@@ -36,11 +36,11 @@
 #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 <linux/ion.h>
 
 #include <mach/msm_adsp.h>
 #include <mach/qdsp5/qdsp5audppcmdi.h>
@@ -186,6 +186,9 @@
 	int eq_needs_commit;
 	audpp_cmd_cfg_object_params_eqalizer eq;
 	audpp_cmd_cfg_object_params_volume vol_pan;
+	struct ion_client *client;
+	struct ion_handle *input_buff_handle;
+	struct ion_handle *output_buff_handle;
 };
 
 static int auddec_dsp_config(struct audio *audio, int enable);
@@ -803,6 +806,10 @@
 	uint16_t enable_mask;
 	int enable;
 	int prev_state;
+	unsigned long ionflag = 0;
+	ion_phys_addr_t addr = 0;
+	struct ion_handle *handle = NULL;
+	int len = 0;
 
 	MM_DBG("cmd = %d\n", cmd);
 
@@ -1031,25 +1038,54 @@
 				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) {
+				handle = ion_alloc(audio->client,
+					(config.buffer_size *
+					config.buffer_count),
+					SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+				if (IS_ERR_OR_NULL(handle)) {
+					MM_ERR("Unable to alloc I/P buffs\n");
+					audio->input_buff_handle = NULL;
 					rc = -ENOMEM;
 					break;
 				}
-				audio->map_v_read = ioremap(
-						audio->read_phys,
-						config.buffer_size *
-						config.buffer_count);
 
+				audio->input_buff_handle = handle;
+
+				rc = ion_phys(audio->client ,
+					handle, &addr, &len);
+				if (rc) {
+					MM_ERR("Invalid phy: %x sz: %x\n",
+						(unsigned int) addr,
+						(unsigned int) len);
+					ion_free(audio->client, handle);
+					audio->input_buff_handle = NULL;
+					rc = -ENOMEM;
+					break;
+				} else {
+					MM_INFO("Got valid phy: %x sz: %x\n",
+						(unsigned int) audio->read_phys,
+						(unsigned int) len);
+				}
+				audio->read_phys = (int32_t)addr;
+
+				rc = ion_handle_get_flags(audio->client,
+					handle, &ionflag);
+				if (rc) {
+					MM_ERR("could not get flags\n");
+					ion_free(audio->client, handle);
+					audio->input_buff_handle = NULL;
+					rc = -ENOMEM;
+					break;
+				}
+
+				audio->map_v_read = ion_map_kernel(
+					audio->client,
+					handle, ionflag);
 				if (IS_ERR(audio->map_v_read)) {
 					MM_ERR("map of read buf failed\n");
+					ion_free(audio->client, handle);
+					audio->input_buff_handle = NULL;
 					rc = -ENOMEM;
-					free_contiguous_memory_by_paddr(
-							audio->read_phys);
 				} else {
 					uint8_t index;
 					uint32_t offset = 0;
@@ -1096,7 +1132,8 @@
 }
 
 /* Only useful in tunnel-mode */
-static int audio_fsync(struct file *file, loff_t a, loff_t b, int datasync)
+static int audio_fsync(struct file *file, loff_t a, loff_t b,
+	int datasync)
 {
 	struct audio *audio = file->private_data;
 	struct buffer *frame;
@@ -1429,12 +1466,13 @@
 	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);
+	ion_unmap_kernel(audio->client, audio->output_buff_handle);
+	ion_free(audio->client, audio->output_buff_handle);
+	if (audio->input_buff_handle != NULL) {
+		ion_unmap_kernel(audio->client, audio->input_buff_handle);
+		ion_free(audio->client, audio->input_buff_handle);
 	}
+	ion_client_destroy(audio->client);
 	mutex_unlock(&audio->lock);
 #ifdef CONFIG_DEBUG_FS
 	if (audio->dentry)
@@ -1576,8 +1614,13 @@
 {
 	struct audio *audio = NULL;
 	int rc, dec_attrb, decid, i;
-	unsigned pmem_sz = DMASZ_MAX;
+	unsigned mem_sz = DMASZ_MAX;
 	struct audwmapro_event *e_node = NULL;
+	unsigned long ionflag = 0;
+	ion_phys_addr_t addr = 0;
+	struct ion_handle *handle = NULL;
+	struct ion_client *client = NULL;
+	int len = 0;
 #ifdef CONFIG_DEBUG_FS
 	/* 4 bytes represents decoder number, 1 byte for terminate string */
 	char name[sizeof "msm_wmapro_" + 5];
@@ -1620,36 +1663,52 @@
 	}
 	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;
+	client = msm_ion_client_create(UINT_MAX, "Audio_WMA_PRO_Client");
+	if (IS_ERR_OR_NULL(client)) {
+		pr_err("Unable to create ION client\n");
+		rc = -ENOMEM;
+		goto client_create_error;
 	}
-	audio->out_dma_sz = pmem_sz;
+	audio->client = client;
+
+	handle = ion_alloc(client, mem_sz, SZ_4K,
+		ION_HEAP(ION_AUDIO_HEAP_ID));
+	if (IS_ERR_OR_NULL(handle)) {
+		MM_ERR("Unable to create allocate O/P buffers\n");
+		rc = -ENOMEM;
+		goto output_buff_alloc_error;
+	}
+	audio->output_buff_handle = handle;
+
+	rc = ion_phys(client, handle, &addr, &len);
+	if (rc) {
+		MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+			(unsigned int) addr, (unsigned int) len);
+		goto output_buff_get_phys_error;
+	} else {
+		MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+			(unsigned int) addr, (unsigned int) len);
+	}
+	audio->phys = (int32_t)addr;
+
+
+	rc = ion_handle_get_flags(client, handle, &ionflag);
+	if (rc) {
+		MM_ERR("could not get flags for the handle\n");
+		goto output_buff_get_flags_error;
+	}
+
+	audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+	if (IS_ERR(audio->map_v_write)) {
+		MM_ERR("could not map write buffers\n");
+		rc = -ENOMEM;
+		goto output_buff_map_error;
+	}
+	audio->data = audio->map_v_write;
+	MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+		audio->phys, (int)audio->data);
+
+	audio->out_dma_sz = mem_sz;
 
 	rc = audmgr_open(&audio->audmgr);
 	if (rc) {
@@ -1677,6 +1736,7 @@
 		goto err;
 	}
 
+	audio->input_buff_handle = NULL;
 	mutex_init(&audio->lock);
 	mutex_init(&audio->write_lock);
 	mutex_init(&audio->read_lock);
@@ -1735,8 +1795,14 @@
 done:
 	return rc;
 err:
-	iounmap(audio->map_v_write);
-	free_contiguous_memory_by_paddr(audio->phys);
+	ion_unmap_kernel(client, audio->output_buff_handle);
+output_buff_map_error:
+output_buff_get_phys_error:
+output_buff_get_flags_error:
+	ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+	ion_client_destroy(client);
+client_create_error:
 	audpp_adec_free(audio->dec_id);
 	kfree(audio);
 	return rc;
diff --git a/arch/arm/mach-msm/rpm_resources.c b/arch/arm/mach-msm/rpm_resources.c
index f9edfc9..667ede0 100644
--- a/arch/arm/mach-msm/rpm_resources.c
+++ b/arch/arm/mach-msm/rpm_resources.c
@@ -1105,8 +1105,8 @@
 
 static int __init msm_rpmrs_l2_init(void)
 {
-	if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_apq8064() ||
-	    cpu_is_msm8627()) {
+	if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
+	    cpu_is_apq8064() || cpu_is_msm8627()) {
 
 		msm_pm_set_l2_flush_flag(0);
 
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index c37943c..08af4d4 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -259,6 +259,9 @@
 	/* 9625 IDs */
 	[134] = MSM_CPU_9625,
 
+	/* 8930AA ID */
+	[142] = MSM_CPU_8930AA,
+
 	/* Uninitialized IDs are not known to run Linux.
 	   MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
 	   considered as unknown CPU. */
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index fb560ba..9d2aedc 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -136,8 +136,8 @@
 
 	reg = saw_bases[cpu];
 
-	if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_apq8064() ||
-	    cpu_is_msm8627()) {
+	if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
+	    cpu_is_apq8064() || cpu_is_msm8627()) {
 		val = 0xA4;
 		reg += 0x14;
 		timeout = 512;
diff --git a/arch/arm/mach-msm/subsystem_map.c b/arch/arm/mach-msm/subsystem_map.c
index fcb8517..5f5a02b 100644
--- a/arch/arm/mach-msm/subsystem_map.c
+++ b/arch/arm/mach-msm/subsystem_map.c
@@ -38,8 +38,10 @@
 	VIDEO_DOMAIN,
 	VIDEO_DOMAIN,
 	CAMERA_DOMAIN,
-	DISPLAY_DOMAIN,
-	ROTATOR_DOMAIN,
+	DISPLAY_READ_DOMAIN,
+	DISPLAY_WRITE_DOMAIN,
+	ROTATOR_SRC_DOMAIN,
+	ROTATOR_DST_DOMAIN,
 	0xFFFFFFFF
 };
 
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index 03db126..a9a25b3 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -568,8 +568,8 @@
 		n_restart_orders = ARRAY_SIZE(orders_8x60_all);
 	}
 
-	if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm9615() ||
-			cpu_is_apq8064() || cpu_is_msm8627()) {
+	if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
+	    cpu_is_msm9615() || cpu_is_apq8064() || cpu_is_msm8627()) {
 		if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_SGLTE) {
 			restart_orders = restart_orders_8960_sglte;
 			n_restart_orders =
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index fcbd432..8d31683 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -964,8 +964,8 @@
 	if (!smp_processor_id())
 		return 0;
 
-	if (cpu_is_msm8x60() || cpu_is_msm8960() || cpu_is_apq8064()
-			|| cpu_is_msm8930() || cpu_is_msm8627())
+	if (cpu_is_msm8x60() || cpu_is_msm8960() || cpu_is_apq8064() ||
+	    cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627())
 		__raw_writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
 
 	if (__get_cpu_var(first_boot)) {
@@ -1062,7 +1062,7 @@
 		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() ||
-		   cpu_is_msm8627()) {
+		   cpu_is_msm8930aa() || cpu_is_msm8627()) {
 		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);
@@ -1071,7 +1071,8 @@
 		gpt->freq = 32765;
 		gpt_hz = 32765;
 		sclk_hz = 32765;
-		if (!cpu_is_msm8930() && !cpu_is_msm8627()) {
+		if (!cpu_is_msm8930() && !cpu_is_msm8930aa() &&
+		    !cpu_is_msm8627()) {
 			gpt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT;
 			dgt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT;
 		}
@@ -1122,8 +1123,8 @@
 
 		ce->irq = clock->irq;
 		if (cpu_is_msm8x60() || cpu_is_msm8960() || cpu_is_apq8064() ||
-				cpu_is_msm8930() || cpu_is_msm9615() ||
-				cpu_is_msm8625() || cpu_is_msm8627()) {
+		    cpu_is_msm8930() || cpu_is_msm8930aa() ||
+		    cpu_is_msm9615() || cpu_is_msm8625() || cpu_is_msm8627()) {
 			clock->percpu_evt = alloc_percpu(struct clock_event_device *);
 			if (!clock->percpu_evt) {
 				pr_err("msm_timer_init: memory allocation "
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 1c0f14b..74416e5 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -133,6 +133,7 @@
 		case MSM_CPU_8064:
 			return APQ8064_TOOLS_ID;
 		case MSM_CPU_8930:
+		case MSM_CPU_8930AA:
 			return MSM8930_TOOLS_ID;
 		case MSM_CPU_8974:
 			return MSM8974_TOOLS_ID;
@@ -157,6 +158,7 @@
 	case MSM_CPU_8960:
 	case MSM_CPU_8064:
 	case MSM_CPU_8930:
+	case MSM_CPU_8930AA:
 	case MSM_CPU_8627:
 	case MSM_CPU_9615:
 	case MSM_CPU_8974:
@@ -175,8 +177,8 @@
 {
 	if (driver->use_device_tree)
 		return 1;
-	else if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm9615() ||
-		cpu_is_apq8064() || cpu_is_msm8627())
+	else if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
+		cpu_is_msm9615() || cpu_is_apq8064() || cpu_is_msm8627())
 		return 1;
 	else
 		return 0;
diff --git a/drivers/char/msm_rotator.c b/drivers/char/msm_rotator.c
index 8650e83..e783a1a 100644
--- a/drivers/char/msm_rotator.c
+++ b/drivers/char/msm_rotator.c
@@ -97,6 +97,7 @@
 #define ROTATOR_REVISION_NONE	0xffffffff
 
 uint32_t rotator_hw_revision;
+static char rot_iommu_split_domain;
 
 /*
  * rotator_hw_revision:
@@ -174,6 +175,7 @@
 	unsigned long *start, unsigned long *len,
 	struct ion_handle **pihdl)
 {
+	int domain;
 	if (!msm_rotator_dev->client)
 		return -EINVAL;
 
@@ -185,8 +187,13 @@
 	pr_debug("%s(): ion_hdl %p, ion_fd %d\n", __func__, *pihdl,
 		ion_share_dma_buf(msm_rotator_dev->client, *pihdl));
 
+	if (rot_iommu_split_domain)
+		domain = src ? ROTATOR_SRC_DOMAIN : ROTATOR_DST_DOMAIN;
+	else
+		domain = ROTATOR_SRC_DOMAIN;
+
 	if (ion_map_iommu(msm_rotator_dev->client,
-		*pihdl,	ROTATOR_DOMAIN, GEN_POOL,
+		*pihdl,	domain, GEN_POOL,
 		SZ_4K, 0, start, len, 0, ION_IOMMU_UNMAP_DELAYED)) {
 		pr_err("ion_map_iommu() failed\n");
 		return -EINVAL;
@@ -862,17 +869,24 @@
 
 }
 
-static void put_img(struct file *p_file, struct ion_handle *p_ihdl)
+static void put_img(struct file *p_file, struct ion_handle *p_ihdl,
+	unsigned char src)
 {
 #ifdef CONFIG_ANDROID_PMEM
 	if (p_file != NULL)
 		put_pmem_file(p_file);
 #endif
+
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 	if (!IS_ERR_OR_NULL(p_ihdl)) {
+		int domain;
+		if (rot_iommu_split_domain)
+			domain = src ? ROTATOR_SRC_DOMAIN : ROTATOR_DST_DOMAIN;
+		else
+			domain = ROTATOR_SRC_DOMAIN;
 		pr_debug("%s(): p_ihdl %p\n", __func__, p_ihdl);
 		ion_unmap_iommu(msm_rotator_dev->client,
-			p_ihdl, ROTATOR_DOMAIN, GEN_POOL);
+			p_ihdl, domain, GEN_POOL);
 
 		ion_free(msm_rotator_dev->client, p_ihdl);
 	}
@@ -1162,15 +1176,15 @@
 #endif
 	schedule_delayed_work(&msm_rotator_dev->rot_clk_work, HZ);
 do_rotate_unlock_mutex:
-	put_img(dstp1_file, dstp1_ihdl);
-	put_img(srcp1_file, srcp1_ihdl);
-	put_img(dstp0_file, dstp0_ihdl);
+	put_img(dstp1_file, dstp1_ihdl, 0);
+	put_img(srcp1_file, srcp1_ihdl, 1);
+	put_img(dstp0_file, dstp0_ihdl, 0);
 
 	/* only source may use frame buffer */
 	if (info.src.flags & MDP_MEMORY_ID_TYPE_FB)
 		fput_light(srcp0_file, ps0_need);
 	else
-		put_img(srcp0_file, srcp0_ihdl);
+		put_img(srcp0_file, srcp0_ihdl, 1);
 	mutex_unlock(&msm_rotator_dev->rotator_lock);
 	dev_dbg(msm_rotator_dev->device, "%s() returning rc = %d\n",
 		__func__, rc);
@@ -1492,6 +1506,7 @@
 
 	pdata = pdev->dev.platform_data;
 	number_of_clks = pdata->number_of_clocks;
+	rot_iommu_split_domain = pdata->rot_iommu_split_domain;
 
 	msm_rotator_dev->imem_owner = IMEM_NO_OWNER;
 	mutex_init(&msm_rotator_dev->imem_lock);
diff --git a/drivers/gpio/gpio-msm-common.c b/drivers/gpio/gpio-msm-common.c
index 5539950..f268f33 100644
--- a/drivers/gpio/gpio-msm-common.c
+++ b/drivers/gpio/gpio-msm-common.c
@@ -31,11 +31,21 @@
 #include <mach/mpm.h>
 #include "gpio-msm-common.h"
 
+#ifdef CONFIG_GPIO_MSM_V3
+enum msm_tlmm_register {
+	SDC4_HDRV_PULL_CTL = 0x0, /* NOT USED */
+	SDC3_HDRV_PULL_CTL = 0x0, /* NOT USED */
+	SDC2_HDRV_PULL_CTL = 0x2048,
+	SDC1_HDRV_PULL_CTL = 0x2044,
+};
+#else
 enum msm_tlmm_register {
 	SDC4_HDRV_PULL_CTL = 0x20a0,
 	SDC3_HDRV_PULL_CTL = 0x20a4,
+	SDC2_HDRV_PULL_CTL = 0x0, /* NOT USED */
 	SDC1_HDRV_PULL_CTL = 0x20a0,
 };
+#endif
 
 struct tlmm_field_cfg {
 	enum msm_tlmm_register reg;
@@ -49,17 +59,24 @@
 	{SDC3_HDRV_PULL_CTL, 6}, /* TLMM_HDRV_SDC3_CLK  */
 	{SDC3_HDRV_PULL_CTL, 3}, /* TLMM_HDRV_SDC3_CMD  */
 	{SDC3_HDRV_PULL_CTL, 0}, /* TLMM_HDRV_SDC3_DATA */
+	{SDC2_HDRV_PULL_CTL, 6}, /* TLMM_HDRV_SDC2_CLK  */
+	{SDC2_HDRV_PULL_CTL, 3}, /* TLMM_HDRV_SDC2_CMD  */
+	{SDC2_HDRV_PULL_CTL, 0}, /* TLMM_HDRV_SDC2_DATA */
 	{SDC1_HDRV_PULL_CTL, 6}, /* TLMM_HDRV_SDC1_CLK  */
 	{SDC1_HDRV_PULL_CTL, 3}, /* TLMM_HDRV_SDC1_CMD  */
 	{SDC1_HDRV_PULL_CTL, 0}, /* TLMM_HDRV_SDC1_DATA */
 };
 
 static const struct tlmm_field_cfg tlmm_pull_cfgs[] = {
+	{SDC4_HDRV_PULL_CTL, 14}, /* TLMM_PULL_SDC4_CLK */
 	{SDC4_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC4_CMD  */
 	{SDC4_HDRV_PULL_CTL, 9},  /* TLMM_PULL_SDC4_DATA */
 	{SDC3_HDRV_PULL_CTL, 14}, /* TLMM_PULL_SDC3_CLK  */
 	{SDC3_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC3_CMD  */
 	{SDC3_HDRV_PULL_CTL, 9},  /* TLMM_PULL_SDC3_DATA */
+	{SDC2_HDRV_PULL_CTL, 14}, /* TLMM_PULL_SDC2_CLK  */
+	{SDC2_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC2_CMD  */
+	{SDC2_HDRV_PULL_CTL, 9},  /* TLMM_PULL_SDC2_DATA */
 	{SDC1_HDRV_PULL_CTL, 13}, /* TLMM_PULL_SDC1_CLK  */
 	{SDC1_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC1_CMD  */
 	{SDC1_HDRV_PULL_CTL, 9},  /* TLMM_PULL_SDC1_DATA */
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 4e34e89..c31f0f0 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -807,6 +807,7 @@
 	mutex_unlock(&client->lock);
 	return vaddr;
 }
+EXPORT_SYMBOL(ion_map_kernel);
 
 void ion_unmap_kernel(struct ion_client *client, struct ion_handle *handle)
 {
@@ -819,6 +820,7 @@
 	mutex_unlock(&buffer->lock);
 	mutex_unlock(&client->lock);
 }
+EXPORT_SYMBOL(ion_unmap_kernel);
 
 static int check_vaddr_bounds(unsigned long start, unsigned long end)
 {
@@ -884,6 +886,7 @@
 	return ret;
 
 }
+EXPORT_SYMBOL(ion_do_cache_op);
 
 static int ion_debug_client_show(struct seq_file *s, void *unused)
 {
@@ -1041,6 +1044,7 @@
 	kfree(client->name);
 	kfree(client);
 }
+EXPORT_SYMBOL(ion_client_destroy);
 
 int ion_handle_get_flags(struct ion_client *client, struct ion_handle *handle,
 			unsigned long *flags)
@@ -1104,6 +1108,7 @@
 	mutex_unlock(&client->lock);
 	return table;
 }
+EXPORT_SYMBOL(ion_sg_table);
 
 static struct sg_table *ion_map_dma_buf(struct dma_buf_attachment *attachment,
 					enum dma_data_direction direction)
@@ -1307,6 +1312,7 @@
 	}
 	return fd;
 }
+EXPORT_SYMBOL(ion_share_dma_buf);
 
 struct ion_handle *ion_import_dma_buf(struct ion_client *client, int fd)
 {
@@ -1343,6 +1349,7 @@
 	dma_buf_put(dmabuf);
 	return handle;
 }
+EXPORT_SYMBOL(ion_import_dma_buf);
 
 static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
@@ -1791,6 +1798,7 @@
 	mutex_unlock(&dev->lock);
 	return ret_val;
 }
+EXPORT_SYMBOL(ion_secure_heap);
 
 int ion_unsecure_heap(struct ion_device *dev, int heap_id, int version,
 			void *data)
@@ -1818,6 +1826,7 @@
 	mutex_unlock(&dev->lock);
 	return ret_val;
 }
+EXPORT_SYMBOL(ion_unsecure_heap);
 
 static int ion_debug_leak_show(struct seq_file *s, void *unused)
 {
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index c33089d..38b1b67 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -570,7 +570,7 @@
 			patchid = 1;
 		else
 			patchid = 0;
-	} else if (cpu_is_msm8930() || cpu_is_msm8627()) {
+	} else if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627()) {
 
 		/* A305 */
 		majorid = 0;
@@ -636,7 +636,8 @@
 static unsigned int
 adreno_getchipid(struct kgsl_device *device)
 {
-	if (cpu_is_apq8064() || cpu_is_msm8930() || cpu_is_msm8627())
+	if (cpu_is_apq8064() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
+	    cpu_is_msm8627())
 		return a3xx_getchipid(device);
 	else
 		return a2xx_getchipid(device);
diff --git a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
index c8a7a71..d6c5e66 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
@@ -181,7 +181,7 @@
 
 	/* Trustzone is only valid for some SOCs */
 	if (!(cpu_is_msm8x60() || cpu_is_msm8960() || cpu_is_apq8064() ||
-		cpu_is_msm8930() || cpu_is_msm8627()))
+		cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627()))
 		return -EINVAL;
 
 	priv = pwrscale->priv = kzalloc(sizeof(struct tz_priv), GFP_KERNEL);
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index 63120da..5703d88 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -11,7 +11,7 @@
   EXTRA_CFLAGS += -Idrivers/media/video/msm/sensors
   EXTRA_CFLAGS += -Idrivers/media/video/msm/actuators
   EXTRA_CFLAGS += -Idrivers/media/video/msm/server
-  obj-$(CONFIG_MSM_CAMERA) += msm_isp.o msm.o msm_mem.o msm_mctl.o msm_mctl_buf.o msm_mctl_pp.o
+  obj-$(CONFIG_MSM_CAMERA) += msm_isp.o msm.o msm_mem.o msm_mctl.o msm_mctl_buf.o msm_mctl_pp.o msm_vfe_stats_buf.o
   obj-$(CONFIG_MSM_CAMERA) += server/ eeprom/ sensors/ actuators/ csi/
   obj-$(CONFIG_MSM_CPP) += cpp/
   obj-$(CONFIG_MSM_CAMERA) += msm_gesture.o
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index c3e8321..08278ff 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -131,6 +131,8 @@
 	uint32_t    id;
 	uint32_t    buffer;
 	uint32_t    frameCounter;
+	int32_t     buf_idx;
+	int32_t     fd;
 };
 
 struct msm_free_buf {
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index 5c61cdb..5fcb62b 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -406,12 +406,14 @@
 		struct msm_stats_buf stats;
 		struct isp_msg_stats *isp_stats = (struct isp_msg_stats *)arg;
 
+		memset(&stats, 0, sizeof(stats));
 		isp_event->isp_data.isp_msg.msg_id = isp_stats->id;
 		isp_event->isp_data.isp_msg.frame_id =
 			isp_stats->frameCounter;
-		stats.buffer = msm_pmem_stats_ptov_lookup(pmctl,
-						isp_stats->buffer,
-						&(stats.fd));
+		stats.buffer = isp_stats->buffer;
+		stats.fd = isp_stats->fd;
+		/* buf_idx used for O(0) lookup */
+		stats.buf_idx = isp_stats->buf_idx;
 		switch (isp_stats->id) {
 		case MSG_ID_STATS_AEC:
 			stats.aec.buff = stats.buffer;
@@ -453,8 +455,8 @@
 				kmalloc(sizeof(struct msm_stats_buf),
 							GFP_ATOMIC);
 			if (!stats_buf) {
-				pr_err("%s: out of memory.\n",
-							__func__);
+				pr_err("%s: out of memory. stats_id = %d\n",
+					__func__, isp_stats->id);
 				rc = -ENOMEM;
 			} else {
 				*stats_buf = stats;
@@ -550,7 +552,6 @@
 	struct msm_cam_media_controller *mctl, void __user *arg)
 {
 	struct msm_vfe_cfg_cmd cfgcmd;
-	struct msm_pmem_region region[8];
 	struct axidata axi_data;
 
 	if (copy_from_user(&cfgcmd, arg, sizeof(cfgcmd))) {
@@ -562,103 +563,13 @@
 	CDBG("%s: cmd_type %d\n", __func__, cfgcmd.cmd_type);
 	switch (cfgcmd.cmd_type) {
 	case CMD_STATS_AF_ENABLE:
-		axi_data.bufnum1 =
-			msm_pmem_region_lookup(
-				&mctl->stats_info.pmem_stats_list,
-				MSM_PMEM_AF, &region[0],
-				NUM_STAT_OUTPUT_BUFFERS);
-		if (!axi_data.bufnum1) {
-			pr_err("%s %d: pmem region lookup error\n",
-				__func__, __LINE__);
-			return -EINVAL;
-		}
-		axi_data.region = &region[0];
-		return msm_isp_subdev_ioctl(sd, &cfgcmd,
-							&axi_data);
 	case CMD_STATS_AEC_ENABLE:
-		axi_data.bufnum1 =
-			msm_pmem_region_lookup(
-				&mctl->stats_info.pmem_stats_list,
-				MSM_PMEM_AEC, &region[0],
-				NUM_STAT_OUTPUT_BUFFERS);
-		if (!axi_data.bufnum1) {
-			pr_err("%s %d: pmem region lookup error\n",
-				__func__, __LINE__);
-			return -EINVAL;
-		}
-		axi_data.region = &region[0];
-		return msm_isp_subdev_ioctl(sd, &cfgcmd,
-							&axi_data);
 	case CMD_STATS_AWB_ENABLE:
-		axi_data.bufnum1 =
-			msm_pmem_region_lookup(
-				&mctl->stats_info.pmem_stats_list,
-				MSM_PMEM_AWB, &region[0],
-				NUM_STAT_OUTPUT_BUFFERS);
-		if (!axi_data.bufnum1) {
-			pr_err("%s %d: pmem region lookup error\n",
-				__func__, __LINE__);
-			return -EINVAL;
-		}
-		axi_data.region = &region[0];
-		return msm_isp_subdev_ioctl(sd, &cfgcmd,
-							&axi_data);
 	case CMD_STATS_AEC_AWB_ENABLE:
-		axi_data.bufnum1 =
-			msm_pmem_region_lookup(
-				&mctl->stats_info.pmem_stats_list,
-				MSM_PMEM_AEC_AWB, &region[0],
-				NUM_STAT_OUTPUT_BUFFERS);
-		if (!axi_data.bufnum1) {
-			pr_err("%s %d: pmem region lookup error\n",
-				__func__, __LINE__);
-			return -EINVAL;
-		}
-		axi_data.region = &region[0];
-		return msm_isp_subdev_ioctl(sd, &cfgcmd,
-							&axi_data);
 	case CMD_STATS_IHIST_ENABLE:
-		axi_data.bufnum1 =
-			msm_pmem_region_lookup(
-				&mctl->stats_info.pmem_stats_list,
-				MSM_PMEM_IHIST, &region[0],
-				NUM_STAT_OUTPUT_BUFFERS);
-		if (!axi_data.bufnum1) {
-			pr_err("%s %d: pmem region lookup error\n",
-				__func__, __LINE__);
-			return -EINVAL;
-		}
-		axi_data.region = &region[0];
-		return msm_isp_subdev_ioctl(sd, &cfgcmd,
-							&axi_data);
 	case CMD_STATS_RS_ENABLE:
-		axi_data.bufnum1 =
-			msm_pmem_region_lookup(
-				&mctl->stats_info.pmem_stats_list,
-				MSM_PMEM_RS, &region[0],
-				NUM_STAT_OUTPUT_BUFFERS);
-		if (!axi_data.bufnum1) {
-			pr_err("%s %d: pmem region lookup error\n",
-				__func__, __LINE__);
-			return -EINVAL;
-		}
-		axi_data.region = &region[0];
-		return msm_isp_subdev_ioctl(sd, &cfgcmd,
-							&axi_data);
 	case CMD_STATS_CS_ENABLE:
-		axi_data.bufnum1 =
-			msm_pmem_region_lookup(
-				&mctl->stats_info.pmem_stats_list,
-				MSM_PMEM_CS, &region[0],
-				NUM_STAT_OUTPUT_BUFFERS);
-		if (!axi_data.bufnum1) {
-			pr_err("%s %d: pmem region lookup error\n",
-				__func__, __LINE__);
-			return -EINVAL;
-		}
-		axi_data.region = &region[0];
-		return msm_isp_subdev_ioctl(sd, &cfgcmd,
-							&axi_data);
+		return msm_isp_subdev_ioctl(sd, &cfgcmd, NULL);
 	case CMD_GENERAL:
 	case CMD_STATS_DISABLE:
 		return msm_isp_subdev_ioctl(sd, &cfgcmd,
@@ -764,6 +675,62 @@
 	return rc;
 }
 
+static int msm_vfe_stats_buf_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd,
+	struct msm_cam_media_controller *mctl,
+	void __user *arg)
+{
+	struct msm_vfe_cfg_cmd cfgcmd;
+	int rc = 0;
+	switch (cmd) {
+	case MSM_CAM_IOCTL_STATS_REQBUF: {
+		struct msm_stats_reqbuf reqbuf;
+		if (copy_from_user(&reqbuf, arg,
+			sizeof(struct msm_stats_reqbuf))) {
+			ERR_COPY_FROM_USER();
+			return -EFAULT;
+		}
+	cfgcmd.cmd_type = VFE_CMD_STATS_REQBUF;
+	cfgcmd.value = (void *)&reqbuf;
+	cfgcmd.length = sizeof(struct msm_stats_reqbuf);
+	rc = msm_isp_subdev_ioctl(sd, &cfgcmd, (void *)mctl->client);
+	break;
+	}
+	case MSM_CAM_IOCTL_STATS_ENQUEUEBUF: {
+		struct msm_stats_buf_info buf_info;
+
+		if (copy_from_user(&buf_info, arg,
+			sizeof(struct msm_stats_buf_info))) {
+			ERR_COPY_FROM_USER();
+			return -EFAULT;
+		}
+	cfgcmd.cmd_type = VFE_CMD_STATS_ENQUEUEBUF;
+	cfgcmd.value = (void *)&buf_info;
+	cfgcmd.length = sizeof(struct msm_stats_buf_info);
+	rc = msm_isp_subdev_ioctl(sd, &cfgcmd, NULL);
+	break;
+	}
+	case MSM_CAM_IOCTL_STATS_FLUSH_BUFQ: {
+		struct msm_stats_flush_bufq bufq_info;
+
+		if (copy_from_user(&bufq_info, arg,
+			sizeof(struct msm_stats_flush_bufq))) {
+			ERR_COPY_FROM_USER();
+			return -EFAULT;
+	}
+	cfgcmd.cmd_type = VFE_CMD_STATS_FLUSH_BUFQ;
+	cfgcmd.value = (void *)&bufq_info;
+	cfgcmd.length = sizeof(struct msm_stats_flush_bufq);
+	rc = msm_isp_subdev_ioctl(sd, &cfgcmd, NULL);
+	break;
+	}
+	default:
+		rc = -1;
+	break;
+	}
+	CDBG("%s\n", __func__);
+	return rc;
+}
 /* config function simliar to origanl msm_ioctl_config*/
 static int msm_isp_config(struct msm_cam_media_controller *pmctl,
 			 unsigned int cmd, unsigned long arg)
@@ -789,6 +756,12 @@
 		rc = msm_put_stats_buffer(sd, pmctl, argp);
 		break;
 
+	case MSM_CAM_IOCTL_STATS_REQBUF:
+	case MSM_CAM_IOCTL_STATS_ENQUEUEBUF:
+	case MSM_CAM_IOCTL_STATS_FLUSH_BUFQ:
+		rc = msm_vfe_stats_buf_ioctl(sd, cmd, pmctl, argp);
+		break;
+
 	default:
 		break;
 	}
diff --git a/drivers/media/video/msm/msm_vfe31_v4l2.c b/drivers/media/video/msm/msm_vfe31_v4l2.c
index fa985ce..2331fcc 100644
--- a/drivers/media/video/msm/msm_vfe31_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe31_v4l2.c
@@ -365,6 +365,229 @@
 	"DEMOSAICV3_UPDATE",
 };
 
+
+static unsigned long vfe31_stats_dqbuf(enum msm_stats_enum_type stats_type)
+{
+	struct msm_stats_meta_buf *buf = NULL;
+	int rc = 0;
+	rc = vfe31_ctrl->stats_ops.dqbuf(vfe31_ctrl->stats_ops.stats_ctrl,
+			stats_type, &buf);
+	if (rc < 0) {
+		pr_err("%s: dq stats buf (type = %d) err = %d",
+			__func__, stats_type, rc);
+		return 0L;
+	}
+	return buf->paddr;
+}
+
+static unsigned long vfe31_stats_flush_enqueue(
+	enum msm_stats_enum_type stats_type)
+{
+	struct msm_stats_bufq *bufq = NULL;
+	struct msm_stats_meta_buf *stats_buf = NULL;
+	int rc = 0;
+	int i;
+	/*
+	 * Passing NULL for ion client as the buffers are already
+	 * mapped at this stage, client is not required, flush all
+	 * the buffers, and buffers move to PREPARE state
+	 */
+
+	rc = vfe31_ctrl->stats_ops.bufq_flush(
+			vfe31_ctrl->stats_ops.stats_ctrl, stats_type, NULL);
+	if (rc < 0) {
+		pr_err("%s: dq stats buf (type = %d) err = %d",
+			__func__, stats_type, rc);
+		return 0L;
+	}
+
+	/* Queue all the buffers back to QUEUED state */
+	bufq = vfe31_ctrl->stats_ctrl.bufq[stats_type];
+	for (i = 0; i < bufq->num_bufs; i++) {
+		stats_buf = &bufq->bufs[i];
+		rc = vfe31_ctrl->stats_ops.enqueue_buf(
+				vfe31_ctrl->stats_ops.stats_ctrl,
+				&(stats_buf->info), NULL);
+		if (rc < 0) {
+			pr_err("%s: dq stats buf (type = %d) err = %d",
+				__func__, stats_type, rc);
+			return rc;
+		}
+	}
+	return 0L;
+}
+
+static int vfe_stats_awb_buf_init(
+	struct vfe_cmd_stats_buf *in)
+{
+	uint32_t addr;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AWB);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq awb ping buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe31_ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR);
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AWB);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq awb ping buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe31_ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR);
+	return 0;
+}
+
+static int vfe_stats_aec_buf_init(
+	struct vfe_cmd_stats_buf *in)
+{
+	uint32_t addr;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AEC);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq aec ping buf from free buf queue",
+			__func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe31_ctrl->vfebase +
+		VFE_BUS_STATS_AEC_WR_PING_ADDR);
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AEC);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq aec pong buf from free buf queue",
+			__func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe31_ctrl->vfebase +
+		VFE_BUS_STATS_AEC_WR_PONG_ADDR);
+	return 0;
+}
+
+static int vfe_stats_af_buf_init(
+	struct vfe_cmd_stats_buf *in)
+{
+	uint32_t addr;
+	unsigned long flags;
+	int rc = 0;
+
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	rc = vfe31_stats_flush_enqueue(MSM_STATS_TYPE_AF);
+	if (rc < 0) {
+		pr_err("%s: dq stats buf err = %d",
+			__func__, rc);
+		spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+		return -EINVAL;
+	}
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AF);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq af ping buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe31_ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR);
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AF);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq af pong buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe31_ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR);
+	return 0;
+}
+
+static int vfe_stats_ihist_buf_init(
+	struct vfe_cmd_stats_buf *in)
+{
+	uint32_t addr;
+	unsigned long flags;
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_IHIST);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq ihist ping buf from free buf queue",
+			__func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe31_ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PING_ADDR);
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_IHIST);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq ihist pong buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe31_ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PONG_ADDR);
+	return 0;
+}
+
+static int vfe_stats_rs_buf_init(struct vfe_cmd_stats_buf *in)
+{
+	uint32_t addr;
+	unsigned long flags;
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_RS);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq rs ping buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe31_ctrl->vfebase + VFE_BUS_STATS_RS_WR_PING_ADDR);
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_RS);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq rs pong buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe31_ctrl->vfebase + VFE_BUS_STATS_RS_WR_PONG_ADDR);
+	return 0;
+}
+
+static int vfe_stats_cs_buf_init(struct vfe_cmd_stats_buf *in)
+{
+	uint32_t addr;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_CS);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq cs ping buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe31_ctrl->vfebase + VFE_BUS_STATS_CS_WR_PING_ADDR);
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_CS);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq cs pong buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
+	msm_camera_io_w(addr,
+		vfe31_ctrl->vfebase + VFE_BUS_STATS_CS_WR_PONG_ADDR);
+	return 0;
+}
+
 static void vfe31_stop(void)
 {
 	uint8_t  axiBusyFlag = true;
@@ -600,101 +823,6 @@
 	return 0;
 }
 
-static uint32_t vfe_stats_awb_buf_init(struct vfe_cmd_stats_buf *in)
-{
-	uint32_t *ptr = in->statsBuf;
-	uint32_t addr;
-
-	addr = ptr[0];
-	msm_camera_io_w(addr,
-		vfe31_ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR);
-	addr = ptr[1];
-	msm_camera_io_w(addr,
-		vfe31_ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR);
-	vfe31_ctrl->awbStatsControl.nextFrameAddrBuf = in->statsBuf[2];
-	return 0;
-}
-
-static uint32_t vfe_stats_aec_buf_init(struct vfe_cmd_stats_buf *in)
-{
-	uint32_t *ptr = in->statsBuf;
-	uint32_t addr;
-
-	addr = ptr[0];
-	msm_camera_io_w(addr,
-		vfe31_ctrl->vfebase + VFE_BUS_STATS_AEC_WR_PING_ADDR);
-	addr = ptr[1];
-	msm_camera_io_w(addr,
-		vfe31_ctrl->vfebase + VFE_BUS_STATS_AEC_WR_PONG_ADDR);
-
-	vfe31_ctrl->aecStatsControl.nextFrameAddrBuf = in->statsBuf[2];
-	return 0;
-}
-
-static uint32_t vfe_stats_af_buf_init(struct vfe_cmd_stats_buf *in)
-{
-	uint32_t *ptr = in->statsBuf;
-	uint32_t addr;
-
-	addr = ptr[0];
-	msm_camera_io_w(addr,
-		vfe31_ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR);
-	addr = ptr[1];
-	msm_camera_io_w(addr,
-		vfe31_ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR);
-
-	vfe31_ctrl->afStatsControl.nextFrameAddrBuf = in->statsBuf[2];
-	return 0;
-}
-
-static uint32_t vfe_stats_ihist_buf_init(struct vfe_cmd_stats_buf *in)
-{
-	uint32_t *ptr = in->statsBuf;
-	uint32_t addr;
-
-	addr = ptr[0];
-	msm_camera_io_w(addr,
-		vfe31_ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PING_ADDR);
-	addr = ptr[1];
-	msm_camera_io_w(addr,
-		vfe31_ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PONG_ADDR);
-
-	vfe31_ctrl->ihistStatsControl.nextFrameAddrBuf = in->statsBuf[2];
-	return 0;
-}
-
-static uint32_t vfe_stats_rs_buf_init(struct vfe_cmd_stats_buf *in)
-{
-	uint32_t *ptr = in->statsBuf;
-	uint32_t addr;
-
-	addr = ptr[0];
-	msm_camera_io_w(addr,
-		vfe31_ctrl->vfebase + VFE_BUS_STATS_RS_WR_PING_ADDR);
-	addr = ptr[1];
-	msm_camera_io_w(addr,
-		vfe31_ctrl->vfebase + VFE_BUS_STATS_RS_WR_PONG_ADDR);
-
-	vfe31_ctrl->rsStatsControl.nextFrameAddrBuf = in->statsBuf[2];
-	return 0;
-}
-
-static uint32_t vfe_stats_cs_buf_init(struct vfe_cmd_stats_buf *in)
-{
-	uint32_t *ptr = in->statsBuf;
-	uint32_t addr;
-
-	addr = ptr[0];
-	msm_camera_io_w(addr,
-		vfe31_ctrl->vfebase + VFE_BUS_STATS_CS_WR_PING_ADDR);
-	addr = ptr[1];
-	msm_camera_io_w(addr,
-		vfe31_ctrl->vfebase + VFE_BUS_STATS_CS_WR_PONG_ADDR);
-
-	vfe31_ctrl->csStatsControl.nextFrameAddrBuf = in->statsBuf[2];
-	return 0;
-}
-
 static void msm_camera_io_dump2(void __iomem *addr, int size)
 {
 	char line_str[BUFF_SIZE_128], *p_str;
@@ -1388,6 +1516,12 @@
 		break;
 
 	case VFE_CMD_STATS_AE_START:
+		rc = vfe_stats_aec_buf_init(NULL);
+		if (rc < 0) {
+			pr_err("%s: cannot config ping/pong address of AEC",
+				__func__);
+			goto proc_general_done;
+		}
 		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
 		if (!cmdp) {
 			rc = -ENOMEM;
@@ -1408,6 +1542,12 @@
 		cmdp, (vfe31_cmd[cmd->id].length));
 		break;
 	case VFE_CMD_STATS_AF_START:
+		rc = vfe_stats_af_buf_init(NULL);
+		if (rc < 0) {
+			pr_err("%s: cannot config ping/pong address of AF",
+				__func__);
+			goto proc_general_done;
+		}
 		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
 		if (!cmdp) {
 			rc = -ENOMEM;
@@ -1428,6 +1568,12 @@
 		cmdp, (vfe31_cmd[cmd->id].length));
 		break;
 	case VFE_CMD_STATS_AWB_START:
+		rc = vfe_stats_awb_buf_init(NULL);
+		if (rc < 0) {
+			pr_err("%s: cannot config ping/pong address of AWB",
+				__func__);
+			goto proc_general_done;
+		}
 		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
 		if (!cmdp) {
 			rc = -ENOMEM;
@@ -1449,6 +1595,12 @@
 		break;
 
 	case VFE_CMD_STATS_IHIST_START:
+		rc = vfe_stats_ihist_buf_init(NULL);
+		if (rc < 0) {
+			pr_err("%s: cannot config ping/pong address of IHIST",
+			__func__);
+			goto proc_general_done;
+		}
 		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
 		if (!cmdp) {
 			rc = -ENOMEM;
@@ -1470,6 +1622,12 @@
 		break;
 
 	case VFE_CMD_STATS_RS_START:
+		rc = vfe_stats_rs_buf_init(NULL);
+		if (rc < 0) {
+			pr_err("%s: cannot config ping/pong address of RS",
+				__func__);
+			goto proc_general_done;
+		}
 		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
 		if (!cmdp) {
 			rc = -ENOMEM;
@@ -1487,6 +1645,12 @@
 		break;
 
 	case VFE_CMD_STATS_CS_START:
+		rc = vfe_stats_cs_buf_init(NULL);
+		if (rc < 0) {
+			pr_err("%s: cannot config ping/pong address of CS",
+				__func__);
+			goto proc_general_done;
+		}
 		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
 		if (!cmdp) {
 			rc = -ENOMEM;
@@ -1987,6 +2151,12 @@
 		old_val &= ~AF_BF_ENABLE_MASK;
 		msm_camera_io_w(old_val,
 			vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+		rc = vfe31_stats_flush_enqueue(MSM_STATS_TYPE_AF);
+		if (rc < 0) {
+			pr_err("%s: dq stats buf err = %d",
+				   __func__, rc);
+			return -EINVAL;
+		}
 		break;
 
 	case VFE_CMD_STATS_IHIST_STOP:
@@ -2172,76 +2342,6 @@
 	return rc;
 }
 
-static void vfe31_stats_af_ack(struct vfe_cmd_stats_ack *pAck)
-{
-	unsigned long flags;
-	spinlock_t *lock = (vfe31_ctrl->stats_comp ?
-		&vfe31_ctrl->comp_stats_ack_lock :
-		&vfe31_ctrl->af_ack_lock);
-	spin_lock_irqsave(lock, flags);
-	vfe31_ctrl->afStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
-	vfe31_ctrl->afStatsControl.ackPending = FALSE;
-	spin_unlock_irqrestore(lock, flags);
-}
-
-static void vfe31_stats_awb_ack(struct vfe_cmd_stats_ack *pAck)
-{
-	unsigned long flags;
-	spinlock_t *lock = (vfe31_ctrl->stats_comp ?
-		&vfe31_ctrl->comp_stats_ack_lock :
-		&vfe31_ctrl->awb_ack_lock);
-	spin_lock_irqsave(lock, flags);
-	vfe31_ctrl->awbStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
-	vfe31_ctrl->awbStatsControl.ackPending = FALSE;
-	spin_unlock_irqrestore(lock, flags);
-}
-
-static void vfe31_stats_aec_ack(struct vfe_cmd_stats_ack *pAck)
-{
-	unsigned long flags;
-	spinlock_t *lock = (vfe31_ctrl->stats_comp ?
-		&vfe31_ctrl->comp_stats_ack_lock :
-		&vfe31_ctrl->aec_ack_lock);
-	spin_lock_irqsave(lock, flags);
-	vfe31_ctrl->aecStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
-	vfe31_ctrl->aecStatsControl.ackPending = FALSE;
-	spin_unlock_irqrestore(lock, flags);
-}
-
-static void vfe31_stats_ihist_ack(struct vfe_cmd_stats_ack *pAck)
-{
-	unsigned long flags;
-	spinlock_t *lock = (vfe31_ctrl->stats_comp ?
-		&vfe31_ctrl->comp_stats_ack_lock :
-		&vfe31_ctrl->ihist_ack_lock);
-	spin_lock_irqsave(lock, flags);
-	vfe31_ctrl->ihistStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
-	vfe31_ctrl->ihistStatsControl.ackPending = FALSE;
-	spin_unlock_irqrestore(lock, flags);
-}
-static void vfe31_stats_rs_ack(struct vfe_cmd_stats_ack *pAck)
-{
-	unsigned long flags;
-	spinlock_t *lock = (vfe31_ctrl->stats_comp ?
-		&vfe31_ctrl->comp_stats_ack_lock :
-		&vfe31_ctrl->rs_ack_lock);
-	spin_lock_irqsave(lock, flags);
-	vfe31_ctrl->rsStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
-	vfe31_ctrl->rsStatsControl.ackPending = FALSE;
-	spin_unlock_irqrestore(lock, flags);
-}
-static void vfe31_stats_cs_ack(struct vfe_cmd_stats_ack *pAck)
-{
-	unsigned long flags;
-	spinlock_t *lock = (vfe31_ctrl->stats_comp ?
-		&vfe31_ctrl->comp_stats_ack_lock :
-		&vfe31_ctrl->cs_ack_lock);
-	spin_lock_irqsave(lock, flags);
-	vfe31_ctrl->csStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
-	vfe31_ctrl->csStatsControl.ackPending = FALSE;
-	spin_unlock_irqrestore(lock, flags);
-}
-
 static inline void vfe31_read_irq_status(struct vfe31_irq_status *out)
 {
 	uint32_t *temp;
@@ -2810,7 +2910,8 @@
 static void
 vfe_send_stats_msg(uint32_t bufAddress, uint32_t statsNum)
 {
-	unsigned long flags;
+	int rc = 0;
+	void *vaddr = NULL;
 	/* fill message with right content. */
 	/* @todo This is causing issues, need further investigate */
 	/* spin_lock_irqsave(&ctrl->state_lock, flags); */
@@ -2821,55 +2922,72 @@
 	switch (statsNum) {
 	case STATS_AE_NUM:{
 		msgStats.id = MSG_ID_STATS_AEC;
-		spin_lock_irqsave(&vfe31_ctrl->aec_ack_lock, flags);
-		vfe31_ctrl->aecStatsControl.ackPending = TRUE;
-		spin_unlock_irqrestore(&vfe31_ctrl->aec_ack_lock, flags);
+		rc = vfe31_ctrl->stats_ops.dispatch(
+				vfe31_ctrl->stats_ops.stats_ctrl,
+				MSM_STATS_TYPE_AEC,	bufAddress,
+				&msgStats.buf_idx, &vaddr, &msgStats.fd,
+				vfe31_ctrl->stats_ops.client);
 		}
 		break;
 	case STATS_AF_NUM:{
 		msgStats.id = MSG_ID_STATS_AF;
-		spin_lock_irqsave(&vfe31_ctrl->af_ack_lock, flags);
-		vfe31_ctrl->afStatsControl.ackPending = TRUE;
-		spin_unlock_irqrestore(&vfe31_ctrl->af_ack_lock, flags);
+		rc = vfe31_ctrl->stats_ops.dispatch(
+				vfe31_ctrl->stats_ops.stats_ctrl,
+				MSM_STATS_TYPE_AF, bufAddress,
+				&msgStats.buf_idx, &vaddr, &msgStats.fd,
+				vfe31_ctrl->stats_ops.client);
 		}
 		break;
 	case STATS_AWB_NUM: {
 		msgStats.id = MSG_ID_STATS_AWB;
-		spin_lock_irqsave(&vfe31_ctrl->awb_ack_lock, flags);
-		vfe31_ctrl->awbStatsControl.ackPending = TRUE;
-		spin_unlock_irqrestore(&vfe31_ctrl->awb_ack_lock, flags);
+		rc = vfe31_ctrl->stats_ops.dispatch(
+				vfe31_ctrl->stats_ops.stats_ctrl,
+				MSM_STATS_TYPE_AWB, bufAddress,
+				&msgStats.buf_idx, &vaddr, &msgStats.fd,
+				vfe31_ctrl->stats_ops.client);
 		}
 		break;
 
 	case STATS_IHIST_NUM: {
 		msgStats.id = MSG_ID_STATS_IHIST;
-		spin_lock_irqsave(&vfe31_ctrl->ihist_ack_lock, flags);
-		vfe31_ctrl->ihistStatsControl.ackPending = TRUE;
-		spin_unlock_irqrestore(&vfe31_ctrl->ihist_ack_lock, flags);
+		rc = vfe31_ctrl->stats_ops.dispatch(
+				vfe31_ctrl->stats_ops.stats_ctrl,
+				MSM_STATS_TYPE_IHIST, bufAddress,
+				&msgStats.buf_idx, &vaddr, &msgStats.fd,
+				vfe31_ctrl->stats_ops.client);
 		}
 		break;
 	case STATS_RS_NUM: {
 		msgStats.id = MSG_ID_STATS_RS;
-		spin_lock_irqsave(&vfe31_ctrl->rs_ack_lock, flags);
-		vfe31_ctrl->rsStatsControl.ackPending = TRUE;
-		spin_unlock_irqrestore(&vfe31_ctrl->rs_ack_lock, flags);
+		rc = vfe31_ctrl->stats_ops.dispatch(
+				vfe31_ctrl->stats_ops.stats_ctrl,
+				MSM_STATS_TYPE_RS, bufAddress,
+				&msgStats.buf_idx, &vaddr, &msgStats.fd,
+				vfe31_ctrl->stats_ops.client);
 		}
 		break;
 	case STATS_CS_NUM: {
 		msgStats.id = MSG_ID_STATS_CS;
-		spin_lock_irqsave(&vfe31_ctrl->cs_ack_lock, flags);
-		vfe31_ctrl->csStatsControl.ackPending = TRUE;
-		spin_unlock_irqrestore(&vfe31_ctrl->cs_ack_lock, flags);
+		rc = vfe31_ctrl->stats_ops.dispatch(
+				vfe31_ctrl->stats_ops.stats_ctrl,
+				MSM_STATS_TYPE_CS, bufAddress,
+				&msgStats.buf_idx, &vaddr, &msgStats.fd,
+				vfe31_ctrl->stats_ops.client);
 		}
 		break;
 
 	default:
 		goto stats_done;
 	}
-
-	v4l2_subdev_notify(&vfe31_ctrl->subdev,
-				NOTIFY_VFE_MSG_STATS,
-				&msgStats);
+	if (rc == 0) {
+		msgStats.buffer = (uint32_t)vaddr;
+		v4l2_subdev_notify(&vfe31_ctrl->subdev,
+			NOTIFY_VFE_MSG_STATS, &msgStats);
+	} else {
+		pr_err("%s: paddr to idx mapping error, stats_id = %d,\n"
+			"paddr = 0x%d\n", __func__,
+			 msgStats.id, msgStats.buffer);
+	}
 stats_done:
 	/* spin_unlock_irqrestore(&ctrl->state_lock, flags); */
 	return;
@@ -2901,17 +3019,18 @@
 static void vfe31_process_stats_ae_irq(void)
 {
 	unsigned long flags;
-	spin_lock_irqsave(&vfe31_ctrl->aec_ack_lock, flags);
-	if (!(vfe31_ctrl->aecStatsControl.ackPending)) {
-		spin_unlock_irqrestore(&vfe31_ctrl->aec_ack_lock, flags);
+	uint32_t addr;
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AEC);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (addr) {
 		vfe31_ctrl->aecStatsControl.bufToRender =
 			vfe31_process_stats_irq_common(STATS_AE_NUM,
-			vfe31_ctrl->aecStatsControl.nextFrameAddrBuf);
+			addr);
 
 		vfe_send_stats_msg(vfe31_ctrl->aecStatsControl.bufToRender,
 			STATS_AE_NUM);
 	} else{
-		spin_unlock_irqrestore(&vfe31_ctrl->aec_ack_lock, flags);
 		vfe31_ctrl->aecStatsControl.droppedStatsFrameCount++;
 		CDBG("%s: droppedStatsFrameCount = %d", __func__,
 			vfe31_ctrl->aecStatsControl.droppedStatsFrameCount);
@@ -2921,17 +3040,18 @@
 static void vfe31_process_stats_awb_irq(void)
 {
 	unsigned long flags;
-	spin_lock_irqsave(&vfe31_ctrl->awb_ack_lock, flags);
-	if (!(vfe31_ctrl->awbStatsControl.ackPending)) {
-		spin_unlock_irqrestore(&vfe31_ctrl->awb_ack_lock, flags);
+	uint32_t addr;
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AWB);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (addr) {
 		vfe31_ctrl->awbStatsControl.bufToRender =
 			vfe31_process_stats_irq_common(STATS_AWB_NUM,
-			vfe31_ctrl->awbStatsControl.nextFrameAddrBuf);
+			addr);
 
 		vfe_send_stats_msg(vfe31_ctrl->awbStatsControl.bufToRender,
 			STATS_AWB_NUM);
 	} else{
-		spin_unlock_irqrestore(&vfe31_ctrl->awb_ack_lock, flags);
 		vfe31_ctrl->awbStatsControl.droppedStatsFrameCount++;
 		CDBG("%s: droppedStatsFrameCount = %d", __func__,
 			vfe31_ctrl->awbStatsControl.droppedStatsFrameCount);
@@ -2941,17 +3061,18 @@
 static void vfe31_process_stats_af_irq(void)
 {
 	unsigned long flags;
-	spin_lock_irqsave(&vfe31_ctrl->af_ack_lock, flags);
-	if (!(vfe31_ctrl->afStatsControl.ackPending)) {
-		spin_unlock_irqrestore(&vfe31_ctrl->af_ack_lock, flags);
+	uint32_t addr;
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AF);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (addr) {
 		vfe31_ctrl->afStatsControl.bufToRender =
 			vfe31_process_stats_irq_common(STATS_AF_NUM,
-			vfe31_ctrl->afStatsControl.nextFrameAddrBuf);
+			addr);
 
 		vfe_send_stats_msg(vfe31_ctrl->afStatsControl.bufToRender,
 			STATS_AF_NUM);
 	} else{
-		spin_unlock_irqrestore(&vfe31_ctrl->af_ack_lock, flags);
 		vfe31_ctrl->afStatsControl.droppedStatsFrameCount++;
 		CDBG("%s: droppedStatsFrameCount = %d", __func__,
 			vfe31_ctrl->afStatsControl.droppedStatsFrameCount);
@@ -2960,27 +3081,35 @@
 
 static void vfe31_process_stats_ihist_irq(void)
 {
-	if (!(vfe31_ctrl->ihistStatsControl.ackPending)) {
+	unsigned long flags;
+	uint32_t addr;
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_IHIST);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (addr) {
 		vfe31_ctrl->ihistStatsControl.bufToRender =
-			vfe31_process_stats_irq_common(STATS_IHIST_NUM,
-			vfe31_ctrl->ihistStatsControl.nextFrameAddrBuf);
-
+			  vfe31_process_stats_irq_common(STATS_IHIST_NUM,
+				addr);
 		vfe_send_stats_msg(vfe31_ctrl->ihistStatsControl.bufToRender,
-			STATS_IHIST_NUM);
+			  STATS_IHIST_NUM);
 	} else {
 		vfe31_ctrl->ihistStatsControl.droppedStatsFrameCount++;
 		CDBG("%s: droppedStatsFrameCount = %d", __func__,
-			vfe31_ctrl->ihistStatsControl.droppedStatsFrameCount);
+			 vfe31_ctrl->ihistStatsControl.droppedStatsFrameCount);
 	}
 }
 
 static void vfe31_process_stats_rs_irq(void)
 {
-	if (!(vfe31_ctrl->rsStatsControl.ackPending)) {
+	unsigned long flags;
+	uint32_t addr;
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_RS);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (addr) {
 		vfe31_ctrl->rsStatsControl.bufToRender =
 			vfe31_process_stats_irq_common(STATS_RS_NUM,
-			vfe31_ctrl->rsStatsControl.nextFrameAddrBuf);
-
+			addr);
 		vfe_send_stats_msg(vfe31_ctrl->rsStatsControl.bufToRender,
 			STATS_RS_NUM);
 	} else {
@@ -2992,12 +3121,29 @@
 
 static void vfe31_process_stats_cs_irq(void)
 {
+	unsigned long flags;
+	uint32_t addr;
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_CS);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
+	if (addr) {
+		vfe31_ctrl->csStatsControl.bufToRender =
+			vfe31_process_stats_irq_common(STATS_CS_NUM,
+				addr);
+			vfe_send_stats_msg(
+				vfe31_ctrl->csStatsControl.bufToRender,
+				STATS_CS_NUM);
+	} else {
+		vfe31_ctrl->csStatsControl.droppedStatsFrameCount++;
+		CDBG("%s: droppedStatsFrameCount = %d", __func__,
+			vfe31_ctrl->csStatsControl.droppedStatsFrameCount);
+	}
 	if (!(vfe31_ctrl->csStatsControl.ackPending)) {
 		vfe31_ctrl->csStatsControl.bufToRender =
 			vfe31_process_stats_irq_common(STATS_CS_NUM,
-			vfe31_ctrl->csStatsControl.nextFrameAddrBuf);
-
-		vfe_send_stats_msg(vfe31_ctrl->csStatsControl.bufToRender,
+				vfe31_ctrl->csStatsControl.nextFrameAddrBuf);
+		vfe_send_stats_msg(
+			vfe31_ctrl->csStatsControl.bufToRender,
 			STATS_CS_NUM);
 	} else {
 		vfe31_ctrl->csStatsControl.droppedStatsFrameCount++;
@@ -3010,15 +3156,16 @@
 {
 	unsigned long flags;
 	int32_t process_stats = false;
+	uint32_t addr;
 	CDBG("%s, stats = 0x%x\n", __func__, status_bits);
 
-	spin_lock_irqsave(&vfe31_ctrl->comp_stats_ack_lock, flags);
+	spin_lock_irqsave(&vfe31_ctrl->stats_bufq_lock, flags);
 	if (status_bits & VFE_IRQ_STATUS0_STATS_AEC) {
-		if (!vfe31_ctrl->aecStatsControl.ackPending) {
-			vfe31_ctrl->aecStatsControl.ackPending = TRUE;
+		addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AEC);
+		if (addr) {
 			vfe31_ctrl->aecStatsControl.bufToRender =
 				vfe31_process_stats_irq_common(STATS_AE_NUM,
-				vfe31_ctrl->aecStatsControl.nextFrameAddrBuf);
+				addr);
 			process_stats = true;
 		} else{
 			vfe31_ctrl->aecStatsControl.bufToRender = 0;
@@ -3029,11 +3176,11 @@
 	}
 
 	if (status_bits & VFE_IRQ_STATUS0_STATS_AWB) {
-		if (!vfe31_ctrl->awbStatsControl.ackPending) {
-			vfe31_ctrl->awbStatsControl.ackPending = TRUE;
+		addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AWB);
+		if (addr) {
 			vfe31_ctrl->awbStatsControl.bufToRender =
 				vfe31_process_stats_irq_common(STATS_AWB_NUM,
-				vfe31_ctrl->awbStatsControl.nextFrameAddrBuf);
+				addr);
 			process_stats = true;
 		} else{
 			vfe31_ctrl->awbStatsControl.droppedStatsFrameCount++;
@@ -3045,11 +3192,11 @@
 
 
 	if (status_bits & VFE_IRQ_STATUS0_STATS_AF) {
-		if (!vfe31_ctrl->afStatsControl.ackPending) {
-			vfe31_ctrl->afStatsControl.ackPending = TRUE;
+		addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_AF);
+		if (addr) {
 			vfe31_ctrl->afStatsControl.bufToRender =
 				vfe31_process_stats_irq_common(STATS_AF_NUM,
-				vfe31_ctrl->afStatsControl.nextFrameAddrBuf);
+				addr);
 			process_stats = true;
 		} else {
 			vfe31_ctrl->afStatsControl.bufToRender = 0;
@@ -3060,11 +3207,11 @@
 	}
 
 	if (status_bits & VFE_IRQ_STATUS0_STATS_IHIST) {
-		if (!vfe31_ctrl->ihistStatsControl.ackPending) {
-			vfe31_ctrl->ihistStatsControl.ackPending = TRUE;
+		addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_IHIST);
+		if (addr) {
 			vfe31_ctrl->ihistStatsControl.bufToRender =
 				vfe31_process_stats_irq_common(STATS_IHIST_NUM,
-				vfe31_ctrl->ihistStatsControl.nextFrameAddrBuf);
+				addr);
 			process_stats = true;
 		} else {
 			vfe31_ctrl->ihistStatsControl.droppedStatsFrameCount++;
@@ -3075,11 +3222,11 @@
 	}
 
 	if (status_bits & VFE_IRQ_STATUS0_STATS_RS) {
-		if (!vfe31_ctrl->rsStatsControl.ackPending) {
-			vfe31_ctrl->rsStatsControl.ackPending = TRUE;
+		addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_RS);
+		if (!addr) {
 			vfe31_ctrl->rsStatsControl.bufToRender =
 				vfe31_process_stats_irq_common(STATS_RS_NUM,
-				vfe31_ctrl->rsStatsControl.nextFrameAddrBuf);
+				addr);
 			process_stats = true;
 		} else {
 			vfe31_ctrl->rsStatsControl.droppedStatsFrameCount++;
@@ -3091,11 +3238,11 @@
 
 
 	if (status_bits & VFE_IRQ_STATUS0_STATS_CS) {
-		if (!vfe31_ctrl->csStatsControl.ackPending) {
-			vfe31_ctrl->csStatsControl.ackPending = TRUE;
+		addr = (uint32_t)vfe31_stats_dqbuf(MSM_STATS_TYPE_CS);
+		if (addr) {
 			vfe31_ctrl->csStatsControl.bufToRender =
 				vfe31_process_stats_irq_common(STATS_CS_NUM,
-				vfe31_ctrl->csStatsControl.nextFrameAddrBuf);
+				addr);
 			process_stats = true;
 		} else {
 			vfe31_ctrl->csStatsControl.droppedStatsFrameCount++;
@@ -3105,13 +3252,91 @@
 		vfe31_ctrl->csStatsControl.bufToRender = 0;
 	}
 
-	spin_unlock_irqrestore(&vfe31_ctrl->comp_stats_ack_lock, flags);
+	spin_unlock_irqrestore(&vfe31_ctrl->stats_bufq_lock, flags);
 	if (process_stats)
 		vfe_send_comp_stats_msg(status_bits);
 
 	return;
 }
 
+static long vfe_stats_bufq_sub_ioctl(struct msm_vfe_cfg_cmd *cmd,
+	void *ion_client)
+{
+	long rc = 0;
+	switch (cmd->cmd_type) {
+	case VFE_CMD_STATS_REQBUF:
+		if (!vfe31_ctrl->stats_ops.stats_ctrl) {
+			/* stats_ctrl has not been init yet */
+			rc = msm_stats_buf_ops_init(&vfe31_ctrl->stats_ctrl,
+					(struct ion_client *)ion_client,
+					&vfe31_ctrl->stats_ops);
+		if (rc < 0) {
+			pr_err("%s: cannot init stats ops", __func__);
+			goto end;
+		}
+		rc = vfe31_ctrl->stats_ops.stats_ctrl_init(
+				&vfe31_ctrl->stats_ctrl);
+		if (rc < 0) {
+			pr_err("%s: cannot init stats_ctrl ops", __func__);
+			memset(&vfe31_ctrl->stats_ops, 0,
+				sizeof(vfe31_ctrl->stats_ops));
+			goto end;
+		}
+		if (sizeof(struct msm_stats_reqbuf) != cmd->length) {
+			/* error. the length not match */
+			pr_err("%s: stats reqbuf input size = %d,\n"
+				"struct size = %d, mis match\n",
+				 __func__, cmd->length,
+				 sizeof(struct msm_stats_reqbuf));
+			rc = -EINVAL;
+			goto end;
+		}
+	}
+	rc = vfe31_ctrl->stats_ops.reqbuf(&vfe31_ctrl->stats_ctrl,
+			(struct msm_stats_reqbuf *)cmd->value,
+			vfe31_ctrl->stats_ops.client);
+	break;
+	case VFE_CMD_STATS_ENQUEUEBUF:
+		if (sizeof(struct msm_stats_buf_info) != cmd->length) {
+			/* error. the length not match */
+			pr_err("%s: stats enqueuebuf input size = %d,\n"
+				"struct size = %d, mis match\n",
+				__func__, cmd->length,
+				sizeof(struct msm_stats_buf_info));
+			rc = -EINVAL ;
+			goto end;
+		}
+		rc = vfe31_ctrl->stats_ops.enqueue_buf(&vfe31_ctrl->stats_ctrl,
+				(struct msm_stats_buf_info *)cmd->value,
+				vfe31_ctrl->stats_ops.client);
+	break;
+	case VFE_CMD_STATS_FLUSH_BUFQ: {
+		struct msm_stats_flush_bufq *flush_req = NULL;
+		flush_req = (struct msm_stats_flush_bufq *)cmd->value;
+		if (sizeof(struct msm_stats_flush_bufq) != cmd->length) {
+			/* error. the length not match */
+			pr_err("%s: stats flush queue input size = %d,\n"
+				"struct size = %d, mitch match\n",
+				__func__, cmd->length,
+				sizeof(struct msm_stats_flush_bufq));
+			rc = -EINVAL ;
+			goto end;
+		}
+		rc = vfe31_ctrl->stats_ops.bufq_flush(&vfe31_ctrl->stats_ctrl,
+				(enum msm_stats_enum_type)flush_req->stats_type,
+				vfe31_ctrl->stats_ops.client);
+	}
+	break;
+	default:
+		rc = -1;
+		pr_err("%s: cmd_type %d not supported", __func__,
+			cmd->cmd_type);
+	break;
+	}
+end:
+	return rc;
+}
+
 static void vfe31_process_stats_irq(uint32_t *irqstatus)
 {
 	uint32_t status_bits = VFE_COM_STATUS & *irqstatus;
@@ -3334,44 +3559,55 @@
 	void *data = vfe_params->data;
 
 	long rc = 0;
-	uint32_t i = 0;
 	struct vfe_cmd_stats_buf *scfg = NULL;
-	struct msm_pmem_region   *regptr = NULL;
 	struct vfe_cmd_stats_ack *sack = NULL;
-	if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
-		cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
-		cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR &&
-		cmd->cmd_type != CMD_STATS_AEC_BUF_RELEASE &&
-		cmd->cmd_type != CMD_STATS_AWB_BUF_RELEASE &&
-		cmd->cmd_type != CMD_STATS_IHIST_BUF_RELEASE &&
-		cmd->cmd_type != CMD_STATS_RS_BUF_RELEASE &&
-		cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE &&
-		cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
-		if (NULL != cmd->value) {
-			if (copy_from_user(&vfecmd,
-				(void __user *)(cmd->value),
-				sizeof(vfecmd))) {
-				pr_err("%s %d: copy_from_user failed\n",
-					__func__, __LINE__);
-				return -EFAULT;
-			}
-		}
-	} else {
-	/* here eith stats release or frame release. */
+
+	switch (cmd->cmd_type) {
+	case VFE_CMD_STATS_REQBUF:
+	case VFE_CMD_STATS_ENQUEUEBUF:
+	case VFE_CMD_STATS_FLUSH_BUFQ:
+		/* for easy porting put in one envelope */
+		rc = vfe_stats_bufq_sub_ioctl(cmd, vfe_params->data);
+		return rc;
+	default:
+		if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
+			cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
+			cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR &&
+			cmd->cmd_type != CMD_STATS_AEC_BUF_RELEASE &&
+			cmd->cmd_type != CMD_STATS_AWB_BUF_RELEASE &&
+			cmd->cmd_type != CMD_STATS_IHIST_BUF_RELEASE &&
+			cmd->cmd_type != CMD_STATS_RS_BUF_RELEASE &&
+			cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE &&
+			cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
+				if (copy_from_user(&vfecmd,
+					(void __user *)(cmd->value),
+					sizeof(vfecmd))) {
+						pr_err("%s %d: copy_from_user failed\n",
+						__func__, __LINE__);
+					return -EFAULT;
+				}
+		} else {
+		/* here eith stats release or frame release. */
 		if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
 			cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
 			cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR) {
 			/* then must be stats release. */
-			if (!data)
+			if (!data) {
+				pr_err("%s: data = NULL, cmd->cmd_type = %d",
+					__func__, cmd->cmd_type);
 				return -EFAULT;
+			}
 			sack = kmalloc(sizeof(struct vfe_cmd_stats_ack),
 							GFP_ATOMIC);
-			if (!sack)
+			if (!sack) {
+				pr_err("%s: no mem for cmd->cmd_type = %d",
+					 __func__, cmd->cmd_type);
 				return -ENOMEM;
+			}
 
 			sack->nextStatsBuf = *(uint32_t *)data;
 		}
-	}
+	  }
 
 	CDBG("%s: cmdType = %d\n", __func__, cmd->cmd_type);
 
@@ -3381,53 +3617,7 @@
 		(cmd->cmd_type == CMD_STATS_RS_ENABLE)    ||
 		(cmd->cmd_type == CMD_STATS_CS_ENABLE)    ||
 		(cmd->cmd_type == CMD_STATS_AEC_ENABLE)) {
-		struct axidata *axid;
-		axid = data;
-		if (!axid) {
-			rc = -EFAULT;
-			goto vfe31_config_done;
-		}
-
-		scfg =
-			kmalloc(sizeof(struct vfe_cmd_stats_buf),
-				GFP_ATOMIC);
-		if (!scfg) {
-			rc = -ENOMEM;
-			goto vfe31_config_done;
-		}
-		regptr = axid->region;
-		if (axid->bufnum1 > 0) {
-			for (i = 0; i < axid->bufnum1; i++) {
-				scfg->statsBuf[i] =
-					(uint32_t)(regptr->paddr);
-				regptr++;
-			}
-		}
-		/* individual */
-		switch (cmd->cmd_type) {
-		case CMD_STATS_AEC_ENABLE:
-			rc = vfe_stats_aec_buf_init(scfg);
-			break;
-		case CMD_STATS_AF_ENABLE:
-			rc = vfe_stats_af_buf_init(scfg);
-			break;
-		case CMD_STATS_AWB_ENABLE:
-			rc = vfe_stats_awb_buf_init(scfg);
-			break;
-		case CMD_STATS_IHIST_ENABLE:
-			rc = vfe_stats_ihist_buf_init(scfg);
-			break;
-		case CMD_STATS_RS_ENABLE:
-			rc = vfe_stats_rs_buf_init(scfg);
-			break;
-		case CMD_STATS_CS_ENABLE:
-			rc = vfe_stats_cs_buf_init(scfg);
-			break;
-		default:
-			pr_err("%s Unsupported cmd type %d",
-				__func__, cmd->cmd_type);
-			break;
-		}
+		scfg = NULL;
 		goto vfe31_config_done;
 	}
 	switch (cmd->cmd_type) {
@@ -3459,36 +3649,6 @@
 	case CMD_SNAP_BUF_RELEASE:
 		break;
 
-	case CMD_STATS_AEC_BUF_RELEASE: {
-		vfe31_stats_aec_ack(sack);
-		}
-		break;
-
-	case CMD_STATS_AF_BUF_RELEASE: {
-		vfe31_stats_af_ack(sack);
-		}
-		break;
-
-	case CMD_STATS_AWB_BUF_RELEASE: {
-		vfe31_stats_awb_ack(sack);
-		}
-		break;
-
-	case CMD_STATS_IHIST_BUF_RELEASE: {
-		vfe31_stats_ihist_ack(sack);
-		}
-		break;
-
-	case CMD_STATS_RS_BUF_RELEASE: {
-		vfe31_stats_rs_ack(sack);
-		}
-		break;
-
-	case CMD_STATS_CS_BUF_RELEASE: {
-		vfe31_stats_cs_ack(sack);
-		}
-		break;
-
 	case CMD_AXI_CFG_PRIM: {
 		uint32_t *axio = NULL;
 		axio = kmalloc(vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length,
@@ -3607,6 +3767,7 @@
 		pr_err("%s Unsupported AXI configuration %x ", __func__,
 			cmd->cmd_type);
 		break;
+		}
 	}
 vfe31_config_done:
 	kfree(scfg);
@@ -3714,17 +3875,10 @@
 
 	spin_lock_init(&vfe31_ctrl->stop_flag_lock);
 	spin_lock_init(&vfe31_ctrl->state_lock);
+	spin_lock_init(&vfe31_ctrl->stats_bufq_lock);
 	spin_lock_init(&vfe31_ctrl->io_lock);
 	spin_lock_init(&vfe31_ctrl->update_ack_lock);
 	spin_lock_init(&vfe31_ctrl->tasklet_lock);
-
-	spin_lock_init(&vfe31_ctrl->aec_ack_lock);
-	spin_lock_init(&vfe31_ctrl->awb_ack_lock);
-	spin_lock_init(&vfe31_ctrl->af_ack_lock);
-	spin_lock_init(&vfe31_ctrl->ihist_ack_lock);
-	spin_lock_init(&vfe31_ctrl->rs_ack_lock);
-	spin_lock_init(&vfe31_ctrl->cs_ack_lock);
-	spin_lock_init(&vfe31_ctrl->comp_stats_ack_lock);
 	spin_lock_init(&vfe31_ctrl->sd_notify_lock);
 	INIT_LIST_HEAD(&vfe31_ctrl->tasklet_q);
 
diff --git a/drivers/media/video/msm/msm_vfe31_v4l2.h b/drivers/media/video/msm/msm_vfe31_v4l2.h
index 739d157..2cba995 100644
--- a/drivers/media/video/msm/msm_vfe31_v4l2.h
+++ b/drivers/media/video/msm/msm_vfe31_v4l2.h
@@ -15,6 +15,7 @@
 #define __MSM_VFE31_V4L2_H__
 
 #include <linux/bitops.h>
+#include "msm_vfe_stats_buf.h"
 
 #ifndef TRUE
 #define TRUE 1
@@ -862,14 +863,7 @@
 	spinlock_t  update_ack_lock;
 	spinlock_t  state_lock;
 	spinlock_t  io_lock;
-
-	spinlock_t  aec_ack_lock;
-	spinlock_t  awb_ack_lock;
-	spinlock_t  af_ack_lock;
-	spinlock_t  ihist_ack_lock;
-	spinlock_t  rs_ack_lock;
-	spinlock_t  cs_ack_lock;
-	spinlock_t  comp_stats_ack_lock;
+	spinlock_t  stats_bufq_lock;
 
 	uint32_t extlen;
 	void *extdata;
@@ -930,6 +924,8 @@
 	uint32_t frame_skip_cnt;
 	uint32_t frame_skip_pattern;
 	uint32_t snapshot_frame_cnt;
+	struct msm_stats_bufq_ctrl stats_ctrl;
+	struct msm_stats_ops stats_ops;
 };
 
 enum VFE31_STATS_NUM {
diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c
index 3ac4c6a..621a016 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -624,116 +624,248 @@
 	return 0;
 }
 
-static uint32_t vfe_stats_awb_buf_init(
-	struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_buf *in)
+static unsigned long vfe32_stats_dqbuf(struct vfe32_ctrl_type *vfe32_ctrl,
+	enum msm_stats_enum_type stats_type)
 {
-	uint32_t *ptr = in->statsBuf;
-	uint32_t addr;
+	struct msm_stats_meta_buf *buf = NULL;
+	int rc = 0;
+	rc = vfe32_ctrl->stats_ops.dqbuf(
+			vfe32_ctrl->stats_ops.stats_ctrl, stats_type, &buf);
+	if (rc < 0) {
+		pr_err("%s: dq stats buf (type = %d) err = %d",
+			__func__, stats_type, rc);
+		return 0L;
+	}
+	return buf->paddr;
+}
 
-	addr = ptr[0];
+static unsigned long vfe32_stats_flush_enqueue(
+	struct vfe32_ctrl_type *vfe32_ctrl,
+	enum msm_stats_enum_type stats_type)
+{
+	struct msm_stats_bufq *bufq = NULL;
+	struct msm_stats_meta_buf *stats_buf = NULL;
+	int rc = 0;
+	int i;
+
+	/*
+	 * Passing NULL for ion client as the buffers are already
+	 * mapped at this stage, client is not required, flush all
+	 * the buffers, and buffers move to PREPARE state
+	 */
+
+	rc = vfe32_ctrl->stats_ops.bufq_flush(
+			vfe32_ctrl->stats_ops.stats_ctrl, stats_type, NULL);
+	if (rc < 0) {
+		pr_err("%s: dq stats buf (type = %d) err = %d",
+			__func__, stats_type, rc);
+		return 0L;
+	}
+	/* Queue all the buffers back to QUEUED state */
+	bufq = vfe32_ctrl->stats_ctrl.bufq[stats_type];
+	for (i = 0; i < bufq->num_bufs; i++) {
+		stats_buf = &bufq->bufs[i];
+		rc = vfe32_ctrl->stats_ops.enqueue_buf(
+				vfe32_ctrl->stats_ops.stats_ctrl,
+				&(stats_buf->info), NULL);
+		if (rc < 0) {
+			pr_err("%s: dq stats buf (type = %d) err = %d",
+				 __func__, stats_type, rc);
+			return rc;
+		}
+	}
+	return 0L;
+}
+
+static int vfe_stats_awb_buf_init(
+	struct vfe32_ctrl_type *vfe32_ctrl,
+	struct vfe_cmd_stats_buf *in)
+{
+	uint32_t addr;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AWB);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq awb ping buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
 	msm_camera_io_w(addr,
 		vfe32_ctrl->share_ctrl->vfebase +
 		VFE_BUS_STATS_AWB_WR_PING_ADDR);
-	addr = ptr[1];
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AWB);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq awb ping buf from free buf queue",
+			__func__);
+		return -ENOMEM;
+	}
 	msm_camera_io_w(addr,
 		vfe32_ctrl->share_ctrl->vfebase +
 		VFE_BUS_STATS_AWB_WR_PONG_ADDR);
-	vfe32_ctrl->awbStatsControl.nextFrameAddrBuf = in->statsBuf[2];
 	return 0;
 }
 
-static uint32_t vfe_stats_aec_buf_init(
+static int vfe_stats_aec_buf_init(
 	struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_buf *in)
 {
-	uint32_t *ptr = in->statsBuf;
 	uint32_t addr;
+	unsigned long flags;
 
-	addr = ptr[0];
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AEC);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq aec ping buf from free buf queue",
+			__func__);
+		return -ENOMEM;
+	}
 	msm_camera_io_w(addr,
 		vfe32_ctrl->share_ctrl->vfebase +
 		VFE_BUS_STATS_AEC_WR_PING_ADDR);
-	addr = ptr[1];
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AEC);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq aec pong buf from free buf queue",
+			__func__);
+		return -ENOMEM;
+	}
 	msm_camera_io_w(addr,
 		vfe32_ctrl->share_ctrl->vfebase +
 		VFE_BUS_STATS_AEC_WR_PONG_ADDR);
-
-	vfe32_ctrl->aecStatsControl.nextFrameAddrBuf = in->statsBuf[2];
 	return 0;
 }
 
-static uint32_t vfe_stats_af_buf_init(
+static int vfe_stats_af_buf_init(
 	struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_buf *in)
 {
-	uint32_t *ptr = in->statsBuf;
 	uint32_t addr;
+	unsigned long flags;
+	int rc = 0;
 
-	addr = ptr[0];
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	rc = vfe32_stats_flush_enqueue(vfe32_ctrl, MSM_STATS_TYPE_AF);
+	if (rc < 0) {
+		pr_err("%s: dq stats buf err = %d",
+			   __func__, rc);
+		spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+		return -EINVAL;
+	}
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AF);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq af ping buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
 	msm_camera_io_w(addr,
 		vfe32_ctrl->share_ctrl->vfebase +
 		VFE_BUS_STATS_AF_WR_PING_ADDR);
-	addr = ptr[1];
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AF);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq af pong buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
 	msm_camera_io_w(addr,
 		vfe32_ctrl->share_ctrl->vfebase +
 		VFE_BUS_STATS_AF_WR_PONG_ADDR);
 
-	vfe32_ctrl->afStatsControl.nextFrameAddrBuf = in->statsBuf[2];
 	return 0;
 }
 
-static uint32_t vfe_stats_ihist_buf_init(
-	struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_buf *in)
+static int vfe_stats_ihist_buf_init(
+	struct vfe32_ctrl_type *vfe32_ctrl,
+	struct vfe_cmd_stats_buf *in)
 {
-	uint32_t *ptr = in->statsBuf;
 	uint32_t addr;
+	unsigned long flags;
 
-	addr = ptr[0];
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_IHIST);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq ihist ping buf from free buf queue",
+			__func__);
+		return -ENOMEM;
+	}
 	msm_camera_io_w(addr,
 		vfe32_ctrl->share_ctrl->vfebase +
 		VFE_BUS_STATS_HIST_WR_PING_ADDR);
-	addr = ptr[1];
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_IHIST);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq ihist pong buf from free buf queue",
+			__func__);
+		return -ENOMEM;
+	}
 	msm_camera_io_w(addr,
 		vfe32_ctrl->share_ctrl->vfebase +
 		VFE_BUS_STATS_HIST_WR_PONG_ADDR);
 
-	vfe32_ctrl->ihistStatsControl.nextFrameAddrBuf = in->statsBuf[2];
 	return 0;
 }
 
-static uint32_t vfe_stats_rs_buf_init(
-	struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_buf *in)
+static int vfe_stats_rs_buf_init(
+	struct vfe32_ctrl_type *vfe32_ctrl,
+	struct vfe_cmd_stats_buf *in)
 {
-	uint32_t *ptr = in->statsBuf;
 	uint32_t addr;
+	unsigned long flags;
 
-	addr = ptr[0];
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_RS);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq rs ping buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
 	msm_camera_io_w(addr,
 		vfe32_ctrl->share_ctrl->vfebase +
 		VFE_BUS_STATS_RS_WR_PING_ADDR);
-	addr = ptr[1];
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_RS);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq rs pong buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
 	msm_camera_io_w(addr,
 		vfe32_ctrl->share_ctrl->vfebase +
 		VFE_BUS_STATS_RS_WR_PONG_ADDR);
-
-	vfe32_ctrl->rsStatsControl.nextFrameAddrBuf = in->statsBuf[2];
 	return 0;
 }
 
-static uint32_t vfe_stats_cs_buf_init(
-	struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_buf *in)
+static int vfe_stats_cs_buf_init(
+	struct vfe32_ctrl_type *vfe32_ctrl,
+	struct vfe_cmd_stats_buf *in)
 {
-	uint32_t *ptr = in->statsBuf;
 	uint32_t addr;
-
-	addr = ptr[0];
+	unsigned long flags;
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_CS);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq cs ping buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
 	msm_camera_io_w(addr,
 		vfe32_ctrl->share_ctrl->vfebase +
 		VFE_BUS_STATS_CS_WR_PING_ADDR);
-	addr = ptr[1];
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_CS);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (!addr) {
+		pr_err("%s: dq cs pong buf from free buf queue", __func__);
+		return -ENOMEM;
+	}
 	msm_camera_io_w(addr,
 		vfe32_ctrl->share_ctrl->vfebase +
 		VFE_BUS_STATS_CS_WR_PONG_ADDR);
-
-	vfe32_ctrl->csStatsControl.nextFrameAddrBuf = in->statsBuf[2];
 	return 0;
 }
 
@@ -1614,6 +1746,12 @@
 		break;
 
 	case VFE_CMD_STATS_AE_START: {
+		rc = vfe_stats_aec_buf_init(vfe32_ctrl, NULL);
+		if (rc < 0) {
+			pr_err("%s: cannot config ping/pong address of AEC",
+				 __func__);
+			goto proc_general_done;
+		}
 		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
 		if (!cmdp) {
 			rc = -ENOMEM;
@@ -1637,6 +1775,12 @@
 		}
 		break;
 	case VFE_CMD_STATS_AF_START: {
+		rc = vfe_stats_af_buf_init(vfe32_ctrl, NULL);
+		if (rc < 0) {
+			pr_err("%s: cannot config ping/pong address of AF",
+				__func__);
+			goto proc_general_done;
+		}
 		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
 		if (!cmdp) {
 			rc = -ENOMEM;
@@ -1660,6 +1804,12 @@
 		}
 		break;
 	case VFE_CMD_STATS_AWB_START: {
+		rc = vfe_stats_awb_buf_init(vfe32_ctrl, NULL);
+		if (rc < 0) {
+			pr_err("%s: cannot config ping/pong address of AWB",
+				 __func__);
+			goto proc_general_done;
+		}
 		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
 		if (!cmdp) {
 			rc = -ENOMEM;
@@ -1684,6 +1834,12 @@
 		break;
 
 	case VFE_CMD_STATS_IHIST_START: {
+		rc = vfe_stats_ihist_buf_init(vfe32_ctrl, NULL);
+		if (rc < 0) {
+			pr_err("%s: cannot config ping/pong address of IHIST",
+				 __func__);
+			goto proc_general_done;
+		}
 		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
 		if (!cmdp) {
 			rc = -ENOMEM;
@@ -1709,6 +1865,12 @@
 
 
 	case VFE_CMD_STATS_RS_START: {
+		rc = vfe_stats_rs_buf_init(vfe32_ctrl, NULL);
+		if (rc < 0) {
+			pr_err("%s: cannot config ping/pong address of RS",
+				__func__);
+			goto proc_general_done;
+		}
 		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
 		if (!cmdp) {
 			rc = -ENOMEM;
@@ -1728,6 +1890,12 @@
 		break;
 
 	case VFE_CMD_STATS_CS_START: {
+		rc = vfe_stats_cs_buf_init(vfe32_ctrl, NULL);
+		if (rc < 0) {
+			pr_err("%s: cannot config ping/pong address of CS",
+				__func__);
+			goto proc_general_done;
+		}
 		cmdp = kmalloc(cmd->length, GFP_ATOMIC);
 		if (!cmdp) {
 			rc = -ENOMEM;
@@ -2430,6 +2598,12 @@
 		old_val &= ~AF_BF_ENABLE_MASK;
 		msm_camera_io_w(old_val,
 			vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+		rc = vfe32_stats_flush_enqueue(vfe32_ctrl, MSM_STATS_TYPE_AF);
+		if (rc < 0) {
+			pr_err("%s: dq stats buf err = %d",
+				   __func__, rc);
+			return -EINVAL;
+		}
 		}
 		break;
 
@@ -2808,82 +2982,6 @@
 	return rc;
 }
 
-static void vfe32_stats_af_ack(
-	struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_ack *pAck)
-{
-	unsigned long flags;
-	spinlock_t *lock = (vfe32_ctrl->share_ctrl->stats_comp ?
-		&vfe32_ctrl->comp_stats_ack_lock :
-		&vfe32_ctrl->af_ack_lock);
-	spin_lock_irqsave(lock, flags);
-	vfe32_ctrl->afStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
-	vfe32_ctrl->afStatsControl.ackPending = FALSE;
-	spin_unlock_irqrestore(lock, flags);
-}
-
-static void vfe32_stats_awb_ack(
-	struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_ack *pAck)
-{
-	unsigned long flags;
-	spinlock_t *lock = (vfe32_ctrl->share_ctrl->stats_comp ?
-		&vfe32_ctrl->comp_stats_ack_lock :
-		&vfe32_ctrl->awb_ack_lock);
-	spin_lock_irqsave(lock, flags);
-	vfe32_ctrl->awbStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
-	vfe32_ctrl->awbStatsControl.ackPending = FALSE;
-	spin_unlock_irqrestore(lock, flags);
-}
-
-static void vfe32_stats_aec_ack(
-	struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_ack *pAck)
-{
-	unsigned long flags;
-	spinlock_t *lock = (vfe32_ctrl->share_ctrl->stats_comp ?
-		&vfe32_ctrl->comp_stats_ack_lock :
-		&vfe32_ctrl->aec_ack_lock);
-	spin_lock_irqsave(lock, flags);
-	vfe32_ctrl->aecStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
-	vfe32_ctrl->aecStatsControl.ackPending = FALSE;
-	spin_unlock_irqrestore(lock, flags);
-}
-
-static void vfe32_stats_ihist_ack(
-	struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_ack *pAck)
-{
-	unsigned long flags;
-	spinlock_t *lock = (vfe32_ctrl->share_ctrl->stats_comp ?
-		&vfe32_ctrl->comp_stats_ack_lock :
-		&vfe32_ctrl->ihist_ack_lock);
-	spin_lock_irqsave(lock, flags);
-	vfe32_ctrl->ihistStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
-	vfe32_ctrl->ihistStatsControl.ackPending = FALSE;
-	spin_unlock_irqrestore(lock, flags);
-}
-static void vfe32_stats_rs_ack(
-	struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_ack *pAck)
-{
-	unsigned long flags;
-	spinlock_t *lock = (vfe32_ctrl->share_ctrl->stats_comp ?
-		&vfe32_ctrl->comp_stats_ack_lock :
-		&vfe32_ctrl->rs_ack_lock);
-	spin_lock_irqsave(lock, flags);
-	vfe32_ctrl->rsStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
-	vfe32_ctrl->rsStatsControl.ackPending = FALSE;
-	spin_unlock_irqrestore(lock, flags);
-}
-static void vfe32_stats_cs_ack(
-	struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_ack *pAck)
-{
-	unsigned long flags;
-	spinlock_t *lock = (vfe32_ctrl->share_ctrl->stats_comp ?
-		&vfe32_ctrl->comp_stats_ack_lock :
-		&vfe32_ctrl->cs_ack_lock);
-	spin_lock_irqsave(lock, flags);
-	vfe32_ctrl->csStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
-	vfe32_ctrl->csStatsControl.ackPending = FALSE;
-	spin_unlock_irqrestore(lock, flags);
-}
-
 static inline void vfe32_read_irq_status(
 	struct axi_ctrl_t *axi_ctrl, struct vfe32_irq_status *out)
 {
@@ -3653,70 +3751,87 @@
 	return returnAddr;
 }
 
-static void
-vfe_send_stats_msg(struct vfe32_ctrl_type *vfe32_ctrl,
+static void vfe_send_stats_msg(
+	struct vfe32_ctrl_type *vfe32_ctrl,
 	uint32_t bufAddress, uint32_t statsNum)
 {
-	unsigned long flags;
+	int rc = 0;
+	void *vaddr = NULL;
 	/* fill message with right content. */
 	/* @todo This is causing issues, need further investigate */
 	/* spin_lock_irqsave(&ctrl->state_lock, flags); */
 	struct isp_msg_stats msgStats;
 	msgStats.frameCounter = vfe32_ctrl->share_ctrl->vfeFrameId;
 	msgStats.buffer = bufAddress;
-
 	switch (statsNum) {
 	case statsAeNum:{
 		msgStats.id = MSG_ID_STATS_AEC;
-		spin_lock_irqsave(&vfe32_ctrl->aec_ack_lock, flags);
-		vfe32_ctrl->aecStatsControl.ackPending = TRUE;
-		spin_unlock_irqrestore(&vfe32_ctrl->aec_ack_lock, flags);
+		rc = vfe32_ctrl->stats_ops.dispatch(
+				vfe32_ctrl->stats_ops.stats_ctrl,
+				MSM_STATS_TYPE_AEC, bufAddress,
+				&msgStats.buf_idx, &vaddr, &msgStats.fd,
+				vfe32_ctrl->stats_ops.client);
 		}
 		break;
 	case statsAfNum:{
 		msgStats.id = MSG_ID_STATS_AF;
-		spin_lock_irqsave(&vfe32_ctrl->af_ack_lock, flags);
-		vfe32_ctrl->afStatsControl.ackPending = TRUE;
-		spin_unlock_irqrestore(&vfe32_ctrl->af_ack_lock, flags);
+		rc = vfe32_ctrl->stats_ops.dispatch(
+				vfe32_ctrl->stats_ops.stats_ctrl,
+				MSM_STATS_TYPE_AF, bufAddress,
+				&msgStats.buf_idx, &vaddr, &msgStats.fd,
+				vfe32_ctrl->stats_ops.client);
 		}
 		break;
 	case statsAwbNum: {
 		msgStats.id = MSG_ID_STATS_AWB;
-		spin_lock_irqsave(&vfe32_ctrl->awb_ack_lock, flags);
-		vfe32_ctrl->awbStatsControl.ackPending = TRUE;
-		spin_unlock_irqrestore(&vfe32_ctrl->awb_ack_lock, flags);
+		rc = vfe32_ctrl->stats_ops.dispatch(
+				vfe32_ctrl->stats_ops.stats_ctrl,
+				MSM_STATS_TYPE_AWB, bufAddress,
+				&msgStats.buf_idx, &vaddr, &msgStats.fd,
+				vfe32_ctrl->stats_ops.client);
 		}
 		break;
 
 	case statsIhistNum: {
 		msgStats.id = MSG_ID_STATS_IHIST;
-		spin_lock_irqsave(&vfe32_ctrl->ihist_ack_lock, flags);
-		vfe32_ctrl->ihistStatsControl.ackPending = TRUE;
-		spin_unlock_irqrestore(&vfe32_ctrl->ihist_ack_lock, flags);
+		rc = vfe32_ctrl->stats_ops.dispatch(
+				vfe32_ctrl->stats_ops.stats_ctrl,
+				MSM_STATS_TYPE_IHIST, bufAddress,
+				&msgStats.buf_idx, &vaddr, &msgStats.fd,
+				vfe32_ctrl->stats_ops.client);
 		}
 		break;
 	case statsRsNum: {
 		msgStats.id = MSG_ID_STATS_RS;
-		spin_lock_irqsave(&vfe32_ctrl->rs_ack_lock, flags);
-		vfe32_ctrl->rsStatsControl.ackPending = TRUE;
-		spin_unlock_irqrestore(&vfe32_ctrl->rs_ack_lock, flags);
+		rc = vfe32_ctrl->stats_ops.dispatch(
+				vfe32_ctrl->stats_ops.stats_ctrl,
+				MSM_STATS_TYPE_RS, bufAddress,
+				&msgStats.buf_idx, &vaddr, &msgStats.fd,
+				vfe32_ctrl->stats_ops.client);
 		}
 		break;
 	case statsCsNum: {
 		msgStats.id = MSG_ID_STATS_CS;
-		spin_lock_irqsave(&vfe32_ctrl->cs_ack_lock, flags);
-		vfe32_ctrl->csStatsControl.ackPending = TRUE;
-		spin_unlock_irqrestore(&vfe32_ctrl->cs_ack_lock, flags);
+		rc = vfe32_ctrl->stats_ops.dispatch(
+				vfe32_ctrl->stats_ops.stats_ctrl,
+				MSM_STATS_TYPE_CS, bufAddress,
+				&msgStats.buf_idx, &vaddr, &msgStats.fd,
+				vfe32_ctrl->stats_ops.client);
 		}
 		break;
 
 	default:
 		goto stats_done;
 	}
-
-	v4l2_subdev_notify(&vfe32_ctrl->subdev,
-				NOTIFY_VFE_MSG_STATS,
-				&msgStats);
+	if (rc == 0) {
+		msgStats.buffer = (uint32_t)vaddr;
+		v4l2_subdev_notify(&vfe32_ctrl->subdev,
+			NOTIFY_VFE_MSG_STATS,
+			&msgStats);
+	} else {
+		pr_err("%s: paddr to idx mapping error, stats_id = %d, paddr = 0x%d",
+			 __func__, msgStats.id, msgStats.buffer);
+	}
 stats_done:
 	/* spin_unlock_irqrestore(&ctrl->state_lock, flags); */
 	return;
@@ -3751,17 +3866,18 @@
 static void vfe32_process_stats_ae_irq(struct vfe32_ctrl_type *vfe32_ctrl)
 {
 	unsigned long flags;
-	spin_lock_irqsave(&vfe32_ctrl->aec_ack_lock, flags);
-	if (!(vfe32_ctrl->aecStatsControl.ackPending)) {
-		spin_unlock_irqrestore(&vfe32_ctrl->aec_ack_lock, flags);
+	uint32_t addr;
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AEC);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (addr) {
 		vfe32_ctrl->aecStatsControl.bufToRender =
 			vfe32_process_stats_irq_common(vfe32_ctrl, statsAeNum,
-			vfe32_ctrl->aecStatsControl.nextFrameAddrBuf);
+			addr);
 
 		vfe_send_stats_msg(vfe32_ctrl,
 			vfe32_ctrl->aecStatsControl.bufToRender, statsAeNum);
 	} else{
-		spin_unlock_irqrestore(&vfe32_ctrl->aec_ack_lock, flags);
 		vfe32_ctrl->aecStatsControl.droppedStatsFrameCount++;
 		CDBG("%s: droppedStatsFrameCount = %d", __func__,
 			vfe32_ctrl->aecStatsControl.droppedStatsFrameCount);
@@ -3771,17 +3887,18 @@
 static void vfe32_process_stats_awb_irq(struct vfe32_ctrl_type *vfe32_ctrl)
 {
 	unsigned long flags;
-	spin_lock_irqsave(&vfe32_ctrl->awb_ack_lock, flags);
-	if (!(vfe32_ctrl->awbStatsControl.ackPending)) {
-		spin_unlock_irqrestore(&vfe32_ctrl->awb_ack_lock, flags);
+	uint32_t addr;
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AWB);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (addr) {
 		vfe32_ctrl->awbStatsControl.bufToRender =
 			vfe32_process_stats_irq_common(vfe32_ctrl, statsAwbNum,
-			vfe32_ctrl->awbStatsControl.nextFrameAddrBuf);
+			addr);
 
 		vfe_send_stats_msg(vfe32_ctrl,
 			vfe32_ctrl->awbStatsControl.bufToRender, statsAwbNum);
 	} else{
-		spin_unlock_irqrestore(&vfe32_ctrl->awb_ack_lock, flags);
 		vfe32_ctrl->awbStatsControl.droppedStatsFrameCount++;
 		CDBG("%s: droppedStatsFrameCount = %d", __func__,
 			vfe32_ctrl->awbStatsControl.droppedStatsFrameCount);
@@ -3791,17 +3908,18 @@
 static void vfe32_process_stats_af_irq(struct vfe32_ctrl_type *vfe32_ctrl)
 {
 	unsigned long flags;
-	spin_lock_irqsave(&vfe32_ctrl->af_ack_lock, flags);
-	if (!(vfe32_ctrl->afStatsControl.ackPending)) {
-		spin_unlock_irqrestore(&vfe32_ctrl->af_ack_lock, flags);
+	uint32_t addr;
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_AF);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (addr) {
 		vfe32_ctrl->afStatsControl.bufToRender =
 			vfe32_process_stats_irq_common(vfe32_ctrl, statsAfNum,
-			vfe32_ctrl->afStatsControl.nextFrameAddrBuf);
+			addr);
 
 		vfe_send_stats_msg(vfe32_ctrl,
 			vfe32_ctrl->afStatsControl.bufToRender, statsAfNum);
 	} else{
-		spin_unlock_irqrestore(&vfe32_ctrl->af_ack_lock, flags);
 		vfe32_ctrl->afStatsControl.droppedStatsFrameCount++;
 		CDBG("%s: droppedStatsFrameCount = %d", __func__,
 			vfe32_ctrl->afStatsControl.droppedStatsFrameCount);
@@ -3810,11 +3928,15 @@
 
 static void vfe32_process_stats_ihist_irq(struct vfe32_ctrl_type *vfe32_ctrl)
 {
-	if (!(vfe32_ctrl->ihistStatsControl.ackPending)) {
+	unsigned long flags;
+	uint32_t addr;
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_IHIST);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (addr) {
 		vfe32_ctrl->ihistStatsControl.bufToRender =
 			vfe32_process_stats_irq_common(
-			vfe32_ctrl, statsIhistNum,
-			vfe32_ctrl->ihistStatsControl.nextFrameAddrBuf);
+			vfe32_ctrl, statsIhistNum, addr);
 
 		vfe_send_stats_msg(vfe32_ctrl,
 			vfe32_ctrl->ihistStatsControl.bufToRender,
@@ -3828,10 +3950,15 @@
 
 static void vfe32_process_stats_rs_irq(struct vfe32_ctrl_type *vfe32_ctrl)
 {
-	if (!(vfe32_ctrl->rsStatsControl.ackPending)) {
+	unsigned long flags;
+	uint32_t addr;
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_RS);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (addr) {
 		vfe32_ctrl->rsStatsControl.bufToRender =
 			vfe32_process_stats_irq_common(vfe32_ctrl, statsRsNum,
-			vfe32_ctrl->rsStatsControl.nextFrameAddrBuf);
+			addr);
 
 		vfe_send_stats_msg(vfe32_ctrl,
 			vfe32_ctrl->rsStatsControl.bufToRender, statsRsNum);
@@ -3844,13 +3971,19 @@
 
 static void vfe32_process_stats_cs_irq(struct vfe32_ctrl_type *vfe32_ctrl)
 {
-	if (!(vfe32_ctrl->csStatsControl.ackPending)) {
+	unsigned long flags;
+	uint32_t addr;
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
+	addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl, MSM_STATS_TYPE_CS);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
+	if (addr) {
 		vfe32_ctrl->csStatsControl.bufToRender =
 			vfe32_process_stats_irq_common(vfe32_ctrl, statsCsNum,
-			vfe32_ctrl->csStatsControl.nextFrameAddrBuf);
+			addr);
 
-		vfe_send_stats_msg(vfe32_ctrl,
-			vfe32_ctrl->csStatsControl.bufToRender, statsCsNum);
+			vfe_send_stats_msg(vfe32_ctrl,
+				vfe32_ctrl->csStatsControl.bufToRender,
+				statsCsNum);
 	} else {
 		vfe32_ctrl->csStatsControl.droppedStatsFrameCount++;
 		CDBG("%s: droppedStatsFrameCount = %d", __func__,
@@ -3863,16 +3996,17 @@
 {
 	unsigned long flags;
 	int32_t process_stats = false;
-	CDBG("%s, stats = 0x%x\n", __func__, status_bits);
+	uint32_t addr;
 
-	spin_lock_irqsave(&vfe32_ctrl->comp_stats_ack_lock, flags);
+	CDBG("%s, stats = 0x%x\n", __func__, status_bits);
+	spin_lock_irqsave(&vfe32_ctrl->stats_bufq_lock, flags);
 	if (status_bits & VFE_IRQ_STATUS0_STATS_AEC) {
-		if (!vfe32_ctrl->aecStatsControl.ackPending) {
-			vfe32_ctrl->aecStatsControl.ackPending = TRUE;
+		addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl,
+				MSM_STATS_TYPE_AEC);
+		if (addr) {
 			vfe32_ctrl->aecStatsControl.bufToRender =
 				vfe32_process_stats_irq_common(
-				vfe32_ctrl, statsAeNum,
-				vfe32_ctrl->aecStatsControl.nextFrameAddrBuf);
+				vfe32_ctrl, statsAeNum,	addr);
 			process_stats = true;
 		} else{
 			vfe32_ctrl->aecStatsControl.bufToRender = 0;
@@ -3883,12 +4017,13 @@
 	}
 
 	if (status_bits & VFE_IRQ_STATUS0_STATS_AWB) {
-		if (!vfe32_ctrl->awbStatsControl.ackPending) {
-			vfe32_ctrl->awbStatsControl.ackPending = TRUE;
+		addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl,
+			MSM_STATS_TYPE_AWB);
+		if (addr) {
 			vfe32_ctrl->awbStatsControl.bufToRender =
 				vfe32_process_stats_irq_common(
 				vfe32_ctrl, statsAwbNum,
-				vfe32_ctrl->awbStatsControl.nextFrameAddrBuf);
+				addr);
 			process_stats = true;
 		} else{
 			vfe32_ctrl->awbStatsControl.droppedStatsFrameCount++;
@@ -3898,14 +4033,14 @@
 		vfe32_ctrl->awbStatsControl.bufToRender = 0;
 	}
 
-
 	if (status_bits & VFE_IRQ_STATUS0_STATS_AF) {
-		if (!vfe32_ctrl->afStatsControl.ackPending) {
-			vfe32_ctrl->afStatsControl.ackPending = TRUE;
+		addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl,
+					MSM_STATS_TYPE_AF);
+		if (addr) {
 			vfe32_ctrl->afStatsControl.bufToRender =
 				vfe32_process_stats_irq_common(
 				vfe32_ctrl, statsAfNum,
-				vfe32_ctrl->afStatsControl.nextFrameAddrBuf);
+				addr);
 			process_stats = true;
 		} else {
 			vfe32_ctrl->afStatsControl.bufToRender = 0;
@@ -3916,12 +4051,13 @@
 	}
 
 	if (status_bits & VFE_IRQ_STATUS0_STATS_IHIST) {
-		if (!vfe32_ctrl->ihistStatsControl.ackPending) {
-			vfe32_ctrl->ihistStatsControl.ackPending = TRUE;
+		addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl,
+					MSM_STATS_TYPE_IHIST);
+		if (addr) {
 			vfe32_ctrl->ihistStatsControl.bufToRender =
 				vfe32_process_stats_irq_common(
 				vfe32_ctrl, statsIhistNum,
-				vfe32_ctrl->ihistStatsControl.nextFrameAddrBuf);
+				addr);
 			process_stats = true;
 		} else {
 			vfe32_ctrl->ihistStatsControl.droppedStatsFrameCount++;
@@ -3932,12 +4068,13 @@
 	}
 
 	if (status_bits & VFE_IRQ_STATUS0_STATS_RS) {
-		if (!vfe32_ctrl->rsStatsControl.ackPending) {
-			vfe32_ctrl->rsStatsControl.ackPending = TRUE;
+		addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl,
+					MSM_STATS_TYPE_RS);
+		if (addr) {
 			vfe32_ctrl->rsStatsControl.bufToRender =
 				vfe32_process_stats_irq_common(
 				vfe32_ctrl, statsRsNum,
-				vfe32_ctrl->rsStatsControl.nextFrameAddrBuf);
+				addr);
 			process_stats = true;
 		} else {
 			vfe32_ctrl->rsStatsControl.droppedStatsFrameCount++;
@@ -3948,12 +4085,13 @@
 	}
 
 	if (status_bits & VFE_IRQ_STATUS0_STATS_CS) {
-		if (!vfe32_ctrl->csStatsControl.ackPending) {
-			vfe32_ctrl->csStatsControl.ackPending = TRUE;
+		addr = (uint32_t)vfe32_stats_dqbuf(vfe32_ctrl,
+					MSM_STATS_TYPE_CS);
+		if (addr) {
 			vfe32_ctrl->csStatsControl.bufToRender =
 				vfe32_process_stats_irq_common(
 				vfe32_ctrl, statsCsNum,
-				vfe32_ctrl->csStatsControl.nextFrameAddrBuf);
+				addr);
 			process_stats = true;
 		} else {
 			vfe32_ctrl->csStatsControl.droppedStatsFrameCount++;
@@ -3962,8 +4100,7 @@
 	} else {
 		vfe32_ctrl->csStatsControl.bufToRender = 0;
 	}
-
-	spin_unlock_irqrestore(&vfe32_ctrl->comp_stats_ack_lock, flags);
+	spin_unlock_irqrestore(&vfe32_ctrl->stats_bufq_lock, flags);
 	if (process_stats)
 		vfe_send_comp_stats_msg(vfe32_ctrl, status_bits);
 
@@ -4259,6 +4396,88 @@
 	return 0;
 }
 
+static long vfe_stats_bufq_sub_ioctl(
+	struct vfe32_ctrl_type *vfe_ctrl,
+	struct msm_vfe_cfg_cmd *cmd, void *ion_client)
+{
+	long rc = 0;
+	switch (cmd->cmd_type) {
+	case VFE_CMD_STATS_REQBUF:
+	if (!vfe_ctrl->stats_ops.stats_ctrl) {
+		/* stats_ctrl has not been init yet */
+		rc = msm_stats_buf_ops_init(&vfe_ctrl->stats_ctrl,
+				(struct ion_client *)ion_client,
+				&vfe_ctrl->stats_ops);
+		if (rc < 0) {
+			pr_err("%s: cannot init stats ops", __func__);
+			goto end;
+		}
+		rc = vfe_ctrl->stats_ops.stats_ctrl_init(&vfe_ctrl->stats_ctrl);
+		if (rc < 0) {
+			pr_err("%s: cannot init stats_ctrl ops", __func__);
+			memset(&vfe_ctrl->stats_ops, 0,
+				sizeof(vfe_ctrl->stats_ops));
+			goto end;
+		}
+		if (sizeof(struct msm_stats_reqbuf) != cmd->length) {
+			/* error. the length not match */
+			pr_err("%s: stats reqbuf input size = %d,\n"
+				"struct size = %d, mitch match\n",
+				 __func__, cmd->length,
+				sizeof(struct msm_stats_reqbuf));
+			rc = -EINVAL ;
+			goto end;
+		}
+	}
+	rc = vfe_ctrl->stats_ops.reqbuf(
+			&vfe_ctrl->stats_ctrl,
+			(struct msm_stats_reqbuf *)cmd->value,
+			vfe_ctrl->stats_ops.client);
+	break;
+	case VFE_CMD_STATS_ENQUEUEBUF:
+	if (sizeof(struct msm_stats_buf_info) != cmd->length) {
+		/* error. the length not match */
+		pr_err("%s: stats enqueuebuf input size = %d,\n"
+			"struct size = %d, mitch match\n",
+			 __func__, cmd->length,
+			sizeof(struct msm_stats_buf_info));
+			rc = -EINVAL;
+			goto end;
+	}
+	rc = vfe_ctrl->stats_ops.enqueue_buf(
+			&vfe_ctrl->stats_ctrl,
+			(struct msm_stats_buf_info *)cmd->value,
+			vfe_ctrl->stats_ops.client);
+	break;
+	case VFE_CMD_STATS_FLUSH_BUFQ:
+	{
+		struct msm_stats_flush_bufq *flush_req = NULL;
+		flush_req = (struct msm_stats_flush_bufq *)cmd->value;
+		if (sizeof(struct msm_stats_flush_bufq) != cmd->length) {
+			/* error. the length not match */
+			pr_err("%s: stats flush queue input size = %d,\n"
+				"struct size = %d, mitch match\n",
+				__func__, cmd->length,
+				sizeof(struct msm_stats_flush_bufq));
+			rc = -EINVAL;
+			goto end;
+	}
+	rc = vfe_ctrl->stats_ops.bufq_flush(
+			&vfe_ctrl->stats_ctrl,
+			(enum msm_stats_enum_type)flush_req->stats_type,
+			vfe_ctrl->stats_ops.client);
+	}
+	break;
+	default:
+		rc = -1;
+		pr_err("%s: cmd_type %d not supported", __func__,
+			cmd->cmd_type);
+	break;
+	}
+end:
+	return rc;
+}
+
 static long msm_vfe_subdev_ioctl(struct v4l2_subdev *sd,
 			unsigned int subdev_cmd, void *arg)
 {
@@ -4273,9 +4492,7 @@
 	void *data = vfe_params->data;
 
 	long rc = 0;
-	uint32_t i = 0;
 	struct vfe_cmd_stats_buf *scfg = NULL;
-	struct msm_pmem_region   *regptr = NULL;
 	struct vfe_cmd_stats_ack *sack = NULL;
 
 	if (!vfe32_ctrl->share_ctrl->vfebase) {
@@ -4283,151 +4500,100 @@
 		return -EFAULT;
 	}
 
-	if (cmd->cmd_type == CMD_VFE_PROCESS_IRQ) {
+	switch (cmd->cmd_type) {
+	case CMD_VFE_PROCESS_IRQ:
 		vfe32_process_irq(vfe32_ctrl, (uint32_t) data);
 		return rc;
-	} else if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
-		cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
-		cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR &&
-		cmd->cmd_type != CMD_STATS_AEC_BUF_RELEASE &&
-		cmd->cmd_type != CMD_STATS_AWB_BUF_RELEASE &&
-		cmd->cmd_type != CMD_STATS_IHIST_BUF_RELEASE &&
-		cmd->cmd_type != CMD_STATS_RS_BUF_RELEASE &&
-		cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE &&
-		cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
-		if (copy_from_user(&vfecmd,
-				(void __user *)(cmd->value),
-				sizeof(vfecmd))) {
-			pr_err("%s %d: copy_from_user failed\n", __func__,
-				__LINE__);
-			return -EFAULT;
-		}
-	} else {
-	/* here eith stats release or frame release. */
+	case VFE_CMD_STATS_REQBUF:
+	case VFE_CMD_STATS_ENQUEUEBUF:
+	case VFE_CMD_STATS_FLUSH_BUFQ:
+		/* for easy porting put in one envelope */
+		rc = vfe_stats_bufq_sub_ioctl(vfe32_ctrl,
+				cmd, vfe_params->data);
+		return rc;
+	default:
 		if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
 			cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
-			cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR) {
-			/* then must be stats release. */
-			if (!data)
-				return -EFAULT;
-			sack = kmalloc(sizeof(struct vfe_cmd_stats_ack),
+			cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR &&
+			cmd->cmd_type != CMD_STATS_AEC_BUF_RELEASE &&
+			cmd->cmd_type != CMD_STATS_AWB_BUF_RELEASE &&
+			cmd->cmd_type != CMD_STATS_IHIST_BUF_RELEASE &&
+			cmd->cmd_type != CMD_STATS_RS_BUF_RELEASE &&
+			cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE &&
+			cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
+				if (copy_from_user(&vfecmd,
+					(void __user *)(cmd->value),
+					sizeof(vfecmd))) {
+						pr_err("%s %d: copy_from_user failed\n",
+							__func__, __LINE__);
+					return -EFAULT;
+				}
+		} else {
+			/* here eith stats release or frame release. */
+			if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
+				cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
+				cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR) {
+				/* then must be stats release. */
+				if (!data) {
+					pr_err("%s: data = NULL, cmd->cmd_type = %d",
+						__func__, cmd->cmd_type);
+					return -EFAULT;
+				}
+				sack = kmalloc(sizeof(struct vfe_cmd_stats_ack),
 							GFP_ATOMIC);
-			if (!sack)
-				return -ENOMEM;
-
-			sack->nextStatsBuf = *(uint32_t *)data;
-		}
-	}
-
-	CDBG("%s: cmdType = %d\n", __func__, cmd->cmd_type);
-
-	if ((cmd->cmd_type == CMD_STATS_AF_ENABLE)    ||
-		(cmd->cmd_type == CMD_STATS_AWB_ENABLE)   ||
-		(cmd->cmd_type == CMD_STATS_IHIST_ENABLE) ||
-		(cmd->cmd_type == CMD_STATS_RS_ENABLE)    ||
-		(cmd->cmd_type == CMD_STATS_CS_ENABLE)    ||
-		(cmd->cmd_type == CMD_STATS_AEC_ENABLE)) {
-		struct axidata *axid;
-		axid = data;
-		if (!axid) {
-			rc = -EFAULT;
-			goto vfe32_config_done;
-		}
-
-		scfg =
-			kmalloc(sizeof(struct vfe_cmd_stats_buf),
-				GFP_ATOMIC);
-		if (!scfg) {
-			rc = -ENOMEM;
-			goto vfe32_config_done;
-		}
-		regptr = axid->region;
-		if (axid->bufnum1 > 0) {
-			for (i = 0; i < axid->bufnum1; i++) {
-				scfg->statsBuf[i] =
-					(uint32_t)(regptr->paddr);
-				regptr++;
+				if (!sack) {
+					pr_err("%s: no mem for cmd->cmd_type = %d",
+					 __func__, cmd->cmd_type);
+					return -ENOMEM;
+				}
+				sack->nextStatsBuf = *(uint32_t *)data;
 			}
 		}
-		/* individual */
-		switch (cmd->cmd_type) {
-		case CMD_STATS_AEC_ENABLE:
-			rc = vfe_stats_aec_buf_init(vfe32_ctrl, scfg);
-			break;
-		case CMD_STATS_AF_ENABLE:
-			rc = vfe_stats_af_buf_init(vfe32_ctrl, scfg);
-			break;
-		case CMD_STATS_AWB_ENABLE:
-			rc = vfe_stats_awb_buf_init(vfe32_ctrl, scfg);
-			break;
-		case CMD_STATS_IHIST_ENABLE:
-			rc = vfe_stats_ihist_buf_init(vfe32_ctrl, scfg);
-			break;
-		case CMD_STATS_RS_ENABLE:
-			rc = vfe_stats_rs_buf_init(vfe32_ctrl, scfg);
-			break;
-		case CMD_STATS_CS_ENABLE:
-			rc = vfe_stats_cs_buf_init(vfe32_ctrl, scfg);
-			break;
-		default:
-			pr_err("%s Unsupported cmd type %d",
-				__func__, cmd->cmd_type);
-			break;
+		CDBG("%s: cmdType = %d\n", __func__, cmd->cmd_type);
+
+		if ((cmd->cmd_type == CMD_STATS_AF_ENABLE)    ||
+			(cmd->cmd_type == CMD_STATS_AWB_ENABLE)   ||
+			(cmd->cmd_type == CMD_STATS_IHIST_ENABLE) ||
+			(cmd->cmd_type == CMD_STATS_RS_ENABLE)    ||
+			(cmd->cmd_type == CMD_STATS_CS_ENABLE)    ||
+			(cmd->cmd_type == CMD_STATS_AEC_ENABLE)) {
+				scfg = NULL;
+				/* individual */
+				goto vfe32_config_done;
 		}
-		goto vfe32_config_done;
-	}
-	switch (cmd->cmd_type) {
-	case CMD_GENERAL:
-		rc = vfe32_proc_general(pmctl, &vfecmd, vfe32_ctrl);
+		switch (cmd->cmd_type) {
+		case CMD_GENERAL:
+			rc = vfe32_proc_general(pmctl, &vfecmd, vfe32_ctrl);
 		break;
-	case CMD_CONFIG_PING_ADDR: {
-		int path = *((int *)cmd->value);
-		struct vfe32_output_ch *outch =
-			vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
-		outch->ping = *((struct msm_free_buf *)data);
-	}
+		case CMD_CONFIG_PING_ADDR: {
+			int path = *((int *)cmd->value);
+			struct vfe32_output_ch *outch =
+				vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
+			outch->ping = *((struct msm_free_buf *)data);
+		}
+		break;
+		case CMD_CONFIG_PONG_ADDR: {
+			int path = *((int *)cmd->value);
+			struct vfe32_output_ch *outch =
+				vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
+			outch->pong = *((struct msm_free_buf *)data);
+		}
 		break;
 
-	case CMD_CONFIG_PONG_ADDR: {
-		int path = *((int *)cmd->value);
-		struct vfe32_output_ch *outch =
-			vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
-		outch->pong = *((struct msm_free_buf *)data);
-	}
+		case CMD_CONFIG_FREE_BUF_ADDR: {
+			int path = *((int *)cmd->value);
+			struct vfe32_output_ch *outch =
+				vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
+			outch->free_buf = *((struct msm_free_buf *)data);
+		}
 		break;
-
-	case CMD_CONFIG_FREE_BUF_ADDR: {
-		int path = *((int *)cmd->value);
-		struct vfe32_output_ch *outch =
-			vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
-		outch->free_buf = *((struct msm_free_buf *)data);
-	}
+		case CMD_SNAP_BUF_RELEASE:
 		break;
-	case CMD_SNAP_BUF_RELEASE:
+		default:
+			pr_err("%s Unsupported AXI configuration %x ", __func__,
+				cmd->cmd_type);
 		break;
-	case CMD_STATS_AEC_BUF_RELEASE:
-		vfe32_stats_aec_ack(vfe32_ctrl, sack);
-		break;
-	case CMD_STATS_AF_BUF_RELEASE:
-		vfe32_stats_af_ack(vfe32_ctrl, sack);
-		break;
-	case CMD_STATS_AWB_BUF_RELEASE:
-		vfe32_stats_awb_ack(vfe32_ctrl, sack);
-		break;
-
-	case CMD_STATS_IHIST_BUF_RELEASE:
-		vfe32_stats_ihist_ack(vfe32_ctrl, sack);
-		break;
-	case CMD_STATS_RS_BUF_RELEASE:
-		vfe32_stats_rs_ack(vfe32_ctrl, sack);
-		break;
-	case CMD_STATS_CS_BUF_RELEASE:
-		vfe32_stats_cs_ack(vfe32_ctrl, sack);
-		break;
-	default:
-		pr_err("%s Unsupported AXI configuration %x ", __func__,
-			cmd->cmd_type);
-		break;
+		}
 	}
 vfe32_config_done:
 	kfree(scfg);
@@ -4542,14 +4708,7 @@
 	spin_lock_init(&vfe32_ctrl->io_lock);
 	spin_lock_init(&vfe32_ctrl->update_ack_lock);
 	spin_lock_init(&vfe32_ctrl->start_ack_lock);
-
-	spin_lock_init(&vfe32_ctrl->aec_ack_lock);
-	spin_lock_init(&vfe32_ctrl->awb_ack_lock);
-	spin_lock_init(&vfe32_ctrl->af_ack_lock);
-	spin_lock_init(&vfe32_ctrl->ihist_ack_lock);
-	spin_lock_init(&vfe32_ctrl->rs_ack_lock);
-	spin_lock_init(&vfe32_ctrl->cs_ack_lock);
-	spin_lock_init(&vfe32_ctrl->comp_stats_ack_lock);
+	spin_lock_init(&vfe32_ctrl->stats_bufq_lock);
 
 	vfe32_ctrl->update_linear = false;
 	vfe32_ctrl->update_rolloff = false;
diff --git a/drivers/media/video/msm/msm_vfe32.h b/drivers/media/video/msm/msm_vfe32.h
index c41df09..542bbf8 100644
--- a/drivers/media/video/msm/msm_vfe32.h
+++ b/drivers/media/video/msm/msm_vfe32.h
@@ -14,6 +14,7 @@
 #define __MSM_VFE32_H__
 
 #include <linux/bitops.h>
+#include "msm_vfe_stats_buf.h"
 
 #define TRUE  1
 #define FALSE 0
@@ -912,8 +913,6 @@
 #define VFE32_OUTPUT_MODE_TERTIARY2		BIT(11)
 
 struct vfe_stats_control {
-	uint8_t  ackPending;
-	uint32_t nextFrameAddrBuf;
 	uint32_t droppedStatsFrameCount;
 	uint32_t bufToRender;
 };
@@ -966,15 +965,7 @@
 	spinlock_t  start_ack_lock;
 	spinlock_t  state_lock;
 	spinlock_t  io_lock;
-
-	spinlock_t  aec_ack_lock;
-	spinlock_t  awb_ack_lock;
-	spinlock_t  af_ack_lock;
-	spinlock_t  ihist_ack_lock;
-	spinlock_t  rs_ack_lock;
-	spinlock_t  cs_ack_lock;
-	spinlock_t  comp_stats_ack_lock;
-
+	spinlock_t  stats_bufq_lock;
 	uint32_t extlen;
 	void *extdata;
 
@@ -1013,6 +1004,8 @@
 	uint32_t frame_skip_cnt;
 	uint32_t frame_skip_pattern;
 	uint32_t snapshot_frame_cnt;
+	struct msm_stats_bufq_ctrl stats_ctrl;
+	struct msm_stats_ops stats_ops;
 };
 
 #define statsAeNum      0
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
index 398621f..5fef610 100644
--- a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
@@ -351,6 +351,221 @@
 static uint32_t raw_mode;
 static struct vfe2x_ctrl_type *vfe2x_ctrl;
 
+static unsigned long vfe2x_stats_dqbuf(enum msm_stats_enum_type stats_type)
+{
+	struct msm_stats_meta_buf *buf = NULL;
+	int rc = 0;
+
+	rc = vfe2x_ctrl->stats_ops.dqbuf(vfe2x_ctrl->stats_ops.stats_ctrl,
+							  stats_type, &buf);
+	if (rc < 0) {
+		pr_err("%s: dq stats buf (type = %d) err = %d",
+			   __func__, stats_type, rc);
+		return 0;
+	}
+	return buf->paddr;
+}
+
+static unsigned long vfe2x_stats_flush_enqueue(
+	enum msm_stats_enum_type stats_type)
+{
+	struct msm_stats_bufq *bufq = NULL;
+	struct msm_stats_meta_buf *stats_buf = NULL;
+	int rc = 0;
+	int i;
+
+	/*
+	 * Passing NULL for ion client as the buffers are already
+	 * mapped at this stage, client is not required, flush all
+	 * the buffers, and buffers move to PREPARE state
+	 */
+	rc = vfe2x_ctrl->stats_ops.bufq_flush(
+			vfe2x_ctrl->stats_ops.stats_ctrl,
+			stats_type, NULL);
+	if (rc < 0) {
+		pr_err("%s: dq stats buf (type = %d) err = %d",
+			 __func__, stats_type, rc);
+		return 0L;
+	}
+
+	/* Queue all the buffers back to QUEUED state */
+	bufq = vfe2x_ctrl->stats_ctrl.bufq[stats_type];
+	for (i = 0; i < bufq->num_bufs; i++) {
+		stats_buf = &bufq->bufs[i];
+		rc = vfe2x_ctrl->stats_ops.enqueue_buf(
+				vfe2x_ctrl->stats_ops.stats_ctrl,
+				&(stats_buf->info), NULL);
+			if (rc < 0) {
+				pr_err("%s: dq stats buf (type = %d) err = %d",
+					 __func__, stats_type, rc);
+				return rc;
+			}
+	}
+	return 0L;
+}
+
+static int vfe2x_stats_buf_init(enum msm_stats_enum_type type)
+{
+	unsigned long flags;
+	int i = 0, rc = 0;
+	if (type == MSM_STATS_TYPE_AF) {
+		spin_lock_irqsave(&vfe2x_ctrl->stats_bufq_lock, flags);
+		rc = vfe2x_stats_flush_enqueue(MSM_STATS_TYPE_AF);
+		if (rc < 0) {
+			pr_err("%s: dq stats buf err = %d",
+				 __func__, rc);
+			spin_unlock_irqrestore(&vfe2x_ctrl->stats_bufq_lock,
+				flags);
+			return -EINVAL;
+		}
+		spin_unlock_irqrestore(&vfe2x_ctrl->stats_bufq_lock, flags);
+	}
+	for (i = 0; i < 3; i++) {
+		spin_lock_irqsave(&vfe2x_ctrl->stats_bufq_lock, flags);
+		if (type == MSM_STATS_TYPE_AE_AW)
+			vfe2x_ctrl->stats_we_buf_ptr[i] =
+				vfe2x_stats_dqbuf(type);
+		else
+			vfe2x_ctrl->stats_af_buf_ptr[i] =
+				vfe2x_stats_dqbuf(type);
+		spin_unlock_irqrestore(&vfe2x_ctrl->stats_bufq_lock, flags);
+		if (!vfe2x_ctrl->stats_we_buf_ptr[i]) {
+			pr_err("%s: dq error type %d ", __func__, type);
+			return -ENOMEM;
+		}
+	}
+	return rc;
+}
+
+static unsigned long vfe2x_stats_enqueuebuf(
+	struct msm_stats_buf_info *info, struct vfe_stats_ack *sack)
+{
+	struct msm_stats_bufq *bufq = NULL;
+	struct msm_stats_meta_buf *stats_buf = NULL;
+	struct msm_stats_meta_buf *buf = NULL;
+	int rc = 0;
+
+	bufq = vfe2x_ctrl->stats_ctrl.bufq[info->type];
+	stats_buf = &bufq->bufs[info->buf_idx];
+
+	CDBG("vfe2x_stats_enqueuebuf: %d\n", stats_buf->state);
+	if (stats_buf->state == MSM_STATS_BUFFER_STATE_INITIALIZED ||
+		stats_buf->state == MSM_STATS_BUFFER_STATE_PREPARED) {
+		rc = vfe2x_ctrl->stats_ops.enqueue_buf(
+				&vfe2x_ctrl->stats_ctrl,
+				info, vfe2x_ctrl->stats_ops.client);
+		if (rc < 0) {
+			pr_err("%s: enqueue_buf (type = %d), index : %d, err = %d",
+				 __func__, info->type, info->buf_idx, rc);
+			return rc;
+		}
+
+	} else {
+		rc = vfe2x_ctrl->stats_ops.querybuf(
+				vfe2x_ctrl->stats_ops.stats_ctrl, info, &buf);
+		if (rc < 0) {
+			pr_err("%s: querybuf (type = %d), index : %d, err = %d",
+				__func__, info->type, info->buf_idx, rc);
+			return rc;
+	}
+		stats_buf->state = MSM_STATS_BUFFER_STATE_DEQUEUED;
+	if (info->type == MSM_STATS_TYPE_AE_AW) {
+		sack->header = VFE_STATS_WB_EXP_ACK;
+		sack->bufaddr = (void *)(uint32_t *)buf->paddr;
+	} else if (info->type == MSM_STATS_TYPE_AF) {
+		sack->header = VFE_STATS_AUTOFOCUS_ACK;
+		sack->bufaddr = (void *)(uint32_t *)buf->paddr;
+	} else
+		pr_err("%s: Invalid stats: should never come here\n", __func__);
+	}
+	return 0L;
+}
+
+static long vfe2x_stats_bufq_sub_ioctl(struct msm_vfe_cfg_cmd *cmd,
+	void *ion_client)
+{
+	long rc = 0;
+
+	switch (cmd->cmd_type) {
+	case VFE_CMD_STATS_REQBUF:
+		if (!vfe2x_ctrl->stats_ops.stats_ctrl) {
+			/* stats_ctrl has not been init yet */
+			rc = msm_stats_buf_ops_init(
+					&vfe2x_ctrl->stats_ctrl,
+					(struct ion_client *)ion_client,
+					&vfe2x_ctrl->stats_ops);
+			if (rc < 0) {
+				pr_err("%s: cannot init stats ops", __func__);
+				goto end;
+			}
+			rc = vfe2x_ctrl->stats_ops.stats_ctrl_init(
+					&vfe2x_ctrl->stats_ctrl);
+			if (rc < 0) {
+				pr_err("%s: cannot init stats_ctrl ops",
+					 __func__);
+				memset(&vfe2x_ctrl->stats_ops, 0,
+				sizeof(vfe2x_ctrl->stats_ops));
+				goto end;
+			}
+			if (sizeof(struct msm_stats_reqbuf) != cmd->length) {
+				/* error. the length not match */
+				pr_err("%s: stats reqbuf input size = %d,\n"
+					"struct size = %d, mismatch\n",
+					__func__, cmd->length,
+					sizeof(struct msm_stats_reqbuf));
+				rc = -EINVAL;
+				goto end;
+			}
+		}
+		rc = vfe2x_ctrl->stats_ops.reqbuf(
+				&vfe2x_ctrl->stats_ctrl,
+				(struct msm_stats_reqbuf *)cmd->value,
+				vfe2x_ctrl->stats_ops.client);
+		break;
+		case VFE_CMD_STATS_ENQUEUEBUF: {
+			if (sizeof(struct msm_stats_buf_info) != cmd->length) {
+				/* error. the length not match */
+				pr_err("%s: stats enqueuebuf input size = %d,\n"
+					"struct size = %d, mismatch\n",
+					 __func__, cmd->length,
+					sizeof(struct msm_stats_buf_info));
+				rc = -EINVAL;
+				goto end;
+		}
+		rc = vfe2x_ctrl->stats_ops.enqueue_buf(
+				&vfe2x_ctrl->stats_ctrl,
+				(struct msm_stats_buf_info *)cmd->value,
+				vfe2x_ctrl->stats_ops.client);
+	}
+	break;
+	case VFE_CMD_STATS_FLUSH_BUFQ: {
+		struct msm_stats_flush_bufq *flush_req = NULL;
+		flush_req = (struct msm_stats_flush_bufq *)cmd->value;
+		if (sizeof(struct msm_stats_flush_bufq) != cmd->length) {
+			/* error. the length not match */
+			pr_err("%s: stats flush queue input size = %d,\n"
+				"struct size = %d, mismatch\n",
+				__func__, cmd->length,
+				sizeof(struct msm_stats_flush_bufq));
+				rc = -EINVAL;
+				goto end;
+		}
+		rc = vfe2x_ctrl->stats_ops.bufq_flush(
+				&vfe2x_ctrl->stats_ctrl,
+				(enum msm_stats_enum_type)flush_req->stats_type,
+				vfe2x_ctrl->stats_ops.client);
+	}
+	break;
+	default:
+		rc = -1;
+		pr_err("%s: cmd_type %d not supported",
+			 __func__, cmd->cmd_type);
+	break;
+	}
+end:
+	return rc;
+}
+
 static void vfe2x_send_isp_msg(
 	struct vfe2x_ctrl_type *vctrl,
 	uint32_t isp_msg_id)
@@ -384,11 +599,26 @@
 static void vfe_send_stats_msg(uint32_t buf_addr, uint32_t msg_id)
 {
 	struct isp_msg_stats msg_stats;
+	void *vaddr = NULL;
+	int rc;
 
 	msg_stats.frameCounter = vfe2x_ctrl->vfeFrameId;
 	msg_stats.buffer       = buf_addr;
 	msg_stats.id           = msg_id;
 
+	if (MSG_ID_STATS_AWB_AEC == msg_id)
+		rc = vfe2x_ctrl->stats_ops.dispatch(
+			vfe2x_ctrl->stats_ops.stats_ctrl,
+			MSM_STATS_TYPE_AE_AW, buf_addr,
+			&msg_stats.buf_idx, &vaddr, &msg_stats.fd,
+			vfe2x_ctrl->stats_ops.client);
+	else if (MSG_ID_STATS_AF == msg_id)
+		rc = vfe2x_ctrl->stats_ops.dispatch(
+			vfe2x_ctrl->stats_ops.stats_ctrl,
+			MSM_STATS_TYPE_AF, buf_addr,
+			&msg_stats.buf_idx, &vaddr, &msg_stats.fd,
+			vfe2x_ctrl->stats_ops.client);
+
 	v4l2_subdev_notify(&vfe2x_ctrl->subdev,
 				NOTIFY_VFE_MSG_STATS,
 				&msg_stats);
@@ -979,21 +1209,54 @@
 
 	CDBG("msm_vfe_subdev_ioctl is called\n");
 	if (cmd->cmd_type != CMD_FRAME_BUF_RELEASE &&
-	    cmd->cmd_type != CMD_STATS_BUF_RELEASE &&
-	    cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_BUF_RELEASE &&
+		cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE &&
 		cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
 		cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
 		cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR &&
-		cmd->cmd_type != CMD_VFE_BUFFER_RELEASE) {
+		cmd->cmd_type != CMD_VFE_BUFFER_RELEASE &&
+		cmd->cmd_type != VFE_CMD_STATS_REQBUF &&
+		cmd->cmd_type != VFE_CMD_STATS_FLUSH_BUFQ &&
+		cmd->cmd_type != VFE_CMD_STATS_ENQUEUEBUF) {
 		if (copy_from_user(&vfecmd,
-				(void __user *)(cmd->value),
-				sizeof(vfecmd))) {
+			   (void __user *)(cmd->value),
+			   sizeof(vfecmd))) {
 			pr_err("copy_from_user in msm_vfe_subdev_ioctl fail\n");
 			return -EFAULT;
 		}
 	}
-
 	switch (cmd->cmd_type) {
+	case VFE_CMD_STATS_REQBUF:
+	case VFE_CMD_STATS_FLUSH_BUFQ:
+		/* for easy porting put in one envelope */
+		rc = vfe2x_stats_bufq_sub_ioctl(cmd, vfe_params->data);
+		return rc;
+	case VFE_CMD_STATS_ENQUEUEBUF:
+		if (sizeof(struct msm_stats_buf_info) != cmd->length) {
+			/* error. the length not match */
+			pr_err("%s: stats enqueuebuf input size = %d,\n"
+				"struct size = %d, mitch match\n",\
+				__func__, cmd->length,
+				sizeof(struct msm_stats_buf_info));
+			rc = -EINVAL;
+			return rc;
+		}
+		sack.header = 0;
+		sack.bufaddr = NULL;
+		rc = vfe2x_stats_enqueuebuf(cmd->value, &sack);
+		if (rc < 0) {
+			pr_err("%s: error", __func__);
+			rc = -EINVAL;
+			return rc;
+		}
+		if (sack.header != 0 && sack.bufaddr != NULL) {
+			queue  = QDSP_CMDQUEUE;
+			vfecmd.length = sizeof(struct vfe_stats_ack) - 4;
+			cmd_data = &sack;
+		} else {
+			return 0;
+		}
+	break;
 	case CMD_VFE_BUFFER_RELEASE: {
 		if (!(vfe2x_ctrl->vfe_started) || op_mode == 1)
 			return 0;
@@ -1041,7 +1304,6 @@
 	}
 		return 0;
 
-	case CMD_STATS_AEC_AWB_ENABLE:
 	case CMD_STATS_AXI_CFG: {
 		axid = data;
 		if (!axid) {
@@ -1096,15 +1358,49 @@
 		}
 	}
 		break;
-	case CMD_STATS_AF_ENABLE:
-	case CMD_STATS_AF_AXI_CFG: {
-		CDBG("CMD_STATS_AF_ENABLE CMD_STATS_AF_AXI_CFG\n");
-		axid = data;
-		if (!axid) {
-			rc = -EFAULT;
+	case CMD_STATS_AEC_AWB_ENABLE: {
+		pr_err("CMD_STATS_AEC_AWB_ENABLE\n");
+		scfg =
+			kmalloc(sizeof(struct vfe_stats_we_cfg),
+				GFP_ATOMIC);
+		if (!scfg) {
+			rc = -ENOMEM;
 			goto config_failure;
 		}
 
+		if (copy_from_user((char *)scfg + 4,
+					(void __user *)(vfecmd.value),
+					vfecmd.length)) {
+
+			rc = -EFAULT;
+			goto config_done;
+		}
+
+		header = cmds_map[vfecmd.id].vfe_id;
+		queue = cmds_map[vfecmd.id].queue;
+		if (header == -1 && queue == -1) {
+			rc = -EFAULT;
+			goto config_failure;
+		}
+		*(uint32_t *)scfg = header;
+		rc = vfe2x_stats_buf_init(MSM_STATS_TYPE_AE_AW);
+		if (rc < 0) {
+			pr_err("%s: cannot config ping/pong address of AWB",
+				 __func__);
+			goto config_failure;
+		}
+		scfg->wb_expstatoutputbuffer[0] =
+			(void *)vfe2x_ctrl->stats_we_buf_ptr[0];
+		scfg->wb_expstatoutputbuffer[1] =
+			(void *)vfe2x_ctrl->stats_we_buf_ptr[1];
+		scfg->wb_expstatoutputbuffer[2] =
+			(void *)vfe2x_ctrl->stats_we_buf_ptr[2];
+		cmd_data = scfg;
+	}
+	break;
+	case CMD_STATS_AF_ENABLE:
+	case CMD_STATS_AF_AXI_CFG: {
+		CDBG("CMD_STATS_AF_ENABLE CMD_STATS_AF_AXI_CFG\n");
 		sfcfg =
 			kmalloc(sizeof(struct vfe_stats_af_cfg),
 				GFP_ATOMIC);
@@ -1122,9 +1418,6 @@
 			goto config_done;
 		}
 
-		CDBG("AF_ENABLE: bufnum = %d, enabling = %d\n",
-			axid->bufnum1, sfcfg->af_enable);
-
 		header = cmds_map[vfecmd.id].vfe_id;
 		queue = cmds_map[vfecmd.id].queue;
 		if (header == -1 && queue == -1) {
@@ -1132,27 +1425,16 @@
 			goto config_failure;
 		}
 		*(uint32_t *)sfcfg = header;
-		CDBG("Number of buffers = %d\n", axid->bufnum1);
-		if (axid->bufnum1 > 0) {
-			regptr = &axid->region[0];
-
-			for (i = 0; i < axid->bufnum1; i++) {
-
-				CDBG("STATS_ENABLE, phy = 0x%lx\n",
-					regptr->paddr);
-
-				sfcfg->af_outbuf[i] =
-					(void *)regptr->paddr;
-
-				regptr++;
-			}
-
-			cmd_data = sfcfg;
-
-		} else {
-			rc = -EINVAL;
-			goto config_done;
+		rc = vfe2x_stats_buf_init(MSM_STATS_TYPE_AF);
+		sfcfg->af_outbuf[0] = (void *)vfe2x_ctrl->stats_af_buf_ptr[0];
+		sfcfg->af_outbuf[1] = (void *)vfe2x_ctrl->stats_af_buf_ptr[1];
+		sfcfg->af_outbuf[2] = (void *)vfe2x_ctrl->stats_af_buf_ptr[2];
+		if (rc < 0) {
+			pr_err("%s: cannot config ping/pong address of AWB",
+				__func__);
+			goto config_failure;
 		}
+		cmd_data = sfcfg;
 	}
 		break;
 	case CMD_SNAP_BUF_RELEASE:
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.h b/drivers/media/video/msm/msm_vfe7x27a_v4l2.h
index 2f2d3c6..b7d6806 100644
--- a/drivers/media/video/msm/msm_vfe7x27a_v4l2.h
+++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.h
@@ -16,6 +16,7 @@
 #include <mach/camera.h>
 #include <linux/list.h>
 #include "msm.h"
+#include "msm_vfe_stats_buf.h"
 
 struct cmd_id_map {
 	uint32_t isp_id;
@@ -111,6 +112,11 @@
 	spinlock_t  sd_notify_lock;
 	uint32_t    reconfig_vfe;
 	uint32_t    zsl_mode;
+	spinlock_t  stats_bufq_lock;
+	struct msm_stats_bufq_ctrl stats_ctrl;
+	struct msm_stats_ops stats_ops;
+	unsigned long stats_we_buf_ptr[3];
+	unsigned long stats_af_buf_ptr[3];
 } __packed;
 
 struct vfe_frame_extra {
diff --git a/drivers/media/video/msm/msm_vfe_stats_buf.c b/drivers/media/video/msm/msm_vfe_stats_buf.c
new file mode 100644
index 0000000..9e8f285
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe_stats_buf.c
@@ -0,0 +1,509 @@
+/* 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/workqueue.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/ioctl.h>
+#include <linux/spinlock.h>
+#include <linux/videodev2.h>
+#include <linux/proc_fs.h>
+#include <linux/vmalloc.h>
+
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+
+#include <linux/android_pmem.h>
+#include <media/msm_camera.h>
+#include <media/msm_isp.h>
+#include "msm.h"
+#include "msm_vfe_stats_buf.h"
+
+#ifdef CONFIG_MSM_CAMERA_DEBUG
+	#define D(fmt, args...) pr_debug("msm_stats: " fmt, ##args)
+#else
+	#define D(fmt, args...) do {} while (0)
+#endif
+
+static int msm_stats_init(struct msm_stats_bufq_ctrl *stats_ctrl)
+{
+	int rc = 0;
+	/* cannot get spinlock here */
+	if (stats_ctrl->init_done > 0) {
+		pr_err("%s: already initialized stats ctrl. no op", __func__);
+		return 0;
+	}
+	memset(stats_ctrl,  0,  sizeof(struct msm_stats_bufq_ctrl));
+	spin_lock_init(&stats_ctrl->lock);
+	stats_ctrl->init_done = 1;
+	return rc;
+}
+
+static int msm_stats_reqbuf(struct msm_stats_bufq_ctrl *stats_ctrl,
+	struct msm_stats_reqbuf *reqbuf,
+	struct ion_client *client)
+{
+	int rc = 0;
+	struct msm_stats_bufq *bufq;
+	struct msm_stats_meta_buf *bufs;
+	int idx = reqbuf->stats_type;
+	int i;
+
+	D("%s: type : %d, buf num : %d\n", __func__,
+		reqbuf->stats_type, reqbuf->num_buf);
+	if (reqbuf->num_buf > 0) {
+		if (stats_ctrl->bufq[idx]) {
+			/* already in use. Error */
+			pr_err("%s: stats type %d aleady requested",
+				 __func__, reqbuf->stats_type);
+			rc = -EEXIST;
+			goto end;
+		} else {
+			/* good case */
+			bufq = (struct msm_stats_bufq *)
+				kzalloc(
+					sizeof(struct msm_stats_bufq),
+					GFP_KERNEL);
+			if (!bufq) {
+				/* no memory */
+				rc = -ENOMEM;
+				pr_err("%s: no mem for stats type %d",
+					__func__, reqbuf->stats_type);
+				goto end;
+			}
+			bufs = (struct msm_stats_meta_buf *)
+				kzalloc((reqbuf->num_buf *
+					sizeof(struct msm_stats_meta_buf)),
+					GFP_KERNEL);
+			if (!bufs) {
+				/* no memory */
+				rc = -ENOMEM;
+				pr_err("%s: no mem for stats buf, stats type = %d",
+					__func__, reqbuf->stats_type);
+				kfree(bufq);
+				goto end;
+			}
+			/* init bufq list head */
+			INIT_LIST_HEAD(&bufq->head);
+			/* set the meta buf state to initialized */
+			bufq->num_bufs = reqbuf->num_buf;
+			for (i = 0; i < reqbuf->num_buf; i++)
+				bufs[i].state =
+					MSM_STATS_BUFFER_STATE_INITIALIZED;
+			bufq->bufs = bufs;
+			bufq->num_bufs = reqbuf->num_buf;
+			bufq->type = reqbuf->stats_type;
+			stats_ctrl->bufq[idx] = bufq;
+			/* done reqbuf (larger than zero case) */
+			goto end;
+		}
+	} else if (reqbuf->num_buf == 0) {
+		if (stats_ctrl->bufq[idx] == NULL) {
+			/* double free case? */
+			pr_err("%s: stats type %d aleady freed",
+				 __func__, reqbuf->stats_type);
+			rc = -ENXIO;
+			goto end;
+		} else {
+			/* good case. need to de-reqbuf */
+			kfree(stats_ctrl->bufq[idx]->bufs);
+			kfree(stats_ctrl->bufq[idx]);
+			stats_ctrl->bufq[idx] = NULL;
+			goto end;
+		}
+	} else {
+		/* error case */
+		pr_err("%s: stats type = %d, req_num_buf = %d, error",
+			   __func__, reqbuf->stats_type, reqbuf->num_buf);
+		rc = -EPERM;
+		goto end;
+	}
+end:
+	return rc;
+}
+static int msm_stats_deinit(struct msm_stats_bufq_ctrl *stats_ctrl)
+{
+	int rc = 0;
+	int i;
+
+	if (stats_ctrl->init_done == 0) {
+		pr_err("%s: not inited yet. no op", __func__);
+		return 0;
+	}
+	/* safe guard in case deallocate memory not done yet. */
+	for (i = 0; i < MSM_STATS_TYPE_MAX; i++) {
+		if (stats_ctrl->bufq[i]) {
+			if (stats_ctrl->bufq[i]->bufs) {
+				rc = -1;
+				pr_err("%s: stats type = %d, buf not freed yet",
+					 __func__, i);
+				BUG_ON(stats_ctrl->bufq[i]->bufs);
+			} else {
+				rc = -1;
+				pr_err("%s: stats type = %d, bufq not freed yet",
+					__func__, i);
+				BUG_ON(stats_ctrl->bufq[i]);
+			}
+		}
+	}
+	memset(stats_ctrl,  0,  sizeof(struct msm_stats_bufq_ctrl));
+	return rc;
+}
+
+#ifdef CONFIG_ANDROID_PMEM
+static int msm_stats_check_pmem_info(struct msm_stats_buf_info *info, int len)
+{
+	if (info->offset < len &&
+		info->offset + info->len <= len &&
+		info->planar0_off < len && info->planar1_off < len)
+		return 0;
+
+	pr_err("%s: check failed: off %d len %d y %d cbcr %d (total len %d)\n",
+		   __func__,
+		   info->offset,
+		   info->len,
+		   info->planar0_off,
+		   info->planar1_off,
+		   len);
+	return -EINVAL;
+}
+#endif
+
+static int msm_stats_buf_prepare(struct msm_stats_bufq_ctrl *stats_ctrl,
+	struct msm_stats_buf_info *info, struct ion_client *client)
+{
+	unsigned long paddr;
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
+	unsigned long kvstart;
+	struct file *file;
+#endif
+	int rc = 0;
+	unsigned long len;
+	struct msm_stats_bufq *bufq = NULL;
+	struct msm_stats_meta_buf *stats_buf = NULL;
+
+	D("%s: type : %d, buf num : %d\n", __func__,
+		info->type, info->buf_idx);
+
+	bufq = stats_ctrl->bufq[info->type];
+	stats_buf = &bufq->bufs[info->buf_idx];
+	if (stats_buf->state == MSM_STATS_BUFFER_STATE_UNUSED) {
+		pr_err("%s: need reqbuf first, stats type = %d",
+			__func__, info->type);
+		rc = -1;
+		goto out1;
+	}
+	if (stats_buf->state != MSM_STATS_BUFFER_STATE_INITIALIZED) {
+		D("%s: stats already mapped, no op, stats type = %d",
+			__func__, info->type);
+		goto out1;
+	}
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	stats_buf->handle = ion_import_dma_buf(client, info->fd);
+	if (IS_ERR_OR_NULL(stats_buf->handle)) {
+		rc = -EINVAL;
+		pr_err("%s: stats_buf has null/error ION handle %p",
+			   __func__, stats_buf->handle);
+		goto out1;
+	}
+	if (ion_map_iommu(client, stats_buf->handle,
+			CAMERA_DOMAIN, GEN_POOL, SZ_4K,
+			0, &paddr, &len, UNCACHED, 0) < 0) {
+		rc = -EINVAL;
+		pr_err("%s: cannot map address", __func__);
+		goto out2;
+	}
+#elif CONFIG_ANDROID_PMEM
+	rc = get_pmem_file(info->fd, &paddr, &kvstart, &len, &file);
+	if (rc < 0) {
+		pr_err("%s: get_pmem_file fd %d error %d\n",
+			   __func__, info->fd, rc);
+		goto out1;
+	}
+	stats_buf->file = file;
+#else
+	paddr = 0;
+	file = NULL;
+	kvstart = 0;
+#endif
+	if (!info->len)
+		info->len = len;
+	rc = msm_stats_check_pmem_info(info, len);
+	if (rc < 0) {
+		pr_err("%s: msm_stats_check_pmem_info err = %d", __func__, rc);
+		goto out3;
+	}
+	paddr += info->offset;
+	len = info->len;
+	stats_buf->paddr = paddr;
+	stats_buf->len = len;
+	memcpy(&stats_buf->info, info, sizeof(stats_buf->info));
+	D("%s Adding buf to list with type %d\n", __func__,
+	  stats_buf->info.type);
+	D("%s pmem_stats address is 0x%ld\n", __func__, paddr);
+	stats_buf->state = MSM_STATS_BUFFER_STATE_PREPARED;
+	return 0;
+out3:
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	ion_unmap_iommu(client, stats_buf->handle, CAMERA_DOMAIN, GEN_POOL);
+#endif
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+out2:
+	ion_free(client, stats_buf->handle);
+#elif CONFIG_ANDROID_PMEM
+	put_pmem_file(stats_buf->file);
+#endif
+out1:
+	return rc;
+}
+static int msm_stats_buf_unprepare(struct msm_stats_bufq_ctrl *stats_ctrl,
+	enum msm_stats_enum_type stats_type, int buf_idx,
+	struct ion_client *client)
+{
+	int rc = 0;
+	struct msm_stats_bufq *bufq = NULL;
+	struct msm_stats_meta_buf *stats_buf = NULL;
+
+	D("%s: type : %d, idx : %d\n", __func__, stats_type, buf_idx);
+	bufq = stats_ctrl->bufq[stats_type];
+	stats_buf = &bufq->bufs[buf_idx];
+	if (stats_buf->state == MSM_STATS_BUFFER_STATE_UNUSED) {
+		pr_err("%s: need reqbuf first, stats type = %d",
+			__func__, stats_type);
+		rc = -1;
+		goto end;
+	}
+	if (stats_buf->state == MSM_STATS_BUFFER_STATE_INITIALIZED) {
+		D("%s: stats already mapped, no op, stats type = %d",
+			__func__, stats_type);
+		goto end;
+	}
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	ion_unmap_iommu(client, stats_buf->handle,
+					CAMERA_DOMAIN, GEN_POOL);
+	ion_free(client, stats_buf->handle);
+#else
+	put_pmem_file(stats_buf->file);
+#endif
+	if (stats_buf->state == MSM_STATS_BUFFER_STATE_QUEUED) {
+		/* buf queued need delete from list */
+		D("%s: delete stats buf, type = %d, idx = %d",
+		  __func__,  stats_type,  buf_idx);
+		list_del_init(&stats_buf->list);
+	}
+end:
+	return rc;
+}
+
+static int msm_stats_bufq_flush(struct msm_stats_bufq_ctrl *stats_ctrl,
+	enum msm_stats_enum_type stats_type, struct ion_client *client)
+{
+	int rc = 0;
+	int i;
+	struct msm_stats_bufq *bufq = NULL;
+	struct msm_stats_meta_buf *stats_buf = NULL;
+
+	D("%s: type : %d\n", __func__, stats_type);
+	bufq = stats_ctrl->bufq[stats_type];
+
+	for (i = 0; i < bufq->num_bufs; i++) {
+		stats_buf = &bufq->bufs[i];
+		switch (stats_buf->state) {
+		case MSM_STATS_BUFFER_STATE_QUEUED:
+			/* buf queued in stats free queue */
+			stats_buf->state = MSM_STATS_BUFFER_STATE_PREPARED;
+			list_del_init(&stats_buf->list);
+			break;
+		case MSM_STATS_BUFFER_STATE_DEQUEUED:
+			/* if stats buf in VFE reset the state */
+			stats_buf->state = MSM_STATS_BUFFER_STATE_PREPARED;
+			break;
+		case MSM_STATS_BUFFER_STATE_DISPATCHED:
+			/* if stats buf in userspace reset the state */
+			stats_buf->state = MSM_STATS_BUFFER_STATE_PREPARED;
+			break;
+		default:
+			break;
+		}
+	}
+	return rc;
+}
+
+static int msm_stats_dqbuf(struct msm_stats_bufq_ctrl *stats_ctrl,
+	enum msm_stats_enum_type stats_type,
+	struct msm_stats_meta_buf **pp_stats_buf)
+{
+	int rc = 0;
+	struct msm_stats_bufq *bufq = NULL;
+	struct msm_stats_meta_buf *stats_buf = NULL;
+
+	D("%s: type : %d\n", __func__, stats_type);
+	*pp_stats_buf = NULL;
+	bufq = stats_ctrl->bufq[stats_type];
+
+	list_for_each_entry(stats_buf, &bufq->head, list) {
+		if (stats_buf->state == MSM_STATS_BUFFER_STATE_QUEUED) {
+			/* found one buf */
+			list_del_init(&stats_buf->list);
+			*pp_stats_buf = stats_buf;
+			break;
+		}
+	}
+	if (!(*pp_stats_buf)) {
+		pr_err("%s: no free stats buf, type = %d",
+			__func__, stats_type);
+		rc = -1;
+		return rc;
+	}
+	stats_buf->state = MSM_STATS_BUFFER_STATE_DEQUEUED;
+	return rc;
+}
+
+
+static int msm_stats_querybuf(struct msm_stats_bufq_ctrl *stats_ctrl,
+	struct msm_stats_buf_info *info,
+	struct msm_stats_meta_buf **pp_stats_buf)
+{
+	int rc = 0;
+	struct msm_stats_bufq *bufq = NULL;
+
+	*pp_stats_buf = NULL;
+	D("%s: stats type : %d, buf_idx : %d", __func__, info->type,
+		   info->buf_idx);
+	bufq = stats_ctrl->bufq[info->type];
+	*pp_stats_buf = &bufq->bufs[info->buf_idx];
+
+	return rc;
+}
+
+static int msm_stats_qbuf(struct msm_stats_bufq_ctrl *stats_ctrl,
+	enum msm_stats_enum_type stats_type,
+	int buf_idx)
+{
+	int rc = 0;
+	struct msm_stats_bufq *bufq = NULL;
+	struct msm_stats_meta_buf *stats_buf = NULL;
+	D("%s: stats type : %d, buf_idx : %d", __func__, stats_type,
+		   buf_idx);
+
+	bufq = stats_ctrl->bufq[stats_type];
+	if (!bufq) {
+		pr_err("%s: null bufq, stats type = %d", __func__, stats_type);
+		rc = -1;
+		goto end;
+	}
+	if (buf_idx >= bufq->num_bufs) {
+		pr_err("%s: stats type = %d, its idx %d larger than buf count %d",
+			   __func__, stats_type, buf_idx, bufq->num_bufs);
+		rc = -1;
+		goto end;
+	}
+	stats_buf = &bufq->bufs[buf_idx];
+	switch (stats_buf->state) {
+	case MSM_STATS_BUFFER_STATE_PREPARED:
+	case MSM_STATS_BUFFER_STATE_DEQUEUED:
+	case MSM_STATS_BUFFER_STATE_DISPATCHED:
+		stats_buf->state = MSM_STATS_BUFFER_STATE_QUEUED;
+		list_add_tail(&stats_buf->list, &bufq->head);
+		break;
+	default:
+		pr_err("%s: incorrect state = %d, stats type = %d, cannot qbuf",
+			   __func__, stats_buf->state, stats_type);
+		rc = -1;
+		break;
+	}
+end:
+	return rc;
+}
+
+static int msm_stats_buf_dispatch(struct msm_stats_bufq_ctrl *stats_ctrl,
+	enum msm_stats_enum_type stats_type,
+	unsigned long phy_addr, int *buf_idx,
+	void **vaddr, int *fd,
+	struct ion_client *client)
+{
+	int rc = 0;
+	int i;
+	struct msm_stats_bufq *bufq = NULL;
+	struct msm_stats_meta_buf *stats_buf = NULL;
+	D("%s: stats type : %d\n", __func__, stats_type);
+
+	*buf_idx = -1;
+	*vaddr = NULL;
+	*fd = 0;
+	bufq = stats_ctrl->bufq[stats_type];
+	for (i = 0; i < bufq->num_bufs; i++) {
+		if (bufq->bufs[i].paddr == phy_addr) {
+			stats_buf = &bufq->bufs[i];
+			*buf_idx = i;
+			*vaddr = stats_buf->info.vaddr;
+			*fd = stats_buf->info.fd;
+			break;
+		}
+	}
+	if (!stats_buf) {
+		pr_err("%s: no match, phy_addr = 0x%ld, stats_type = %d",
+			   __func__, phy_addr, stats_type);
+		return -EFAULT;
+	}
+	switch (stats_buf->state) {
+	case MSM_STATS_BUFFER_STATE_DEQUEUED:
+		stats_buf->state = MSM_STATS_BUFFER_STATE_DISPATCHED;
+		break;
+	default:
+		pr_err("%s: type = %d, idx = %d, cur_state = %d,\n"
+			   "cannot set state to DISPATCHED\n",
+			   __func__, stats_type, *buf_idx, stats_buf->state);
+		rc = -EFAULT;
+		break;
+	}
+	return rc;
+}
+static int msm_stats_enqueue_buf(struct msm_stats_bufq_ctrl *stats_ctrl,
+	struct msm_stats_buf_info *info, struct ion_client *client)
+{
+	int rc = 0;
+	rc = msm_stats_buf_prepare(stats_ctrl, info, client);
+	if (rc < 0) {
+		pr_err("%s: buf_prepare failed, rc = %d", __func__, rc);
+		return -EINVAL;
+	}
+	rc = msm_stats_qbuf(stats_ctrl,   info->type, info->buf_idx);
+	if (rc < 0) {
+		pr_err("%s: msm_stats_qbuf failed, rc = %d", __func__, rc);
+		return -EINVAL;
+	}
+	return rc;
+}
+
+int msm_stats_buf_ops_init(struct msm_stats_bufq_ctrl *stats_ctrl,
+	struct ion_client *client, struct msm_stats_ops *ops)
+{
+	ops->stats_ctrl = stats_ctrl;
+	ops->client = client;
+	ops->enqueue_buf = msm_stats_enqueue_buf;
+	ops->qbuf = msm_stats_qbuf;
+	ops->dqbuf = msm_stats_dqbuf;
+	ops->bufq_flush = msm_stats_bufq_flush;
+	ops->buf_unprepare = msm_stats_buf_unprepare;
+	ops->buf_prepare = msm_stats_buf_prepare;
+	ops->reqbuf = msm_stats_reqbuf;
+	ops->querybuf = msm_stats_querybuf;
+	ops->dispatch = msm_stats_buf_dispatch;
+	ops->stats_ctrl_init = msm_stats_init;
+	ops->stats_ctrl_deinit = msm_stats_deinit;
+	return 0;
+}
+
diff --git a/drivers/media/video/msm/msm_vfe_stats_buf.h b/drivers/media/video/msm/msm_vfe_stats_buf.h
new file mode 100644
index 0000000..18fd425
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe_stats_buf.h
@@ -0,0 +1,93 @@
+/* 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_STATS_BUF_H_
+#define _MSM_STATS_BUF_H_
+
+enum msm_stats_buffer_state {
+	MSM_STATS_BUFFER_STATE_UNUSED,	  /* not used */
+	MSM_STATS_BUFFER_STATE_INITIALIZED,	   /* REQBUF done */
+	MSM_STATS_BUFFER_STATE_PREPARED,	/* BUF mapped */
+	MSM_STATS_BUFFER_STATE_QUEUED,	  /* buf queued */
+	MSM_STATS_BUFFER_STATE_DEQUEUED,	/* in use in VFE */
+	MSM_STATS_BUFFER_STATE_DISPATCHED,	  /* sent to userspace */
+};
+
+struct msm_stats_meta_buf {
+	struct list_head list;
+	enum msm_stats_buffer_state state;
+	int type;
+	int fd;
+	uint32_t offset;
+	unsigned long paddr;
+	unsigned long len;
+	struct file *file;
+	struct msm_stats_buf_info info;
+	struct ion_handle *handle;
+};
+
+struct msm_stats_bufq {
+	struct list_head head;
+	int num_bufs;
+	int type;
+	struct msm_stats_meta_buf *bufs;
+};
+
+
+struct msm_stats_bufq_ctrl {
+	/* not use spin lock for now. Assume vfe holds spin lock */
+	spinlock_t lock;
+	int init_done;
+	struct msm_stats_bufq *bufq[MSM_STATS_TYPE_MAX];
+};
+
+struct msm_stats_ops {
+	struct msm_stats_bufq_ctrl *stats_ctrl;
+	struct ion_client *client;
+	int (*enqueue_buf) (struct msm_stats_bufq_ctrl *stats_ctrl,
+						struct msm_stats_buf_info *info,
+						struct ion_client *client);
+	int (*qbuf) (struct msm_stats_bufq_ctrl *stats_ctrl,
+				 enum msm_stats_enum_type stats_type,
+				 int buf_idx);
+	int (*dqbuf) (struct msm_stats_bufq_ctrl *stats_ctrl,
+				  enum msm_stats_enum_type stats_type,
+				  struct msm_stats_meta_buf **pp_stats_buf);
+	int (*bufq_flush) (struct msm_stats_bufq_ctrl *stats_ctrl,
+					   enum msm_stats_enum_type stats_type,
+					   struct ion_client *client);
+	int (*buf_unprepare) (struct msm_stats_bufq_ctrl *stats_ctrl,
+		enum msm_stats_enum_type stats_type,
+		int buf_idx,
+		struct ion_client *client);
+	int (*buf_prepare) (struct msm_stats_bufq_ctrl *stats_ctrl,
+						struct msm_stats_buf_info *info,
+						struct ion_client *client);
+	int (*reqbuf) (struct msm_stats_bufq_ctrl *stats_ctrl,
+				   struct msm_stats_reqbuf *reqbuf,
+				   struct ion_client *client);
+	int (*dispatch) (struct msm_stats_bufq_ctrl *stats_ctrl,
+		enum msm_stats_enum_type stats_type,
+		unsigned long phy_addr, int *buf_idx, void **vaddr, int *fd,
+		struct ion_client *client);
+	int (*querybuf) (struct msm_stats_bufq_ctrl *stats_ctrl,
+		struct msm_stats_buf_info *info,
+		struct msm_stats_meta_buf **pp_stats_buf);
+	int (*stats_ctrl_init) (struct msm_stats_bufq_ctrl *stats_ctrl);
+	int (*stats_ctrl_deinit) (struct msm_stats_bufq_ctrl *stats_ctrl);
+};
+
+int msm_stats_buf_ops_init(struct msm_stats_bufq_ctrl *stats_ctrl,
+	struct ion_client *client, struct msm_stats_ops *ops);
+
+#endif /* _MSM_STATS_BUF_H_ */
diff --git a/drivers/media/video/msm/sensors/ov8825_v4l2.c b/drivers/media/video/msm/sensors/ov8825_v4l2.c
index 9f09208..1ae3dfd 100644
--- a/drivers/media/video/msm/sensors/ov8825_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov8825_v4l2.c
@@ -236,6 +236,7 @@
 	{0x3619, 0x00},
 	{0x361a, 0xB0},
 	{0x361b, 0x04},
+	{0x361c, 0x07},
 	{0x3701, 0x44},
 	{0x370b, 0x01},
 	{0x370c, 0x50},
diff --git a/drivers/media/video/msm/wfd/wfd-ioctl.c b/drivers/media/video/msm/wfd/wfd-ioctl.c
index c198815..4c27f19 100644
--- a/drivers/media/video/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/video/msm/wfd/wfd-ioctl.c
@@ -23,6 +23,7 @@
 #include <linux/sched.h>
 #include <linux/kthread.h>
 #include <linux/time.h>
+#include <mach/board.h>
 
 #include <media/v4l2-dev.h>
 #include <media/v4l2-ioctl.h>
@@ -54,6 +55,7 @@
 	struct ion_client *ion_client;
 	bool secure_device;
 	bool in_use;
+	bool mdp_iommu_split_domain;
 };
 
 struct mem_info {
@@ -287,10 +289,28 @@
 		mdp_mregion->cookie = 0;
 		mdp_mregion->ion_handle = enc_mregion->ion_handle;
 
-		rc = ion_map_iommu(wfd_dev->ion_client, mdp_mregion->ion_handle,
-				DISPLAY_DOMAIN, GEN_POOL, SZ_4K,
+		if (wfd_dev->mdp_iommu_split_domain) {
+			if (wfd_dev->secure_device) {
+				rc = ion_phys(wfd_dev->ion_client,
+					mdp_mregion->ion_handle,
+					(unsigned long *)&mdp_mregion->paddr,
+					(size_t *)&mdp_mregion->size);
+			} else {
+				rc = ion_map_iommu(wfd_dev->ion_client,
+					mdp_mregion->ion_handle,
+					DISPLAY_WRITE_DOMAIN, GEN_POOL, SZ_4K,
+					0, (unsigned long *)&mdp_mregion->paddr,
+					(unsigned long *)&mdp_mregion->size,
+					0, 0);
+			}
+		} else {
+			rc = ion_map_iommu(wfd_dev->ion_client,
+				mdp_mregion->ion_handle,
+				DISPLAY_READ_DOMAIN, GEN_POOL, SZ_4K,
 				0, (unsigned long *)&mdp_mregion->paddr,
 				(unsigned long *)&mdp_mregion->size, 0, 0);
+		}
+
 		if (rc) {
 			WFD_MSG_ERR("Failed to map to mdp\n");
 			mdp_mregion->kvaddr = NULL;
@@ -360,10 +380,20 @@
 				WFD_MSG_ERR("Failed to free buffers "
 						"from encoder\n");
 
-			if (mpair->mdp->paddr)
-				ion_unmap_iommu(wfd_dev->ion_client,
+			if (mpair->mdp->paddr) {
+				if (wfd_dev->mdp_iommu_split_domain) {
+					if (!wfd_dev->secure_device)
+						ion_unmap_iommu(wfd_dev->
+							ion_client,
+							mpair->mdp->ion_handle,
+							DISPLAY_WRITE_DOMAIN,
+							GEN_POOL);
+				} else {
+					ion_unmap_iommu(wfd_dev->ion_client,
 						mpair->mdp->ion_handle,
-						DISPLAY_DOMAIN, GEN_POOL);
+						DISPLAY_READ_DOMAIN, GEN_POOL);
+				}
+			}
 
 			if (mpair->enc->paddr)
 				ion_unmap_iommu(wfd_dev->ion_client,
@@ -1467,6 +1497,7 @@
 	int rc = 0, c = 0;
 	struct wfd_device *wfd_dev; /* Should be taken as an array*/
 	struct ion_client *ion_client = NULL;
+	struct msm_wfd_platform_data *wfd_priv;
 
 	WFD_MSG_DBG("__wfd_probe: E\n");
 	wfd_dev = kzalloc(sizeof(*wfd_dev)*WFD_NUM_DEVICES, GFP_KERNEL);
@@ -1476,6 +1507,13 @@
 		rc = -ENOMEM;
 		goto err_v4l2_probe;
 	}
+
+	wfd_priv = pdev->dev.platform_data;
+	if (wfd_priv && wfd_priv->wfd_check_mdp_iommu_split) {
+		wfd_dev->mdp_iommu_split_domain =
+			wfd_priv->wfd_check_mdp_iommu_split();
+	}
+
 	pdev->dev.platform_data = (void *) wfd_dev;
 
 	ion_client = msm_ion_client_create(-1, "wfd");
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index 0c26027..09c7215 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -202,6 +202,14 @@
 		.type = OUTPUT_PORT,
 	},
 	{
+		.name = "VC1",
+		.description = "VC-1 compressed format",
+		.fourcc = V4L2_PIX_FMT_VC1_ANNEX_G,
+		.num_planes = 1,
+		.get_frame_size = get_frame_size_compressed,
+		.type = OUTPUT_PORT,
+	},
+	{
 		.name = "H264",
 		.description = "H264 compressed format",
 		.fourcc = V4L2_PIX_FMT_H264,
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index 63f23eb..e835aaa 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -23,7 +23,7 @@
 #define MIN_NUM_OUTPUT_BUFFERS 2
 #define MAX_NUM_OUTPUT_BUFFERS 8
 #define MIN_BIT_RATE 64
-#define MAX_BIT_RATE 8000
+#define MAX_BIT_RATE 20000
 #define DEFAULT_BIT_RATE 64
 #define BIT_RATE_STEP 1
 #define MIN_FRAME_RATE 1
@@ -37,6 +37,7 @@
 #define B_FRAME_QP 30
 #define MAX_INTRA_REFRESH_MBS 300
 #define L_MODE V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY
+#define CODING V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY
 
 static const char *const mpeg_video_rate_control[] = {
 	"No Rate Control",
@@ -79,7 +80,7 @@
 		.type = V4L2_CTRL_TYPE_INTEGER,
 		.minimum = 0,
 		.maximum = 10*MAX_FRAME_RATE,
-		.default_value = 0,
+		.default_value = DEFAULT_FRAME_RATE,
 		.step = 1,
 		.menu_skip_mask = 0,
 		.qmenu = NULL,
@@ -174,6 +175,26 @@
 		.qmenu = h264_video_entropy_cabac_model,
 	},
 	{
+		.id = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
+		.name = "MPEG4 Profile",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
+		.maximum = CODING,
+		.default_value = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
+		.step = 1,
+		.menu_skip_mask = 0,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
+		.name = "MPEG4 Level",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
+		.maximum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_5,
+		.default_value = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
+		.step = 1,
+		.menu_skip_mask = 0,
+	},
+	{
 		.id = V4L2_CID_MPEG_VIDEO_H264_PROFILE,
 		.name = "H264 Profile",
 		.type = V4L2_CTRL_TYPE_MENU,
@@ -385,14 +406,17 @@
 static struct hal_intra_period
 	venc_intra_period = {2*DEFAULT_FRAME_RATE-1 , 0};
 static struct hal_profile_level
-	venc_profile_level = {V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
-				V4L2_MPEG_VIDEO_H264_LEVEL_1_0};
+	venc_h264_profile_level = {HAL_H264_PROFILE_BASELINE,
+		HAL_H264_LEVEL_1};
+static struct hal_profile_level
+	venc_mpeg4_profile_level = {HAL_H264_PROFILE_BASELINE,
+		HAL_H264_LEVEL_1};
 static struct hal_h264_entropy_control
-	venc_h264_entropy_control = {V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
-				V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_0};
+	venc_h264_entropy_control = {HAL_H264_ENTROPY_CAVLC,
+		HAL_H264_CABAC_MODEL_0};
 static struct hal_multi_slice_control
-	venc_multi_slice_control = {V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE ,
-				0};
+	venc_multi_slice_control = {HAL_MULTI_SLICE_OFF ,
+		0};
 
 static const struct msm_vidc_format venc_formats[] = {
 	{
@@ -717,6 +741,57 @@
 			venc_h264_entropy_control.entropy_mode;
 		pdata = &h264_entropy_control;
 		break;
+	case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
+		property_id =
+			HAL_PARAM_PROFILE_LEVEL_CURRENT;
+		switch (control.value) {
+		case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE:
+			control.value = HAL_MPEG4_PROFILE_SIMPLE;
+			break;
+		case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE:
+			control.value = HAL_MPEG4_PROFILE_ADVANCEDSIMPLE;
+			break;
+		default:
+			break;
+			}
+		profile_level.profile = control.value;
+		venc_mpeg4_profile_level.profile = control.value;
+		profile_level.level = venc_mpeg4_profile_level.level;
+		pdata = &profile_level;
+		break;
+	case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
+		property_id =
+			HAL_PARAM_PROFILE_LEVEL_CURRENT;
+		switch (control.value) {
+		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0:
+			control.value = HAL_MPEG4_LEVEL_0;
+			break;
+		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B:
+			control.value = HAL_MPEG4_LEVEL_0b;
+			break;
+		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_1:
+			control.value = HAL_MPEG4_LEVEL_1;
+			break;
+		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_2:
+			control.value = HAL_MPEG4_LEVEL_2;
+			break;
+		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_3:
+			control.value = HAL_MPEG4_LEVEL_3;
+			break;
+		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_4:
+			control.value = HAL_MPEG4_LEVEL_4;
+			break;
+		case V4L2_MPEG_VIDEO_MPEG4_LEVEL_5:
+			control.value = HAL_MPEG4_LEVEL_5;
+			break;
+		default:
+			break;
+		}
+		profile_level.level = control.value;
+		venc_mpeg4_profile_level.level = control.value;
+		profile_level.profile = venc_mpeg4_profile_level.profile;
+		pdata = &profile_level;
+		break;
 	case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
 		property_id =
 			HAL_PARAM_PROFILE_LEVEL_CURRENT;
@@ -747,8 +822,8 @@
 			break;
 			}
 		profile_level.profile = control.value;
-		venc_profile_level.profile = control.value;
-		profile_level.level = venc_profile_level.level;
+		venc_h264_profile_level.profile = control.value;
+		profile_level.level = venc_h264_profile_level.level;
 		pdata = &profile_level;
 		pr_debug("\nprofile: %d\n",
 			   profile_level.profile);
@@ -810,8 +885,9 @@
 			break;
 		}
 		profile_level.level = control.value;
-		venc_profile_level.level = control.value;
-		profile_level.profile = venc_profile_level.profile;
+		venc_h264_profile_level.level = control.value;
+		profile_level.profile = venc_h264_profile_level.profile;
+		pdata = &profile_level;
 		pdata = &profile_level;
 		pr_debug("\nLevel: %d\n",
 			   profile_level.level);
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index ba5fdc4..a5cff9c 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -25,6 +25,11 @@
 	__rc; \
 })
 
+#define V4L2_EVENT_SEQ_CHANGED_SUFFICIENT \
+		V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_SUFFICIENT
+#define V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT \
+		V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_INSUFFICIENT
+
 struct msm_vidc_core *get_vidc_core(int core_id)
 {
 	struct msm_vidc_core *core;
@@ -199,9 +204,20 @@
 	struct msm_vidc_cb_event *event_notify;
 	if (response) {
 		inst = (struct msm_vidc_inst *)response->session_id;
-		dqevent.type = V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED;
 		dqevent.id = 0;
 		event_notify = (struct msm_vidc_cb_event *) response->data;
+		switch (event_notify->hal_event_type) {
+		case HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES:
+			dqevent.type =
+				V4L2_EVENT_SEQ_CHANGED_SUFFICIENT;
+			break;
+		case HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES:
+			dqevent.type =
+				V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
+			break;
+		default:
+			break;
+		}
 		inst->reconfig_height = event_notify->height;
 		inst->reconfig_width = event_notify->width;
 		inst->in_reconfig = true;
diff --git a/drivers/media/video/msm_vidc/vidc_hal_api.h b/drivers/media/video/msm_vidc/vidc_hal_api.h
index b3ea92a..332bbac 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_api.h
+++ b/drivers/media/video/msm_vidc/vidc_hal_api.h
@@ -793,6 +793,12 @@
 	HAL_UNUSED_FLUSH = 0x10000000,
 };
 
+enum hal_event_type {
+	HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES,
+	HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES,
+	HAL_UNUSED_SEQCHG = 0x10000000,
+};
+
 /* HAL Response */
 
 enum command_response {
@@ -843,6 +849,7 @@
 	u32 status;
 	u32 height;
 	u32 width;
+	u32 hal_event_type;
 };
 
 /* Data callback structure */
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index b08fc7d..0c3d4ad 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -50,4 +50,14 @@
 	help
 	  No-Data-Path BAM is used to improve BAM performance.
 
+config QPNP_PWM
+	depends on SPMI
+	depends on OF_SPMI
+        tristate "Qualcomm QPNP LPG/PWM support"
+        help
+          This driver supports PWM/LPG devices in Qualcomm PMIC chips which
+          comply with QPNP.  QPNP is a SPMI based PMIC implementation.  These
+          devices support Pulse Width Modulation output with user generated
+          patterns. They share a lookup table with size of 64 entries.
+
 endmenu
diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile
index 92eb492..6deb6ee 100644
--- a/drivers/platform/msm/Makefile
+++ b/drivers/platform/msm/Makefile
@@ -4,3 +4,4 @@
 obj-$(CONFIG_MSM_SSBI) += ssbi.o
 obj-$(CONFIG_USB_BAM) += usb_bam.o
 obj-$(CONFIG_SPS) += sps/
+obj-$(CONFIG_QPNP_PWM) += qpnp-pwm.o
diff --git a/drivers/platform/msm/qpnp-pwm.c b/drivers/platform/msm/qpnp-pwm.c
new file mode 100644
index 0000000..c9cd0e0
--- /dev/null
+++ b/drivers/platform/msm/qpnp-pwm.c
@@ -0,0 +1,1661 @@
+/* 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.
+ */
+/*
+ * Qualcomm QPNP Pulse Width Modulation (PWM) driver
+ *
+ * The HW module is also called LPG (Light Pattern Generator).
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/spmi.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/radix-tree.h>
+#include <linux/qpnp/pwm.h>
+
+#define QPNP_LPG_DRIVER_NAME	"qcom,qpnp-pwm"
+
+/* LPG Control for LPG_PATTERN_CONFIG */
+#define QPNP_RAMP_DIRECTION_SHIFT	4
+#define QPNP_RAMP_DIRECTION_MASK	0x10
+#define QPNP_PATTERN_REPEAT_SHIFT	3
+#define QPNP_PATTERN_REPEAT_MASK	0x08
+#define QPNP_RAMP_TOGGLE_SHIFT		2
+#define QPNP_RAMP_TOGGLE_MASK		0x04
+#define QPNP_EN_PAUSE_HI_SHIFT		1
+#define QPNP_EN_PAUSE_HI_MASK		0x02
+#define QPNP_EN_PAUSE_LO_MASK		0x01
+
+/* LPG Control for LPG_PWM_SIZE_CLK */
+#define QPNP_PWM_SIZE_SHIFT			4
+#define QPNP_PWM_SIZE_MASK			0x30
+#define QPNP_PWM_FREQ_CLK_SELECT_SHIFT		0
+#define QPNP_PWM_FREQ_CLK_SELECT_MASK		0x03
+#define QPNP_PWM_SIZE_9_BIT			0x03
+
+#define QPNP_SET_PWM_CLK(val, clk, pwm_size) \
+do { \
+	val = (clk + 1) & QPNP_PWM_FREQ_CLK_SELECT_MASK; \
+	val |= ((pwm_size > 6 ? QPNP_PWM_SIZE_9_BIT : 0) << \
+			QPNP_PWM_SIZE_SHIFT) & QPNP_PWM_SIZE_MASK; \
+} while (0)
+
+#define QPNP_GET_PWM_SIZE(reg) ((reg & QPNP_PWM_SIZE_MASK) \
+					>> QPNP_PWM_SIZE_SHIFT)
+
+/* LPG Control for LPG_PWM_FREQ_PREDIV_CLK */
+#define QPNP_PWM_FREQ_PRE_DIVIDE_SHIFT		5
+#define QPNP_PWM_FREQ_PRE_DIVIDE_MASK		0x60
+#define QPNP_PWM_FREQ_EXP_MASK			0x07
+
+#define QPNP_SET_PWM_FREQ_PREDIV(val, pre_div, pre_div_exp) \
+do { \
+	val = (pre_div << QPNP_PWM_FREQ_PRE_DIVIDE_SHIFT) & \
+				QPNP_PWM_FREQ_PRE_DIVIDE_MASK;	\
+	val |= pre_div_exp & QPNP_PWM_FREQ_EXP_MASK;	\
+} while (0)
+
+/* LPG Control for LPG_PWM_TYPE_CONFIG */
+#define QPNP_EN_GLITCH_REMOVAL_SHIFT		5
+#define QPNP_EN_GLITCH_REMOVAL_MASK		0x20
+#define QPNP_EN_FULL_SCALE_SHIFT		3
+#define QPNP_EN_FULL_SCALE_MASK			0x08
+#define QPNP_EN_PHASE_STAGGER_SHIFT		2
+#define QPNP_EN_PHASE_STAGGER_MASK		0x04
+#define QPNP_PHASE_STAGGER_MASK			0x03
+
+/* LPG Control for PWM_VALUE_LSB */
+#define QPNP_PWM_VALUE_LSB_MASK			0xFF
+
+/* LPG Control for PWM_VALUE_MSB */
+#define QPNP_PWM_VALUE_MSB_SHIFT		8
+#define QPNP_PWM_VALUE_MSB_MASK			0x01
+
+/* LPG Control for ENABLE_CONTROL */
+#define QPNP_EN_PWM_HIGH_SHIFT			7
+#define QPNP_EN_PWM_HIGH_MASK			0x80
+#define QPNP_EN_PWM_LO_SHIFT			6
+#define QPNP_EN_PWM_LO_MASK			0x40
+#define QPNP_EN_PWM_OUTPUT_SHIFT		5
+#define QPNP_EN_PWM_OUTPUT_MASK			0x20
+#define QPNP_PWM_SRC_SELECT_SHIFT		2
+#define QPNP_PWM_SRC_SELECT_MASK		0x04
+#define QPNP_PWM_EN_RAMP_GEN_SHIFT		1
+#define QPNP_PWM_EN_RAMP_GEN_MASK		0x02
+
+#define QPNP_ENABLE_PWM(value) \
+	(value |= (1 << QPNP_EN_PWM_OUTPUT_SHIFT) & QPNP_EN_PWM_OUTPUT_MASK)
+
+#define QPNP_DISABLE_PWM(value)  (value &= ~QPNP_EN_PWM_OUTPUT_MASK)
+
+/* LPG Control for RAMP_CONTROL */
+#define QPNP_RAMP_START_MASK			0x01
+
+#define QPNP_ENABLE_LUT(value) (value |= QPNP_RAMP_START_MASK)
+#define QPNP_DISABLE_LUT(value) (value &= ~QPNP_RAMP_START_MASK)
+
+/* LPG Control for RAMP_STEP_DURATION_LSB */
+#define QPNP_RAMP_STEP_DURATION_LSB_MASK	0xFF
+
+/* LPG Control for RAMP_STEP_DURATION_MSB */
+#define QPNP_RAMP_STEP_DURATION_MSB_SHIFT	8
+#define QPNP_RAMP_STEP_DURATION_MSB_MASK	0x01
+
+#define QPNP_PWM_1KHZ				1024
+#define QPNP_GET_RAMP_STEP_DURATION(ramp_time_ms) \
+		((ramp_time_ms * QPNP_PWM_1KHZ) / 1000)
+
+/* LPG Control for PAUSE_HI_MULTIPLIER_LSB */
+#define QPNP_PAUSE_HI_MULTIPLIER_LSB_MASK	0xFF
+
+/* LPG Control for PAUSE_HI_MULTIPLIER_MSB */
+#define QPNP_PAUSE_HI_MULTIPLIER_MSB_SHIFT	8
+#define QPNP_PAUSE_HI_MULTIPLIER_MSB_MASK	0x1F
+
+/* LPG Control for PAUSE_LO_MULTIPLIER_LSB */
+#define QPNP_PAUSE_LO_MULTIPLIER_LSB_MASK	0xFF
+
+/* LPG Control for PAUSE_LO_MULTIPLIER_MSB */
+#define QPNP_PAUSE_LO_MULTIPLIER_MSB_SHIFT	8
+#define QPNP_PAUSE_LO_MULTIPLIER_MSB_MASK	0x1F
+
+/* LPG Control for HI_INDEX */
+#define QPNP_HI_INDEX_MASK			0x3F
+
+/* LPG Control for LO_INDEX */
+#define QPNP_LO_INDEX_MASK			0x3F
+
+#define NUM_CLOCKS				3
+#define QPNP_PWM_M_MAX				7
+#define NSEC_1024HZ	(NSEC_PER_SEC / 1024)
+#define NSEC_32768HZ	(NSEC_PER_SEC / 32768)
+#define NSEC_19P2MHZ	(NSEC_PER_SEC / 19200000)
+
+#define NUM_LPG_PRE_DIVIDE	4
+
+#define PRE_DIVIDE_1		1
+#define PRE_DIVIDE_3		3
+#define PRE_DIVIDE_5		5
+#define PRE_DIVIDE_6		6
+
+#define SPMI_LPG_REG_ADDR_BASE	0x40
+#define SPMI_LPG_REG_ADDR(b, n)	(b + SPMI_LPG_REG_ADDR_BASE + (n))
+#define SPMI_MAX_BUF_LEN	8
+
+/* SPMI LPG registers */
+enum qpnp_lpg_registers_list {
+	QPNP_LPG_PATTERN_CONFIG,
+	QPNP_LPG_PWM_SIZE_CLK,
+	QPNP_LPG_PWM_FREQ_PREDIV_CLK,
+	QPNP_LPG_PWM_TYPE_CONFIG,
+	QPNP_PWM_VALUE_LSB,
+	QPNP_PWM_VALUE_MSB,
+	QPNP_ENABLE_CONTROL,
+	QPNP_RAMP_CONTROL,
+	QPNP_RAMP_STEP_DURATION_LSB = QPNP_RAMP_CONTROL + 9,
+	QPNP_RAMP_STEP_DURATION_MSB,
+	QPNP_PAUSE_HI_MULTIPLIER_LSB,
+	QPNP_PAUSE_HI_MULTIPLIER_MSB,
+	QPNP_PAUSE_LO_MULTIPLIER_LSB,
+	QPNP_PAUSE_LO_MULTIPLIER_MSB,
+	QPNP_HI_INDEX,
+	QPNP_LO_INDEX,
+	QPNP_TOTAL_LPG_SPMI_REGISTERS
+};
+
+/*
+ * Formula from HSID,
+ * pause_time (hi/lo) = (pause_cnt- 1)*(ramp_ms)
+ * OR,
+ * pause_cnt = (pause_time / ramp_ms) + 1
+ */
+#define QPNP_SET_PAUSE_CNT(to_pause_cnt, from_pause, ramp_ms) \
+	(to_pause_cnt = (from_pause / (ramp_ms ? ramp_ms : 1)) + 1)
+
+
+static unsigned int pt_t[NUM_LPG_PRE_DIVIDE][NUM_CLOCKS] = {
+	{	PRE_DIVIDE_1 * NSEC_1024HZ,
+		PRE_DIVIDE_1 * NSEC_32768HZ,
+		PRE_DIVIDE_1 * NSEC_19P2MHZ,
+	},
+	{	PRE_DIVIDE_3 * NSEC_1024HZ,
+		PRE_DIVIDE_3 * NSEC_32768HZ,
+		PRE_DIVIDE_3 * NSEC_19P2MHZ,
+	},
+	{	PRE_DIVIDE_5 * NSEC_1024HZ,
+		PRE_DIVIDE_5 * NSEC_32768HZ,
+		PRE_DIVIDE_5 * NSEC_19P2MHZ,
+	},
+	{	PRE_DIVIDE_6 * NSEC_1024HZ,
+		PRE_DIVIDE_6 * NSEC_32768HZ,
+		PRE_DIVIDE_6 * NSEC_19P2MHZ,
+	},
+};
+
+static RADIX_TREE(lpg_dev_tree, GFP_KERNEL);
+
+struct qpnp_lut_default_config {
+	u32		*duty_pct_list;
+	int		size;
+	int		start_idx;
+};
+
+struct qpnp_lut_config {
+	struct qpnp_lut_default_config def_config;
+	u8		*duty_pct_list;
+	int		list_size;
+	int		lo_index;
+	int		hi_index;
+	int		lut_pause_hi_cnt;
+	int		lut_pause_lo_cnt;
+	int		ramp_step_ms;
+	bool		ramp_direction;
+	bool		pattern_repeat;
+	bool		ramp_toggle;
+	bool		enable_pause_hi;
+	bool		enable_pause_lo;
+};
+
+struct qpnp_lpg_config {
+	struct qpnp_lut_config	lut_config;
+	u16			base_addr;
+	u16			lut_base_addr;
+	u16			lut_size;
+	bool			bypass_lut;
+	bool			lpg_configured;
+};
+
+struct qpnp_pwm_config {
+	int				channel_id;
+	bool				in_use;
+	const char			*lable;
+	int				pwm_value;
+	int				pwm_period;
+	int				pwm_duty;
+	struct pwm_period_config	period;
+};
+
+/* Public facing structure */
+struct pwm_device {
+	struct qpnp_lpg_chip	*chip;
+	struct qpnp_pwm_config	pwm_config;
+};
+
+struct qpnp_lpg_chip {
+	struct	spmi_device	*spmi_dev;
+	struct	pwm_device	pwm_dev;
+	struct	mutex		lpg_mutex;
+	struct	qpnp_lpg_config	lpg_config;
+	u8	qpnp_lpg_registers[QPNP_TOTAL_LPG_SPMI_REGISTERS];
+};
+
+/* Internal functions */
+static inline void qpnp_set_pattern_config(u8 *val,
+			struct qpnp_lut_config *lut_config)
+{
+	*val = lut_config->enable_pause_lo & QPNP_EN_PAUSE_LO_MASK;
+	*val |= (lut_config->enable_pause_hi << QPNP_EN_PAUSE_HI_SHIFT) &
+						QPNP_EN_PAUSE_HI_MASK;
+	*val |= (lut_config->ramp_toggle << QPNP_RAMP_TOGGLE_SHIFT) &
+						QPNP_RAMP_TOGGLE_MASK;
+	*val |= (lut_config->pattern_repeat << QPNP_PATTERN_REPEAT_SHIFT) &
+						QPNP_PATTERN_REPEAT_MASK;
+	*val |= (lut_config->ramp_direction << QPNP_RAMP_DIRECTION_SHIFT) &
+						QPNP_RAMP_DIRECTION_MASK;
+}
+
+static inline void qpnp_set_pwm_type_config(u8 *val, bool glitch,
+			bool full_scale, bool en_phase, bool phase)
+{
+	*val = phase;
+	*val |= (en_phase << QPNP_EN_PHASE_STAGGER_SHIFT) &
+				QPNP_EN_PHASE_STAGGER_MASK;
+	*val |= (full_scale << QPNP_EN_FULL_SCALE_SHIFT) &
+				QPNP_EN_FULL_SCALE_MASK;
+	*val |= (glitch << QPNP_EN_GLITCH_REMOVAL_SHIFT) &
+				QPNP_EN_GLITCH_REMOVAL_MASK;
+}
+
+static inline void qpnp_set_control(u8 *val, bool pwm_hi, bool pwm_lo,
+			bool pwm_out, bool pwm_src, bool ramp_gen)
+{
+	*val = (ramp_gen << QPNP_PWM_EN_RAMP_GEN_SHIFT) &
+				QPNP_PWM_EN_RAMP_GEN_MASK;
+	*val |= (pwm_src << QPNP_PWM_SRC_SELECT_SHIFT) &
+				QPNP_PWM_SRC_SELECT_MASK;
+	*val |= (pwm_out << QPNP_EN_PWM_OUTPUT_SHIFT) &
+				QPNP_EN_PWM_OUTPUT_MASK;
+	*val |= (pwm_lo << QPNP_EN_PWM_LO_SHIFT) & QPNP_EN_PWM_LO_MASK;
+	*val |= (pwm_hi << QPNP_EN_PWM_HIGH_SHIFT) & QPNP_EN_PWM_HIGH_MASK;
+}
+
+#define QPNP_ENABLE_LUT_CONTROL(p_val)	qpnp_set_control(p_val, 1, 1, 1, 0, 1)
+#define QPNP_ENABLE_PWM_CONTROL(p_val)	qpnp_set_control(p_val, 1, 1, 0, 1, 0)
+
+static inline void qpnp_convert_to_lut_flags(int *flags,
+				struct qpnp_lut_config *l_config)
+{
+	*flags = ((l_config->ramp_direction ? PM_PWM_LUT_RAMP_UP : 0) |
+		(l_config->pattern_repeat ? PM_PWM_LUT_LOOP : 0)|
+		(l_config->ramp_toggle ? PM_PWM_LUT_REVERSE : 0) |
+		(l_config->enable_pause_hi ? PM_PWM_LUT_PAUSE_HI_EN : 0) |
+		(l_config->enable_pause_lo ? PM_PWM_LUT_PAUSE_LO_EN : 0));
+}
+
+static inline void qpnp_set_lut_params(struct lut_params *l_params,
+				struct qpnp_lut_config *l_config)
+{
+	l_params->start_idx = l_config->def_config.start_idx;
+	l_params->idx_len = l_config->def_config.size;
+	l_params->lut_pause_hi = l_config->lut_pause_hi_cnt;
+	l_params->lut_pause_lo = l_config->lut_pause_lo_cnt;
+	l_params->ramp_step_ms = l_config->ramp_step_ms;
+	qpnp_convert_to_lut_flags(&l_params->flags, l_config);
+}
+
+static void qpnp_lpg_save(u8 *u8p, u8 mask, u8 val)
+{
+	*u8p &= ~mask;
+	*u8p |= val & mask;
+}
+
+static int qpnp_lpg_save_and_write(u8 value, u8 mask, u8 *reg, u16 base_addr,
+			u16 offset, u16 size, struct qpnp_lpg_chip *chip)
+{
+	qpnp_lpg_save(reg, mask, value);
+
+	return spmi_ext_register_writel(chip->spmi_dev->ctrl,
+	chip->spmi_dev->sid, SPMI_LPG_REG_ADDR(base_addr, offset), reg, size);
+}
+
+/*
+ * PWM Frequency = Clock Frequency / (N * T)
+ *	or
+ * PWM Period = Clock Period * (N * T)
+ *	where
+ * N = 2^9 or 2^6 for 9-bit or 6-bit PWM size
+ * T = Pre-divide * 2^m, where m = 0..7 (exponent)
+ *
+ * This is the formula to figure out m for the best pre-divide and clock:
+ * (PWM Period / N) = (Pre-divide * Clock Period) * 2^m
+ */
+static void qpnp_lpg_calc_period(unsigned int period_us,
+				   struct pwm_period_config *period)
+{
+	int		n, m, clk, div;
+	int		best_m, best_div, best_clk;
+	unsigned int	last_err, cur_err, min_err;
+	unsigned int	tmp_p, period_n;
+
+	/* PWM Period / N */
+	if (period_us < ((unsigned)(-1) / NSEC_PER_USEC)) {
+		period_n = (period_us * NSEC_PER_USEC) >> 6;
+		n = 6;
+	} else {
+		period_n = (period_us >> 9) * NSEC_PER_USEC;
+		n = 9;
+	}
+
+	min_err = last_err = (unsigned)(-1);
+	best_m = 0;
+	best_clk = 0;
+	best_div = 0;
+	for (clk = 0; clk < NUM_CLOCKS; clk++) {
+		for (div = 0; div < NUM_LPG_PRE_DIVIDE; div++) {
+			/* period_n = (PWM Period / N) */
+			/* tmp_p = (Pre-divide * Clock Period) * 2^m */
+			tmp_p = pt_t[div][clk];
+			for (m = 0; m <= QPNP_PWM_M_MAX; m++) {
+				if (period_n > tmp_p)
+					cur_err = period_n - tmp_p;
+				else
+					cur_err = tmp_p - period_n;
+
+				if (cur_err < min_err) {
+					min_err = cur_err;
+					best_m = m;
+					best_clk = clk;
+					best_div = div;
+				}
+
+				if (m && cur_err > last_err)
+					/* Break for bigger cur_err */
+					break;
+
+				last_err = cur_err;
+				tmp_p <<= 1;
+			}
+		}
+	}
+
+	/* Use higher resolution */
+	if (best_m >= 3 && n == 6) {
+		n += 3;
+		best_m -= 3;
+	}
+
+	period->pwm_size = n;
+	period->clk = best_clk;
+	period->pre_div = best_div;
+	period->pre_div_exp = best_m;
+}
+
+static void qpnp_lpg_calc_pwm_value(struct pwm_device *pwm,
+				      unsigned int period_us,
+				      unsigned int duty_us)
+{
+	unsigned int		max_pwm_value, tmp;
+	struct qpnp_pwm_config	*pwm_config = &pwm->pwm_config;
+
+	/* Figure out pwm_value with overflow handling */
+	tmp = 1 << (sizeof(tmp) * 8 - pwm_config->period.pwm_size);
+	if (duty_us < tmp) {
+		tmp = duty_us << pwm_config->period.pwm_size;
+		pwm_config->pwm_value = tmp / period_us;
+	} else {
+		tmp = period_us >> pwm_config->period.pwm_size;
+		pwm_config->pwm_value = duty_us / tmp;
+	}
+	max_pwm_value = (1 << pwm_config->period.pwm_size) - 1;
+	if (pwm_config->pwm_value > max_pwm_value)
+		pwm_config->pwm_value = max_pwm_value;
+}
+
+static int qpnp_lpg_change_table(struct pwm_device *pwm,
+					int duty_pct[], int raw_value)
+{
+	unsigned int		pwm_value, max_pwm_value;
+	struct qpnp_lpg_chip	*chip = pwm->chip;
+	struct qpnp_lut_config	*lut = &chip->lpg_config.lut_config;
+	int			i, pwm_size, rc;
+	int			burst_size = SPMI_MAX_BUF_LEN;
+	int			list_len = lut->list_size << 1;
+	int			offset = lut->lo_index << 2;
+
+	pwm_size = QPNP_GET_PWM_SIZE(
+			chip->qpnp_lpg_registers[QPNP_LPG_PWM_SIZE_CLK]) &
+						QPNP_PWM_SIZE_9_BIT ? 9 : 6;
+
+	max_pwm_value = (1 << pwm_size) - 1;
+
+	if (unlikely(lut->list_size != (lut->hi_index - lut->lo_index + 1))) {
+		pr_err("LUT internal Data structure corruption detected\n");
+		pr_err("LUT list size: %d\n", lut->list_size);
+		pr_err("However, index size is: %d\n",
+				(lut->hi_index - lut->lo_index + 1));
+		return -EINVAL;
+	}
+
+	for (i = 0; i <= lut->list_size; i++) {
+		if (raw_value)
+			pwm_value = duty_pct[i];
+		else
+			pwm_value = (duty_pct[i] << pwm_size) / 100;
+
+		if (pwm_value > max_pwm_value)
+			pwm_value = max_pwm_value;
+
+		lut->duty_pct_list[i*2] = pwm_value;
+		lut->duty_pct_list[(i*2)+1] = (pwm_value >>
+			 QPNP_PWM_VALUE_MSB_SHIFT) & QPNP_PWM_VALUE_MSB_MASK;
+	}
+
+	/* Write with max allowable burst mode, each entry is of two bytes */
+	for (i = 0; i < list_len;) {
+		if (i + burst_size >= list_len)
+			burst_size = list_len - i;
+		rc = spmi_ext_register_writel(chip->spmi_dev->ctrl,
+			chip->spmi_dev->sid,
+			chip->lpg_config.lut_base_addr + offset + i,
+			lut->duty_pct_list + i, burst_size);
+		i += burst_size;
+	}
+
+	return rc;
+}
+
+static void qpnp_lpg_save_period(struct pwm_device *pwm)
+{
+	u8 mask, val;
+	struct qpnp_lpg_chip	*chip = pwm->chip;
+	struct qpnp_pwm_config	*pwm_config = &pwm->pwm_config;
+
+	QPNP_SET_PWM_CLK(val, pwm_config->period.clk,
+				pwm_config->period.pwm_size);
+
+	mask = QPNP_PWM_SIZE_MASK | QPNP_PWM_FREQ_CLK_SELECT_MASK;
+
+	qpnp_lpg_save(&chip->qpnp_lpg_registers[QPNP_LPG_PWM_SIZE_CLK],
+							mask, val);
+
+	QPNP_SET_PWM_FREQ_PREDIV(val, pwm_config->period.pre_div,
+					pwm_config->period.pre_div_exp);
+
+	mask = QPNP_PWM_FREQ_PRE_DIVIDE_MASK | QPNP_PWM_FREQ_EXP_MASK;
+
+	qpnp_lpg_save(&chip->qpnp_lpg_registers[QPNP_LPG_PWM_FREQ_PREDIV_CLK],
+								mask, val);
+}
+
+static int qpnp_lpg_save_pwm_value(struct pwm_device *pwm)
+{
+	unsigned int		max_pwm_value;
+	int			pwm_size;
+	u8			mask, value;
+	struct qpnp_lpg_chip	*chip = pwm->chip;
+	struct qpnp_pwm_config	*pwm_config = &pwm->pwm_config;
+	struct qpnp_lpg_config	*lpg_config = &chip->lpg_config;
+	int rc;
+
+	pwm_size = QPNP_GET_PWM_SIZE(
+			chip->qpnp_lpg_registers[QPNP_LPG_PWM_SIZE_CLK]) &
+						QPNP_PWM_SIZE_9_BIT ? 9 : 6;
+
+	max_pwm_value = (1 << pwm_size) - 1;
+
+	if (pwm_config->pwm_value > max_pwm_value)
+		pwm_config->pwm_value = max_pwm_value;
+
+	value = pwm_config->pwm_value;
+	mask = QPNP_PWM_VALUE_LSB_MASK;
+
+	rc = qpnp_lpg_save_and_write(value, mask,
+			&pwm->chip->qpnp_lpg_registers[QPNP_PWM_VALUE_LSB],
+			lpg_config->base_addr, QPNP_PWM_VALUE_LSB, 1, chip);
+	if (rc)
+		return rc;
+
+	value = (pwm_config->pwm_value >> QPNP_PWM_VALUE_MSB_SHIFT) &
+					QPNP_PWM_VALUE_MSB_MASK;
+
+	mask = QPNP_PWM_VALUE_MSB_MASK;
+
+	return qpnp_lpg_save_and_write(value, mask,
+			&pwm->chip->qpnp_lpg_registers[QPNP_PWM_VALUE_MSB],
+			lpg_config->base_addr, QPNP_PWM_VALUE_MSB, 1, chip);
+}
+
+static int qpnp_lpg_configure_pattern(struct pwm_device *pwm)
+{
+	struct qpnp_lpg_config	*lpg_config = &pwm->chip->lpg_config;
+	struct qpnp_lut_config	*lut_config = &lpg_config->lut_config;
+	struct qpnp_lpg_chip	*chip = pwm->chip;
+	u8			value, mask;
+
+	qpnp_set_pattern_config(&value, lut_config);
+
+	mask = QPNP_RAMP_DIRECTION_MASK | QPNP_PATTERN_REPEAT_MASK |
+			QPNP_RAMP_TOGGLE_MASK | QPNP_EN_PAUSE_HI_MASK |
+			QPNP_EN_PAUSE_LO_MASK;
+
+	return qpnp_lpg_save_and_write(value, mask,
+		&pwm->chip->qpnp_lpg_registers[QPNP_LPG_PATTERN_CONFIG],
+		lpg_config->base_addr, QPNP_LPG_PATTERN_CONFIG, 1, chip);
+}
+
+static int qpnp_lpg_configure_pwm(struct pwm_device *pwm)
+{
+	struct qpnp_lpg_config	*lpg_config = &pwm->chip->lpg_config;
+	struct qpnp_lpg_chip	*chip = pwm->chip;
+	int			rc;
+	u8			value, mask;
+
+	rc = spmi_ext_register_writel(chip->spmi_dev->ctrl, chip->spmi_dev->sid,
+		SPMI_LPG_REG_ADDR(lpg_config->base_addr, QPNP_LPG_PWM_SIZE_CLK),
+		&chip->qpnp_lpg_registers[QPNP_LPG_PWM_SIZE_CLK], 1);
+
+	if (rc)
+		return rc;
+
+	rc = spmi_ext_register_writel(chip->spmi_dev->ctrl, chip->spmi_dev->sid,
+		SPMI_LPG_REG_ADDR(lpg_config->base_addr,
+		QPNP_LPG_PWM_FREQ_PREDIV_CLK),
+		&chip->qpnp_lpg_registers[QPNP_LPG_PWM_FREQ_PREDIV_CLK], 1);
+	if (rc)
+		return rc;
+
+	qpnp_set_pwm_type_config(&value, 1, 0, 0, 0);
+
+	mask = QPNP_EN_GLITCH_REMOVAL_MASK | QPNP_EN_FULL_SCALE_MASK |
+			QPNP_EN_PHASE_STAGGER_MASK | QPNP_PHASE_STAGGER_MASK;
+
+	return qpnp_lpg_save_and_write(value, mask,
+		&pwm->chip->qpnp_lpg_registers[QPNP_LPG_PWM_TYPE_CONFIG],
+		lpg_config->base_addr, QPNP_LPG_PWM_TYPE_CONFIG, 1, chip);
+}
+
+static int qpnp_pwm_configure_control(struct pwm_device *pwm)
+{
+	struct qpnp_lpg_config	*lpg_config = &pwm->chip->lpg_config;
+	struct qpnp_lpg_chip	*chip = pwm->chip;
+	u8			value, mask;
+
+	QPNP_ENABLE_PWM_CONTROL(&value);
+
+	mask = QPNP_EN_PWM_HIGH_MASK | QPNP_EN_PWM_LO_MASK |
+		QPNP_EN_PWM_OUTPUT_MASK | QPNP_PWM_SRC_SELECT_MASK |
+					QPNP_PWM_EN_RAMP_GEN_MASK;
+
+	return qpnp_lpg_save_and_write(value, mask,
+		&pwm->chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL],
+		lpg_config->base_addr, QPNP_ENABLE_CONTROL, 1, chip);
+
+}
+
+static int qpnp_lpg_configure_control(struct pwm_device *pwm)
+{
+	struct qpnp_lpg_config	*lpg_config = &pwm->chip->lpg_config;
+	struct qpnp_lpg_chip	*chip = pwm->chip;
+	u8			value, mask;
+
+	QPNP_ENABLE_LUT_CONTROL(&value);
+
+	mask = QPNP_EN_PWM_HIGH_MASK | QPNP_EN_PWM_LO_MASK |
+		QPNP_EN_PWM_OUTPUT_MASK | QPNP_PWM_SRC_SELECT_MASK |
+				QPNP_PWM_EN_RAMP_GEN_MASK;
+
+	return qpnp_lpg_save_and_write(value, mask,
+		&pwm->chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL],
+		lpg_config->base_addr, QPNP_ENABLE_CONTROL, 1, chip);
+
+}
+
+static int qpnp_lpg_configure_ramp_step_duration(struct pwm_device *pwm)
+{
+	struct qpnp_lpg_config	*lpg_config = &pwm->chip->lpg_config;
+	struct qpnp_lut_config	lut_config = lpg_config->lut_config;
+	struct qpnp_lpg_chip	*chip = pwm->chip;
+	int			rc, value;
+	u8			val, mask;
+
+	value = QPNP_GET_RAMP_STEP_DURATION(lut_config.ramp_step_ms);
+	val = value & QPNP_RAMP_STEP_DURATION_LSB_MASK;
+	mask = QPNP_RAMP_STEP_DURATION_LSB_MASK;
+
+	rc = qpnp_lpg_save_and_write(val, mask,
+		&pwm->chip->qpnp_lpg_registers[QPNP_RAMP_STEP_DURATION_LSB],
+		lpg_config->base_addr, QPNP_RAMP_STEP_DURATION_LSB, 1, chip);
+	if (rc)
+		return rc;
+
+	val = (value >> QPNP_RAMP_STEP_DURATION_MSB_SHIFT) &
+				QPNP_RAMP_STEP_DURATION_MSB_MASK;
+
+	mask = QPNP_RAMP_STEP_DURATION_MSB_MASK;
+
+	return qpnp_lpg_save_and_write(val, mask,
+		&pwm->chip->qpnp_lpg_registers[QPNP_RAMP_STEP_DURATION_MSB],
+		lpg_config->base_addr, QPNP_RAMP_STEP_DURATION_MSB, 1, chip);
+}
+
+static int qpnp_lpg_configure_pause(struct pwm_device *pwm)
+{
+	struct qpnp_lpg_config	*lpg_config = &pwm->chip->lpg_config;
+	struct qpnp_lut_config	lut_config = lpg_config->lut_config;
+	struct qpnp_lpg_chip	*chip = pwm->chip;
+	u8			value, mask;
+	int			rc = 0;
+
+	if (lut_config.enable_pause_hi) {
+		value = lut_config.lut_pause_hi_cnt;
+		mask = QPNP_PAUSE_HI_MULTIPLIER_LSB_MASK;
+
+		rc = qpnp_lpg_save_and_write(value, mask,
+		&pwm->chip->qpnp_lpg_registers[QPNP_PAUSE_HI_MULTIPLIER_LSB],
+		lpg_config->base_addr, QPNP_PAUSE_HI_MULTIPLIER_LSB, 1, chip);
+		if (rc)
+			return rc;
+
+		value = (lut_config.lut_pause_hi_cnt >>
+			QPNP_PAUSE_HI_MULTIPLIER_MSB_SHIFT) &
+					QPNP_PAUSE_HI_MULTIPLIER_MSB_MASK;
+
+		mask = QPNP_PAUSE_HI_MULTIPLIER_MSB_MASK;
+
+		rc = qpnp_lpg_save_and_write(value, mask,
+		&pwm->chip->qpnp_lpg_registers[QPNP_PAUSE_HI_MULTIPLIER_MSB],
+		lpg_config->base_addr, QPNP_PAUSE_HI_MULTIPLIER_MSB, 1, chip);
+	} else {
+		value = 0;
+		mask = QPNP_PAUSE_HI_MULTIPLIER_LSB_MASK;
+
+		rc = qpnp_lpg_save_and_write(value, mask,
+		&pwm->chip->qpnp_lpg_registers[QPNP_PAUSE_HI_MULTIPLIER_LSB],
+		lpg_config->base_addr, QPNP_PAUSE_HI_MULTIPLIER_LSB, 1, chip);
+		if (rc)
+			return rc;
+
+		mask = QPNP_PAUSE_HI_MULTIPLIER_MSB_MASK;
+
+		rc = qpnp_lpg_save_and_write(value, mask,
+		&pwm->chip->qpnp_lpg_registers[QPNP_PAUSE_HI_MULTIPLIER_MSB],
+		lpg_config->base_addr, QPNP_PAUSE_HI_MULTIPLIER_MSB, 1, chip);
+		if (rc)
+			return rc;
+
+	}
+
+	if (lut_config.enable_pause_lo) {
+		value = lut_config.lut_pause_lo_cnt;
+		mask = QPNP_PAUSE_LO_MULTIPLIER_LSB_MASK;
+
+		rc = qpnp_lpg_save_and_write(value, mask,
+		&pwm->chip->qpnp_lpg_registers[QPNP_PAUSE_LO_MULTIPLIER_LSB],
+		lpg_config->base_addr, QPNP_PAUSE_LO_MULTIPLIER_LSB, 1, chip);
+		if (rc)
+			return rc;
+
+		value = (lut_config.lut_pause_lo_cnt >>
+				QPNP_PAUSE_LO_MULTIPLIER_MSB_SHIFT) &
+					QPNP_PAUSE_LO_MULTIPLIER_MSB_MASK;
+
+		mask = QPNP_PAUSE_LO_MULTIPLIER_MSB_MASK;
+
+		rc = qpnp_lpg_save_and_write(value, mask,
+		&pwm->chip->qpnp_lpg_registers[QPNP_PAUSE_LO_MULTIPLIER_MSB],
+		lpg_config->base_addr, QPNP_PAUSE_LO_MULTIPLIER_MSB, 1, chip);
+	} else {
+		value = 0;
+		mask = QPNP_PAUSE_LO_MULTIPLIER_LSB_MASK;
+
+		rc = qpnp_lpg_save_and_write(value, mask,
+		&pwm->chip->qpnp_lpg_registers[QPNP_PAUSE_LO_MULTIPLIER_LSB],
+		lpg_config->base_addr, QPNP_PAUSE_LO_MULTIPLIER_LSB, 1, chip);
+		if (rc)
+			return rc;
+
+		mask = QPNP_PAUSE_LO_MULTIPLIER_MSB_MASK;
+
+		rc = qpnp_lpg_save_and_write(value, mask,
+		&pwm->chip->qpnp_lpg_registers[QPNP_PAUSE_LO_MULTIPLIER_MSB],
+		lpg_config->base_addr, QPNP_PAUSE_LO_MULTIPLIER_MSB, 1, chip);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int qpnp_lpg_configure_index(struct pwm_device *pwm)
+{
+	struct qpnp_lpg_config	*lpg_config = &pwm->chip->lpg_config;
+	struct qpnp_lut_config	lut_config = lpg_config->lut_config;
+	struct qpnp_lpg_chip	*chip = pwm->chip;
+	u8			value, mask;
+	int			rc = 0;
+
+	value = lut_config.hi_index;
+	mask = QPNP_HI_INDEX_MASK;
+
+	rc = qpnp_lpg_save_and_write(value, mask,
+		&pwm->chip->qpnp_lpg_registers[QPNP_HI_INDEX],
+		lpg_config->base_addr, QPNP_HI_INDEX, 1, chip);
+	if (rc)
+		return rc;
+
+	value = lut_config.lo_index;
+	mask = QPNP_LO_INDEX_MASK;
+
+	rc = qpnp_lpg_save_and_write(value, mask,
+		&pwm->chip->qpnp_lpg_registers[QPNP_LO_INDEX],
+		lpg_config->base_addr, QPNP_LO_INDEX, 1, chip);
+
+	return rc;
+}
+
+static int qpnp_lpg_change_lut(struct pwm_device *pwm)
+{
+	int	rc;
+
+	rc = qpnp_lpg_configure_pattern(pwm);
+	if (rc) {
+		pr_err("Failed to configure LUT pattern");
+		return rc;
+	}
+	rc = qpnp_lpg_configure_pwm(pwm);
+	if (rc) {
+		pr_err("Failed to configure LUT pattern");
+		return rc;
+	}
+	rc = qpnp_lpg_configure_control(pwm);
+	if (rc) {
+		pr_err("Failed to configure pause registers");
+		return rc;
+	}
+	rc = qpnp_lpg_configure_ramp_step_duration(pwm);
+	if (rc) {
+		pr_err("Failed to configure duty time");
+		return rc;
+	}
+	rc = qpnp_lpg_configure_pause(pwm);
+	if (rc) {
+		pr_err("Failed to configure pause registers");
+		return rc;
+	}
+	rc = qpnp_lpg_configure_index(pwm);
+	if (rc) {
+		pr_err("Failed to configure index registers");
+		return rc;
+	}
+	return rc;
+}
+
+static int qpnp_lpg_enable_lut(struct pwm_device *pwm)
+{
+	struct qpnp_lpg_config	*lpg_config = &pwm->chip->lpg_config;
+	struct qpnp_lpg_chip	*chip = pwm->chip;
+	u8			value, mask;
+
+	value = pwm->chip->qpnp_lpg_registers[QPNP_RAMP_CONTROL];
+
+	QPNP_ENABLE_LUT(value);
+
+	mask = QPNP_RAMP_START_MASK;
+
+	return qpnp_lpg_save_and_write(value, mask,
+		&pwm->chip->qpnp_lpg_registers[QPNP_RAMP_CONTROL],
+		lpg_config->base_addr, QPNP_RAMP_CONTROL, 1, chip);
+}
+
+static int qpnp_lpg_disable_lut(struct pwm_device *pwm)
+{
+	struct qpnp_lpg_config	*lpg_config = &pwm->chip->lpg_config;
+	struct qpnp_lpg_chip	*chip = pwm->chip;
+	u8			value, mask;
+
+	value = pwm->chip->qpnp_lpg_registers[QPNP_RAMP_CONTROL];
+
+	QPNP_DISABLE_LUT(value);
+
+	mask = QPNP_RAMP_START_MASK;
+
+	return qpnp_lpg_save_and_write(value, mask,
+		&pwm->chip->qpnp_lpg_registers[QPNP_RAMP_CONTROL],
+		lpg_config->base_addr, QPNP_RAMP_CONTROL, 1, chip);
+}
+
+static int qpnp_lpg_enable_pwm(struct pwm_device *pwm)
+{
+	struct qpnp_lpg_config	*lpg_config = &pwm->chip->lpg_config;
+	struct qpnp_lpg_chip	*chip = pwm->chip;
+	u8			value, mask;
+
+	value = pwm->chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL];
+
+	QPNP_ENABLE_PWM(value);
+
+	mask = QPNP_EN_PWM_OUTPUT_MASK;
+
+	return qpnp_lpg_save_and_write(value, mask,
+		&pwm->chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL],
+		lpg_config->base_addr, QPNP_RAMP_CONTROL, 1, chip);
+}
+
+static int qpnp_lpg_disable_pwm(struct pwm_device *pwm)
+{
+	struct qpnp_lpg_config	*lpg_config = &pwm->chip->lpg_config;
+	struct qpnp_lpg_chip	*chip = pwm->chip;
+	u8			value, mask;
+
+	value = pwm->chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL];
+
+	QPNP_DISABLE_PWM(value);
+
+	mask = QPNP_EN_PWM_OUTPUT_MASK;
+
+	return qpnp_lpg_save_and_write(value, mask,
+		&pwm->chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL],
+		lpg_config->base_addr, QPNP_RAMP_CONTROL, 1, chip);
+}
+
+static int _pwm_config(struct pwm_device *pwm, int duty_us, int period_us)
+{
+	struct qpnp_pwm_config		*pwm_config;
+	struct qpnp_lpg_chip		*chip;
+	struct pwm_period_config	*period;
+	int				rc;
+
+	chip = pwm->chip;
+	pwm_config = &pwm->pwm_config;
+	period = &pwm_config->period;
+
+	if (pwm_config->pwm_period != period_us) {
+		qpnp_lpg_calc_period(period_us, period);
+		qpnp_lpg_save_period(pwm);
+		pwm_config->pwm_period = period_us;
+	}
+
+	pwm_config->pwm_duty = duty_us;
+	qpnp_lpg_calc_pwm_value(pwm, period_us, duty_us);
+	rc = qpnp_lpg_save_pwm_value(pwm);
+
+	if (rc) {
+		pr_err("Could not update PWM value for channel %d rc=%d\n",
+						pwm_config->channel_id, rc);
+		return rc;
+	}
+
+	rc = qpnp_lpg_configure_pwm(pwm);
+	if (rc) {
+		pr_err("Could not configure PWM clock for\n");
+		pr_err("channel %d rc=%d\n", pwm_config->channel_id, rc);
+		return rc;
+	}
+
+	rc = qpnp_pwm_configure_control(pwm);
+	if (rc) {
+		pr_err("Could not update PWM control for");
+		pr_err("channel %d rc=%d\n", pwm_config->channel_id, rc);
+		return rc;
+	}
+
+	pwm->chip->lpg_config.lpg_configured = 1;
+
+	pr_debug("duty/period=%u/%u usec: pwm_value=%d (of %d)\n",
+		 (unsigned)duty_us, (unsigned)period_us,
+		 pwm_config->pwm_value, 1 << period->pwm_size);
+
+	return 0;
+}
+
+static int _pwm_lut_config(struct pwm_device *pwm, int period_us,
+			int duty_pct[], struct lut_params lut_params)
+{
+	struct qpnp_lpg_config		*lpg_config;
+	struct qpnp_lut_config		*lut_config;
+	struct qpnp_lut_default_config  *def_lut_config =
+					&lut_config->def_config;
+	struct pwm_period_config	*period;
+	struct qpnp_pwm_config		*pwm_config;
+	int				start_idx = lut_params.start_idx;
+	int				len = lut_params.idx_len;
+	int				flags = lut_params.flags;
+	int				raw_lut, ramp_step_ms;
+	int				rc = 0;
+
+	pwm_config = &pwm->pwm_config;
+	lpg_config = &pwm->chip->lpg_config;
+	lut_config = &lpg_config->lut_config;
+	def_lut_config = &lut_config->def_config;
+
+	if ((start_idx + len) > lpg_config->lut_size) {
+		pr_err("Exceed LUT limit\n");
+		return -EINVAL;
+	}
+	if ((unsigned)period_us > PM_PWM_PERIOD_MAX ||
+		(unsigned)period_us < PM_PWM_PERIOD_MIN) {
+		pr_err("Period out of range\n");
+		return -EINVAL;
+	}
+
+	if (!pwm_config->in_use) {
+		pr_err("channel_id: %d: stale handle?\n",
+				pwm_config->channel_id);
+		return -EINVAL;
+	}
+
+	period = &pwm_config->period;
+
+	if (pwm_config->pwm_period != period_us) {
+		qpnp_lpg_calc_period(period_us, period);
+		qpnp_lpg_save_period(pwm);
+		pwm_config->pwm_period = period_us;
+	}
+
+	if (flags & PM_PWM_LUT_NO_TABLE)
+		goto after_table_write;
+
+	raw_lut = 0;
+	if (flags & PM_PWM_LUT_USE_RAW_VALUE)
+		raw_lut = 1;
+
+	lut_config->list_size = len;
+	lut_config->lo_index = start_idx;
+	lut_config->hi_index = start_idx + len - 1;
+
+	/*
+	 * LUT may not be specified in device tree by default.
+	 * This is the first time user is configuring it.
+	 */
+	if (lpg_config->bypass_lut) {
+		def_lut_config->duty_pct_list = kzalloc(sizeof(u32) *
+							len, GFP_KERNEL);
+		if (!def_lut_config->duty_pct_list) {
+			pr_err("kzalloc failed on def_duty_pct_list\n");
+			return -ENOMEM;
+		}
+
+		lut_config->duty_pct_list = kzalloc(lpg_config->lut_size *
+						sizeof(u16), GFP_KERNEL);
+		if (!lut_config->duty_pct_list) {
+			pr_err("kzalloc failed on duty_pct_list\n");
+			kfree(def_lut_config->duty_pct_list);
+			return -ENOMEM;
+		}
+
+		def_lut_config->size = len;
+		def_lut_config->start_idx = start_idx;
+		memcpy(def_lut_config->duty_pct_list, duty_pct, len);
+
+		lpg_config->bypass_lut = 0;
+	}
+
+	rc = qpnp_lpg_change_table(pwm, duty_pct, raw_lut);
+	if (rc) {
+		pr_err("qpnp_lpg_change_table: rc=%d\n", rc);
+		return -EINVAL;
+	}
+
+after_table_write:
+	ramp_step_ms = lut_params.ramp_step_ms;
+
+	if (ramp_step_ms > PM_PWM_LUT_RAMP_STEP_TIME_MAX)
+		ramp_step_ms = PM_PWM_LUT_RAMP_STEP_TIME_MAX;
+
+	QPNP_SET_PAUSE_CNT(lut_config->lut_pause_lo_cnt,
+			lut_params.lut_pause_lo, ramp_step_ms);
+	if (lut_config->lut_pause_lo_cnt > PM_PWM_LUT_PAUSE_MAX)
+		lut_config->lut_pause_lo_cnt = PM_PWM_LUT_PAUSE_MAX;
+
+	QPNP_SET_PAUSE_CNT(lut_config->lut_pause_hi_cnt,
+			lut_params.lut_pause_hi, ramp_step_ms);
+	if (lut_config->lut_pause_hi_cnt > PM_PWM_LUT_PAUSE_MAX)
+			lut_config->lut_pause_hi_cnt = PM_PWM_LUT_PAUSE_MAX;
+
+	lut_config->ramp_step_ms = ramp_step_ms;
+
+	lut_config->ramp_direction  = !!(flags & PM_PWM_LUT_RAMP_UP);
+	lut_config->pattern_repeat  = !!(flags & PM_PWM_LUT_LOOP);
+	lut_config->ramp_toggle	    = !!(flags & PM_PWM_LUT_REVERSE);
+	lut_config->enable_pause_hi = !!(flags & PM_PWM_LUT_PAUSE_HI_EN);
+	lut_config->enable_pause_lo = !!(flags & PM_PWM_LUT_PAUSE_LO_EN);
+	lpg_config->bypass_lut = 0;
+
+	rc = qpnp_lpg_change_lut(pwm);
+
+	if (!rc)
+		lpg_config->lpg_configured = 1;
+
+	return rc;
+}
+
+/* APIs */
+/**
+ * pwm_request - request a PWM device
+ * @channel_id: PWM id or channel
+ * @lable: the label to identify the user
+ */
+struct pwm_device *pwm_request(int pwm_id, const char *lable)
+{
+	struct qpnp_lpg_chip	*chip;
+	struct pwm_device	*pwm;
+
+	chip = radix_tree_lookup(&lpg_dev_tree, pwm_id);
+
+	if (!chip) {
+		pr_err("Could not find PWM Device for the\n");
+		pr_err("input pwm channel %d\n", pwm_id);
+		return ERR_PTR(-EINVAL);
+	}
+
+	mutex_lock(&chip->lpg_mutex);
+
+	pwm = &chip->pwm_dev;
+
+	if (pwm->pwm_config.in_use) {
+		pr_err("PWM device associated with the");
+		pr_err("input pwm id: %d is in use by %s",
+			pwm_id, pwm->pwm_config.lable);
+		pwm = ERR_PTR(-EBUSY);
+	} else {
+		pwm->pwm_config.in_use = 1;
+		pwm->pwm_config.lable  = lable;
+	}
+
+	mutex_unlock(&chip->lpg_mutex);
+
+	return pwm;
+}
+EXPORT_SYMBOL_GPL(pwm_request);
+
+/**
+ * pwm_free - free a PWM device
+ * @pwm: the PWM device
+ */
+void pwm_free(struct pwm_device *pwm)
+{
+	struct qpnp_pwm_config	*pwm_config;
+
+	if (pwm == NULL || IS_ERR(pwm) || pwm->chip == NULL) {
+		pr_err("Invalid pwm handle or no pwm_chip\n");
+		return;
+	}
+
+	mutex_lock(&pwm->chip->lpg_mutex);
+
+	pwm_config = &pwm->pwm_config;
+
+	if (pwm_config->in_use) {
+		qpnp_lpg_disable_pwm(pwm);
+		qpnp_lpg_disable_lut(pwm);
+		pwm_config->in_use = 0;
+		pwm_config->lable = NULL;
+		pwm->chip->lpg_config.lpg_configured = 0;
+	}
+
+	mutex_unlock(&pwm->chip->lpg_mutex);
+}
+EXPORT_SYMBOL_GPL(pwm_free);
+
+/**
+ * pwm_config - change a PWM device configuration
+ * @pwm: the PWM device
+ * @period_us: period in microseconds
+ * @duty_us: duty cycle in microseconds
+ */
+int pwm_config(struct pwm_device *pwm, int duty_us, int period_us)
+{
+	int rc;
+
+	if (pwm == NULL || IS_ERR(pwm) ||
+		duty_us > period_us ||
+		(unsigned)period_us > PM_PWM_PERIOD_MAX ||
+		(unsigned)period_us < PM_PWM_PERIOD_MIN) {
+		pr_err("Invalid pwm handle or parameters\n");
+		return -EINVAL;
+	}
+
+	if (!pwm->pwm_config.in_use)
+		return -EINVAL;
+
+	mutex_lock(&pwm->chip->lpg_mutex);
+	rc = _pwm_config(pwm, duty_us, period_us);
+	mutex_unlock(&pwm->chip->lpg_mutex);
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(pwm_config);
+
+/**
+ * pwm_enable - start a PWM output toggling
+ * @pwm: the PWM device
+ */
+int pwm_enable(struct pwm_device *pwm)
+{
+	struct qpnp_pwm_config	*p_config;
+	struct qpnp_lpg_chip	*chip;
+	int			rc = 0;
+
+	if (pwm == NULL || IS_ERR(pwm) || pwm->chip == NULL) {
+		pr_err("Invalid pwm handle or no pwm_chip\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&pwm->chip->lpg_mutex);
+
+	chip = pwm->chip;
+	p_config = &pwm->pwm_config;
+
+	if (!p_config->in_use) {
+		pr_err("channel_id: %d: stale handle?\n", p_config->channel_id);
+		rc = -EINVAL;
+		goto out_unlock;
+	}
+
+	if (!pwm->chip->lpg_config.lpg_configured) {
+		pr_err("Request received to enable PWM for channel Id: %d\n",
+							p_config->channel_id);
+		pr_err("However, PWM isn't configured\n");
+		pr_err("falling back to defaultconfiguration\n");
+		rc = _pwm_config(pwm, p_config->pwm_duty,
+					p_config->pwm_period);
+		if (rc) {
+			pr_err("Could not apply default PWM config\n");
+			goto out_unlock;
+		}
+	}
+
+	rc = qpnp_lpg_enable_pwm(pwm);
+
+out_unlock:
+	mutex_unlock(&pwm->chip->lpg_mutex);
+	return rc;
+}
+EXPORT_SYMBOL_GPL(pwm_enable);
+
+/**
+ * pwm_disable - stop a PWM output toggling
+ * @pwm: the PWM device
+ */
+void pwm_disable(struct pwm_device *pwm)
+{
+	struct qpnp_pwm_config	*pwm_config;
+	struct qpnp_lpg_chip	*chip;
+
+	if (pwm == NULL || IS_ERR(pwm) || pwm->chip == NULL) {
+		pr_err("Invalid pwm handle or no pwm_chip\n");
+		return;
+	}
+
+	mutex_lock(&pwm->chip->lpg_mutex);
+
+	chip = pwm->chip;
+	pwm_config = &pwm->pwm_config;
+
+	if (pwm_config->in_use) {
+		if (!pwm->chip->lpg_config.lpg_configured) {
+			pr_err("Request received to disable PWM for\n");
+			pr_err("channel Id: %d\n", pwm_config->channel_id);
+			pr_err("However PWM is not configured by any means\n");
+			goto out_unlock;
+		}
+		qpnp_lpg_disable_pwm(pwm);
+	}
+
+out_unlock:
+	mutex_unlock(&pwm->chip->lpg_mutex);
+}
+EXPORT_SYMBOL_GPL(pwm_disable);
+
+/**
+ * pwm_config_period - change PWM period
+ *
+ * @pwm: the PWM device
+ * @pwm_p: period in struct qpnp_lpg_period
+ */
+int pwm_config_period(struct pwm_device *pwm,
+			     struct pwm_period_config *period)
+{
+	struct qpnp_pwm_config	*pwm_config;
+	struct qpnp_lpg_config	*lpg_config;
+	struct qpnp_lpg_chip	*chip;
+	int			rc = 0;
+
+	if (pwm == NULL || IS_ERR(pwm) || period == NULL)
+		return -EINVAL;
+	if (pwm->chip == NULL)
+		return -ENODEV;
+
+	mutex_lock(&pwm->chip->lpg_mutex);
+
+	chip = pwm->chip;
+	pwm_config = &pwm->pwm_config;
+	lpg_config = &chip->lpg_config;
+
+	if (!pwm_config->in_use) {
+		rc = -EINVAL;
+		goto out_unlock;
+	}
+
+	pwm_config->period.pwm_size = period->pwm_size;
+	pwm_config->period.clk = period->clk;
+	pwm_config->period.pre_div = period->pre_div;
+	pwm_config->period.pre_div_exp = period->pre_div_exp;
+
+	qpnp_lpg_save_period(pwm);
+
+	rc = spmi_ext_register_writel(chip->spmi_dev->ctrl, chip->spmi_dev->sid,
+			SPMI_LPG_REG_ADDR(lpg_config->base_addr,
+			QPNP_LPG_PWM_SIZE_CLK),
+			&chip->qpnp_lpg_registers[QPNP_LPG_PWM_SIZE_CLK], 1);
+
+	if (rc) {
+		pr_err("Write failed: QPNP_LPG_PWM_SIZE_CLK register, rc: %d\n",
+									rc);
+		goto out_unlock;
+	}
+
+	rc = spmi_ext_register_writel(chip->spmi_dev->ctrl, chip->spmi_dev->sid,
+			SPMI_LPG_REG_ADDR(lpg_config->base_addr,
+			QPNP_LPG_PWM_FREQ_PREDIV_CLK),
+		&chip->qpnp_lpg_registers[QPNP_LPG_PWM_FREQ_PREDIV_CLK], 1);
+	if (rc) {
+		pr_err("Failed to write to QPNP_LPG_PWM_FREQ_PREDIV_CLK\n");
+		pr_err("register, rc = %d\n", rc);
+	}
+
+out_unlock:
+	mutex_unlock(&pwm->chip->lpg_mutex);
+	return rc;
+}
+EXPORT_SYMBOL(pwm_config_period);
+
+/**
+ * pwm_config_pwm_value - change a PWM device configuration
+ * @pwm: the PWM device
+ * @pwm_value: the duty cycle in raw PWM value (< 2^pwm_size)
+ */
+int pwm_config_pwm_value(struct pwm_device *pwm, int pwm_value)
+{
+	struct qpnp_lpg_config	*lpg_config;
+	struct qpnp_pwm_config	*pwm_config;
+	int			rc = 0;
+
+	if (pwm == NULL || IS_ERR(pwm))
+		return -EINVAL;
+
+	if (pwm->chip == NULL)
+		return -ENODEV;
+
+	lpg_config = &pwm->chip->lpg_config;
+	pwm_config = &pwm->pwm_config;
+
+	mutex_lock(&pwm->chip->lpg_mutex);
+
+	if (!pwm_config->in_use || !pwm_config->pwm_period) {
+		rc = -EINVAL;
+		goto out_unlock;
+	}
+
+	if (pwm_config->pwm_value == pwm_value)
+		goto out_unlock;
+
+	pwm_config->pwm_value = pwm_value;
+
+	rc = qpnp_lpg_save_pwm_value(pwm);
+
+	if (rc)
+		pr_err("Could not update PWM value for channel %d rc=%d\n",
+						pwm_config->channel_id, rc);
+
+out_unlock:
+	mutex_unlock(&pwm->chip->lpg_mutex);
+	return rc;
+}
+EXPORT_SYMBOL_GPL(pwm_config_pwm_value);
+
+/**
+ * pwm_lut_config - change LPG LUT device configuration
+ * @pwm: the PWM device
+ * @period_us: period in micro second
+ * @duty_pct: array of duty cycles in percent, like 20, 50.
+ * @lut_params: Lookup table parameters
+ */
+int pwm_lut_config(struct pwm_device *pwm, int period_us,
+		int duty_pct[], struct lut_params lut_params)
+{
+	int rc = 0;
+
+	if (pwm == NULL || IS_ERR(pwm) || !lut_params.idx_len) {
+		pr_err("Invalid pwm handle or idx_len=0\n");
+		return -EINVAL;
+	}
+
+	if (pwm->chip == NULL)
+		return -ENODEV;
+
+	if (duty_pct == NULL && !(lut_params.flags & PM_PWM_LUT_NO_TABLE)) {
+		pr_err("Invalid duty_pct with flag\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&pwm->chip->lpg_mutex);
+
+	rc = _pwm_lut_config(pwm, period_us, duty_pct, lut_params);
+
+	mutex_unlock(&pwm->chip->lpg_mutex);
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(pwm_lut_config);
+
+/**
+ * pwm_lut_enable - control a PWM device to start/stop LUT ramp
+ * @pwm: the PWM device
+ * @start: to start (1), or stop (0)
+ */
+int pwm_lut_enable(struct pwm_device *pwm, int start)
+{
+	struct qpnp_lpg_config	*lpg_config;
+	struct qpnp_pwm_config	*p_config;
+	struct lut_params	lut_params;
+	int			rc = 0;
+
+	if (pwm == NULL || IS_ERR(pwm)) {
+		pr_err("Invalid pwm handle\n");
+		return -EINVAL;
+	}
+
+	if (pwm->chip == NULL)
+		return -ENODEV;
+
+	lpg_config = &pwm->chip->lpg_config;
+	p_config = &pwm->pwm_config;
+
+	mutex_lock(&pwm->chip->lpg_mutex);
+
+	if (start) {
+		if (!lpg_config->lpg_configured) {
+			pr_err("Request received to enable LUT for\n");
+			pr_err("LPG channel %d\n", pwm->pwm_config.channel_id);
+			pr_err("But LPG is not configured, falling back to\n");
+			pr_err(" default LUT configuration if available\n");
+
+			if (lpg_config->bypass_lut) {
+				pr_err("No default LUT configuration found\n");
+				pr_err("Use pwm_lut_config() to configure\n");
+				rc = -EINVAL;
+				goto out;
+			}
+
+			qpnp_set_lut_params(&lut_params,
+					&lpg_config->lut_config);
+
+			rc = _pwm_lut_config(pwm, p_config->pwm_period,
+			(int *)lpg_config->lut_config.def_config.duty_pct_list,
+			lut_params);
+			if (rc) {
+				pr_err("Could not set the default LUT conf\n");
+				goto out;
+			}
+		}
+
+		rc = qpnp_lpg_enable_lut(pwm);
+	} else {
+		if (unlikely(!lpg_config->lpg_configured)) {
+			pr_err("LPG isn't configured\n");
+			rc = -EINVAL;
+			goto out;
+		}
+		rc = qpnp_lpg_disable_lut(pwm);
+	}
+
+out:
+	mutex_unlock(&pwm->chip->lpg_mutex);
+	return rc;
+}
+EXPORT_SYMBOL_GPL(pwm_lut_enable);
+
+/* Fill in lpg device elements based on values found in device tree. */
+static int qpnp_lpg_get_dt_config(struct spmi_device *spmi,
+					struct qpnp_lpg_chip *chip)
+{
+	int			rc;
+	struct resource		*res;
+	struct device_node	*of_node = spmi->dev.of_node;
+	struct qpnp_lpg_config	*lpg_config = &chip->lpg_config;
+	struct pwm_device	*pwm_dev = &chip->pwm_dev;
+	struct qpnp_lut_config	*lut_config = &chip->lpg_config.lut_config;
+	struct qpnp_lut_default_config	*def_lut_config =
+						&lut_config->def_config;
+
+	res = spmi_get_resource(spmi, 0, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&spmi->dev, "%s: node is missing base address\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	lpg_config->base_addr = res->start;
+
+	res = spmi_get_resource(spmi, 0, IORESOURCE_MEM, 1);
+	if (!res) {
+		dev_err(&spmi->dev, "%s: node is missing LUT base address\n",
+								__func__);
+		return -EINVAL;
+	}
+
+	lpg_config->lut_base_addr = res->start;
+	/* Each entry of LUT is of 2 bytes */
+	lpg_config->lut_size = resource_size(res) >> 1;
+
+
+	rc = of_property_read_u32(of_node, "qcom,channel-id",
+				&pwm_dev->pwm_config.channel_id);
+	if (rc) {
+		dev_err(&spmi->dev, "%s: node is missing LPG channel id",
+								__func__);
+		return rc;
+	}
+
+	rc = of_property_read_u32(of_node, "qcom,period",
+				&pwm_dev->pwm_config.pwm_period);
+	if (rc) {
+		dev_err(&spmi->dev, "%s: node is missing PWM Period value",
+								__func__);
+		return rc;
+	}
+
+	if (!of_get_property(of_node, "qcom,duty-percents",
+						&def_lut_config->size)) {
+		lpg_config->bypass_lut = 1;
+	}
+
+	if (lpg_config->bypass_lut)
+		goto read_opt_props;
+
+	rc = of_property_read_u32(of_node, "qcom,start-index",
+					&def_lut_config->start_idx);
+
+	if (rc) {
+		dev_err(&spmi->dev, "Missing start index");
+		return rc;
+	}
+
+	def_lut_config->size /= sizeof(u32);
+
+	def_lut_config->duty_pct_list = kzalloc(sizeof(u32) *
+					def_lut_config->size, GFP_KERNEL);
+	if (!def_lut_config->duty_pct_list) {
+		dev_err(&spmi->dev, "%s: kzalloc failed on duty_pct_list\n",
+								__func__);
+		return -ENOMEM;
+	}
+
+	rc = of_property_read_u32_array(of_node, "qcom,duty-percents",
+		def_lut_config->duty_pct_list, def_lut_config->size);
+	if (rc) {
+		dev_err(&spmi->dev, "invalid or missing property:\n");
+		dev_err(&spmi->dev, "qcom,duty-pcts-list\n");
+		kfree(def_lut_config->duty_pct_list);
+		return rc;
+	}
+
+	lut_config->duty_pct_list = kzalloc(lpg_config->lut_size * sizeof(u16),
+								GFP_KERNEL);
+	if (!lut_config->duty_pct_list) {
+		dev_err(&spmi->dev, "can not allocate duty pct list\n");
+		kfree(def_lut_config->duty_pct_list);
+		return -ENOMEM;
+	}
+
+read_opt_props:
+	/* Initialize optional config parameters from DT if provided */
+	of_property_read_u32(of_node, "qcom,duty",
+					&pwm_dev->pwm_config.pwm_duty);
+	of_property_read_u32(of_node, "qcom,ramp-step-duration",
+					&lut_config->ramp_step_ms);
+	of_property_read_u32(of_node, "qcom,lpg-lut-pause-hi",
+					&lut_config->lut_pause_hi_cnt);
+	of_property_read_u32(of_node, "qcom,lpg-lut-pause-lo",
+					&lut_config->lut_pause_lo_cnt);
+	of_property_read_u32(of_node, "qcom,lpg-lut-ramp-direction",
+					(u32 *)&lut_config->ramp_direction);
+	of_property_read_u32(of_node, "qcom,lpg-lut-pattern-repeat",
+					(u32 *)&lut_config->pattern_repeat);
+	of_property_read_u32(of_node, "qcom,lpg-lut-ramp-toggle",
+					(u32 *)&lut_config->ramp_toggle);
+	of_property_read_u32(of_node, "qcom,lpg-lut-enable-pause-hi",
+					(u32 *)&lut_config->enable_pause_hi);
+	of_property_read_u32(of_node, "qcom,lpg-lut-enable-pause-lo",
+					(u32 *)&lut_config->enable_pause_lo);
+
+	return 0;
+}
+
+static int __devinit qpnp_pwm_probe(struct spmi_device *spmi)
+{
+	struct qpnp_lpg_chip	*chip;
+	int			rc, id;
+
+	chip = kzalloc(sizeof *chip, GFP_KERNEL);
+	if (chip == NULL) {
+		pr_err("kzalloc() failed.\n");
+		return -ENOMEM;
+	}
+
+	mutex_init(&chip->lpg_mutex);
+
+	chip->spmi_dev = spmi;
+	chip->pwm_dev.chip = chip;
+	dev_set_drvdata(&spmi->dev, chip);
+
+	rc = qpnp_lpg_get_dt_config(spmi, chip);
+
+	if (rc)
+		goto failed_config;
+
+	id = chip->pwm_dev.pwm_config.channel_id;
+
+	rc = radix_tree_insert(&lpg_dev_tree, id, chip);
+
+	if (rc) {
+		dev_err(&spmi->dev, "%s: Failed to register LPG Channel %d\n",
+								__func__, id);
+		goto failed_insert;
+	}
+
+	return 0;
+
+failed_insert:
+	kfree(chip->lpg_config.lut_config.duty_pct_list);
+failed_config:
+	dev_set_drvdata(&spmi->dev, NULL);
+	mutex_destroy(&chip->lpg_mutex);
+	kfree(chip);
+	return rc;
+}
+
+static int __devexit qpnp_pwm_remove(struct spmi_device *spmi)
+{
+	struct qpnp_lpg_chip *chip;
+	struct qpnp_lpg_config *lpg_config;
+
+	chip = dev_get_drvdata(&spmi->dev);
+
+	dev_set_drvdata(&spmi->dev, NULL);
+
+	if (chip) {
+		lpg_config = &chip->lpg_config;
+		kfree(lpg_config->lut_config.duty_pct_list);
+		kfree(lpg_config->lut_config.def_config.duty_pct_list);
+		mutex_destroy(&chip->lpg_mutex);
+		kfree(chip);
+	}
+
+	return 0;
+}
+
+static struct of_device_id spmi_match_table[] = {
+	{ .compatible = QPNP_LPG_DRIVER_NAME, },
+	{}
+};
+
+static const struct spmi_device_id qpnp_lpg_id[] = {
+	{ QPNP_LPG_DRIVER_NAME, 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(spmi, qpnp_lpg_id);
+
+static struct spmi_driver qpnp_lpg_driver = {
+	.driver		= {
+		.name	= QPNP_LPG_DRIVER_NAME,
+		.of_match_table = spmi_match_table,
+		.owner = THIS_MODULE,
+	},
+	.probe		= qpnp_pwm_probe,
+	.remove		= __devexit_p(qpnp_pwm_remove),
+	.id_table	= qpnp_lpg_id,
+};
+
+/**
+ * qpnp_lpg_init() - register spmi driver for qpnp-lpg
+ */
+int __init qpnp_lpg_init(void)
+{
+	return spmi_driver_register(&qpnp_lpg_driver);
+}
+
+static void __exit qpnp_lpg_exit(void)
+{
+	spmi_driver_unregister(&qpnp_lpg_driver);
+}
+
+MODULE_DESCRIPTION("QPNP PMIC LPG driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" QPNP_LPG_DRIVER_NAME);
+
+subsys_initcall(qpnp_lpg_init);
+module_exit(qpnp_lpg_exit);
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 87b307c..c95f82d 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -123,13 +123,7 @@
 #   - discrete ones (including all PCI-only controllers)
 #   - debug/dummy gadget+hcd is last.
 #
-choice
-	prompt "USB Peripheral Controller"
-	help
-	   A USB device uses a controller to talk to its host.
-	   Systems should have only one such upstream link.
-	   Many controller drivers are platform-specific; these
-	   often need board-specific hooks.
+menu "USB Peripheral Controller"
 
 #
 # Integrated controllers
@@ -574,7 +568,7 @@
 # NOTE:  Please keep dummy_hcd LAST so that "real hardware" appears
 # first and will be selected by default.
 
-endchoice
+endmenu
 
 # Selected by UDC drivers that support high-speed operation.
 config USB_GADGET_DUALSPEED
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index b5a7291..a13b5da 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -1801,6 +1801,9 @@
 		goto err_dev;
 	}
 
+	if (pdata)
+		composite_driver.usb_core_id = pdata->usb_core_id;
+
 	ret = usb_composite_probe(&android_usb_driver, android_bind);
 	if (ret) {
 		pr_err("%s(): Failed to register android "
diff --git a/drivers/usb/gadget/ci13xxx_msm_hsic.c b/drivers/usb/gadget/ci13xxx_msm_hsic.c
index f353b07..5d5ee00 100644
--- a/drivers/usb/gadget/ci13xxx_msm_hsic.c
+++ b/drivers/usb/gadget/ci13xxx_msm_hsic.c
@@ -635,7 +635,7 @@
 	struct resource *res;
 	struct msm_hsic_per *mhsic;
 	int ret = 0;
-	struct msm_hsic_peripheral_platform_data *pdata;
+	struct ci13xxx_platform_data *pdata;
 
 	dev_dbg(&pdev->dev, "msm-hsic probe\n");
 
@@ -654,7 +654,8 @@
 	the_mhsic = mhsic;
 	platform_set_drvdata(pdev, mhsic);
 	mhsic->dev = &pdev->dev;
-	mhsic->pdata = pdata;
+	mhsic->pdata =
+		(struct msm_hsic_peripheral_platform_data *)pdata->prv_data;
 
 	mhsic->irq = platform_get_irq(pdev, 0);
 	if (mhsic->irq < 0) {
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 771dbb7..bb6bb2c 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -2739,6 +2739,11 @@
 {
 	static bool init;
 	struct msm_otg *motg = the_msm_otg;
+	struct usb_otg *otg = motg->phy.otg;
+
+	/* In A Host Mode, ignore received BSV interrupts */
+	if (otg->phy->state >= OTG_STATE_A_IDLE)
+		return;
 
 	if (online) {
 		pr_debug("PMIC: BSV set\n");
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index ea9e5ab..2cbef69 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -49,6 +49,7 @@
 static struct clk *mdp_pclk;
 static struct clk *mdp_lut_clk;
 int mdp_rev;
+int mdp_iommu_split_domain;
 
 static struct platform_device *mdp_init_pdev;
 static struct regulator *footswitch, *hdmi_pll_fs;
@@ -2240,6 +2241,7 @@
 		}
 
 		mdp_rev = mdp_pdata->mdp_rev;
+		mdp_iommu_split_domain = mdp_pdata->mdp_iommu_split_domain;
 
 		rc = mdp_irq_clk_setup(pdev, mdp_pdata->cont_splash_enabled);
 
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index e60b24e..f8d54bd 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -42,6 +42,7 @@
 extern ulong mdp4_display_intf;
 extern spinlock_t mdp_spin_lock;
 extern int mdp_rev;
+extern int mdp_iommu_split_domain;
 extern struct mdp_csc_cfg mdp_csc_convert[4];
 
 extern struct workqueue_struct *mdp_hist_wq;
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index ad37d2f..3afe28b 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -126,7 +126,7 @@
 	pr_debug("mixer %u, pipe %u, plane %u\n", pipe->mixer_num,
 		pipe->pipe_ndx, plane);
 	if (ion_map_iommu(display_iclient, *srcp_ihdl,
-		DISPLAY_DOMAIN, GEN_POOL, SZ_4K, 0, start,
+		DISPLAY_READ_DOMAIN, GEN_POOL, SZ_4K, 0, start,
 		len, 0, ION_IOMMU_UNMAP_DELAYED)) {
 		ion_free(display_iclient, *srcp_ihdl);
 		pr_err("ion_map_iommu() failed\n");
@@ -140,7 +140,7 @@
 		if (iom_pipe_info->prev_ihdl[plane]) {
 			ion_unmap_iommu(display_iclient,
 				iom_pipe_info->prev_ihdl[plane],
-				DISPLAY_DOMAIN, GEN_POOL);
+				DISPLAY_READ_DOMAIN, GEN_POOL);
 			ion_free(display_iclient,
 				iom_pipe_info->prev_ihdl[plane]);
 			pr_debug("Previous: mixer %u, pipe %u, plane %u, "
@@ -175,7 +175,7 @@
 					iom_pipe_info->prev_ihdl[i]);
 				ion_unmap_iommu(display_iclient,
 					iom_pipe_info->prev_ihdl[i],
-					DISPLAY_DOMAIN, GEN_POOL);
+					DISPLAY_READ_DOMAIN, GEN_POOL);
 				ion_free(display_iclient,
 					iom_pipe_info->prev_ihdl[i]);
 				iom_pipe_info->prev_ihdl[i] = NULL;
@@ -191,7 +191,7 @@
 						iom_pipe_info->ihdl[i]);
 					ion_unmap_iommu(display_iclient,
 						iom_pipe_info->ihdl[i],
-						DISPLAY_DOMAIN, GEN_POOL);
+						DISPLAY_READ_DOMAIN, GEN_POOL);
 					ion_free(display_iclient,
 						iom_pipe_info->ihdl[i]);
 					iom_pipe_info->ihdl[i] = NULL;
@@ -424,9 +424,6 @@
 	if (mdp_is_in_isr == FALSE)
 		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 
-	/* dma_p source */
-	MDP_OUTP(MDP_BASE + 0x90004,
-			(pipe->src_height << 16 | pipe->src_width));
 	if (pipe->blt_addr) {
 #ifdef BLT_RGB565
 		bpp = 2; /* overlay ouput is RGB565 */
@@ -443,6 +440,9 @@
 		MDP_OUTP(MDP_BASE + 0x90008, pipe->srcp0_addr);
 		MDP_OUTP(MDP_BASE + 0x9000c, pipe->srcp0_ystride);
 	}
+	/* dma_p source */
+	MDP_OUTP(MDP_BASE + 0x90004,
+			(pipe->src_height << 16 | pipe->src_width));
 
 	/* dma_p dest */
 	MDP_OUTP(MDP_BASE + 0x90010, (pipe->dst_y << 16 | pipe->dst_x));
@@ -3120,7 +3120,6 @@
 		/* primary interface */
 		ctrl->mixer0_played++;
 		if (ctrl->panel_mode & MDP4_PANEL_LCDC) {
-			mdp4_overlay_reg_flush(pipe, 0);
 			mdp4_overlay_lcdc_start();
 			mdp4_overlay_lcdc_vsync_push(mfd, pipe);
 			if (!mfd->use_ov0_blt &&
@@ -3129,7 +3128,6 @@
 		}
 #ifdef CONFIG_FB_MSM_MIPI_DSI
 		else if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) {
-			mdp4_overlay_reg_flush(pipe, 0);
 			mdp4_overlay_dsi_video_start();
 			mdp4_overlay_dsi_video_vsync_push(mfd, pipe);
 			if (!mfd->use_ov0_blt &&
@@ -3182,29 +3180,54 @@
 	return ret;
 }
 
-static struct {
+struct msm_iommu_ctx {
 	char *name;
 	int  domain;
-} msm_iommu_ctx_names[] = {
-	/* Display */
+};
+
+static struct msm_iommu_ctx msm_iommu_ctx_names[] = {
+	/* Display read*/
 	{
 		.name = "mdp_port0_cb0",
-		.domain = DISPLAY_DOMAIN,
+		.domain = DISPLAY_READ_DOMAIN,
 	},
-	/* Display */
+	/* Display read*/
 	{
 		.name = "mdp_port0_cb1",
-		.domain = DISPLAY_DOMAIN,
+		.domain = DISPLAY_READ_DOMAIN,
 	},
-	/* Display */
+	/* Display write */
 	{
 		.name = "mdp_port1_cb0",
-		.domain = DISPLAY_DOMAIN,
+		.domain = DISPLAY_READ_DOMAIN,
 	},
-	/* Display */
+	/* Display write */
 	{
 		.name = "mdp_port1_cb1",
-		.domain = DISPLAY_DOMAIN,
+		.domain = DISPLAY_READ_DOMAIN,
+	},
+};
+
+static struct msm_iommu_ctx msm_iommu_split_ctx_names[] = {
+	/* Display read*/
+	{
+		.name = "mdp_port0_cb0",
+		.domain = DISPLAY_READ_DOMAIN,
+	},
+	/* Display read*/
+	{
+		.name = "mdp_port0_cb1",
+		.domain = DISPLAY_WRITE_DOMAIN,
+	},
+	/* Display write */
+	{
+		.name = "mdp_port1_cb0",
+		.domain = DISPLAY_READ_DOMAIN,
+	},
+	/* Display write */
+	{
+		.name = "mdp_port1_cb1",
+		.domain = DISPLAY_WRITE_DOMAIN,
 	},
 };
 
@@ -3218,19 +3241,28 @@
 void mdp4_iommu_attach(void)
 {
 	static int done;
+	struct msm_iommu_ctx *ctx_names;
 	struct iommu_domain *domain;
-	int i;
+	int i, arr_size;
 
 	if (!done) {
-		for (i = 0; i < ARRAY_SIZE(msm_iommu_ctx_names); i++) {
+		if (mdp_iommu_split_domain) {
+			ctx_names = msm_iommu_split_ctx_names;
+			arr_size = ARRAY_SIZE(msm_iommu_split_ctx_names);
+		} else {
+			ctx_names = msm_iommu_ctx_names;
+			arr_size = ARRAY_SIZE(msm_iommu_ctx_names);
+		}
+
+		for (i = 0; i < arr_size; i++) {
 			int domain_idx;
 			struct device *ctx = msm_iommu_get_ctx(
-				msm_iommu_ctx_names[i].name);
+				ctx_names[i].name);
 
 			if (!ctx)
 				continue;
 
-			domain_idx = msm_iommu_ctx_names[i].domain;
+			domain_idx = ctx_names[i].domain;
 
 			domain = msm_get_iommu_domain(domain_idx);
 			if (!domain)
@@ -3242,7 +3274,7 @@
 				WARN(1, "%s: could not attach domain %d to context %s."
 					" iommu programming will not occur.\n",
 					__func__, domain_idx,
-					msm_iommu_ctx_names[i].name);
+					ctx_names[i].name);
 				continue;
 			}
 		}
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index 3cdd72e..b0f3e17 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -655,7 +655,7 @@
 	data &= 0x01;
 	if (data) {	/* timing generator enabled */
 		mdp4_overlay_dsi_video_wait4event(mfd, INTR_DMA_P_DONE);
-		mdp4_overlay_dsi_video_wait4event(mfd, INTR_PRIMARY_VSYNC);
+		msleep(20);
 	}
 
 
diff --git a/drivers/video/msm/mdp4_overlay_writeback.c b/drivers/video/msm/mdp4_overlay_writeback.c
index d59c4a8..f426f8c 100644
--- a/drivers/video/msm/mdp4_overlay_writeback.c
+++ b/drivers/video/msm/mdp4_overlay_writeback.c
@@ -390,6 +390,8 @@
 {
 	struct msmfb_writeback_data_list *temp;
 	bool found = false;
+	int domain;
+
 	if (!list_empty(&mfd->writeback_register_queue)) {
 		list_for_each_entry(temp,
 				&mfd->writeback_register_queue,
@@ -420,9 +422,14 @@
 				goto register_ion_fail;
 			}
 
+			if (mdp_iommu_split_domain)
+				domain = DISPLAY_WRITE_DOMAIN;
+			else
+				domain = DISPLAY_READ_DOMAIN;
+
 			if (ion_map_iommu(mfd->iclient,
 					  srcp_ihdl,
-					  DISPLAY_DOMAIN,
+					  domain,
 					  GEN_POOL,
 					  SZ_4K,
 					  0,
@@ -501,7 +508,7 @@
 {
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
 	struct msmfb_writeback_data_list *node = NULL;
-	int rc = 0;
+	int rc = 0, domain;
 
 	rc = wait_event_interruptible(mfd->wait_q, is_buffer_ready(mfd));
 	if (rc) {
@@ -523,9 +530,14 @@
 		memcpy(data, &node->buf_info, sizeof(struct msmfb_data));
 		if (!data->iova)
 			if (mfd->iclient && node->ihdl) {
+				if (mdp_iommu_split_domain)
+					domain = DISPLAY_WRITE_DOMAIN;
+				else
+					domain = DISPLAY_READ_DOMAIN;
+
 				ion_unmap_iommu(mfd->iclient,
 						node->ihdl,
-						DISPLAY_DOMAIN,
+						domain,
 						GEN_POOL);
 				ion_free(mfd->iclient,
 					 node->ihdl);
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index f192b12..8bd125b 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -2591,11 +2591,30 @@
 		buf->ihdl = ion_alloc(mfd->iclient, buffer_size, SZ_4K,
 			mfd->mem_hid);
 		if (!IS_ERR_OR_NULL(buf->ihdl)) {
-			if (ion_map_iommu(mfd->iclient, buf->ihdl,
-				DISPLAY_DOMAIN, GEN_POOL, SZ_4K, 0, &addr,
-				&len, 0, 0)) {
-				pr_err("ion_map_iommu() failed\n");
-				return -ENOMEM;
+			if (mdp_iommu_split_domain) {
+				if (mfd->mem_hid & ION_SECURE) {
+					if (ion_phys(mfd->iclient, buf->ihdl,
+						&addr, (size_t *)&len)) {
+						pr_err("%s:%d: ion_phys map failed\n",
+							 __func__, __LINE__);
+						return -ENOMEM;
+					}
+				} else {
+					if (ion_map_iommu(mfd->iclient,
+						buf->ihdl, DISPLAY_WRITE_DOMAIN,
+						GEN_POOL, SZ_4K, 0, &addr, &len,
+						0, 0)) {
+						pr_err("ion_map_iommu() failed\n");
+						return -ENOMEM;
+					}
+				}
+			} else {
+				if (ion_map_iommu(mfd->iclient, buf->ihdl,
+					DISPLAY_READ_DOMAIN, GEN_POOL, SZ_4K,
+					0, &addr, &len, 0, 0)) {
+					pr_err("ion_map_iommu() failed\n");
+					return -ENOMEM;
+				}
 			}
 		} else {
 			pr_err("%s:%d: ion_alloc failed\n", __func__,
@@ -2629,8 +2648,14 @@
 
 	if (!IS_ERR_OR_NULL(mfd->iclient)) {
 		if (!IS_ERR_OR_NULL(buf->ihdl)) {
-			ion_unmap_iommu(mfd->iclient, buf->ihdl,
-				DISPLAY_DOMAIN, GEN_POOL);
+			if (mdp_iommu_split_domain) {
+				if (!(mfd->mem_hid & ION_SECURE))
+					ion_unmap_iommu(mfd->iclient, buf->ihdl,
+						DISPLAY_WRITE_DOMAIN, GEN_POOL);
+			} else {
+				ion_unmap_iommu(mfd->iclient, buf->ihdl,
+					DISPLAY_READ_DOMAIN, GEN_POOL);
+			}
 			ion_free(mfd->iclient, buf->ihdl);
 			pr_debug("%s:%d free writeback imem\n", __func__,
 				__LINE__);
diff --git a/drivers/video/msm/mdp_ppp.c b/drivers/video/msm/mdp_ppp.c
index 4009ffc..8999395 100644
--- a/drivers/video/msm/mdp_ppp.c
+++ b/drivers/video/msm/mdp_ppp.c
@@ -61,6 +61,7 @@
 
 extern uint32 mdp_plv[];
 extern struct semaphore mdp_ppp_mutex;
+static struct ion_client *ppp_display_iclient;
 
 int mdp_get_bytes_per_pixel(uint32_t format,
 				 struct msm_fb_data_type *mfd)
@@ -1276,41 +1277,69 @@
 	return kgsl_gem_obj_addr(img->memory_id, (int) img->priv, start, len);
 }
 
-int get_img(struct mdp_img *img, struct fb_info *info, unsigned long *start,
-	    unsigned long *len, struct file **pp_file)
+int get_img(struct mdp_img *img, struct mdp_blit_req *req,
+		struct fb_info *info, unsigned long *start, unsigned long *len,
+		struct file **srcp_file, struct ion_handle **srcp_ihdl)
 {
-	int put_needed, ret = 0;
+	int put_needed, fb_num, ret = 0;
 	struct file *file;
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+#endif
 #ifdef CONFIG_ANDROID_PMEM
 	unsigned long vstart;
 #endif
 
-#ifdef CONFIG_ANDROID_PMEM
-	if (!get_pmem_file(img->memory_id, start, &vstart, len, pp_file))
-		return 0;
-#endif
-	file = fget_light(img->memory_id, &put_needed);
-	if (file == NULL)
-		return -1;
+	if (req->flags & MDP_MEMORY_ID_TYPE_FB) {
+		file = fget_light(img->memory_id, &put_needed);
+		if (file == NULL)
+			return -EINVAL;
 
-	if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
-		*start = info->fix.smem_start;
-		*len = info->fix.smem_len;
-		*pp_file = file;
-	} else {
-		ret = -1;
-		fput_light(file, put_needed);
+		if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
+			fb_num = MINOR(file->f_dentry->d_inode->i_rdev);
+			if (get_fb_phys_info(start, len, fb_num,
+				DISPLAY_SUBSYSTEM_ID)) {
+				pr_err("get_fb_phys_info() failed\n");
+				fput_light(file, put_needed);
+			} else {
+				*srcp_file = file;
+			}
+
+			return ret;
+		} else {
+			fput_light(file, put_needed);
+		}
 	}
-	return ret;
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+		*srcp_ihdl = ion_import_dma_buf(mfd->iclient, img->memory_id);
+		if (IS_ERR_OR_NULL(*srcp_ihdl))
+			return PTR_ERR(*srcp_ihdl);
+
+		if (!ion_phys(mfd->iclient, *srcp_ihdl, start, (size_t *) len))
+			return ret;
+		 else
+			return -EINVAL;
+#endif
+
+#ifdef CONFIG_ANDROID_PMEM
+	if (!get_pmem_file(img->memory_id, start, &vstart, len, srcp_file))
+		return ret;
+	else
+		return -EINVAL;
+#endif
 }
 
-
-void put_img(struct file *p_src_file)
+void put_img(struct file *p_src_file, struct ion_handle *p_ihdl)
 {
 #ifdef CONFIG_ANDROID_PMEM
 	if (p_src_file)
 		put_pmem_file(p_src_file);
 #endif
+
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	if (!IS_ERR_OR_NULL(p_ihdl))
+		ion_free(ppp_display_iclient, p_ihdl);
+#endif
 }
 
 
@@ -1318,7 +1347,8 @@
 	unsigned long srcp0_start, unsigned long srcp0_len,
 	unsigned long srcp1_start, unsigned long srcp1_len,
 	unsigned long dst_start, unsigned long dst_len,
-	struct file *p_src_file, struct file *p_dst_file)
+	struct file *p_src_file, struct file *p_dst_file,
+	struct ion_handle **src_ihdl, struct ion_handle **dst_ihdl)
 {
 	MDPIBUF iBuf;
 	u32 dst_width, dst_height;
@@ -1330,9 +1360,9 @@
 		req->src.format = mfd->fb_imgType;
 
 	if (mdp_ppp_verify_req(req)) {
-		printk(KERN_ERR "mdp_ppp: invalid image!\n");
-		put_img(p_src_file);
-		put_img(p_dst_file);
+		pr_err("mdp_ppp: invalid image!\n");
+		put_img(p_src_file, *src_ihdl);
+		put_img(p_dst_file, *dst_ihdl);
 		return -1;
 	}
 
@@ -1402,8 +1432,8 @@
 #if defined(CONFIG_FB_MSM_MDP31) || defined(CONFIG_FB_MSM_MDP303)
 		iBuf.mdpImg.mdpOp |= MDPOP_FG_PM_ALPHA;
 #else
-		put_img(p_src_file);
-		put_img(p_dst_file);
+		put_img(p_src_file, *src_ihdl);
+		put_img(p_dst_file, *dst_ihdl);
 		return -EINVAL;
 #endif
 	}
@@ -1413,8 +1443,8 @@
 		if ((req->src.format != MDP_Y_CBCR_H2V2) &&
 			(req->src.format != MDP_Y_CRCB_H2V2)) {
 #endif
-			put_img(p_src_file);
-			put_img(p_dst_file);
+			put_img(p_src_file, *src_ihdl);
+			put_img(p_dst_file, *dst_ihdl);
 			return -EINVAL;
 #ifdef CONFIG_FB_MSM_MDP31
 		}
@@ -1453,16 +1483,16 @@
 			printk(KERN_ERR
 				"%s: sharpening strength out of range\n",
 				__func__);
-			put_img(p_src_file);
-			put_img(p_dst_file);
+			put_img(p_src_file, *src_ihdl);
+			put_img(p_dst_file, *dst_ihdl);
 			return -EINVAL;
 		}
 
 		iBuf.mdpImg.mdpOp |= MDPOP_ASCALE | MDPOP_SHARPENING;
 		iBuf.mdpImg.sp_value = req->sharpening_strength & 0xff;
 #else
-		put_img(p_src_file);
-		put_img(p_dst_file);
+		put_img(p_src_file, *src_ihdl);
+		put_img(p_dst_file, *dst_ihdl);
 		return -EINVAL;
 #endif
 	}
@@ -1567,8 +1597,8 @@
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 	up(&mdp_ppp_mutex);
 
-	put_img(p_src_file);
-	put_img(p_dst_file);
+	put_img(p_src_file, *src_ihdl);
+	put_img(p_dst_file, *dst_ihdl);
 	return 0;
 }
 
@@ -1578,29 +1608,36 @@
 	unsigned long src_len = 0;
 	unsigned long dst_len = 0;
 	struct file *p_src_file = 0 , *p_dst_file = 0;
+	struct ion_handle *src_ihdl = NULL;
+	struct ion_handle *dst_ihdl = NULL;
+	struct msm_fb_data_type *mfd = info->par;
+	ppp_display_iclient = mfd->iclient;
 
 	if (req->flags & MDP_BLIT_SRC_GEM)
 		get_gem_img(&req->src, &src_start, &src_len);
 	else
-		get_img(&req->src, info, &src_start, &src_len, &p_src_file);
+		get_img(&req->src, req, info, &src_start, &src_len, &p_src_file,
+			&src_ihdl);
 	if (src_len == 0) {
-		printk(KERN_ERR "mdp_ppp: could not retrieve image from "
+		pr_err("mdp_ppp: could not retrieve source image from "
 		       "memory\n");
 		return -EINVAL;
 	}
 	if (req->flags & MDP_BLIT_DST_GEM)
 		get_gem_img(&req->dst, &dst_start, &dst_len);
 	else
-		get_img(&req->dst, info, &dst_start, &dst_len, &p_dst_file);
+		get_img(&req->dst, req, info, &dst_start, &dst_len, &p_dst_file,
+			&dst_ihdl);
+
 	if (dst_len == 0) {
-		put_img(p_src_file);
-		printk(KERN_ERR "mdp_ppp: could not retrieve image from "
+		put_img(p_src_file, src_ihdl);
+		pr_err("mdp_ppp: could not retrieve destination image from "
 		       "memory\n");
 		return -EINVAL;
 	}
 
 	return mdp_ppp_blit_addr(info, req, src_start, src_len, 0, 0, dst_start,
-		dst_len, p_src_file, p_dst_file);
+		dst_len, p_src_file, p_dst_file, &src_ihdl, &dst_ihdl);
 }
 
 static struct mdp_blit_req overlay_req;
@@ -1677,7 +1714,8 @@
 
 	ret = mdp_ppp_blit_addr(info, &overlay_req,
 		srcp0_addr, srcp0_size, srcp1_addr, srcp1_size,
-		info->fix.smem_start, info->fix.smem_len, NULL, NULL);
+		info->fix.smem_start, info->fix.smem_len, NULL, NULL,
+		NULL, NULL);
 
 	if (ret)
 		pr_err("%s:Blitting overlay failed(%d)\n", __func__, ret);
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 81a6e50..18ee3e6 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -1326,7 +1326,7 @@
 	fbi->fix.smem_start = (unsigned long)fbram_phys;
 
 	msm_iommu_map_contig_buffer(fbi->fix.smem_start,
-					DISPLAY_DOMAIN,
+					DISPLAY_READ_DOMAIN,
 					GEN_POOL,
 					fbi->fix.smem_len,
 					SZ_4K,
@@ -1334,7 +1334,7 @@
 					&(mfd->display_iova));
 
 	msm_iommu_map_contig_buffer(fbi->fix.smem_start,
-					ROTATOR_DOMAIN,
+					ROTATOR_SRC_DOMAIN,
 					GEN_POOL,
 					fbi->fix.smem_len,
 					SZ_4K,
diff --git a/include/linux/msm_audio_mvs.h b/include/linux/msm_audio_mvs.h
index 1807cb0..6fe5b70 100644
--- a/include/linux/msm_audio_mvs.h
+++ b/include/linux/msm_audio_mvs.h
@@ -9,10 +9,10 @@
 	(AUDIO_MAX_COMMON_IOCTL_NUM + 1), unsigned)
 
 /* MVS modes */
-#define MVS_MODE_IS733 0x1
-#define MVS_MODE_IS127 0x2
-#define MVS_MODE_4GV_NB 0x3
-#define MVS_MODE_4GV_WB 0x4
+#define MVS_MODE_IS733 0x1 /*QCELP 13K*/
+#define MVS_MODE_IS127 0x2 /*EVRC-8k*/
+#define MVS_MODE_4GV_NB 0x3 /*EVRC-B*/
+#define MVS_MODE_4GV_WB 0x4 /*EVRC-WB*/
 #define MVS_MODE_AMR 0x5
 #define MVS_MODE_EFR 0x6
 #define MVS_MODE_FR 0x7
@@ -47,12 +47,17 @@
 	MVS_AMR_MODE_UNDEF
 };
 
+/*The MVS VOC rate type is used to identify the rate of QCELP 13K(IS733),
+EVRC(IS127), 4GV, or 4GV-WB frame.*/
 enum msm_audio_voc_rate {
 		MVS_VOC_0_RATE, /* Blank frame */
 		MVS_VOC_8_RATE, /* 1/8 rate    */
 		MVS_VOC_4_RATE, /* 1/4 rate    */
 		MVS_VOC_2_RATE, /* 1/2 rate    */
-		MVS_VOC_1_RATE	/* Full rate   */
+		MVS_VOC_1_RATE,/* Full rate   */
+		MVS_VOC_ERASURE, /* erasure frame */
+		MVS_VOC_RATE_MAX,
+		MVS_VOC_RATE_UNDEF = MVS_VOC_RATE_MAX
 };
 
 enum msm_audio_amr_frame_type {
@@ -72,6 +77,11 @@
 	MVS_G711A_MODE_ALAW
 };
 
+enum msm_audio_g711_mode {
+	MVS_G711_MODE_MULAW,
+	MVS_G711_MODE_ALAW
+};
+
 enum mvs_g722_mode_type {
 	MVS_G722_MODE_01,
 	MVS_G722_MODE_02,
diff --git a/include/linux/msm_rotator.h b/include/linux/msm_rotator.h
index 0f15a8b..463e5ce 100644
--- a/include/linux/msm_rotator.h
+++ b/include/linux/msm_rotator.h
@@ -55,6 +55,7 @@
 #ifdef CONFIG_MSM_BUS_SCALING
 	struct msm_bus_scale_pdata *bus_scale_table;
 #endif
+	char rot_iommu_split_domain;
 };
 #endif
 
diff --git a/include/linux/qpnp/pwm.h b/include/linux/qpnp/pwm.h
new file mode 100644
index 0000000..de89a37
--- /dev/null
+++ b/include/linux/qpnp/pwm.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 __QPNP_PWM_H__
+#define __QPNP_PWM_H__
+
+#include <linux/pwm.h>
+
+/* usec: 19.2M, n=6, m=0, pre=2 */
+#define PM_PWM_PERIOD_MIN			7
+/* 1K, n=9, m=7, pre=6 */
+#define PM_PWM_PERIOD_MAX			(384 * USEC_PER_SEC)
+#define PM_PWM_LUT_RAMP_STEP_TIME_MAX		499
+#define PM_PWM_MAX_PAUSE_CNT			8191
+/*
+ * Formula from HSID,
+ * pause_time (hi/lo) = (pause_code - 1)*(duty_ms)
+ */
+#define PM_PWM_LUT_PAUSE_MAX \
+	((PM_PWM_MAX_PAUSE_CNT - 1) * PM_PWM_LUT_RAMP_STEP_TIME_MAX) /* ms */
+
+/* Flags for Look Up Table */
+#define PM_PWM_LUT_LOOP			0x01
+#define PM_PWM_LUT_RAMP_UP		0x02
+#define PM_PWM_LUT_REVERSE		0x04
+#define PM_PWM_LUT_PAUSE_HI_EN		0x08
+#define PM_PWM_LUT_PAUSE_LO_EN		0x10
+
+#define PM_PWM_LUT_NO_TABLE		0x20
+#define PM_PWM_LUT_USE_RAW_VALUE	0x40
+
+/*
+ * PWM frequency/period control
+ *
+ * PWM Frequency = ClockFrequency / (N * T)
+ *   or
+ * PWM Period = Clock Period * (N * T)
+ *   where
+ * N = 2^9 or 2^6 for 9-bit or 6-bit PWM size
+ * T = Pre-divide * 2^m, m = 0..7 (exponent)
+ */
+
+/*
+ * enum pm_pwm_size - PWM bit mode selection
+ * %PM_PWM_SIZE_6BIT - Select 6 bit mode; 64 levels
+ * %PM_PWM_SIZE_9BIT - Select 9 bit mode; 512 levels
+ */
+enum pm_pwm_size {
+	PM_PWM_SIZE_6BIT =	6,
+	PM_PWM_SIZE_9BIT =	9,
+};
+
+/*
+ * enum pm_pwm_clk - PWM clock selection
+ * %PM_PWM_CLK_1KHZ - 1KHz clock
+ * %PM_PWM_CLK_32KHZ - 32KHz clock
+ * %PM_PWM_CLK_19P2MHZ - 19.2MHz clock
+ * Note: Here 1KHz = 1024Hz
+ */
+enum pm_pwm_clk {
+	PM_PWM_CLK_1KHZ,
+	PM_PWM_CLK_32KHZ,
+	PM_PWM_CLK_19P2MHZ,
+};
+
+/* PWM pre-divider selection */
+enum pm_pwm_pre_div {
+	PM_PWM_PDIV_2,
+	PM_PWM_PDIV_3,
+	PM_PWM_PDIV_5,
+	PM_PWM_PDIV_6,
+};
+
+/*
+ * struct pwm_period_config - PWM period configuration
+ * @pwm_size: enum pm_pwm_size
+ * @clk: enum pm_pwm_clk
+ * @pre_div: enum pm_pwm_pre_div
+ * @pre_div_exp: exponent of 2 as part of pre-divider: 0..7
+ */
+struct pwm_period_config {
+	enum pm_pwm_size	pwm_size;
+	enum pm_pwm_clk		clk;
+	enum pm_pwm_pre_div	pre_div;
+	int			pre_div_exp;
+};
+
+/*
+ * struct pwm_duty_cycles - PWM duty cycle info
+ * duty_pcts - pointer to an array of duty percentage for a pwm period
+ * num_duty_pcts - total entries in duty_pcts array
+ * duty_ms - duty cycle time in ms
+ * start_idx - index in the LUT
+ */
+struct pwm_duty_cycles {
+	int *duty_pcts;
+	int num_duty_pcts;
+	int duty_ms;
+	int start_idx;
+};
+
+int pwm_config_period(struct pwm_device *pwm,
+			     struct pwm_period_config *pwm_p);
+
+int pwm_config_pwm_value(struct pwm_device *pwm, int pwm_value);
+
+/*
+ * lut_params: Lookup table (LUT) parameters
+ * @start_idx: start index in lookup table from 0 to MAX-1
+ * @idx_len: number of index
+ * @pause_lo: pause time in millisecond at low index
+ * @pause_hi: pause time in millisecond at high index
+ * @ramp_step_ms: time before loading next LUT pattern in millisecond
+ * @flags: control flags
+ */
+struct lut_params {
+	int start_idx;
+	int idx_len;
+	int lut_pause_hi;
+	int lut_pause_lo;
+	int ramp_step_ms;
+	int flags;
+};
+
+int pwm_lut_config(struct pwm_device *pwm, int period_us,
+		int duty_pct[], struct lut_params lut_params);
+
+int pwm_lut_enable(struct pwm_device *pwm, int start);
+
+/* Standard APIs supported */
+/*
+ * pwm_request - request a PWM device
+ * @pwm_id: PWM id or channel
+ * @label: the label to identify the user
+ */
+
+/*
+ * pwm_free - free a PWM device
+ * @pwm: the PWM device
+ */
+
+/*
+ * pwm_config - change a PWM device configuration
+ * @pwm: the PWM device
+ * @period_us: period in microsecond
+ * @duty_us: duty cycle in microsecond
+ */
+
+/*
+ * pwm_enable - start a PWM output toggling
+ * @pwm: the PWM device
+ */
+
+/*
+ * pwm_disable - stop a PWM output toggling
+ * @pwm: the PWM device
+ */
+
+#endif /* __QPNP_PWM_H__ */
diff --git a/include/linux/usb/android.h b/include/linux/usb/android.h
index 6d3c3ad..bf65ebb 100644
--- a/include/linux/usb/android.h
+++ b/include/linux/usb/android.h
@@ -20,6 +20,7 @@
 struct android_usb_platform_data {
 	int (*update_pid_and_serial_num)(uint32_t, const char *);
 	u32 swfi_latency;
+	u8 usb_core_id;
 };
 
 #endif	/* __LINUX_USB_ANDROID_H */
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 63ebdea..42f7349 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -2296,10 +2296,13 @@
 #define V4L2_EVENT_PRIVATE_START		0x08000000
 
 #define V4L2_EVENT_MSM_VIDC_START	(V4L2_EVENT_PRIVATE_START + 0x00001000)
-#define V4L2_EVENT_MSM_VIDC_FLUSH_DONE	(V4L2_EVENT_PRIVATE_START + 1)
-#define V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED	\
-		(V4L2_EVENT_PRIVATE_START + 2)
-#define V4L2_EVENT_MSM_VIDC_CLOSE_DONE	(V4L2_EVENT_PRIVATE_START + 3)
+#define V4L2_EVENT_MSM_VIDC_FLUSH_DONE	(V4L2_EVENT_MSM_VIDC_START + 1)
+#define V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_SUFFICIENT	\
+		(V4L2_EVENT_MSM_VIDC_START + 2)
+#define V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_INSUFFICIENT	\
+		(V4L2_EVENT_MSM_VIDC_START + 3)
+#define V4L2_EVENT_MSM_VIDC_CLOSE_DONE	(V4L2_EVENT_MSM_VIDC_START + 4)
+
 
 /* Payload for V4L2_EVENT_VSYNC */
 struct v4l2_event_vsync {
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 81b6a40..48058e6 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -195,6 +195,24 @@
 #define MSM_CAM_IOCTL_ISPIF_IO_CFG \
 	_IOR(MSM_CAM_IOCTL_MAGIC, 54, struct ispif_cfg_data *)
 
+#define MSM_CAM_IOCTL_STATS_REQBUF \
+	_IOR(MSM_CAM_IOCTL_MAGIC, 55, struct msm_stats_reqbuf *)
+
+#define MSM_CAM_IOCTL_STATS_ENQUEUEBUF \
+	_IOR(MSM_CAM_IOCTL_MAGIC, 56, struct msm_stats_buf_info *)
+
+#define MSM_CAM_IOCTL_STATS_FLUSH_BUFQ \
+	_IOR(MSM_CAM_IOCTL_MAGIC, 57, struct msm_stats_flush_bufq *)
+
+struct msm_stats_reqbuf {
+	int num_buf;		/* how many buffers requested */
+	int stats_type;	/* stats type */
+};
+
+struct msm_stats_flush_bufq {
+	int stats_type;	/* enum msm_stats_enum_type */
+};
+
 struct msm_mctl_pp_cmd {
 	int32_t  id;
 	uint16_t length;
@@ -515,6 +533,36 @@
 #define FRAME_RAW_SNAPSHOT		4
 #define FRAME_MAX			5
 
+enum msm_stats_enum_type {
+	MSM_STATS_TYPE_AEC, /* legacy based AEC */
+	MSM_STATS_TYPE_AF,  /* legacy based AF */
+	MSM_STATS_TYPE_AWB, /* legacy based AWB */
+	MSM_STATS_TYPE_RS,  /* legacy based RS */
+	MSM_STATS_TYPE_CS,  /* legacy based CS */
+	MSM_STATS_TYPE_IHIST,   /* legacy based HIST */
+	MSM_STATS_TYPE_SKIN,    /* legacy based SKIN */
+	MSM_STATS_TYPE_BG,  /* Bayer Grids */
+	MSM_STATS_TYPE_BF,  /* Bayer Focus */
+	MSM_STATS_TYPE_BHIST,   /* Bayer Hist */
+	MSM_STATS_TYPE_AE_AW,   /* legacy stats for vfe 2.x*/
+	MSM_STATS_TYPE_MAX  /* MAX */
+};
+
+struct msm_stats_buf_info {
+	int type; /* msm_stats_enum_type */
+	int fd;
+	void *vaddr;
+	uint32_t offset;
+	uint32_t len;
+	uint32_t y_off;
+	uint32_t cbcr_off;
+	uint32_t planar0_off;
+	uint32_t planar1_off;
+	uint32_t planar2_off;
+	uint8_t active;
+	int buf_idx;
+};
+
 struct msm_pmem_info {
 	int type;
 	int fd;
@@ -678,6 +726,7 @@
 	int length;
 	struct ion_handle *handle;
 	uint32_t frame_id;
+	int buf_idx;
 };
 #define MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT 0
 /* video capture mode in VIDIOC_S_PARM */
diff --git a/include/media/msm_isp.h b/include/media/msm_isp.h
index 6547795..1f3527b 100644
--- a/include/media/msm_isp.h
+++ b/include/media/msm_isp.h
@@ -203,6 +203,9 @@
 #define VFE_CMD_CAPTURE_RAW                             136
 #define VFE_CMD_STOP_LIVESHOT                           137
 #define VFE_CMD_RECONFIG_VFE                            138
+#define VFE_CMD_STATS_REQBUF                            139
+#define VFE_CMD_STATS_ENQUEUEBUF                        140
+#define VFE_CMD_STATS_FLUSH_BUFQ                        141
 
 struct msm_isp_cmd {
 	int32_t  id;
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index a91c97c..0a89c11 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -1,6 +1,7 @@
 /*
    HIDP implementation for Linux Bluetooth stack (BlueZ).
    Copyright (C) 2003-2004 Marcel Holtmann <marcel@holtmann.org>
+   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 as
@@ -92,6 +93,26 @@
 	return NULL;
 }
 
+static struct device *hidp_get_device(struct hidp_session *session)
+{
+	bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src;
+	bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst;
+	struct device *device = NULL;
+	struct hci_dev *hdev;
+
+	hdev = hci_get_route(dst, src);
+	if (!hdev)
+		return NULL;
+
+	session->conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
+	if (session->conn)
+		device = &session->conn->dev;
+
+	hci_dev_put(hdev);
+
+	return device;
+}
+
 static void __hidp_link_session(struct hidp_session *session)
 {
 	__module_get(THIS_MODULE);
@@ -102,7 +123,11 @@
 
 static void __hidp_unlink_session(struct hidp_session *session)
 {
-	hci_conn_put_device(session->conn);
+	struct device *dev;
+
+	dev = hidp_get_device(session);
+	if (dev)
+		hci_conn_put_device(session->conn);
 
 	list_del(&session->list);
 	module_put(THIS_MODULE);
@@ -635,26 +660,6 @@
 	return 0;
 }
 
-static struct device *hidp_get_device(struct hidp_session *session)
-{
-	bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src;
-	bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst;
-	struct device *device = NULL;
-	struct hci_dev *hdev;
-
-	hdev = hci_get_route(dst, src);
-	if (!hdev)
-		return NULL;
-
-	session->conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
-	if (session->conn)
-		device = &session->conn->dev;
-
-	hci_dev_put(hdev);
-
-	return device;
-}
-
 static int hidp_setup_input(struct hidp_session *session,
 				struct hidp_connadd_req *req)
 {
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index d07cdff..a0cad55 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -1222,7 +1222,7 @@
 {
 	int ret;
 
-	if (!cpu_is_msm8930() && !cpu_is_msm8627()) {
+	if (!cpu_is_msm8930() && !cpu_is_msm8930aa() && !cpu_is_msm8627()) {
 		pr_err("%s: Not the right machine type\n", __func__);
 		return -ENODEV ;
 	}
@@ -1260,7 +1260,7 @@
 
 static void __exit msm8930_audio_exit(void)
 {
-	if (!cpu_is_msm8930() && !cpu_is_msm8627()) {
+	if (!cpu_is_msm8930() && !cpu_is_msm8930aa() && !cpu_is_msm8627()) {
 		pr_err("%s: Not the right machine type\n", __func__);
 		return ;
 	}