Merge "crypto: msm: fix hmac ahashing issues with simultaneous multiple requests."
diff --git a/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi
index 5ebb516..39b10b3 100644
--- a/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi
@@ -118,5 +118,7 @@
 		qcom,mdss-dsi-mdp-trigger = "none";
 		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
 		qcom,mdss-dsi-reset-sequence = <1 20>, <0 2>, <1 20>;
+		qcom,mdss-dsi-lp11-init;
+		qcom,mdss-dsi-init-delay-us = <50000>;
 	};
 };
diff --git a/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts b/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts
index 6b62391..d4bb37b 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -22,5 +22,5 @@
 };
 
 &sdhc_1 {
-	qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+	qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
 };
diff --git a/arch/arm/mach-msm/smp2p.c b/arch/arm/mach-msm/smp2p.c
index df241f8..5574eae 100644
--- a/arch/arm/mach-msm/smp2p.c
+++ b/arch/arm/mach-msm/smp2p.c
@@ -940,7 +940,7 @@
 
 	if (size < sizeof(struct smp2p_smem)) {
 		SMP2P_ERR(
-			"%s pid %d item size too small; expected: %d actual: %d\n",
+			"%s pid %d item size too small; expected: %zu actual: %d\n",
 			__func__, remote_pid,
 			sizeof(struct smp2p_smem), size);
 		smem_item = NULL;
diff --git a/arch/arm/mach-msm/smp2p_private.h b/arch/arm/mach-msm/smp2p_private.h
index 8e0d7a3..7174950 100644
--- a/arch/arm/mach-msm/smp2p_private.h
+++ b/arch/arm/mach-msm/smp2p_private.h
@@ -1,6 +1,6 @@
 /* arch/arm/mach-msm/smp2p_private.h
  *
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, 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
@@ -44,10 +44,10 @@
 #define SMP2P_GET_BITS(hdr_val, mask, bit) \
 	(((hdr_val) & (mask)) >> (bit))
 #define SMP2P_SET_BITS(hdr_val, mask, bit, new_value) \
-	do {\
+	{\
 		hdr_val = (hdr_val & ~(mask)) \
 		| (((new_value) << (bit)) & (mask)); \
-	} while (0)
+	}
 
 #define SMP2P_GET_LOCAL_PID(hdr) \
 	SMP2P_GET_BITS(hdr, SMP2P_LOCAL_PID_MASK, SMP2P_LOCAL_PID_BIT)
diff --git a/drivers/devfreq/governor_cpubw_hwmon.c b/drivers/devfreq/governor_cpubw_hwmon.c
index fb5a562..e7d373b 100644
--- a/drivers/devfreq/governor_cpubw_hwmon.c
+++ b/drivers/devfreq/governor_cpubw_hwmon.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, 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
@@ -77,13 +77,15 @@
 
 static int l2pm_irq;
 static unsigned int bytes_per_beat;
-static unsigned int sample_ms = 50;
 static unsigned int tolerance_percent = 10;
 static unsigned int guard_band_mbps = 100;
 static unsigned int decay_rate = 90;
-static unsigned int io_percent = 15;
-static unsigned int bw_step = 200;
+static unsigned int io_percent = 16;
+static unsigned int bw_step = 190;
 
+#define MIN_MS	10U
+#define MAX_MS	500U
+static unsigned int sample_ms = 50;
 static u32 prev_r_start_val;
 static u32 prev_w_start_val;
 static unsigned long prev_ab;
@@ -245,7 +247,7 @@
 	}
 
 	*ab = roundup(mbps, bw_step);
-	*freq = roundup((mbps * 100) / io_percent, bw_step);
+	*freq = (mbps * 100) / io_percent;
 }
 
 #define TOO_SOON_US	(1 * USEC_PER_MSEC)
@@ -343,7 +345,6 @@
 	return 0;
 }
 
-gov_attr(sample_ms, 10U, 500U);
 gov_attr(tolerance_percent, 0U, 30U);
 gov_attr(guard_band_mbps, 0U, 2000U);
 gov_attr(decay_rate, 0U, 100U);
@@ -351,7 +352,6 @@
 gov_attr(bw_step, 50U, 1000U);
 
 static struct attribute *dev_attr[] = {
-	&dev_attr_sample_ms.attr,
 	&dev_attr_tolerance_percent.attr,
 	&dev_attr_guard_band_mbps.attr,
 	&dev_attr_decay_rate.attr,
@@ -378,7 +378,13 @@
 		ret = sysfs_create_group(&df->dev.kobj, &dev_attr_group);
 		if (ret)
 			return ret;
+
+		sample_ms = df->profile->polling_ms;
+		sample_ms = max(MIN_MS, sample_ms);
+		sample_ms = min(MAX_MS, sample_ms);
+		df->profile->polling_ms = sample_ms;
 		devfreq_monitor_start(df);
+
 		pr_debug("Enabled CPU BW HW monitor governor\n");
 		break;
 
@@ -391,7 +397,10 @@
 		break;
 
 	case DEVFREQ_GOV_INTERVAL:
-		devfreq_interval_update(df, (unsigned int *)data);
+		sample_ms = *(unsigned int *)data;
+		sample_ms = max(MIN_MS, sample_ms);
+		sample_ms = min(MAX_MS, sample_ms);
+		devfreq_interval_update(df, &sample_ms);
 		break;
 	}
 
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index a39ceef..95e4017 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -397,7 +397,7 @@
 	 */
 
 	if (count)
-		wake_up_interruptible_all(&drawctxt->wq);
+		wake_up_all(&drawctxt->wq);
 
 	/*
 	 * Return positive if the context submitted commands or if we figured
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index 6007a3f..d727423 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2014, 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
@@ -138,7 +138,7 @@
 		u32 timestamp, u32 type)
 {
 	struct adreno_context *drawctxt = priv;
-	wake_up_interruptible_all(&drawctxt->waiting);
+	wake_up_all(&drawctxt->waiting);
 }
 
 #define adreno_wait_event_interruptible_timeout(wq, condition, timeout, io)   \
@@ -266,7 +266,7 @@
 {
 	struct adreno_context *drawctxt = priv;
 
-	wake_up_interruptible_all(&drawctxt->waiting);
+	wake_up_all(&drawctxt->waiting);
 	kgsl_context_put(&drawctxt->base);
 }
 
@@ -310,7 +310,7 @@
 	mutex_unlock(&device->mutex);
 
 	if (timeout) {
-		ret = (int) wait_event_interruptible_timeout(drawctxt->waiting,
+		ret = (int) wait_event_timeout(drawctxt->waiting,
 			_check_global_timestamp(device, timestamp),
 			msecs_to_jiffies(timeout));
 
@@ -319,7 +319,7 @@
 		else if (ret > 0)
 			ret = 0;
 	} else {
-		ret = (int) wait_event_interruptible(drawctxt->waiting,
+		wait_event(drawctxt->waiting,
 			_check_global_timestamp(device, timestamp));
 	}
 
@@ -386,8 +386,8 @@
 	mutex_unlock(&drawctxt->mutex);
 
 	/* Give the bad news to everybody waiting around */
-	wake_up_interruptible_all(&drawctxt->waiting);
-	wake_up_interruptible_all(&drawctxt->wq);
+	wake_up_all(&drawctxt->waiting);
+	wake_up_all(&drawctxt->wq);
 }
 
 /**
@@ -543,6 +543,14 @@
 	ret = adreno_drawctxt_wait_global(adreno_dev, context,
 		drawctxt->internal_timestamp, 10 * 1000);
 
+	/*
+	 * If the wait for global fails then nothing after this point is likely
+	 * to work very well - BUG_ON() so we can take advantage of the debug
+	 * tools to figure out what the h - e - double hockey sticks happened
+	 */
+
+	BUG_ON(ret);
+
 	kgsl_sharedmem_writel(device, &device->memstore,
 			KGSL_MEMSTORE_OFFSET(context->id, soptimestamp),
 			drawctxt->timestamp);
