Merge "msm: ipa: disable IPA dropping of packets on WLAN TX pipes"
diff --git a/arch/arm/boot/dts/msm8610-coresight.dtsi b/arch/arm/boot/dts/msm8610-coresight.dtsi
index 2515e62..3fbd6fc 100644
--- a/arch/arm/boot/dts/msm8610-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8610-coresight.dtsi
@@ -23,6 +23,7 @@
 		coresight-id = <0>;
 		coresight-name = "coresight-tmc-etr";
 		coresight-nr-inports = <1>;
+		coresight-ctis = <&cti0 &cti8>;
 	};
 
 	tpiu: tpiu@fc320000 {
@@ -60,6 +61,7 @@
 		coresight-child-list = <&replicator>;
 		coresight-child-ports = <0>;
 		coresight-default-sink;
+		coresight-ctis = <&cti0 &cti8>;
 	};
 
 	funnel_merg: funnel@fc323000 {
@@ -203,4 +205,134 @@
 
 		qcom,blk-size = <3>;
 	};
+
+	cti0: cti@fc310000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc310000 0x1000>;
+		reg-names = "cti0-base";
+
+		coresight-id = <14>;
+		coresight-name = "coresight-cti0";
+		coresight-nr-inports = <0>;
+	};
+
+	cti1: cti@fc311000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc311000 0x1000>;
+		reg-names = "cti1-base";
+
+		coresight-id = <15>;
+		coresight-name = "coresight-cti1";
+		coresight-nr-inports = <0>;
+	};
+
+	cti2: cti@fc312000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc312000 0x1000>;
+		reg-names = "cti2-base";
+
+		coresight-id = <16>;
+		coresight-name = "coresight-cti2";
+		coresight-nr-inports = <0>;
+	};
+
+	cti3: cti@fc313000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc313000 0x1000>;
+		reg-names = "cti3-base";
+
+		coresight-id = <17>;
+		coresight-name = "coresight-cti3";
+		coresight-nr-inports = <0>;
+	};
+
+	cti4: cti@fc314000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc314000 0x1000>;
+		reg-names = "cti4-base";
+
+		coresight-id = <18>;
+		coresight-name = "coresight-cti4";
+		coresight-nr-inports = <0>;
+	};
+
+	cti5: cti@fc315000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc315000 0x1000>;
+		reg-names = "cti5-base";
+
+		coresight-id = <19>;
+		coresight-name = "coresight-cti5";
+		coresight-nr-inports = <0>;
+	};
+
+	cti6: cti@fc316000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc316000 0x1000>;
+		reg-names = "cti6-base";
+
+		coresight-id = <20>;
+		coresight-name = "coresight-cti6";
+		coresight-nr-inports = <0>;
+	};
+
+	cti7: cti@fc317000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc317000 0x1000>;
+		reg-names = "cti7-base";
+
+		coresight-id = <21>;
+		coresight-name = "coresight-cti7";
+		coresight-nr-inports = <0>;
+	};
+
+	cti8: cti@fc318000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc318000 0x1000>;
+		reg-names = "cti8-base";
+
+		coresight-id = <22>;
+		coresight-name = "coresight-cti8";
+		coresight-nr-inports = <0>;
+	};
+
+	cti_cpu0: cti@fc351000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc351000 0x1000>;
+		reg-names = "cti-cpu0-base";
+
+		coresight-id = <23>;
+		coresight-name = "coresight-cti-cpu0";
+		coresight-nr-inports = <0>;
+	};
+
+	cti_cpu1: cti@fc352000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc352000 0x1000>;
+		reg-names = "cti-cpu1-base";
+
+		coresight-id = <24>;
+		coresight-name = "coresight-cti-cpu1";
+		coresight-nr-inports = <0>;
+	};
+
+	cti_cpu2: cti@fc353000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc353000 0x1000>;
+		reg-names = "cti-cpu2-base";
+
+		coresight-id = <25>;
+		coresight-name = "coresight-cti-cpu2";
+		coresight-nr-inports = <0>;
+	};
+
+	cti_cpu3: cti@fc354000 {
+		compatible = "arm,coresight-cti";
+		reg = <0xfc354000 0x1000>;
+		reg-names = "cti-cpu3-base";
+
+		coresight-id = <26>;
+		coresight-name = "coresight-cti-cpu3";
+		coresight-nr-inports = <0>;
+	};
 };
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 2f5f7f0..d2c97b1 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -226,6 +226,8 @@
 CONFIG_BT_BNEP_PROTO_FILTER=y
 CONFIG_BT_HIDP=y
 CONFIG_BT_HCISMD=y
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_ATH3K=y
 CONFIG_MSM_BT_POWER=y
 CONFIG_CFG80211=y
 CONFIG_NL80211_TESTMODE=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 4aebfdb..c9d6112 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -230,6 +230,8 @@
 CONFIG_BT_BNEP_PROTO_FILTER=y
 CONFIG_BT_HIDP=y
 CONFIG_BT_HCISMD=y
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_ATH3K=y
 CONFIG_MSM_BT_POWER=y
 CONFIG_CFG80211=y
 CONFIG_NL80211_TESTMODE=y
