diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index 5c185c8d181d3f7b228d9c53f982c463a3d97738..784ffc10a7a15d926b03a1530737c760a73e9919 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -24,6 +24,7 @@
 #include <linux/platform_device.h>
 #include <linux/rbtree.h>
 #include <linux/uaccess.h>
+#include <linux/interrupt.h>
 #include <linux/msm-bus.h>
 #include <linux/msm-bus-board.h>
 #include "ipa_i.h"
@@ -1800,6 +1801,65 @@ static int ipa_init_flt_block(void)
 	return result;
 }
 
+/**
+* ipa_suspend_handler() - Handles the suspend interrupt:
+* wakes up the suspended peripheral by requesting its consumer
+* @interrupt:		Interrupt type
+* @private_data:	The client's private data
+* @interrupt_data:	Interrupt specific information data
+*/
+void ipa_suspend_handler(enum ipa_irq_type interrupt,
+				void *private_data,
+				void *interrupt_data)
+{
+	enum ipa_rm_resource_name resource;
+	u32 suspend_data =
+		((struct ipa_tx_suspend_irq_data *)interrupt_data)->endpoints;
+	u32 bmsk = 1;
+	u32 i = 0;
+
+	IPADBG("interrupt=%d, interrupt_data=%u\n", interrupt, suspend_data);
+	for (i = 0; i < IPA_NUM_PIPES; i++) {
+		if ((suspend_data & bmsk) && (ipa_ctx->ep[i].valid)) {
+			resource = ipa_get_rm_resource_from_ep(i);
+			ipa_rm_request_resource_with_timer(resource);
+		}
+		bmsk = bmsk << 1;
+	}
+}
+
+static int apps_cons_release_resource(void)
+{
+	return 0;
+}
+
+static int apps_cons_request_resource(void)
+{
+	return 0;
+}
+
+static int ipa_create_apps_resource(void)
+{
+	struct ipa_rm_create_params apps_cons_create_params;
+	struct ipa_rm_perf_profile profile;
+	int result = 0;
+
+	memset(&apps_cons_create_params, 0,
+				sizeof(apps_cons_create_params));
+	apps_cons_create_params.name = IPA_RM_RESOURCE_APPS_CONS;
+	apps_cons_create_params.request_resource = apps_cons_request_resource;
+	apps_cons_create_params.release_resource = apps_cons_release_resource;
+	result = ipa_rm_create_resource(&apps_cons_create_params);
+	if (result) {
+		IPAERR("ipa_rm_create_resource failed\n");
+		return result;
+	}
+
+	profile.max_supported_bandwidth_mbps = IPA_APPS_MAX_BW_IN_MBPS;
+	ipa_rm_set_perf_profile(IPA_RM_RESOURCE_APPS_CONS, &profile);
+
+	return result;
+}
 /**
 * ipa_init() - Initialize the IPA Driver
 * @resource_p:	contain platform specific values from DST file
@@ -2074,7 +2134,7 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p,
 	spin_lock_init(&ipa_ctx->idr_lock);
 
 	mutex_init(&ipa_ctx->ipa_active_clients_lock);
-	ipa_ctx->ipa_active_clients = 0;
+	ipa_ctx->ipa_active_clients = 1;
 
 	/* wlan related member */
 	spin_lock_init(&ipa_ctx->wlan_spinlock);
@@ -2082,9 +2142,6 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p,
 	ipa_ctx->wlan_comm_cnt = 0;
 	INIT_LIST_HEAD(&ipa_ctx->wlan_comm_desc_list);
 	memset(&ipa_ctx->wstats, 0, sizeof(struct ipa_wlan_stats));
-	/* enable IPA clocks until the end of the initialization */
-	ipa_inc_client_enable_clks();
-
 	/*
 	 * setup an empty routing table in system memory, this will be used
 	 * to delete a routing table cleanly and safely
@@ -2166,13 +2223,29 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p,
 	}
 	IPADBG("IPA resource manager initialized");
 
+	result = ipa_create_apps_resource();
+	if (result) {
+		IPAERR("Failed to create APPS_CONS resource\n");
+		result = -ENODEV;
+		goto fail_create_apps_resource;
+	}
+
 	/*register IPA IRQ handler*/