@@ -557,8 +565,8 @@
 		drawctxt->ops->detach(drawctxt);
 
 	/* wake threads waiting to submit commands from this context */
-	wake_up_interruptible_all(&drawctxt->waiting);
-	wake_up_interruptible_all(&drawctxt->wq);
+	wake_up_all(&drawctxt->waiting);
+	wake_up_all(&drawctxt->wq);
 
 	return ret;
 }
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index c6996a4..cd6989c 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -2550,6 +2550,15 @@
 	.resume		= mxt_resume,
 #endif
 };
+#else
+static int mxt_suspend(struct device *dev)
+{
+	return 0;
+};
+static int mxt_resume(struct device *dev)
+{
+	return 0;
+};
 #endif
 
 static int mxt_debugfs_object_show(struct seq_file *m, void *v)
diff --git a/drivers/input/touchscreen/synaptics_fw_update.c b/drivers/input/touchscreen/synaptics_fw_update.c
index 7da0376..e577353 100644
--- a/drivers/input/touchscreen/synaptics_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_fw_update.c
@@ -1559,7 +1559,7 @@
 		}
 
 		dev_dbg(&fwu->rmi4_data->i2c_client->dev,
-				"%s: Firmware image size = %d\n",
+				"%s: Firmware image size = %zu\n",
 				__func__, fw_entry->size);
 
 		fwu->data_buffer = fw_entry->data;
@@ -1670,7 +1670,7 @@
 
 	if (count < fwu->config_size) {
 		dev_err(&rmi4_data->i2c_client->dev,
-				"%s: Not enough space (%d bytes) in buffer\n",
+				"%s: Not enough space (%zu bytes) in buffer\n",
 				__func__, count);
 		return -EINVAL;
 	}
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h
index c8a4366..567a263 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -34,12 +34,20 @@
 #define ISPIF_VFE_m_INTF_CMD_0(m)                (0x0004 + ISPIF_VFE(m))
 #define ISPIF_VFE_m_INTF_CMD_1(m)                (0x0030 + ISPIF_VFE(m))
 #define ISPIF_VFE_m_PIX_INTF_n_CID_MASK(m, n)    (0x0010 + ISPIF_VFE(m) + 4*(n))
-#define ISPIF_VFE_m_RDI_INTF_n_CID_MASK(m, n)    (0x0014 + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_RDI_INTF_n_CID_MASK(m, n)    (0x0014 + ISPIF_VFE(m) + \
+							((n > 0) ? (0x20) : 0) \
+							+ 8*(n))
 #define ISPIF_VFE_m_PIX_OUTPUT_n_MISR(m, n)      (0x0290 + ISPIF_VFE(m) + 4*(n))
-#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_0(m, n)    (0x0298 + ISPIF_VFE(m) + 8*(n))
-#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_1(m, n)    (0x029C + ISPIF_VFE(m) + 8*(n))
+#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_0(m, n)    (0x001C + ISPIF_VFE(m) + \
+							((n > 0) ? (0x24) : 0) \
+							+ 0xc*(n))
+#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_1(m, n)    (0x0020 + ISPIF_VFE(m) + \
+							((n > 0) ? (0x24) : 0) \
+							+ 0xc*(n))
 #define ISPIF_VFE_m_PIX_INTF_n_STATUS(m, n)      (0x0024 + ISPIF_VFE(m) + 4*(n))
-#define ISPIF_VFE_m_RDI_INTF_n_STATUS(m, n)      (0x0028 + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_RDI_INTF_n_STATUS(m, n)      (0x0028 + ISPIF_VFE(m) + \
+							((n > 0) ? (0x34) : 0) \
+							+ 8*(n))
 
 /* Defines for compatibility with newer ISPIF versions */
 #define ISPIF_RST_CMD_1_ADDR                     (0x0000)
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 035fc4b..9774c3c 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -246,38 +246,38 @@
 	return ret;
 }
 