diff --git a/arch/arm/mach-msm/gpiomux.c b/arch/arm/mach-msm/gpiomux.c
index 4714210..1f7d56a 100644
--- a/arch/arm/mach-msm/gpiomux.c
+++ b/arch/arm/mach-msm/gpiomux.c
@@ -13,7 +13,9 @@
 #include <linux/of.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <linux/io.h>
 #include <mach/gpiomux.h>
+#include <mach/msm_iomap.h>
 
 struct msm_gpiomux_rec {
 	struct gpiomux_setting *sets[GPIOMUX_NSETTINGS];
@@ -121,6 +123,13 @@
 }
 EXPORT_SYMBOL(msm_gpiomux_put);
 
+void msm_tlmm_misc_reg_write(enum msm_tlmm_misc_reg misc_reg, int val)
+{
+	writel_relaxed(val, MSM_TLMM_BASE + misc_reg);
+	/* ensure the write completes before returning */
+	mb();
+}
+
 int msm_gpiomux_init(size_t ngpio)
 {
 	if (!ngpio)
diff --git a/arch/arm/mach-msm/include/mach/gpiomux.h b/arch/arm/mach-msm/include/mach/gpiomux.h
index 5ffcabb..9aae3fb 100644
--- a/arch/arm/mach-msm/include/mach/gpiomux.h
+++ b/arch/arm/mach-msm/include/mach/gpiomux.h
@@ -109,6 +109,14 @@
 	size_t                     ncfg;
 };
 
