Merge "soc: swr-mstr: synchronize swr clock requests"
diff --git a/soc/swr-mstr-ctrl.c b/soc/swr-mstr-ctrl.c
index c7fe7d2..d727b46 100644
--- a/soc/swr-mstr-ctrl.c
+++ b/soc/swr-mstr-ctrl.c
@@ -231,21 +231,37 @@
 
 static int swrm_clk_request(struct swr_mstr_ctrl *swrm, bool enable)
 {
+	int ret = 0;
+
 	if (!swrm->clk || !swrm->handle)
 		return -EINVAL;
 
+	mutex_lock(&swrm->clklock);
 	if (enable) {
+		if (!swrm->dev_up)
+			goto exit;
 		swrm->clk_ref_count++;
 		if (swrm->clk_ref_count == 1) {
-			swrm->clk(swrm->handle, true);
+			ret = swrm->clk(swrm->handle, true);
+			if (ret) {
+				dev_err(swrm->dev,
+					"%s: clock enable req failed",
+					__func__);
+				--swrm->clk_ref_count;
+			}
 		}
 	} else if (--swrm->clk_ref_count == 0) {
 		swrm->clk(swrm->handle, false);
-	} else if (swrm->clk_ref_count < 0) {
+		complete(&swrm->clk_off_complete);
+	}
+	if (swrm->clk_ref_count < 0) {
 		pr_err("%s: swrm clk count mismatch\n", __func__);
 		swrm->clk_ref_count = 0;
 	}
-	return 0;
+
+exit:
+	mutex_unlock(&swrm->clklock);
+	return ret;
 }
 
 static int swrm_ahb_write(struct swr_mstr_ctrl *swrm,
@@ -1723,10 +1739,12 @@
 	swrm->state = SWR_MSTR_UP;
 	init_completion(&swrm->reset);
 	init_completion(&swrm->broadcast);
+	init_completion(&swrm->clk_off_complete);
 	mutex_init(&swrm->mlock);
 	mutex_init(&swrm->reslock);
 	mutex_init(&swrm->force_down_lock);
 	mutex_init(&swrm->iolock);
+	mutex_init(&swrm->clklock);
 	mutex_init(&swrm->devlock);
 
 	for (i = 0 ; i < SWR_MSTR_PORT_LEN; i++)
@@ -1845,6 +1863,7 @@
 	mutex_destroy(&swrm->reslock);
 	mutex_destroy(&swrm->force_down_lock);
 	mutex_destroy(&swrm->iolock);
+	mutex_destroy(&swrm->clklock);
 err_pdata_fail:
 err_memory_fail:
 	return ret;
@@ -1865,6 +1884,8 @@
 	msm_aud_evt_unregister_client(&swrm->event_notifier);
 	mutex_destroy(&swrm->mlock);
 	mutex_destroy(&swrm->reslock);
+	mutex_destroy(&swrm->iolock);
+	mutex_destroy(&swrm->clklock);
 	mutex_destroy(&swrm->force_down_lock);
 	devm_kfree(&pdev->dev, swrm);
 	return 0;
@@ -2063,6 +2084,13 @@
 		mutex_unlock(&swrm->reslock);
 		break;
 	case SWR_DEVICE_SSR_UP:
+		/* wait for clk voting to be zero */
+		if (swrm->clk_ref_count &&
+			 !wait_for_completion_timeout(&swrm->clk_off_complete,
+						   (1 * HZ/100)))
+			dev_err(swrm->dev, "%s: clock voting not zero\n",
+				__func__);
+
 		mutex_lock(&swrm->devlock);
 		swrm->dev_up = true;
 		mutex_unlock(&swrm->devlock);
diff --git a/soc/swr-mstr-ctrl.h b/soc/swr-mstr-ctrl.h
index f9faed5..4a40fa3 100644
--- a/soc/swr-mstr-ctrl.h
+++ b/soc/swr-mstr-ctrl.h
@@ -110,8 +110,10 @@
 	struct resource *supplies;
 	struct clk *mclk;
 	int clk_ref_count;
+	struct completion clk_off_complete;
 	struct completion reset;
 	struct completion broadcast;
+	struct mutex clklock;
 	struct mutex iolock;
 	struct mutex devlock;
 	struct mutex mlock;