-struct buffer_info *get_same_fd_buffer(struct msm_vidc_inst *inst,
-			struct list_head *list, int fd, int *plane)
+struct msm_smem *get_same_fd_buffer(struct msm_vidc_inst *inst,
+			struct list_head *list, int fd)
 {
 	struct buffer_info *temp;
-	struct buffer_info *ret = NULL;
+	struct msm_smem *same_fd_handle = NULL;
+
 	int i;
 	if (fd == 0)
 		return NULL;
-	if (!list || fd < 0 || !plane) {
+	if (!list || fd < 0) {
 		dprintk(VIDC_ERR, "Invalid input\n");
 		goto err_invalid_input;
 	}
-	*plane = 0;
 	mutex_lock(&inst->lock);
 	list_for_each_entry(temp, list, list) {
 		for (i = 0; (i < temp->num_planes)
 			&& (i < VIDEO_MAX_PLANES); i++) {
-			if (temp && temp->fd[i] == fd)  {
+			if (temp && (temp->fd[i] == fd) &&
+				temp->handle[i] && temp->mapped[i])  {
 				temp->same_fd_ref[i]++;
 				dprintk(VIDC_INFO,
 				"Found same fd buffer\n");
-				ret = temp;
-				*plane = i;
+				same_fd_handle = temp->handle[i];
 				break;
 			}
 		}
-		if (ret)
+		if (same_fd_handle)
 			break;
 	}
 	mutex_unlock(&inst->lock);
 err_invalid_input:
-	return ret;
+	return same_fd_handle;
 }
 
 struct buffer_info *device_to_uvaddr(struct msm_vidc_inst *inst,
@@ -423,6 +423,7 @@
 	struct buffer_info *temp = NULL;
 	int plane = 0;
 	int i = 0, rc = 0;
+	struct msm_smem *same_fd_handle = NULL;
 
 	if (!b || !inst) {
 		dprintk(VIDC_ERR, "%s: invalid input\n", __func__);
@@ -480,16 +481,17 @@
 		if (rc < 0)
 			goto exit;
 
-		temp = get_same_fd_buffer(inst, &inst->registered_bufs,
-					b->m.planes[i].reserved[0], &plane);
+		same_fd_handle = get_same_fd_buffer(inst,
+					&inst->registered_bufs,
+					b->m.planes[i].reserved[0]);
 
 		populate_buf_info(binfo, b, i);
-		if (temp) {
+		if (same_fd_handle) {
 			binfo->device_addr[i] =
-			temp->handle[plane]->device_addr + binfo->buff_off[i];
+			same_fd_handle->device_addr + binfo->buff_off[i];
 			b->m.planes[i].m.userptr = binfo->device_addr[i];
 			binfo->mapped[i] = false;
-			binfo->handle[i] = temp->handle[i];
+			binfo->handle[i] = same_fd_handle;
 		} else {
 			if (inst->map_output_buffer) {
 				binfo->handle[i] =
diff --git a/drivers/misc/isa1200.c b/drivers/misc/isa1200.c
index 8090b95..d7fa87b 100644
--- a/drivers/misc/isa1200.c
+++ b/drivers/misc/isa1200.c
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2009 Samsung Electronics
  *  Kyungmin Park <kyungmin.park@samsung.com>
- *  Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ *  Copyright (c) 2010-2014, 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 as
@@ -318,7 +318,7 @@
 
 	value |= (haptic->pdata->mode_ctrl << 3) |
 		(haptic->pdata->overdrive_high << 5) |
-		(haptic->pdata->overdrive_en << 5) |
+		(haptic->pdata->overdrive_en << 6) |
 		(haptic->pdata->chip_en << 7);
 
 	rc = isa1200_write_reg(client, ISA1200_HCTRL0, value);
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 2fe9c72..aad7fb3 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -71,6 +71,9 @@
 
 #define RPMB_SERVICE			0x2000
 
+#define QSEECOM_SEND_CMD_CRYPTO_TIMEOUT	2000
+#define QSEECOM_LOAD_APP_CRYPTO_TIMEOUT	2000
+
 enum qseecom_clk_definitions {
 	CLK_DFAB = 0,
 	CLK_SFPB,
@@ -162,6 +165,12 @@
 	struct qseecom_clk qsee;
 	struct qseecom_clk ce_drv;
 	struct cdev cdev;
+
+	bool support_bus_scaling;
+	uint32_t  cumulative_mode;
+	enum qseecom_bandwidth_request_mode  current_mode;
+	struct timer_list bw_scale_down_timer;
+	struct work_struct bw_inactive_req_ws;
 };
 
 struct qseecom_client_handle {
@@ -191,6 +200,7 @@
 	atomic_t          ioctl_count;
 	bool  perf_enabled;
 	bool  fast_load_enabled;
+	enum qseecom_bandwidth_request_mode mode;
 };
 
 enum qseecom_set_clear_key_flag {
@@ -328,6 +338,7 @@
 		return -EFAULT;
 
 	data->listener.id = 0;
+	data->type = QSEECOM_LISTENER_SERVICE;
 	if (!__qseecom_is_svc_unique(data, &rcvd_lstnr)) {
 		pr_err("Service is not unique and is already registered\n");
 		data->released = true;
@@ -437,6 +448,157 @@
 	return ret;
 }
 
+static int __qseecom_set_msm_bus_request(uint32_t mode)
+{
+	int ret = 0;
+	struct qseecom_clk *qclk;
+
+	qclk = &qseecom.qsee;
+	if (qclk->ce_core_src_clk != NULL) {
+		if (mode == INACTIVE) {
+			__qseecom_disable_clk(CLK_QSEE);
+		} else {
+			ret = __qseecom_enable_clk(CLK_QSEE);
+			if (ret)
+				pr_err("CLK enabling failed (%d) MODE (%d)\n",
+							ret, mode);
+		}
+	}
+
+	if ((!ret) && (qseecom.current_mode != mode)) {
+		ret = msm_bus_scale_client_update_request(
+					qseecom.qsee_perf_client, mode);
+		if (ret) {
+			pr_err("Bandwidth req failed(%d) MODE (%d)\n",
+							ret, mode);
+			if (qclk->ce_core_src_clk != NULL) {
+				if (mode == INACTIVE)
+					__qseecom_enable_clk(CLK_QSEE);
+				else
+					__qseecom_disable_clk(CLK_QSEE);
+			}
+		}
+		qseecom.current_mode = mode;
+	}
+	return ret;
+}
+
+static void qseecom_bw_inactive_req_work(struct work_struct *work)
+{
+	mutex_lock(&app_access_lock);
+	mutex_lock(&qsee_bw_mutex);
+	__qseecom_set_msm_bus_request(INACTIVE);
+	pr_debug("current_mode = %d, cumulative_mode = %d\n",
+				qseecom.current_mode, qseecom.cumulative_mode);
+	mutex_unlock(&qsee_bw_mutex);
+	mutex_unlock(&app_access_lock);
+	return;
+}
+
+static void qseecom_scale_bus_bandwidth_timer_callback(unsigned long data)
+{
+	schedule_work(&qseecom.bw_inactive_req_ws);
+	return;
+}
+
+static int qseecom_scale_bus_bandwidth_timer(uint32_t mode, uint32_t duration)
+{
+	int32_t ret = 0;
+	int32_t request_mode = INACTIVE;
+
+	mutex_lock(&qsee_bw_mutex);
+	if (mode == 0) {
+		if (qseecom.cumulative_mode > MEDIUM)
+			request_mode = HIGH;
+		else
+			request_mode = qseecom.cumulative_mode;
+	} else {
+		request_mode = mode;
+	}
+	__qseecom_set_msm_bus_request(request_mode);
+
+	del_timer_sync(&(qseecom.bw_scale_down_timer));
+	qseecom.bw_scale_down_timer.expires = jiffies +
+				msecs_to_jiffies(duration);
+	add_timer(&(qseecom.bw_scale_down_timer));
+
+	mutex_unlock(&qsee_bw_mutex);
+	return ret;
+}
+
+
+static int qseecom_unregister_bus_bandwidth_needs(
+					struct qseecom_dev_handle *data)
+{
+	int32_t ret = 0;
+
+	qseecom.cumulative_mode -= data->mode;
+	data->mode = INACTIVE;
+
+	return ret;
+}
+
+static int __qseecom_register_bus_bandwidth_needs(
+			struct qseecom_dev_handle *data, uint32_t request_mode)
+{
+	int32_t ret = 0;
+
+	if (data->mode == INACTIVE) {
+		qseecom.cumulative_mode += request_mode;
+		data->mode = request_mode;
+	} else {
+		if (data->mode != request_mode) {
+			qseecom.cumulative_mode -= data->mode;
+			qseecom.cumulative_mode += request_mode;
+			data->mode = request_mode;
+		}
+	}
+	return ret;
+}
+
+static int qseecom_scale_bus_bandwidth(struct qseecom_dev_handle *data,
+						void __user *argp)
+{
+	int32_t ret = 0;
+	int32_t req_mode;
+
+	ret = copy_from_user(&req_mode, argp, sizeof(req_mode));
+	if (ret) {
+		pr_err("copy_from_user failed\n");
+		return ret;
+	}
+	if (req_mode > HIGH) {
+		pr_err("Invalid bandwidth mode (%d)\n", req_mode);
+		return ret;
+	}
+	mutex_lock(&qsee_bw_mutex);
+	ret = __qseecom_register_bus_bandwidth_needs(data, req_mode);
+	mutex_unlock(&qsee_bw_mutex);
+
+	return ret;
+}
+
+static void __qseecom_disable_clk_scale_down(struct qseecom_dev_handle *data)
+{
+	if (!qseecom.support_bus_scaling)
+		qsee_disable_clock_vote(data, CLK_SFPB);
+	return;
+}
+
+static int __qseecom_enable_clk_scale_up(struct qseecom_dev_handle *data)
+{
+	int ret = 0;
+	if (qseecom.support_bus_scaling) {
+		qseecom_scale_bus_bandwidth_timer(
+			MEDIUM, QSEECOM_LOAD_APP_CRYPTO_TIMEOUT);
+	} else {
+		ret = qsee_vote_for_clock(data, CLK_SFPB);
+		if (ret)
+			pr_err("Fail vote for clk SFPB ret %d\n", ret);
+	}
+	return ret;
+}
+
 static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data,
 						void __user *argp)
 {
@@ -626,7 +788,7 @@
 	u32 app_id = 0;
 	struct ion_handle *ihandle;	/* Ion handle */
 	struct qseecom_load_img_req load_img_req;
-	int32_t ret;
+	int32_t ret = 0;
 	ion_phys_addr_t pa = 0;
 	uint32_t len;
 	struct qseecom_command_scm_resp resp;
@@ -641,16 +803,16 @@
 		return -EFAULT;
 	}
 	/* Vote for the SFPB clock */
-	ret = qsee_vote_for_clock(data, CLK_SFPB);
+	ret = __qseecom_enable_clk_scale_up(data);
 	if (ret)
-		pr_warning("Unable to vote for SFPB clock");
+		return ret;
 	req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
 	load_img_req.img_name[MAX_APP_NAME_SIZE-1] = '\0';
 	memcpy(req.app_name, load_img_req.img_name, MAX_APP_NAME_SIZE);
 
 	ret = __qseecom_check_app_exists(req);
 	if (ret < 0) {
-		qsee_disable_clock_vote(data, CLK_SFPB);
+		__qseecom_disable_clk_scale_down(data);
 		return ret;
 	}
 
@@ -676,7 +838,7 @@
 					load_img_req.ifd_data_fd);
 		if (IS_ERR_OR_NULL(ihandle)) {
 			pr_err("Ion client could not retrieve the handle\n");
-			qsee_disable_clock_vote(data, CLK_SFPB);
+			__qseecom_disable_clk_scale_down(data);
 			return -ENOMEM;
 		}
 
@@ -701,7 +863,7 @@
 			pr_err("scm_call to load app failed\n");
 			if (!IS_ERR_OR_NULL(ihandle))
 				ion_free(qseecom.ion_clnt, ihandle);
-			qsee_disable_clock_vote(data, CLK_SFPB);
+			__qseecom_disable_clk_scale_down(data);
 			return -EINVAL;
 		}
 
@@ -709,7 +871,7 @@
 			pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
 			if (!IS_ERR_OR_NULL(ihandle))
 				ion_free(qseecom.ion_clnt, ihandle);
-			qsee_disable_clock_vote(data, CLK_SFPB);
+			__qseecom_disable_clk_scale_down(data);
 			return -EFAULT;
 		}
 
@@ -720,7 +882,7 @@
 					ret);
 				if (!IS_ERR_OR_NULL(ihandle))
 					ion_free(qseecom.ion_clnt, ihandle);
-				qsee_disable_clock_vote(data, CLK_SFPB);
+				__qseecom_disable_clk_scale_down(data);
 				return ret;
 			}
 		}
@@ -730,7 +892,7 @@
 				resp.result);
 			if (!IS_ERR_OR_NULL(ihandle))
 				ion_free(qseecom.ion_clnt, ihandle);