+/* Provide an enum and an API to write to misc TLMM registers */
+enum msm_tlmm_misc_reg {
+	TLMM_ETM_MODE_REG = 0x2014,
+	TLMM_SDC2_HDRV_PULL_CTL = 0x2048,
+};
+
+void msm_tlmm_misc_reg_write(enum msm_tlmm_misc_reg misc_reg, int val);
+
 #ifdef CONFIG_MSM_GPIOMUX
 
 /* Before using gpiomux, initialize the subsystem by telling it how many
diff --git a/drivers/media/platform/msm/camera_v2/Kconfig b/drivers/media/platform/msm/camera_v2/Kconfig
index e4777e6..d1e9b9e 100644
--- a/drivers/media/platform/msm/camera_v2/Kconfig
+++ b/drivers/media/platform/msm/camera_v2/Kconfig
@@ -109,6 +109,15 @@
 		1280 * 270. It does not support auto focus. It supports
 		few special effects like saturation.
 
+config OV8825
+	bool "OmniVision OV8825 (BAYER 8MP)"
+	depends on MSMB_CAMERA
+	---help---
+		OmniVision 8 MP Bayer Sensor with auto focus.uses
+		2 mipi lanes, preview config = 1632*1224 30 fps,
+		snapshot config = 3264 * 2448 at 18 fps.
+		2 lanes max fps is 18, 4 lanes max fps is 24.
+
 config MSM_V4L2_VIDEO_OVERLAY_DEVICE
 	tristate "Qualcomm MSM V4l2 video overlay device"
 	---help---
@@ -119,7 +128,7 @@
 
 config MSMB_JPEG
 	tristate "Qualcomm MSM Jpeg Encoder Engine support"
-	depends on MSMB_CAMERA && ARCH_MSM8974
+	depends on MSMB_CAMERA && (ARCH_MSM8974 || ARCH_MSM8226)
 	---help---
 	  Enable support for Jpeg Encoder/Decoder
 	  Engine for 8974.
diff --git a/drivers/media/platform/msm/camera_v2/sensor/Makefile b/drivers/media/platform/msm/camera_v2/sensor/Makefile
index 6f941f7..62911bf 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/Makefile
+++ b/drivers/media/platform/msm/camera_v2/sensor/Makefile
@@ -7,5 +7,6 @@
 obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor.o
 obj-$(CONFIG_S5K3L1YX) += s5k3l1yx.o
 obj-$(CONFIG_IMX135) += imx135.o
+obj-$(CONFIG_OV8825) += ov8825.o
 obj-$(CONFIG_OV2720) += ov2720.o
 obj-$(CONFIG_MT9M114) += mt9m114.o
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ov8825.c b/drivers/media/platform/msm/camera_v2/sensor/ov8825.c
new file mode 100644
index 0000000..b56eb10
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/ov8825.c
@@ -0,0 +1,167 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include "msm_sensor.h"
+#define OV8825_SENSOR_NAME "ov8825"
+DEFINE_MSM_MUTEX(ov8825_mut);
+
+static struct msm_sensor_ctrl_t ov8825_s_ctrl;
+
+static struct msm_sensor_power_setting ov8825_power_setting[] = {
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VIO,
+		.config_val = 0,
+		.delay = 5,
+	},
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VANA,
+		.config_val = 0,
+		.delay = 5,
+	},
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VDIG,
+		.config_val = 0,
+		.delay = 5,
+	},
+	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VAF,
+		.config_val = 0,
+		.delay = 15,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_STANDBY,
+		.config_val = GPIO_OUT_LOW,
+		.delay = 15,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_RESET,
+		.config_val = GPIO_OUT_LOW,
+		.delay = 40,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_STANDBY,
+		.config_val = GPIO_OUT_HIGH,
+		.delay = 40,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_RESET,
+		.config_val = GPIO_OUT_HIGH,
+		.delay = 40,
+	},
+	{
+		.seq_type = SENSOR_CLK,
+		.seq_val = SENSOR_CAM_MCLK,
+		.config_val = 24000000,
+		.delay = 5,
+	},
+	{
+		.seq_type = SENSOR_I2C_MUX,
+		.seq_val = 0,
+		.config_val = 0,
+		.delay = 0,
+	},
+};
+
+static struct v4l2_subdev_info ov8825_subdev_info[] = {
+	{
+		.code   = V4L2_MBUS_FMT_SBGGR10_1X10,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.fmt    = 1,
+		.order    = 0,
+	},
+};
+
+static const struct i2c_device_id ov8825_i2c_id[] = {
+	{OV8825_SENSOR_NAME, (kernel_ulong_t)&ov8825_s_ctrl},
+	{ }
+};
+
+static struct i2c_driver ov8825_i2c_driver = {
+	.id_table = ov8825_i2c_id,
+	.probe  = msm_sensor_i2c_probe,
+	.driver = {
+		.name = OV8825_SENSOR_NAME,
+	},
+};
+
+static struct msm_camera_i2c_client ov8825_sensor_i2c_client = {
+	.addr_type = MSM_CAMERA_I2C_WORD_ADDR,
+};
+
+static const struct of_device_id ov8825_dt_match[] = {
+	{.compatible = "qcom,ov8825", .data = &ov8825_s_ctrl},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, ov8825_dt_match);
+
+static struct platform_driver ov8825_platform_driver = {
+	.driver = {
+		.name = "qcom,ov8825",
+		.owner = THIS_MODULE,
+		.of_match_table = ov8825_dt_match,
+	},
+};
+
+static int32_t ov8825_platform_probe(struct platform_device *pdev)
+{
+	int32_t rc = 0;
+	const struct of_device_id *match;
+	match = of_match_device(ov8825_dt_match, &pdev->dev);
+	rc = msm_sensor_platform_probe(pdev, match->data);
+	return rc;
+}
+
+static int __init ov8825_init_module(void)
+{
+	int32_t rc = 0;
+	pr_info("%s:%d\n", __func__, __LINE__);
+	rc = platform_driver_probe(&ov8825_platform_driver,
+		ov8825_platform_probe);
+	if (!rc)
+		return rc;
+	pr_err("%s:%d rc %d\n", __func__, __LINE__, rc);
+	return i2c_add_driver(&ov8825_i2c_driver);
+}
+
+static void __exit ov8825_exit_module(void)
+{
+	pr_info("%s:%d\n", __func__, __LINE__);
+	if (ov8825_s_ctrl.pdev) {
+		msm_sensor_free_sensor_data(&ov8825_s_ctrl);
+		platform_driver_unregister(&ov8825_platform_driver);
+	} else
+		i2c_del_driver(&ov8825_i2c_driver);
+	return;
+}
+
+static struct msm_sensor_ctrl_t ov8825_s_ctrl = {
+	.sensor_i2c_client = &ov8825_sensor_i2c_client,
+	.power_setting_array.power_setting = ov8825_power_setting,
+	.power_setting_array.size = ARRAY_SIZE(ov8825_power_setting),
+	.msm_sensor_mutex = &ov8825_mut,
+	.sensor_v4l2_subdev_info = ov8825_subdev_info,
+	.sensor_v4l2_subdev_info_size = ARRAY_SIZE(ov8825_subdev_info),
+};
+
+module_init(ov8825_init_module);
+module_exit(ov8825_exit_module);
+MODULE_DESCRIPTION("ov8825");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/dvb/adapter/mpq_stream_buffer.c b/drivers/media/platform/msm/dvb/adapter/mpq_stream_buffer.c
index 6ec1994..76ce0c0 100644
--- a/drivers/media/platform/msm/dvb/adapter/mpq_stream_buffer.c
+++ b/drivers/media/platform/msm/dvb/adapter/mpq_stream_buffer.c
@@ -19,8 +19,6 @@
 #include "mpq_stream_buffer.h"
 
 
-
-
 int mpq_streambuffer_init(
 		struct mpq_streambuffer *sbuff,
 		enum mpq_streambuffer_mode mode,
@@ -29,7 +27,8 @@
 		void *packet_buff,
 		size_t packet_buff_size)
 {
-	if ((NULL == sbuff) || (NULL == data_buffers) || (NULL == packet_buff))
+	if ((NULL == sbuff) || (NULL == data_buffers) ||
+		(NULL == packet_buff) || (data_buff_num == 0))
 		return -EINVAL;
 
 	if (data_buff_num > 1) {
@@ -41,7 +40,7 @@
 			data_buffers,
 			data_buff_num *
 			sizeof(struct mpq_streambuffer_buffer_desc));
-	} else if (data_buff_num == 1) {
+	} else {
 		if (mode != MPQ_STREAMBUFFER_BUFFER_MODE_RING)
 			return -EINVAL;
 		/* Single ring-buffer */
