Merge "soc: qcom: bgrsb: Enable rsb after rsb configure"
diff --git a/drivers/soc/qcom/bg_rsb.c b/drivers/soc/qcom/bg_rsb.c
index 05fb9ab..c35e385 100644
--- a/drivers/soc/qcom/bg_rsb.c
+++ b/drivers/soc/qcom/bg_rsb.c
@@ -139,6 +139,7 @@
 
 	bool is_cnfgrd;
 	bool blk_rsb_cmnds;
+	bool pending_enable;
 };
 
 static void *bgrsb_drv;
@@ -406,6 +407,8 @@
 	struct bgrsb_priv *dev = container_of(work, struct bgrsb_priv,
 								bg_down_work);
 
+	mutex_lock(&dev->rsb_state_mutex);
+
 	if (dev->bgrsb_current_state == BGRSB_STATE_RSB_ENABLED) {
 		if (bgrsb_ldo_work(dev, BGRSB_DISABLE_LDO15) == 0)
 			dev->bgrsb_current_state = BGRSB_STATE_RSB_CONFIGURED;
@@ -428,6 +431,8 @@
 		if (dev->is_calibrd)
 			dev->calibration_needed = true;
 	}
+
+	mutex_unlock(&dev->rsb_state_mutex);
 }
 
 static void bgrsb_glink_bgdown_work(struct work_struct *work)
@@ -436,17 +441,19 @@
 	struct bgrsb_priv *dev = container_of(work, struct bgrsb_priv,
 							rsb_glink_down_work);
 
+	mutex_lock(&dev->rsb_state_mutex);
+
 	if (dev->bgrsb_current_state == BGRSB_STATE_RSB_ENABLED) {
 
 		rc = bgrsb_enable(dev, false);
 		if (rc != 0) {
 			pr_err("Failed to send disable command to BG\n");
-			return;
+			goto unlock;
 		}
 
 		if (bgrsb_ldo_work(dev, BGRSB_DISABLE_LDO15) != 0) {
 			pr_err("Failed to un-vote LDO-15\n");
-			return;
+			goto unlock;
 		}
 
 		dev->bgrsb_current_state = BGRSB_STATE_RSB_CONFIGURED;
@@ -468,6 +475,9 @@
 		glink_close(dev->handle);
 	dev->handle = NULL;
 	pr_debug("BG Glink Close connection\n");
+
+unlock:
+	mutex_unlock(&dev->rsb_state_mutex);
 }
 
 static int bgrsb_tx_msg(struct bgrsb_priv *dev, void  *msg, size_t len)
@@ -558,6 +568,7 @@
 	struct bgrsb_priv *dev = container_of(work, struct bgrsb_priv,
 								bg_up_work);
 
+	mutex_lock(&dev->rsb_state_mutex);
 	if (bgrsb_ldo_work(dev, BGRSB_ENABLE_LDO11) == 0) {
 
 		rc = wait_event_timeout(dev->link_state_wait,
@@ -565,20 +576,24 @@
 					msecs_to_jiffies(TIMEOUT_MS));
 		if (rc == 0) {
 			pr_err("Glink channel connection time out\n");
-			return;
+			goto unlock;
 		}
 		rc = bgrsb_configr_rsb(dev, true);
 		if (rc != 0) {
 			pr_err("BG failed to configure RSB %d\n", rc);
 			if (bgrsb_ldo_work(dev, BGRSB_DISABLE_LDO11) == 0)
 				dev->bgrsb_current_state = BGRSB_STATE_INIT;
-			return;
+			goto unlock;
 		}
 
 		dev->is_cnfgrd = true;
 		dev->bgrsb_current_state = BGRSB_STATE_RSB_CONFIGURED;
 		pr_debug("RSB Cofigured\n");
+		if (dev->pending_enable)
+			queue_work(dev->bgrsb_wq, &dev->rsb_up_work);
 	}
+unlock:
+	mutex_unlock(&dev->rsb_state_mutex);
 }
 
 static void bgrsb_glink_bgup_work(struct work_struct *work)
@@ -587,6 +602,7 @@
 	struct bgrsb_priv *dev = container_of(work, struct bgrsb_priv,
 							rsb_glink_up_work);
 
+	mutex_lock(&dev->rsb_state_mutex);
 	if (bgrsb_ldo_work(dev, BGRSB_ENABLE_LDO11) == 0) {
 
 		INIT_WORK(&dev->glink_work, bgrsb_glink_open_work);
@@ -597,19 +613,25 @@
 						msecs_to_jiffies(TIMEOUT_MS));
 		if (rc == 0) {
 			pr_err("Glink channel connection time out\n");
-			return;
+			goto unlock;
 		}
 		rc = bgrsb_configr_rsb(dev, true);
 		if (rc != 0) {
 			pr_err("BG Glink failed to configure RSB %d\n", rc);
 			if (bgrsb_ldo_work(dev, BGRSB_DISABLE_LDO11) == 0)
 				dev->bgrsb_current_state = BGRSB_STATE_INIT;
-			return;
+			goto unlock;
 		}
 		dev->is_cnfgrd = true;
 		dev->bgrsb_current_state = BGRSB_STATE_RSB_CONFIGURED;
 		pr_debug("Glink RSB Cofigured\n");