-			qsee_disable_clock_vote(data, CLK_SFPB);
+			__qseecom_disable_clk_scale_down(data);
 			return -EFAULT;
 		}
 
@@ -739,7 +901,7 @@
 		entry = kmalloc(sizeof(*entry), GFP_KERNEL);
 		if (!entry) {
 			pr_err("kmalloc failed\n");
-			qsee_disable_clock_vote(data, CLK_SFPB);
+			__qseecom_disable_clk_scale_down(data);
 			return -ENOMEM;
 		}
 		entry->app_id = app_id;
@@ -762,10 +924,10 @@
 	if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) {
 		pr_err("copy_to_user failed\n");
 		kzfree(entry);
-		qsee_disable_clock_vote(data, CLK_SFPB);
+		__qseecom_disable_clk_scale_down(data);
 		return -EFAULT;
 	}
-	qsee_disable_clock_vote(data, CLK_SFPB);
+	__qseecom_disable_clk_scale_down(data);
 	return 0;
 }
 
@@ -953,6 +1115,8 @@
 		return -EINVAL;
 	}
 
+	data->type = QSEECOM_SECURE_SERVICE;
+
 	switch (req.cmd_id) {
 	case QSEOS_RPMB_PROVISION_KEY_COMMAND:
 	case QSEOS_RPMB_ERASE_COMMAND:
@@ -965,15 +1129,25 @@
 		return -EINVAL;
 	}
 