@@ -58,12 +57,38 @@
 }
 EXPORT_SYMBOL(mpq_streambuffer_init);
 
+void mpq_streambuffer_terminate(struct mpq_streambuffer *sbuff)
+{
+	spin_lock(&sbuff->packet_data.lock);
+	spin_lock(&sbuff->raw_data.lock);
+	sbuff->packet_data.error = -ENODEV;
+	sbuff->raw_data.error = -ENODEV;
+	spin_unlock(&sbuff->raw_data.lock);
+	spin_unlock(&sbuff->packet_data.lock);
+
+	wake_up_all(&sbuff->raw_data.queue);
+	wake_up_all(&sbuff->packet_data.queue);
+}
+EXPORT_SYMBOL(mpq_streambuffer_terminate);
 
 ssize_t mpq_streambuffer_pkt_next(
 		struct mpq_streambuffer *sbuff,
 		ssize_t idx, size_t *pktlen)
 {
-	return dvb_ringbuffer_pkt_next(&sbuff->packet_data, idx, pktlen);
+	ssize_t packet_idx;
+
+	spin_lock(&sbuff->packet_data.lock);
+
+	/* buffer was released, return no packet available */
+	if (sbuff->packet_data.error == -ENODEV) {
+		spin_unlock(&sbuff->packet_data.lock);
+		return -ENODEV;
+	}
+
+	packet_idx = dvb_ringbuffer_pkt_next(&sbuff->packet_data, idx, pktlen);
+	spin_unlock(&sbuff->packet_data.lock);
+
+	return packet_idx;
 }
 EXPORT_SYMBOL(mpq_streambuffer_pkt_next);
 
@@ -77,6 +102,14 @@
 	size_t ret;
 	size_t read_len;
 