+
+		if (dev->pending_enable)
+			queue_work(dev->bgrsb_wq, &dev->rsb_up_work);
 	}
+
+unlock:
+	mutex_unlock(&dev->rsb_state_mutex);
 }
 
 /**
@@ -625,6 +647,8 @@
 
 	switch (opcode) {
 	case SUBSYS_BEFORE_SHUTDOWN:
+		if (dev->bgrsb_current_state == BGRSB_STATE_RSB_ENABLED)
+			dev->pending_enable = true;
 		queue_work(dev->bgrsb_wq, &dev->bg_down_work);
 		break;
 	case SUBSYS_AFTER_POWERUP:
@@ -669,8 +693,13 @@
 								rsb_up_work);
 
 	mutex_lock(&dev->rsb_state_mutex);
+	if (dev->bgrsb_current_state == BGRSB_STATE_RSB_ENABLED) {
+		pr_debug("RSB is already enabled\n");
+		goto unlock;
+	}
 	if (dev->bgrsb_current_state != BGRSB_STATE_RSB_CONFIGURED) {
 		pr_err("BG is not yet configured for RSB\n");
+		dev->pending_enable = true;
 		goto unlock;
 	}
 
@@ -685,6 +714,7 @@
 		}
 	}
 	dev->bgrsb_current_state = BGRSB_STATE_RSB_ENABLED;
+	dev->pending_enable = false;
 	pr_debug("RSB Enabled\n");
 
 	if (dev->calibration_needed) {
@@ -703,6 +733,7 @@
 								rsb_down_work);
 
 	mutex_lock(&dev->rsb_state_mutex);
+	dev->pending_enable = false;
 	if (dev->bgrsb_current_state == BGRSB_STATE_RSB_ENABLED) {
 
 		rc = bgrsb_enable(dev, false);
@@ -730,9 +761,11 @@
 			container_of(work, struct bgrsb_priv,
 							rsb_calibration_work);
 
+	mutex_lock(&dev->rsb_state_mutex);
+
 	if (!dev->is_cnfgrd) {
 		pr_err("RSB is not configured\n");
-		return;
+		goto unlock;
 	}
 
 	req.cmd_id = 0x03;
@@ -741,7 +774,7 @@
 	rc = bgrsb_tx_msg(dev, &req, 5);
 	if (rc != 0) {
 		pr_err("Failed to send resolution value to BG\n");
-		return;
+		goto unlock;
 	}
 
 	req.cmd_id = 0x04;
@@ -750,10 +783,13 @@
 	rc = bgrsb_tx_msg(dev, &req, 5);
 	if (rc != 0) {
 		pr_err("Failed to send interval value to BG\n");
-		return;
+		goto unlock;
 	}
 	dev->is_calibrd = true;
 	pr_debug("RSB Calibbered\n");
+
+unlock:
+	mutex_unlock(&dev->rsb_state_mutex);
 }
 
 static void bgrsb_buttn_configration(struct work_struct *work)
@@ -764,9 +800,10 @@
 			container_of(work, struct bgrsb_priv,
 							bttn_configr_work);
 
+	mutex_lock(&dev->rsb_state_mutex);
 	if (!dev->is_cnfgrd) {
 		pr_err("RSB is not configured\n");
-		return;
+		goto unlock;
 	}
 
 	req.cmd_id = 0x05;
@@ -775,11 +812,36 @@
 	rc = bgrsb_tx_msg(dev, &req, 5);
 	if (rc != 0) {
 		pr_err("Failed to send button configuration cmnd to BG\n");
-		return;
+		goto unlock;
 	}
 
 	dev->bttn_configs = 0;
 	pr_debug("Button configured\n");
+
+unlock:
+	mutex_unlock(&dev->rsb_state_mutex);
+}
+
+static int bgrsb_handle_cmd_in_ssr(struct bgrsb_priv *dev, char *str)
+{
+	long val;
+	int ret;
+	char *tmp;
+
+	tmp = strsep(&str, ":");
+	if (!tmp)
+		return -EINVAL;
+
+	ret = kstrtol(tmp, 10, &val);
+	if (ret < 0)
+		return ret;
+
+	if (val == BGRSB_POWER_ENABLE)
+		dev->pending_enable = true;
+	else if (val == BGRSB_POWER_DISABLE)
+		dev->pending_enable = false;
+
+	return 0;
 }
 
 static int split_bg_work(struct bgrsb_priv *dev, char *str)
@@ -868,6 +930,7 @@
 	}
 
 	if (!dev->is_cnfgrd) {
+		bgrsb_handle_cmd_in_ssr(dev, arr);
 		kfree(arr);
 		return -ENOMEDIUM;
 	}
@@ -875,6 +938,7 @@
 	rc = split_bg_work(dev, arr);
 	if (rc != 0)
 		pr_err("Not able to process request\n");
+	kfree(arr);
 	return count;
 }