-	ret = qsee_vote_for_clock(data, CLK_DFAB);
-	if (ret) {
-		pr_err("Failed to vote for DFAB clock%d\n", ret);
-		return ret;
-	}
-	ret = qsee_vote_for_clock(data, CLK_SFPB);
-	if (ret) {
-		pr_err("Failed to vote for SFPB clock%d\n", ret);
-		goto exit_reset_dfab_freq;
+	if (qseecom.support_bus_scaling) {
+		qseecom_scale_bus_bandwidth_timer(HIGH,
+					QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
+		if (ret) {
+			pr_err("Fail to set bw HIGH%d\n", ret);
+			return ret;
+		}
+	} else {
+		ret = qsee_vote_for_clock(data, CLK_DFAB);
+		if (ret) {
+			pr_err("Failed to vote for DFAB clock%d\n", ret);
+			return ret;
+		}
+		ret = qsee_vote_for_clock(data, CLK_SFPB);
+		if (ret) {
+			qsee_disable_clock_vote(data, CLK_DFAB);
+			pr_err("Failed to vote for SFPB clock%d\n", ret);
+			goto exit;
+		}
 	}
 
 	msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
@@ -987,7 +1161,11 @@
 				ION_IOC_INV_CACHES);
 	if (ret) {
 		pr_err("qseecom_scm_call failed with err: %d\n", ret);
-		goto exit_reset_sdfab_freq;
+		if (!qseecom.support_bus_scaling) {
+			qsee_disable_clock_vote(data, CLK_DFAB);
+			qsee_disable_clock_vote(data, CLK_SFPB);
+		}
+		goto exit;
 	}
 
 	switch (resp.result) {
@@ -1010,10 +1188,7 @@
 		ret = -EINVAL;
 		break;
 	}
-exit_reset_sdfab_freq:
-	qsee_disable_clock_vote(data, CLK_SFPB);
-exit_reset_dfab_freq:
-	qsee_disable_clock_vote(data, CLK_DFAB);
+exit:
 	return ret;
 }
 
@@ -1484,10 +1659,9 @@
 	/* Populate the remaining parameters */
 	load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
 	memcpy(load_req.app_name, appname, MAX_APP_NAME_SIZE);
-	ret = qsee_vote_for_clock(data, CLK_SFPB);
+	ret = __qseecom_enable_clk_scale_up(data);
 	if (ret) {
 		kzfree(img_data);
-		pr_warning("Unable to vote for SFPB clock");
 		return -EIO;
 	}
 
@@ -1499,7 +1673,7 @@
 	kzfree(img_data);
 	if (ret) {
 		pr_err("scm_call to load failed : ret %d\n", ret);
-		qsee_disable_clock_vote(data, CLK_SFPB);
+		__qseecom_disable_clk_scale_down(data);
 		return -EIO;
 	}
 
@@ -1522,7 +1696,7 @@
 		ret = -EINVAL;
 		break;
 	}
-	qsee_disable_clock_vote(data, CLK_SFPB);
+	__qseecom_disable_clk_scale_down(data);
 
 	return ret;
 }
@@ -1551,9 +1725,8 @@
 	/* Populate the remaining parameters */
 	load_req.qsee_cmd_id = QSEOS_LOAD_SERV_IMAGE_COMMAND;
 	/* Vote for the SFPB clock */
-	ret = qsee_vote_for_clock(data, CLK_SFPB);
+	ret = __qseecom_enable_clk_scale_up(data);
 	if (ret) {
-		pr_err("Unable to vote for SFPB clock: ret = %d", ret);
 		kzfree(img_data);
 		return -EIO;
 	}
@@ -1589,7 +1762,7 @@
 		}
 	}
 	kzfree(img_data);
-	qsee_disable_clock_vote(data, CLK_SFPB);
+	__qseecom_disable_clk_scale_down(data);
 	return ret;
 }
 
@@ -1799,10 +1972,24 @@
 		pr_err("Unable to find the handle, exiting\n");
 	else
 		ret = qseecom_unload_app(data);