+	spin_lock(&sbuff->packet_data.lock);
+
+	/* buffer was released, return no packet available */
+	if (sbuff->packet_data.error == -ENODEV) {
+		spin_unlock(&sbuff->packet_data.lock);
+		return -ENODEV;
+	}
+
 	/* read-out the packet header first */
 	ret = dvb_ringbuffer_pkt_read(
 				&sbuff->packet_data, idx, 0,
@@ -84,8 +117,10 @@
 				sizeof(struct mpq_streambuffer_packet_header));
 
 	/* verify length, at least packet header should exist */
-	if (ret != sizeof(struct mpq_streambuffer_packet_header))
+	if (ret != sizeof(struct mpq_streambuffer_packet_header)) {
+		spin_unlock(&sbuff->packet_data.lock);
 		return -EINVAL;
+	}
 
 	read_len = ret;
 
@@ -98,12 +133,16 @@
 				user_data,
 				packet->user_data_len);
 
-		if (ret < 0)
+		if (ret < 0) {
+			spin_unlock(&sbuff->packet_data.lock);
 			return ret;
+		}
 
 		read_len += ret;
 	}
 
+	spin_unlock(&sbuff->packet_data.lock);
+
 	return read_len;
 }
 EXPORT_SYMBOL(mpq_streambuffer_pkt_read);
@@ -120,12 +159,22 @@
 	if (NULL == sbuff)
 		return -EINVAL;
 
+	spin_lock(&sbuff->packet_data.lock);
+
+	/* check if buffer was released */
+	if (sbuff->packet_data.error == -ENODEV) {
+		spin_unlock(&sbuff->packet_data.lock);
+		return -ENODEV;
+	}
+
 	/* read-out the packet header first */
 	ret = dvb_ringbuffer_pkt_read(&sbuff->packet_data, idx,
 			0,
 			(u8 *)&packet,
 			sizeof(struct mpq_streambuffer_packet_header));
 
+	spin_unlock(&sbuff->packet_data.lock);
+
 	if (ret != sizeof(struct mpq_streambuffer_packet_header))
 		return -EINVAL;
 
@@ -138,6 +187,17 @@
 			return ret;
 	}
 
+	spin_lock(&sbuff->packet_data.lock);
+	spin_lock(&sbuff->raw_data.lock);
+
+	/* check if buffer was released */
+	if ((sbuff->packet_data.error == -ENODEV) ||
+		(sbuff->raw_data.error == -ENODEV)) {
+		spin_unlock(&sbuff->raw_data.lock);
+		spin_unlock(&sbuff->packet_data.lock);
+		return -ENODEV;
+	}
+
 	/* Move read pointer to the next linear buffer for subsequent reads */
 	if ((MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR == sbuff->mode) &&
 		(packet.raw_data_len > 0)) {
@@ -159,6 +219,9 @@
 	/* Now clear the packet from the packet header */
 	dvb_ringbuffer_pkt_dispose(&sbuff->packet_data, idx);
 
+	spin_unlock(&sbuff->raw_data.lock);
+	spin_unlock(&sbuff->packet_data.lock);
+
 	if (sbuff->cb)
 		sbuff->cb(sbuff, sbuff->cb_user_data);
 
@@ -177,12 +240,22 @@
 	if ((NULL == sbuff) || (NULL == packet))
 		return -EINVAL;
 
+	spin_lock(&sbuff->packet_data.lock);
+
+	/* check if buffer was released */
+	if (sbuff->packet_data.error == -ENODEV) {
+		spin_unlock(&sbuff->packet_data.lock);
+		return -ENODEV;
+	}
+
 	len = sizeof(struct mpq_streambuffer_packet_header) +
 		packet->user_data_len;
 
 	/* Make sure enough space available for packet header */
-	if (dvb_ringbuffer_free(&sbuff->packet_data) < len)
+	if (dvb_ringbuffer_free(&sbuff->packet_data) < len) {
+		spin_unlock(&sbuff->packet_data.lock);
 		return -ENOSPC;
+	}
 
 	/* Starting writing packet header */
 	idx = dvb_ringbuffer_pkt_start(&sbuff->packet_data, len);
@@ -202,20 +275,22 @@
 	/* Move write pointer to next linear buffer for subsequent writes */
 	if ((MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR == sbuff->mode) &&
 		(packet->raw_data_len > 0)) {
-		if (sbuff->pending_buffers_count == sbuff->buffers_num)
+		if (sbuff->pending_buffers_count == sbuff->buffers_num) {
+			spin_unlock(&sbuff->packet_data.lock);
 			return -ENOSPC;
+		}
 		DVB_RINGBUFFER_PUSH(&sbuff->raw_data,
 				sizeof(struct mpq_streambuffer_buffer_desc));
 		sbuff->pending_buffers_count++;
 	}
 
+	spin_unlock(&sbuff->packet_data.lock);
 	wake_up_all(&sbuff->packet_data.queue);
 
 	return 0;
 }
 EXPORT_SYMBOL(mpq_streambuffer_pkt_write);
 