-	result = ipa_interrupts_init(resource_p->ipa_irq, resource_p->ee,
+	result = ipa_interrupts_init(resource_p->ipa_irq, 0,
 			ipa_dev);
 	if (result) {
 		IPAERR("ipa interrupts initialization failed\n");
 		result = -ENODEV;
-		goto fail_ipa_rm_init;
+		goto fail_ipa_interrupts_init;
+	}
+
+	/*add handler for suspend interrupt*/
+	result = ipa_add_interrupt_handler(IPA_TX_SUSPEND_IRQ,
+			ipa_suspend_handler, true, NULL);
+	if (result) {
+		IPAERR("register handler for suspend interrupt failed\n");
+		result = -ENODEV;
+		goto fail_add_interrupt_handler;
 	}
 
 	if (ipa_ctx->use_ipa_teth_bridge) {
@@ -2181,7 +2254,7 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p,
 		if (result) {
 			IPAERR(":teth_bridge init failed (%d)\n", -result);
 			result = -ENODEV;
-			goto fail_teth_bridge_init;
+			goto fail_add_interrupt_handler;
 		}
 		IPADBG("teth_bridge initialized");
 	}
@@ -2193,7 +2266,11 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p,
 
 	return 0;
 
-fail_teth_bridge_init:
+fail_add_interrupt_handler:
+	free_irq(resource_p->ipa_irq, ipa_dev);
+fail_ipa_interrupts_init:
+	ipa_rm_delete_resource(IPA_RM_RESOURCE_APPS_CONS);
+fail_create_apps_resource:
 	ipa_rm_exit();
 fail_ipa_rm_init:
 	cdev_del(&ipa_ctx->cdev);
diff --git a/drivers/platform/msm/ipa/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_debugfs.c
index 37aa781568984e40359ae5ae7dca207f954e2db9..bc318587faa07a6d2ac13db6e75145c59a924bbe 100644
--- a/drivers/platform/msm/ipa/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_debugfs.c
@@ -720,6 +720,7 @@ static ssize_t ipa_read_stats(struct file *file, char __user *ubuf,
 			"stat_compl=%u\n"
 			"lan_aggr_close=%u\n"
 			"wan_aggr_close=%u\n"
+			"act_clnt=%u\n"
 			"con_clnt_bmap=0x%x\n",
 			ipa_ctx->stats.tx_sw_pkts,
 			ipa_ctx->stats.tx_hw_pkts,
@@ -728,6 +729,7 @@ static ssize_t ipa_read_stats(struct file *file, char __user *ubuf,
 			ipa_ctx->stats.stat_compl,
 			ipa_ctx->stats.aggr_close,
 			ipa_ctx->stats.wan_aggr_close,
+			ipa_ctx->ipa_active_clients,
 			connect);
 		cnt += nbytes;
 
diff --git a/drivers/platform/msm/ipa/ipa_interrupts.c b/drivers/platform/msm/ipa/ipa_interrupts.c
index 3e9f4766d48fb921beb59e32544a03d5ef200578..dbc45d58f50e9d31766854fe8e0e34d8a67d79aa 100644
--- a/drivers/platform/msm/ipa/ipa_interrupts.c
+++ b/drivers/platform/msm/ipa/ipa_interrupts.c
@@ -38,7 +38,7 @@ static void deferred_interrupt_work(struct work_struct *work)
 			container_of(work,
 			struct ipa_interrupt_work_wrap,
 			interrupt_work);
-	IPAERR("call handler from workq...\n");
+	IPADBG("call handler from workq...\n");
 	work_data->handler(work_data->interrupt, work_data->private_data,
 			work_data->interrupt_data);
 	kfree(work_data->interrupt_data);
@@ -127,10 +127,12 @@ static irqreturn_t ipa_isr(int irq, void *ctxt)
 	u32 reg;
 	u32 bmsk = 1;
 	u32 i = 0;
+	u32 en;
 
+	en = ipa_read_reg(ipa_ctx->mmio, IPA_IRQ_EN_EE_n_ADDR(ipa_ee));
 	reg = ipa_read_reg(ipa_ctx->mmio, IPA_IRQ_STTS_EE_n_ADDR(ipa_ee));
 	for (i = 0; i < IPA_IRQ_MAX; i++) {
-		if (reg & bmsk)
+		if (en & reg & bmsk)
 			handle_interrupt(i);
 		bmsk = bmsk << 1;
 	}
@@ -138,7 +140,6 @@ static irqreturn_t ipa_isr(int irq, void *ctxt)
 
 	return IRQ_HANDLED;
 }
-
 /**
 * ipa_add_interrupt_handler() - Adds handler to an interrupt type
 * @interrupt:		Interrupt type
diff --git a/drivers/platform/msm/ipa/ipa_rm.c b/drivers/platform/msm/ipa/ipa_rm.c
index d65e282e3308b19d54c983445c0bbeebeb5cd644..95851ad04600a10805e086caa1875d4cdbc85cfc 100644
--- a/drivers/platform/msm/ipa/ipa_rm.c
+++ b/drivers/platform/msm/ipa/ipa_rm.c
@@ -16,7 +16,6 @@
 #include "ipa_i.h"
 #include "ipa_rm_dependency_graph.h"
 #include "ipa_rm_i.h"
-#include "ipa_rm_resource.h"
 
 static const char *resource_name_to_str[IPA_RM_RESOURCE_MAX] = {
 	__stringify(IPA_RM_RESOURCE_Q6_PROD),
@@ -254,6 +253,82 @@ bail:
 }
 EXPORT_SYMBOL(ipa_rm_request_resource);
 
+void delayed_release_work_func(struct work_struct *work)
+{
+	struct ipa_rm_resource *resource;
+	struct ipa_rm_delayed_release_work_type *rwork = container_of(
+			to_delayed_work(work),
+			struct ipa_rm_delayed_release_work_type,
+			work);
+
+	if (!IPA_RM_RESORCE_IS_CONS(rwork->resource_name)) {
+		IPA_RM_ERR("can be called on CONS only\n");
+		kfree(rwork);
+		return;
+	}
+	spin_lock(&ipa_rm_ctx->ipa_rm_lock);
+	if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
+					rwork->resource_name,
+					&resource) != 0) {
+		IPA_RM_ERR("resource does not exists\n");
+		goto bail;
+	}
+
+	ipa_rm_resource_consumer_release(
+		(struct ipa_rm_resource_cons *)resource, rwork->needed_bw);
+
+bail:
+	spin_unlock(&ipa_rm_ctx->ipa_rm_lock);
+	kfree(rwork);
+
+}
+
+/**
+ * ipa_rm_request_resource_with_timer() - requests the specified consumer
+ * resource and releases it after 1 second
+ * @resource_name: name of the requested resource
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int ipa_rm_request_resource_with_timer(enum ipa_rm_resource_name resource_name)
+{
+	struct ipa_rm_resource *resource;
+	struct ipa_rm_delayed_release_work_type *release_work;
+	int result;
+
+	if (!IPA_RM_RESORCE_IS_CONS(resource_name)) {
+		IPA_RM_ERR("can be called on CONS only\n");
+		return -EINVAL;
+	}
+
+	spin_lock(&ipa_rm_ctx->ipa_rm_lock);
+	if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
+			resource_name,
+			&resource) != 0) {
+		IPA_RM_ERR("resource does not exists\n");
+		result = -EPERM;
+		goto bail;
+	}
+	result = ipa_rm_resource_consumer_request(
+			(struct ipa_rm_resource_cons *)resource, 0);
+	if (result != 0 && result != -EINPROGRESS) {
+		IPA_RM_ERR("consumer request returned error %d\n", result);
+		result = -EPERM;
+		goto bail;
+	}
+
+	release_work = kzalloc(sizeof(*release_work), GFP_ATOMIC);
+	release_work->resource_name = resource->name;
+	release_work->needed_bw = 0;
+	INIT_DELAYED_WORK(&release_work->work, delayed_release_work_func);
+	schedule_delayed_work(&release_work->work,
+			msecs_to_jiffies(IPA_RM_RELEASE_DELAY_IN_MSEC));
+	result = 0;
+bail:
+	spin_unlock(&ipa_rm_ctx->ipa_rm_lock);
+
+	return result;
+}
 /**
  * ipa_rm_release_resource() - release resource
  * @resource_name: [in] name of the requested resource
@@ -504,6 +579,71 @@ static void ipa_rm_wq_handler(struct work_struct *work)
 	kfree((void *) work);
 }
 
+static void ipa_rm_wq_resume_handler(struct work_struct *work)
+{
+	struct ipa_rm_resource *resource;
+	struct ipa_rm_wq_suspend_resume_work_type *ipa_rm_work =
+			container_of(work,
+			struct ipa_rm_wq_suspend_resume_work_type,
+			work);
+	IPA_RM_DBG("resume work handler: %s",
+		ipa_rm_resource_str(ipa_rm_work->resource_name));
+
+	if (!IPA_RM_RESORCE_IS_CONS(ipa_rm_work->resource_name)) {
+		IPA_RM_ERR("resource is not CONS\n");
+		return;
+	}
+	ipa_inc_client_enable_clks();
+	spin_lock(&ipa_rm_ctx->ipa_rm_lock);
+	if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
+					ipa_rm_work->resource_name,
+					&resource) != 0){
+		IPA_RM_ERR("resource does not exists\n");
+		spin_unlock(&ipa_rm_ctx->ipa_rm_lock);
+		ipa_dec_client_disable_clks();
+		goto bail;
+	}
+	ipa_rm_resource_consumer_request_work(
+			(struct ipa_rm_resource_cons *)resource,
+			ipa_rm_work->prev_state, ipa_rm_work->needed_bw, true);
+	spin_unlock(&ipa_rm_ctx->ipa_rm_lock);
+bail:
+	kfree(ipa_rm_work);
+}
+
+
+static void ipa_rm_wq_suspend_handler(struct work_struct *work)
+{
+	struct ipa_rm_resource *resource;
+	struct ipa_rm_wq_suspend_resume_work_type *ipa_rm_work =
+			container_of(work,
+			struct ipa_rm_wq_suspend_resume_work_type,
+			work);
+	IPA_RM_DBG("suspend work handler: %s",
+		ipa_rm_resource_str(ipa_rm_work->resource_name));
+
+	if (!IPA_RM_RESORCE_IS_CONS(ipa_rm_work->resource_name)) {
+		IPA_RM_ERR("resource is not CONS\n");
+		return;
+	}
+	ipa_suspend_resource_sync(ipa_rm_work->resource_name);
+	spin_lock(&ipa_rm_ctx->ipa_rm_lock);
+	if (ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
+					ipa_rm_work->resource_name,
+					&resource) != 0){
+		IPA_RM_ERR("resource does not exists\n");
+		spin_unlock(&ipa_rm_ctx->ipa_rm_lock);
+		return;
+	}
+	ipa_rm_resource_consumer_release_work(
+			(struct ipa_rm_resource_cons *)resource,
+			ipa_rm_work->prev_state,
+			true);
+	spin_unlock(&ipa_rm_ctx->ipa_rm_lock);
+
+	kfree(ipa_rm_work);
+}
+
 /**
  * ipa_rm_wq_send_cmd() - send a command for deferred work
  * @wq_cmd: command that should be executed
@@ -535,6 +675,48 @@ int ipa_rm_wq_send_cmd(enum ipa_rm_wq_cmd wq_cmd,
 	return result;
 }
 
+int ipa_rm_wq_send_suspend_cmd(enum ipa_rm_resource_name resource_name,
+		enum ipa_rm_resource_state prev_state,
+		u32 needed_bw)
+{
+	int result = -ENOMEM;
+	struct ipa_rm_wq_suspend_resume_work_type *work = kzalloc(sizeof(*work),
+			GFP_ATOMIC);
+	if (work) {
+		INIT_WORK((struct work_struct *)work,
+				ipa_rm_wq_suspend_handler);
+		work->resource_name = resource_name;
+		work->prev_state = prev_state;
+		work->needed_bw = needed_bw;
+		result = queue_work(ipa_rm_ctx->ipa_rm_wq,
+				(struct work_struct *)work);
+	} else {
+		IPA_RM_ERR("no mem\n");
+	}
+
+	return result;
+}
+
+int ipa_rm_wq_send_resume_cmd(enum ipa_rm_resource_name resource_name,
+		enum ipa_rm_resource_state prev_state,
+		u32 needed_bw)
+{
+	int result = -ENOMEM;
+	struct ipa_rm_wq_suspend_resume_work_type *work = kzalloc(sizeof(*work),
+			GFP_ATOMIC);
+	if (work) {
+		INIT_WORK((struct work_struct *)work, ipa_rm_wq_resume_handler);
+		work->resource_name = resource_name;
+		work->prev_state = prev_state;
+		work->needed_bw = needed_bw;
+		result = queue_work(ipa_rm_ctx->ipa_rm_wq,
+				(struct work_struct *)work);
+	} else {
+		IPA_RM_ERR("no mem\n");
+	}
+
+	return result;
+}
 /**
  * ipa_rm_initialize() - initialize IPA RM component
  *
diff --git a/drivers/platform/msm/ipa/ipa_rm_i.h b/drivers/platform/msm/ipa/ipa_rm_i.h
index 2882ffbe1c6d017f54fb378b591be609490dafa4..488dcf74b9519ee3fdc07c231477a835acebce1c 100644
--- a/drivers/platform/msm/ipa/ipa_rm_i.h
+++ b/drivers/platform/msm/ipa/ipa_rm_i.h
@@ -15,6 +15,7 @@
 
 #include <linux/workqueue.h>
 #include <linux/ipa.h>
+#include "ipa_rm_resource.h"
 
 #define IPA_RM_DRV_NAME "ipa_rm"
 
@@ -30,10 +31,25 @@
 #define IPA_RM_RESORCE_IS_CONS(x) \
 	(x >= IPA_RM_RESOURCE_PROD_MAX && x < IPA_RM_RESOURCE_MAX)
 #define IPA_RM_INDEX_INVALID	(-1)
+#define IPA_RM_RELEASE_DELAY_IN_MSEC 1000
 
 int ipa_rm_prod_index(enum ipa_rm_resource_name resource_name);
 int ipa_rm_cons_index(enum ipa_rm_resource_name resource_name);
 
+/**
+ * struct ipa_rm_delayed_release_work_type - IPA RM delayed resource release
+ *				work type
+ * @delayed_work: work struct
+ * @ipa_rm_resource_name: name of the resource on which this work should be done
+ * @needed_bw: bandwidth required for resource in Mbps
+ */
+struct ipa_rm_delayed_release_work_type {
+	struct delayed_work		work;
+	enum ipa_rm_resource_name	resource_name;
+	u32				needed_bw;
+
+};
+
 /**
  * enum ipa_rm_wq_cmd - workqueue commands
  */
@@ -63,11 +79,36 @@ struct ipa_rm_wq_work_type {
 	bool				notify_registered_only;
 };
 
+/**
+ * struct ipa_rm_wq_suspend_resume_work_type - IPA RM worqueue resume or
+ *				suspend work type
+ * @work: work struct
+ * @resource_name: name of the resource on which this work
+ *			should be done
+ * @prev_state:
+ * @needed_bw:
+ */
+struct ipa_rm_wq_suspend_resume_work_type {
+	struct work_struct		work;
+	enum ipa_rm_resource_name	resource_name;
+	enum ipa_rm_resource_state	prev_state;
+	u32				needed_bw;
+
+};
+
 int ipa_rm_wq_send_cmd(enum ipa_rm_wq_cmd wq_cmd,
 		enum ipa_rm_resource_name resource_name,
 		enum ipa_rm_event event,
 		bool notify_registered_only);
 
+int ipa_rm_wq_send_resume_cmd(enum ipa_rm_resource_name resource_name,
+		enum ipa_rm_resource_state prev_state,
+		u32 needed_bw);
+
+int ipa_rm_wq_send_suspend_cmd(enum ipa_rm_resource_name resource_name,
+		enum ipa_rm_resource_state prev_state,
+		u32 needed_bw);
+
 int ipa_rm_initialize(void);
 
 int ipa_rm_stat(char *buf, int size);
@@ -76,6 +117,10 @@ const char *ipa_rm_resource_str(enum ipa_rm_resource_name resource_name);
 
 void ipa_rm_perf_profile_change(enum ipa_rm_resource_name resource_name);
 
+int ipa_rm_request_resource_with_timer(enum ipa_rm_resource_name resource_name);
+
+void delayed_release_work_func(struct work_struct *work);
+
 void ipa_rm_exit(void);
 
 #endif /* _IPA_RM_I_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_rm_peers_list.c b/drivers/platform/msm/ipa/ipa_rm_peers_list.c
index 073f21b131a64606b98b5427052a0aea9ed4baca..41ae20466d16551487160a5d2c599fc81e8bd97d 100644
--- a/drivers/platform/msm/ipa/ipa_rm_peers_list.c
+++ b/drivers/platform/msm/ipa/ipa_rm_peers_list.c
@@ -13,7 +13,6 @@
 #include <linux/slab.h>
 #include "ipa_i.h"
 #include "ipa_rm_i.h"
-#include "ipa_rm_resource.h"
 
 /**
  * ipa_rm_peers_list_get_resource_index() - resource name to index
diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.c b/drivers/platform/msm/ipa/ipa_rm_resource.c
index 9dd7f11aa67306a73e940ced1cbdffc043c36a5b..d3d965e9d62a4af65b21168ff83a7d508c6d80f1 100644
--- a/drivers/platform/msm/ipa/ipa_rm_resource.c
+++ b/drivers/platform/msm/ipa/ipa_rm_resource.c
@@ -75,40 +75,94 @@ int ipa_rm_cons_index(enum ipa_rm_resource_name resource_name)
 	return result;
 }
 
-static int ipa_rm_resource_consumer_request(
+int ipa_rm_resource_consumer_release_work(
+		struct ipa_rm_resource_cons *consumer,
+		enum ipa_rm_resource_state prev_state,
+		bool notify_completion)
+{
+	int driver_result;
+
+	IPA_RM_DBG("calling driver CB\n");
+	driver_result = consumer->release_resource();
+	IPA_RM_DBG("driver CB returned with %d\n", driver_result);
+	if (driver_result != 0 && driver_result != -EINPROGRESS) {
+		IPA_RM_ERR("driver CB returned error %d\n", driver_result);
+		consumer->resource.state = prev_state;
+		goto bail;
+	}
+	if (driver_result == 0) {
+		if (notify_completion)
+			ipa_rm_resource_consumer_handle_cb(consumer,
+					IPA_RM_RESOURCE_RELEASED);
+		else
+			consumer->resource.state = IPA_RM_RELEASED;
+	}
+
+	ipa_rm_perf_profile_change(consumer->resource.name);
+bail:
+	return driver_result;
+}
+
+int ipa_rm_resource_consumer_request_work(struct ipa_rm_resource_cons *consumer,
+		enum ipa_rm_resource_state prev_state,
+		u32 prod_needed_bw,
+		bool notify_completion)
+{
+	int driver_result;
+
+	IPA_RM_DBG("calling driver CB\n");
+	driver_result = consumer->request_resource();
+	IPA_RM_DBG("driver CB returned with %d\n", driver_result);
+	if (driver_result == 0) {
+		if (notify_completion) {
+			ipa_rm_resource_consumer_handle_cb(consumer,
+					IPA_RM_RESOURCE_GRANTED);
+		} else {
+			consumer->resource.state = IPA_RM_GRANTED;
+			ipa_rm_perf_profile_change(consumer->resource.name);
+			ipa_resume_resource(consumer->resource.name);
+		}
+	} else if (driver_result != -EINPROGRESS) {
+		consumer->resource.state = prev_state;
+		consumer->resource.needed_bw -= prod_needed_bw;
+		consumer->usage_count--;
+	}
+
+	return driver_result;
+}
+
+int ipa_rm_resource_consumer_request(
 		struct ipa_rm_resource_cons *consumer,
 		u32 prod_needed_bw)
 {
 	int result = 0;
-	int driver_result;
+	enum ipa_rm_resource_state prev_state;
 
 	IPA_RM_DBG("%s state: %d\n",
 			ipa_rm_resource_str(consumer->resource.name),
 			consumer->resource.state);
 
+	prev_state = consumer->resource.state;
 	consumer->resource.needed_bw += prod_needed_bw;
 	switch (consumer->resource.state) {
 	case IPA_RM_RELEASED:
 	case IPA_RM_RELEASE_IN_PROGRESS:
-	{
-		enum ipa_rm_resource_state prev_state =
-						consumer->resource.state;
 		consumer->resource.state = IPA_RM_REQUEST_IN_PROGRESS;
-		IPA_RM_DBG("calling driver CB\n");
-		driver_result = consumer->request_resource();
-		IPA_RM_DBG("driver CB returned with %d\n", driver_result);
-		if (driver_result == 0) {
-			consumer->resource.state = IPA_RM_GRANTED;
-			ipa_rm_perf_profile_change(consumer->resource.name);
-		} else if (driver_result != -EINPROGRESS) {
-			consumer->resource.state = prev_state;
-			consumer->resource.needed_bw -= prod_needed_bw;
-			result = driver_result;
-			goto bail;
+		if (prev_state == IPA_RM_RELEASE_IN_PROGRESS ||
+				ipa_inc_client_enable_clks_no_block() != 0) {
+			IPA_RM_DBG("async resume work for %s\n",
+				ipa_rm_resource_str(consumer->resource.name));
+			ipa_rm_wq_send_resume_cmd(consumer->resource.name,
+						prev_state,
+						prod_needed_bw);
+			result = -EINPROGRESS;
+			break;
 		}
-		result = driver_result;
+		result = ipa_rm_resource_consumer_request_work(consumer,
+						prev_state,
+						prod_needed_bw,
+						false);
 		break;
-	}
 	case IPA_RM_GRANTED:
 		ipa_rm_perf_profile_change(consumer->resource.name);
 		break;
@@ -130,7 +184,7 @@ bail:
 	return result;
 }
 
-static int ipa_rm_resource_consumer_release(
+int ipa_rm_resource_consumer_release(
 		struct ipa_rm_resource_cons *consumer,
 		u32 prod_needed_bw)
 {
@@ -140,6 +194,7 @@ static int ipa_rm_resource_consumer_release(
 	IPA_RM_DBG("%s state: %d\n",
 		ipa_rm_resource_str(consumer->resource.name),
 		consumer->resource.state);
+	save_state = consumer->resource.state;
 	consumer->resource.needed_bw -= prod_needed_bw;
 	switch (consumer->resource.state) {
 	case IPA_RM_RELEASED:
@@ -153,22 +208,20 @@ static int ipa_rm_resource_consumer_release(
 		}
 		consumer->usage_count--;
 		if (consumer->usage_count == 0) {
-			save_state = consumer->resource.state;
 			consumer->resource.state = IPA_RM_RELEASE_IN_PROGRESS;
-			IPA_RM_DBG("calling driver CB\n");
-			result = consumer->release_resource();
-			IPA_RM_DBG("driver CB returned with %d\n",
-				result);
-			if (result != 0 && result != -EINPROGRESS) {
-				IPA_RM_ERR("driver CB returned error %d\n",
-					result);
-				consumer->resource.state = save_state;
+			if (save_state == IPA_RM_REQUEST_IN_PROGRESS ||
+			    ipa_suspend_resource_no_block(
+						consumer->resource.name) != 0) {
+				ipa_rm_wq_send_suspend_cmd(
+						consumer->resource.name,
+						save_state,
+						prod_needed_bw);
+				result = -EINPROGRESS;
 				goto bail;
 			}
-			if (result == 0)
-				consumer->resource.state = IPA_RM_RELEASED;
-			ipa_rm_perf_profile_change(consumer->resource.name);
-
+			result = ipa_rm_resource_consumer_release_work(consumer,
+					save_state, false);
+			goto bail;
 		} else if (consumer->resource.state == IPA_RM_GRANTED) {
 			ipa_rm_perf_profile_change(consumer->resource.name);
 		}
@@ -912,6 +965,7 @@ void ipa_rm_resource_consumer_handle_cb(struct ipa_rm_resource_cons *consumer,
 			goto bail;
 		consumer->resource.state = IPA_RM_GRANTED;
 		ipa_rm_perf_profile_change(consumer->resource.name);
+		ipa_resume_resource(consumer->resource.name);
 		break;
 	case IPA_RM_RELEASE_IN_PROGRESS:
 		if (event == IPA_RM_RESOURCE_GRANTED)
diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.h b/drivers/platform/msm/ipa/ipa_rm_resource.h
index c1b73746cf39295b56a732455f5d74d6d918cdbc..4a66ca48d09783e858420eb22c5d1cef8aff66bd 100644
--- a/drivers/platform/msm/ipa/ipa_rm_resource.h
+++ b/drivers/platform/msm/ipa/ipa_rm_resource.h
@@ -122,6 +122,12 @@ int ipa_rm_resource_producer_request(struct ipa_rm_resource_prod *producer);
 
 int ipa_rm_resource_producer_release(struct ipa_rm_resource_prod *producer);
 
+int ipa_rm_resource_consumer_request(struct ipa_rm_resource_cons *consumer,
+				u32 needed_bw);
+
+int ipa_rm_resource_consumer_release(struct ipa_rm_resource_cons *consumer,
+				u32 needed_bw);
+
 int ipa_rm_resource_set_perf_profile(struct ipa_rm_resource *resource,
 				     struct ipa_rm_perf_profile *profile);
 
@@ -138,4 +144,14 @@ int ipa_rm_resource_producer_print_stat(
 		char *buf,
 		int size);
 
+int ipa_rm_resource_consumer_request_work(struct ipa_rm_resource_cons *consumer,
+		enum ipa_rm_resource_state prev_state,
+		u32 needed_bw,
+		bool notify_completion);
+
+int ipa_rm_resource_consumer_release_work(
+		struct ipa_rm_resource_cons *consumer,
+		enum ipa_rm_resource_state prev_state,
+		bool notify_completion);
+
 #endif /* _IPA_RM_RESOURCE_H_ */
diff --git a/include/linux/ipa.h b/include/linux/ipa.h
index 2a06f46cb5f55da4fbb0c8f0c8da14fe45a88adb..96278509076c0e882722fd9dc318e974e94c4056 100644
--- a/include/linux/ipa.h
+++ b/include/linux/ipa.h
@@ -18,6 +18,8 @@
 #include <linux/types.h>
 #include <linux/msm-sps.h>
 
+#define IPA_APPS_MAX_BW_IN_MBPS 200
+
 /**
  * enum ipa_nat_en_type - NAT setting type in IPA end-point
  */