-	if (data->fast_load_enabled == true)
-		qsee_disable_clock_vote(data, CLK_SFPB);
-	if (data->perf_enabled == true)
-		qsee_disable_clock_vote(data, CLK_DFAB);
+
+	if (qseecom.support_bus_scaling) {
+		mutex_lock(&qsee_bw_mutex);
+		if (data->mode != INACTIVE) {
+			qseecom_unregister_bus_bandwidth_needs(data);
+			if (qseecom.cumulative_mode == INACTIVE) {
+				ret = __qseecom_set_msm_bus_request(INACTIVE);
+				if (ret)
+					pr_err("Fail to scale down bus\n");
+			}
+		}
+		mutex_unlock(&qsee_bw_mutex);
+	} else {
+		if (data->fast_load_enabled == true)
+			qsee_disable_clock_vote(data, CLK_SFPB);
+		if (data->perf_enabled == true)
+			qsee_disable_clock_vote(data, CLK_DFAB);
+	}
 	if (ret == 0) {
 		kzfree(data);
 		kzfree(*handle);
@@ -1833,7 +2020,9 @@
 
 	mutex_lock(&app_access_lock);
 	atomic_inc(&data->ioctl_count);
-
+	if (qseecom.support_bus_scaling)
+		qseecom_scale_bus_bandwidth_timer(INACTIVE,
+					QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
 	ret = __qseecom_send_cmd(data, &req);
 
 	atomic_dec(&data->ioctl_count);
@@ -1856,17 +2045,30 @@
 		return -EINVAL;
 	}
 	if (high) {
-		ret = qsee_vote_for_clock(handle->dev, CLK_DFAB);
-		if (ret)
-			pr_err("Failed to vote for DFAB clock%d\n", ret);
-		ret = qsee_vote_for_clock(handle->dev, CLK_SFPB);
-		if (ret) {
-			pr_err("Failed to vote for SFPB clock%d\n", ret);
-			qsee_disable_clock_vote(handle->dev, CLK_DFAB);
+		if (qseecom.support_bus_scaling) {
+			mutex_lock(&qsee_bw_mutex);
+			__qseecom_register_bus_bandwidth_needs(handle->dev,
+									HIGH);
+			mutex_unlock(&qsee_bw_mutex);
+			if (ret)
+				pr_err("Failed to scale bus (med) %d\n", ret);
+		} else {
+			ret = qsee_vote_for_clock(handle->dev, CLK_DFAB);
+			if (ret)
+				pr_err("Failed to vote for DFAB clock%d\n",
+									ret);
+			ret = qsee_vote_for_clock(handle->dev, CLK_SFPB);
+			if (ret) {
+				pr_err("Failed to vote for SFPB clock%d\n",
+									ret);
+				qsee_disable_clock_vote(handle->dev, CLK_DFAB);
+			}
 		}
 	} else {
-		qsee_disable_clock_vote(handle->dev, CLK_DFAB);
-		qsee_disable_clock_vote(handle->dev, CLK_SFPB);
+		if (!qseecom.support_bus_scaling) {
+			qsee_disable_clock_vote(handle->dev, CLK_DFAB);
+			qsee_disable_clock_vote(handle->dev, CLK_SFPB);
+		}
 	}
 	return ret;
 }
@@ -2231,9 +2433,8 @@
 	}
 
 	/* Vote for the SFPB clock */
-	ret = qsee_vote_for_clock(data, CLK_SFPB);
+	ret = __qseecom_enable_clk_scale_up(data);
 	if (ret) {
-		pr_err("Unable to vote for SFPB clock: ret = %d", ret);
 		ret = -EIO;
 		goto exit_cpu_restore;
 	}
@@ -2271,7 +2472,7 @@
 	}
 
 exit_disable_clock:
-	qsee_disable_clock_vote(data, CLK_SFPB);
+	__qseecom_disable_clk_scale_down(data);
 exit_cpu_restore:
 	/* Restore the CPU mask */
 	mask = CPU_MASK_ALL;