-
 ssize_t mpq_streambuffer_data_write(
 			struct mpq_streambuffer *sbuff,
 			const u8 *buf, size_t len)
@@ -225,15 +300,27 @@
 	if ((NULL == sbuff) || (NULL == buf))
 		return -EINVAL;
 
+	spin_lock(&sbuff->raw_data.lock);
+
+	/* check if buffer was released */
+	if (sbuff->raw_data.error == -ENODEV) {
+		spin_unlock(&sbuff->raw_data.lock);
+		return -ENODEV;
+	}
+
 	if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode) {
-		if (unlikely(dvb_ringbuffer_free(&sbuff->raw_data) < len))
+		if (unlikely(dvb_ringbuffer_free(&sbuff->raw_data) < len)) {
+			spin_unlock(&sbuff->raw_data.lock);
 			return -ENOSPC;
+		}
 		/*
 		 * Secure buffers are not permitted to be mapped into kernel
 		 * memory, and so buffer base address may be NULL
 		 */
-		if (NULL == sbuff->raw_data.data)
+		if (NULL == sbuff->raw_data.data) {
+			spin_unlock(&sbuff->raw_data.lock);
 			return -EPERM;
+		}
 		res = dvb_ringbuffer_write(&sbuff->raw_data, buf, len);
 		wake_up_all(&sbuff->raw_data.queue);
 	} else {
@@ -247,8 +334,10 @@
 		 * Secure buffers are not permitted to be mapped into kernel
 		 * memory, and so buffer base address may be NULL
 		 */
-		if (NULL == desc->base)
+		if (NULL == desc->base) {
+			spin_unlock(&sbuff->raw_data.lock);
 			return -EPERM;
+		}
 
 		if ((sbuff->pending_buffers_count == sbuff->buffers_num) ||
 			((desc->size - desc->write_ptr) < len)) {
@@ -259,6 +348,7 @@
 				sbuff->buffers_num,
 				desc->write_ptr,
 				desc->size);
+			spin_unlock(&sbuff->raw_data.lock);
 			return -ENOSPC;
 		}
 		memcpy(desc->base + desc->write_ptr, buf, len);
@@ -266,6 +356,7 @@
 		res = len;
 	}
 
+	spin_unlock(&sbuff->raw_data.lock);
 	return res;
 }
 EXPORT_SYMBOL(mpq_streambuffer_data_write);
@@ -278,9 +369,19 @@
 	if (NULL == sbuff)
 		return -EINVAL;
 
+	spin_lock(&sbuff->raw_data.lock);
+
+	/* check if buffer was released */
+	if (sbuff->raw_data.error == -ENODEV) {
+		spin_unlock(&sbuff->raw_data.lock);
+		return -ENODEV;
+	}
+
 	if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode) {
-		if (unlikely(dvb_ringbuffer_free(&sbuff->raw_data) < len))
+		if (unlikely(dvb_ringbuffer_free(&sbuff->raw_data) < len)) {
+			spin_unlock(&sbuff->raw_data.lock);
 			return -ENOSPC;
+		}
 
 		DVB_RINGBUFFER_PUSH(&sbuff->raw_data, len);
 		wake_up_all(&sbuff->raw_data.queue);
@@ -295,11 +396,13 @@
 			MPQ_DVB_ERR_PRINT(
 				"%s: No space available!\n",
 				__func__);
+			spin_unlock(&sbuff->raw_data.lock);
 			return -ENOSPC;
 		}
 		desc->write_ptr += len;
 	}
 
+	spin_unlock(&sbuff->raw_data.lock);
 	return 0;
 }
 EXPORT_SYMBOL(mpq_streambuffer_data_write_deposit);
@@ -314,13 +417,23 @@
 	if ((NULL == sbuff) || (NULL == buf))
 		return -EINVAL;
 