@@ -2914,6 +3115,7 @@
 		break;
 	}
 	case QSEECOM_IOCTL_SEND_CMD_REQ: {
+		pr_debug("qseecom.current_mode %d\n", qseecom.current_mode);
 		if ((data->client.app_id == 0) ||
 			(data->type != QSEECOM_CLIENT_APP)) {
 			pr_err("send cmd req: invalid handle (%d) app_id(%d)\n",
@@ -2923,6 +3125,9 @@
 		}
 		/* Only one client allowed here at a time */
 		mutex_lock(&app_access_lock);
+		if (qseecom.support_bus_scaling)
+			qseecom_scale_bus_bandwidth_timer(INACTIVE,
+					QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
 		atomic_inc(&data->ioctl_count);
 		ret = qseecom_send_cmd(data, argp);
 		atomic_dec(&data->ioctl_count);
@@ -2933,6 +3138,7 @@
 		break;
 	}
 	case QSEECOM_IOCTL_SEND_MODFD_CMD_REQ: {
+		pr_debug("qseecom.current_mode %d\n", qseecom.current_mode);
 		if ((data->client.app_id == 0) ||
 			(data->type != QSEECOM_CLIENT_APP)) {
 			pr_err("send mdfd cmd: invalid handle (%d) appid(%d)\n",
@@ -2942,6 +3148,9 @@
 		}
 		/* Only one client allowed here at a time */
 		mutex_lock(&app_access_lock);
+		if (qseecom.support_bus_scaling)
+			qseecom_scale_bus_bandwidth_timer(INACTIVE,
+					QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
 		atomic_inc(&data->ioctl_count);
 		ret = qseecom_send_modfd_cmd(data, argp);
 		atomic_dec(&data->ioctl_count);
@@ -3068,12 +3277,18 @@
 			break;
 		}
 		atomic_inc(&data->ioctl_count);
-		ret = qsee_vote_for_clock(data, CLK_DFAB);
-		if (ret)
-			pr_err("Failed to vote for DFAB clock%d\n", ret);
-		ret = qsee_vote_for_clock(data, CLK_SFPB);
-		if (ret)
-			pr_err("Failed to vote for SFPB clock%d\n", ret);
+		if (qseecom.support_bus_scaling) {
+			mutex_lock(&qsee_bw_mutex);
+			__qseecom_register_bus_bandwidth_needs(data, HIGH);
+			mutex_unlock(&qsee_bw_mutex);
+		} else {
+			ret = qsee_vote_for_clock(data, CLK_DFAB);
+			if (ret)
+				pr_err("Fail to vote for DFAB clock%d\n", ret);
+			ret = qsee_vote_for_clock(data, CLK_SFPB);
+			if (ret)
+				pr_err("Fail to vote for SFPB clock%d\n", ret);
+		}
 		atomic_dec(&data->ioctl_count);
 		break;
 	}
@@ -3093,8 +3308,24 @@
 			break;
 		}
 		atomic_inc(&data->ioctl_count);
+		if (!qseecom.support_bus_scaling) {
 			qsee_disable_clock_vote(data, CLK_DFAB);
 			qsee_disable_clock_vote(data, CLK_SFPB);
+		}
+		atomic_dec(&data->ioctl_count);
+		break;
+	}
+
+	case QSEECOM_IOCTL_SET_BUS_SCALING_REQ: {
+		if ((data->client.app_id == 0) ||
+			(data->type != QSEECOM_CLIENT_APP)) {
+			pr_err("set bus scale: invalid handle (%d) appid(%d)\n",
+					data->type, data->client.app_id);
+			ret = -EINVAL;
+			break;
+		}
+		atomic_inc(&data->ioctl_count);
+		ret = qseecom_scale_bus_bandwidth(data, argp);
 		atomic_dec(&data->ioctl_count);
 		break;
 	}
@@ -3292,6 +3523,7 @@
 	data->abort = 0;
 	data->type = QSEECOM_GENERIC;
 	data->released = false;
+	data->mode = INACTIVE;
 	init_waitqueue_head(&data->abort_wq);
 	atomic_set(&data->ioctl_count, 0);
 
@@ -3304,8 +3536,8 @@
 	int ret = 0;
 
 	if (data->released == false) {
-		pr_warn("data: released = false, type = %d, data = 0x%x\n",
-			data->type, (u32)data);
+		pr_warn("data: released=false, type=%d, mode=%d, data=0x%x\n",
+			data->type, data->mode, (u32)data);
 		switch (data->type) {
 		case QSEECOM_LISTENER_SERVICE:
 			ret = qseecom_unregister_listener(data);
@@ -3328,11 +3560,23 @@
 		}
 	}
 
-	if (data->fast_load_enabled == true)
-		qsee_disable_clock_vote(data, CLK_SFPB);
-	if (data->perf_enabled == true)
-		qsee_disable_clock_vote(data, CLK_DFAB);
-
+	if (qseecom.support_bus_scaling) {
+		mutex_lock(&qsee_bw_mutex);
+		if (data->mode != INACTIVE) {
+			qseecom_unregister_bus_bandwidth_needs(data);
+			if (qseecom.cumulative_mode == INACTIVE) {
+				ret = __qseecom_set_msm_bus_request(INACTIVE);
+				if (ret)
+					pr_err("Fail to scale down bus\n");
+			}
+		}
+		mutex_unlock(&qsee_bw_mutex);
+	} else {
+		if (data->fast_load_enabled == true)
+			qsee_disable_clock_vote(data, CLK_SFPB);
+		if (data->perf_enabled == true)
+			qsee_disable_clock_vote(data, CLK_DFAB);
+	}
 	kfree(data);
 
 	return ret;
@@ -3475,6 +3719,10 @@
 	qseecom.qsee.ce_core_src_clk = NULL;
 	qseecom.qsee.ce_bus_clk = NULL;
 
+	qseecom.cumulative_mode = 0;
+	qseecom.current_mode = INACTIVE;
+	qseecom.support_bus_scaling = false;
+
 	qseecom.ce_drv.ce_core_clk = NULL;
 	qseecom.ce_drv.ce_clk = NULL;
 	qseecom.ce_drv.ce_core_src_clk = NULL;
@@ -3554,7 +3802,11 @@
 
 	/* register client for bus scaling */
 	if (pdev->dev.of_node) {
-
+		qseecom.support_bus_scaling =
+				of_property_read_bool((&pdev->dev)->of_node,
+						"qcom,support-bus-scaling");
+		pr_warn("support_bus_scaling=0x%x",
+				qseecom.support_bus_scaling);
 		if (of_property_read_u32((&pdev->dev)->of_node,
 				"qcom,disk-encrypt-pipe-pair",
 				&qseecom.ce_info.disk_encrypt_pipe)) {
@@ -3647,7 +3899,13 @@
 		qseecom_platform_support = (struct msm_bus_scale_pdata *)
 						pdev->dev.platform_data;
 	}
-
+	if (qseecom.support_bus_scaling) {
+		init_timer(&(qseecom.bw_scale_down_timer));
+		INIT_WORK(&qseecom.bw_inactive_req_ws,
+					qseecom_bw_inactive_req_work);
+		qseecom.bw_scale_down_timer.function =
+				qseecom_scale_bus_bandwidth_timer_callback;
+	}
 	qseecom.qsee_perf_client = msm_bus_scale_register_client(
 					qseecom_platform_support);
 
@@ -3713,6 +3971,11 @@
 	if (pdev->dev.platform_data != NULL)
 		msm_bus_scale_unregister_client(qseecom.qsee_perf_client);
 
+	if (qseecom.support_bus_scaling) {
+		cancel_work_sync(&qseecom.bw_inactive_req_ws);
+		del_timer_sync(&qseecom.bw_scale_down_timer);
+	}
+
 	/* register client for bus scaling */
 	if (pdev->dev.of_node) {
 		__qseecom_deinit_clk(CLK_QSEE);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index a29fb751..9985c71 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -20,6 +20,7 @@
 #include <linux/of_gpio.h>
 #include <linux/of_platform.h>
 #include <linux/types.h>
+#include <linux/msm_hdmi.h>
 #include <mach/msm_hdmi_audio_codec.h>
 
 #define REG_DUMP 0
@@ -222,6 +223,77 @@
 		{20480, 247500} } },
 };
 
+int register_hdmi_cable_notification(struct hdmi_cable_notify *handler)
+{
+	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+	struct list_head *pos;
+
+	if (!hdmi_tx_hw.ptr) {
+		DEV_WARN("%s: HDMI Tx core not ready\n", __func__);
+		return -EPROBE_DEFER;
+	}
+
+	if (!handler) {
+		DEV_ERR("%s: Empty handler\n", __func__);
+		return -ENODEV;
+	}
+
+	hdmi_ctrl = (struct hdmi_tx_ctrl *) hdmi_tx_hw.ptr;
+
+	mutex_lock(&hdmi_ctrl->cable_notify_mutex);
+	handler->status = hdmi_ctrl->hpd_state;
+	list_for_each(pos, &hdmi_ctrl->cable_notify_handlers);
+	list_add_tail(&handler->link, pos);
+	mutex_unlock(&hdmi_ctrl->cable_notify_mutex);
+
+	return handler->status;
+} /* register_hdmi_cable_notification */
+
+int unregister_hdmi_cable_notification(struct hdmi_cable_notify *handler)
+{
+	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+
+	if (!hdmi_tx_hw.ptr) {
+		DEV_WARN("%s: HDMI Tx core not ready\n", __func__);
+		return -ENODEV;
+	}
+
+	if (!handler) {
+		DEV_ERR("%s: Empty handler\n", __func__);
+		return -ENODEV;
+	}
+
+	hdmi_ctrl = (struct hdmi_tx_ctrl *) hdmi_tx_hw.ptr;
+
+	mutex_lock(&hdmi_ctrl->cable_notify_mutex);
+	list_del(&handler->link);
+	mutex_unlock(&hdmi_ctrl->cable_notify_mutex);
+
+	return 0;
+} /* unregister_hdmi_cable_notification */
+
+static void hdmi_tx_cable_notify_work(struct work_struct *work)
+{
+	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+	struct hdmi_cable_notify *pos;
+
+	hdmi_ctrl = container_of(work, struct hdmi_tx_ctrl, cable_notify_work);
+
+	if (!hdmi_ctrl) {
+		DEV_ERR("%s: invalid hdmi data\n", __func__);
+		return;
+	}
+
+	mutex_lock(&hdmi_ctrl->cable_notify_mutex);
+	list_for_each_entry(pos, &hdmi_ctrl->cable_notify_handlers, link) {
+		if (pos->status != hdmi_ctrl->hpd_state) {
+			pos->status = hdmi_ctrl->hpd_state;
+			pos->hpd_notify(pos);
+		}
+	}
+	mutex_unlock(&hdmi_ctrl->cable_notify_mutex);
+} /* hdmi_tx_cable_notify_work */
+
 static bool hdmi_tx_is_cea_format(int mode)
 {
 	bool cea_fmt;
@@ -327,6 +399,9 @@
 
 	if (!hdmi_ctrl->pdata.primary && (hdmi_ctrl->sdev.state != val))
 		switch_set_state(&hdmi_ctrl->sdev, val);
+
+	/* Notify all registered modules of cable connection status */
+	schedule_work(&hdmi_ctrl->cable_notify_work);
 } /* hdmi_tx_send_cable_notification */
 
 static inline u32 hdmi_tx_is_dvi_mode(struct hdmi_tx_ctrl *hdmi_ctrl)