+	spin_lock(&sbuff->raw_data.lock);
+
+	/* check if buffer was released */
+	if (sbuff->raw_data.error == -ENODEV) {
+		spin_unlock(&sbuff->raw_data.lock);
+		return -ENODEV;
+	}
+
 	if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode) {
 		/*
 		 * Secure buffers are not permitted to be mapped into kernel
 		 * memory, and so buffer base address may be NULL
 		 */
-		if (NULL == sbuff->raw_data.data)
+		if (NULL == sbuff->raw_data.data) {
+			spin_unlock(&sbuff->raw_data.lock);
 			return -EPERM;
+		}
 
 		actual_len = dvb_ringbuffer_avail(&sbuff->raw_data);
 		if (actual_len < len)
@@ -340,8 +453,10 @@
 		 * Secure buffers are not permitted to be mapped into kernel
 		 * memory, and so buffer base address may be NULL
 		 */
-		if (NULL == desc->base)
+		if (NULL == desc->base) {
+			spin_unlock(&sbuff->raw_data.lock);
 			return -EPERM;
+		}
 
 		actual_len = (desc->write_ptr - desc->read_ptr);
 		if (actual_len < len)
@@ -350,6 +465,7 @@
 		desc->read_ptr += len;
 	}
 
+	spin_unlock(&sbuff->raw_data.lock);
 	return len;
 }
 EXPORT_SYMBOL(mpq_streambuffer_data_read);
@@ -364,6 +480,10 @@
 	if ((NULL == sbuff) || (NULL == buf))
 		return -EINVAL;
 
+	/* check if buffer was released */
+	if (sbuff->raw_data.error == -ENODEV)
+		return -ENODEV;
+
 	if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode) {
 		/*
 		 * Secure buffers are not permitted to be mapped into kernel
@@ -397,6 +517,7 @@
 			len = actual_len;
 		if (copy_to_user(buf, desc->base + desc->read_ptr, len))
 			return -EFAULT;
+
 		desc->read_ptr += len;
 	}
 
@@ -404,7 +525,6 @@
 }
 EXPORT_SYMBOL(mpq_streambuffer_data_read_user);
 
-
 int mpq_streambuffer_data_read_dispose(
 			struct mpq_streambuffer *sbuff,
 			size_t len)
@@ -412,9 +532,19 @@
 	if (NULL == sbuff)
 		return -EINVAL;
 
+	spin_lock(&sbuff->raw_data.lock);
+
+	/* check if buffer was released */
+	if (sbuff->raw_data.error == -ENODEV) {
+		spin_unlock(&sbuff->raw_data.lock);
+		return -ENODEV;
+	}
+
 	if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode) {
-		if (unlikely(dvb_ringbuffer_avail(&sbuff->raw_data) < len))
+		if (unlikely(dvb_ringbuffer_avail(&sbuff->raw_data) < len)) {
+			spin_unlock(&sbuff->raw_data.lock);
 			return -EINVAL;
+		}
 
 		DVB_RINGBUFFER_SKIP(&sbuff->raw_data, len);
 		wake_up_all(&sbuff->raw_data.queue);
@@ -429,6 +559,8 @@
 			desc->read_ptr += len;
 	}
 
+	spin_unlock(&sbuff->raw_data.lock);
+
 	return 0;
 }
 EXPORT_SYMBOL(mpq_streambuffer_data_read_dispose);
@@ -444,6 +576,14 @@
 	if ((NULL == sbuff) || (NULL == handle))
 		return -EINVAL;
 
+	spin_lock(&sbuff->raw_data.lock);
+
+	/* check if buffer was released */
+	if (sbuff->raw_data.error == -ENODEV) {
+		spin_unlock(&sbuff->raw_data.lock);
+		return -ENODEV;
+	}
+
 	if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode) {
 		*handle = sbuff->buffers[0].handle;
 	} else {
@@ -455,6 +595,9 @@
 				&sbuff->raw_data.data[sbuff->raw_data.pwrite];
 		*handle = desc->handle;
 	}
+
+	spin_unlock(&sbuff->raw_data.lock);
+
 	return 0;
 }
 EXPORT_SYMBOL(mpq_streambuffer_get_buffer_handle);
@@ -484,15 +627,29 @@
 	if (NULL == sbuff)
 		return -EINVAL;
 
-	if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode)
-		return dvb_ringbuffer_free(&sbuff->raw_data);
+	spin_lock(&sbuff->raw_data.lock);
 
-	if (sbuff->pending_buffers_count == sbuff->buffers_num)
+	/* check if buffer was released */
+	if (sbuff->raw_data.error == -ENODEV) {
+		spin_unlock(&sbuff->raw_data.lock);
+		return -ENODEV;
+	}
+
+	if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode) {
+		spin_unlock(&sbuff->raw_data.lock);
+		return dvb_ringbuffer_free(&sbuff->raw_data);
+	}
+
+	if (sbuff->pending_buffers_count == sbuff->buffers_num) {
+		spin_unlock(&sbuff->raw_data.lock);
 		return 0;
+	}
 
 	desc = (struct mpq_streambuffer_buffer_desc *)
 		&sbuff->raw_data.data[sbuff->raw_data.pwrite];
 
+	spin_unlock(&sbuff->raw_data.lock);
+
 	return desc->size - desc->write_ptr;
 }
 EXPORT_SYMBOL(mpq_streambuffer_data_free);
@@ -506,12 +663,25 @@
 	if (NULL == sbuff)
 		return -EINVAL;
 
-	if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode)
-		return dvb_ringbuffer_avail(&sbuff->raw_data);
+	spin_lock(&sbuff->raw_data.lock);
+
+	/* check if buffer was released */
+	if (sbuff->raw_data.error == -ENODEV) {
+		spin_unlock(&sbuff->raw_data.lock);
+		return -ENODEV;
+	}
+
+	if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode) {
+		ssize_t avail = dvb_ringbuffer_avail(&sbuff->raw_data);
+		spin_unlock(&sbuff->raw_data.lock);
+		return avail;
+	}
 
 	desc = (struct mpq_streambuffer_buffer_desc *)
 		&sbuff->raw_data.data[sbuff->raw_data.pread];
 
+	spin_unlock(&sbuff->raw_data.lock);
+
 	return desc->write_ptr - desc->read_ptr;
 }
 EXPORT_SYMBOL(mpq_streambuffer_data_avail);
@@ -524,6 +694,14 @@
 	if (NULL == sbuff)
 		return -EINVAL;
 
+	spin_lock(&sbuff->raw_data.lock);
+
+	/* check if buffer was released */
+	if (sbuff->raw_data.error == -ENODEV) {
+		spin_unlock(&sbuff->raw_data.lock);
+		return -ENODEV;
+	}
+
 	if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode) {
 		if (read_offset)
 			*read_offset = sbuff->raw_data.pread;
@@ -544,6 +722,8 @@
 		}
 	}
 
+	spin_unlock(&sbuff->raw_data.lock);
+
 	return 0;
 }
 EXPORT_SYMBOL(mpq_streambuffer_get_data_rw_offset);
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
index 9be4704..83b9bb3 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
@@ -1469,7 +1469,6 @@
 			dec_buffs->buffers_size,
 			dec_buffs->is_linear);
 
-	feed_data->buffer_desc.decoder_buffers_num = dec_buffs->buffers_num;
 	if (0 == dec_buffs->buffers_num)
 		ret = mpq_dmx_init_internal_buffers(
 			feed_data, dec_buffs, client);
@@ -1515,6 +1514,8 @@
 
 	mpq_adapter_unregister_stream_if(feed_data->stream_interface);
 
+	mpq_streambuffer_terminate(video_buffer);
+
 	vfree(video_buffer->packet_data.data);
 
 	buf_num = feed_data->buffer_desc.decoder_buffers_num;
diff --git a/drivers/media/platform/msm/dvb/include/mpq_stream_buffer.h b/drivers/media/platform/msm/dvb/include/mpq_stream_buffer.h
index 3804fb2..1707c85 100644
--- a/drivers/media/platform/msm/dvb/include/mpq_stream_buffer.h
+++ b/drivers/media/platform/msm/dvb/include/mpq_stream_buffer.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -211,6 +211,18 @@
 		size_t packet_buff_size);
 
 /**
+ * mpq_streambuffer_terminate - Terminate stream buffer
+ *
+ * @sbuff: The buffer to terminate
+ *
+ * The function sets the the buffers error flags to ENODEV
+ * and wakeup any waiting threads on the buffer queues.
+ * Threads waiting on the buffer queues should check if
+ * error was set.
+ */
+void mpq_streambuffer_terminate(struct mpq_streambuffer *sbuff);
+
+/**
  * mpq_streambuffer_packet_next - Returns index of next available packet.
  *
  * @sbuff: The stream buffer