@@ -2835,6 +2910,7 @@
 	if (hdmi_ctrl->workq)
 		destroy_workqueue(hdmi_ctrl->workq);
 	mutex_destroy(&hdmi_ctrl->lut_lock);
+	mutex_destroy(&hdmi_ctrl->cable_notify_mutex);
 	mutex_destroy(&hdmi_ctrl->mutex);
 
 	hdmi_tx_hw.ptr = NULL;
@@ -2864,6 +2940,10 @@
 	hdmi_setup_video_mode_lut();
 	mutex_init(&hdmi_ctrl->mutex);
 	mutex_init(&hdmi_ctrl->lut_lock);
+	mutex_init(&hdmi_ctrl->cable_notify_mutex);
+
+	INIT_LIST_HEAD(&hdmi_ctrl->cable_notify_handlers);
+
 	hdmi_ctrl->workq = create_workqueue("hdmi_tx_workq");
 	if (!hdmi_ctrl->workq) {
 		DEV_ERR("%s: hdmi_tx_workq creation failed.\n", __func__);
@@ -2881,8 +2961,9 @@
 	hdmi_ctrl->hpd_initialized = false;
 	hdmi_ctrl->hpd_off_pending = false;
 	init_completion(&hdmi_ctrl->hpd_done);
-	INIT_WORK(&hdmi_ctrl->hpd_int_work, hdmi_tx_hpd_int_work);
 
+	INIT_WORK(&hdmi_ctrl->hpd_int_work, hdmi_tx_hpd_int_work);
+	INIT_WORK(&hdmi_ctrl->cable_notify_work, hdmi_tx_cable_notify_work);
 	INIT_WORK(&hdmi_ctrl->power_off_work, hdmi_tx_power_off_work);
 
 	spin_lock_init(&hdmi_ctrl->hpd_state_lock);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.h b/drivers/video/msm/mdss/mdss_hdmi_tx.h
index 0787dee..8233ba8 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2014, 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
@@ -55,6 +55,8 @@
 
 	struct mutex mutex;
 	struct mutex lut_lock;
+	struct mutex cable_notify_mutex;
+	struct list_head cable_notify_handlers;
 	struct kobject *kobj;
 	struct switch_dev sdev;
 	struct switch_dev audio_sdev;
@@ -78,6 +80,7 @@
 	struct work_struct hpd_int_work;
 
 	struct work_struct power_off_work;
+	struct work_struct cable_notify_work;
 
 	bool hdcp_feature_on;
 	u32 present_hdcp;
diff --git a/include/linux/msm_hdmi.h b/include/linux/msm_hdmi.h
new file mode 100644
index 0000000..70fae94
--- /dev/null
+++ b/include/linux/msm_hdmi.h
@@ -0,0 +1,57 @@
+/* include/linux/msm_hdmi.h
+ *
+ * Copyright (c) 2014 The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _MSM_HDMI_H_
+#define _MSM_HDMI_H_
+
+/*
+ * HDMI cable notify handler sturcture.
+ * link A link for the linked list
+ * status Current status of HDMI cable connection
+ * hpd_notify Callback function to provide cable status
+ */
+struct hdmi_cable_notify {
+	struct list_head link;
+	int status;
+	void (*hpd_notify) (struct hdmi_cable_notify *h);
+};
+
+#ifdef CONFIG_FB_MSM_MDSS_HDMI_PANEL
+/*
+ * Register for HDMI cable connect or disconnect notification.
+ * @param handler callback handler for notification
+ * @return negative value as error otherwise current status of cable
+ */
+int register_hdmi_cable_notification(
+		struct hdmi_cable_notify *handler);
+
+/*
+ * Un-register for HDMI cable connect or disconnect notification.
+ * @param handler callback handler for notification
+ * @return negative value as error
+ */
+int unregister_hdmi_cable_notification(
+		struct hdmi_cable_notify *handler);
+#else
+int register_hdmi_cable_notification(
+		struct hdmi_cable_notify *handler) {
+	return 0;
+}
+
+int unregister_hdmi_cable_notification(
+		struct hdmi_cable_notify *handler) {
+	return 0;
+}
+#endif /* CONFIG_FB_MSM_MDSS_HDMI_PANEL */
+
+#endif /*_MSM_HDMI_H_*/
diff --git a/include/linux/qrng.h b/include/linux/qrng.h
index 35708e3..8c09627 100644
--- a/include/linux/qrng.h
+++ b/include/linux/qrng.h
@@ -1,5 +1,5 @@
-#ifndef __QRNG_H_
-#define __QRNG_H_
+#ifndef _QRNG_H_
+#define _QRNG_H_
 
 #include <linux/types.h>
 #include <linux/ioctl.h>
@@ -9,4 +9,4 @@
 #define QRNG_IOCTL_RESET_BUS_BANDWIDTH\
 	_IO(QRNG_IOC_MAGIC, 1)
 
-#endif /* __QRNG_H_ */
+#endif /* _QRNG_H_ */