Bläddra i källkod

Merge "soc: swr-mstr: Add proper handling of SSR and clock stop"

Linux Build Service Account 6 år sedan
förälder
incheckning
13bf73f231
1 ändrade filer med 47 tillägg och 26 borttagningar
  1. 47 26
      soc/swr-mstr-ctrl.c

+ 47 - 26
soc/swr-mstr-ctrl.c

@@ -238,11 +238,9 @@ static int swrm_clk_request(struct swr_mstr_ctrl *swrm, bool enable)
 		swrm->clk_ref_count++;
 		if (swrm->clk_ref_count == 1) {
 			swrm->clk(swrm->handle, true);
-			swrm->state = SWR_MSTR_UP;
 		}
 	} else if (--swrm->clk_ref_count == 0) {
 		swrm->clk(swrm->handle, false);
-		swrm->state = SWR_MSTR_DOWN;
 	} else if (swrm->clk_ref_count < 0) {
 		pr_err("%s: swrm clk count mismatch\n", __func__);
 		swrm->clk_ref_count = 0;
@@ -1065,6 +1063,13 @@ static int swrm_connect_port(struct swr_master *master,
 	}
 
 	mutex_lock(&swrm->mlock);
+	mutex_lock(&swrm->devlock);
+	if (!swrm->dev_up) {
+		mutex_unlock(&swrm->devlock);
+		mutex_unlock(&swrm->mlock);
+		return -EINVAL;
+	}
+	mutex_unlock(&swrm->devlock);
 	if (!swrm_is_port_en(master))
 		pm_runtime_get_sync(swrm->dev);
 
@@ -1257,7 +1262,7 @@ static irqreturn_t swr_mstr_interrupt(int irq, void *dev)
 			if (ret) {
 				dev_err(swrm->dev, "no slave alert found.\
 						spurious interrupt\n");
-				return ret;
+				break;
 			}
 			swrm_cmd_fifo_rd_cmd(swrm, &temp, devnum, 0x0,
 						SWRS_SCP_INT_STATUS_CLEAR_1, 1);
@@ -1381,11 +1386,14 @@ static void swrm_wakeup_work(struct work_struct *work)
 		pr_err("%s: swrm or dev is null\n", __func__);
 		return;
 	}
-	pm_runtime_get_sync(swrm->dev);
-
-	swrm_cmd_fifo_wr_cmd(swrm, 0x4, 0xF, 0xF,
-			     SWRS_SCP_INT_STATUS_MASK_1);
 
+	mutex_lock(&swrm->devlock);
+	if (!swrm->dev_up) {
+		mutex_unlock(&swrm->devlock);
+		return;
+	}
+	mutex_unlock(&swrm->devlock);
+	pm_runtime_get_sync(swrm->dev);
 	pm_runtime_mark_last_busy(swrm->dev);
 	pm_runtime_put_autosuspend(swrm->dev);
 }
@@ -1419,6 +1427,14 @@ static int swrm_get_logical_dev_num(struct swr_master *mstr, u64 dev_id,
 		num_dev = swrm->num_dev;
 	else
 		num_dev = mstr->num_dev;
+
+	mutex_lock(&swrm->devlock);
+	if (!swrm->dev_up) {
+		mutex_unlock(&swrm->devlock);
+		return ret;
+	}
+	mutex_unlock(&swrm->devlock);
+
 	pm_runtime_get_sync(swrm->dev);
 	for (i = 1; i < (num_dev + 1); i++) {
 		id = ((u64)(swr_master_read(swrm,
@@ -1704,7 +1720,7 @@ static int swrm_probe(struct platform_device *pdev)
 	swrm->clk_ref_count = 0;
 	swrm->mclk_freq = MCLK_FREQ;
 	swrm->dev_up = true;
-	swrm->state = SWR_MSTR_RESUME;
+	swrm->state = SWR_MSTR_UP;
 	init_completion(&swrm->reset);
 	init_completion(&swrm->broadcast);
 	mutex_init(&swrm->mlock);
@@ -1863,7 +1879,6 @@ static int swrm_clk_pause(struct swr_mstr_ctrl *swrm)
 	val = swr_master_read(swrm, SWRM_MCP_CFG_ADDR);
 	val |= SWRM_MCP_CFG_BUS_CLK_PAUSE_BMSK;
 	swr_master_write(swrm, SWRM_MCP_CFG_ADDR, val);
-	swrm->state = SWR_MSTR_PAUSE;
 
 	return 0;
 }
@@ -1880,18 +1895,17 @@ static int swrm_runtime_resume(struct device *dev)
 	dev_dbg(dev, "%s: pm_runtime: resume, state:%d\n",
 		__func__, swrm->state);
 	mutex_lock(&swrm->reslock);
-	if ((swrm->state == SWR_MSTR_PAUSE) ||
-	    (swrm->state == SWR_MSTR_DOWN)) {
+
+	if ((swrm->state == SWR_MSTR_DOWN) ||
+	    (swrm->state == SWR_MSTR_SSR && swrm->dev_up)) {
 		if (swrm->clk_stop_mode0_supp && swrm->wakeup_req) {
 			msm_aud_evt_blocking_notifier_call_chain(
 				SWR_WAKE_IRQ_DEREGISTER, (void *)swrm);
 		}
 
-		if (swrm->state == SWR_MSTR_DOWN) {
-			if (swrm_clk_request(swrm, true))
-				goto exit;
-		}
-		if (!swrm->clk_stop_mode0_supp) {
+		if (swrm_clk_request(swrm, true))
+			goto exit;
+		if (!swrm->clk_stop_mode0_supp || swrm->state == SWR_MSTR_SSR) {
 			list_for_each_entry(swr_dev, &mstr->devices, dev_list) {
 				ret = swr_device_up(swr_dev);
 				if (ret) {
@@ -1902,14 +1916,18 @@ static int swrm_runtime_resume(struct device *dev)
 					goto exit;
 				}
 			}
+			swr_master_write(swrm, SWRM_COMP_SW_RESET, 0x01);
+			swr_master_write(swrm, SWRM_COMP_SW_RESET, 0x01);
+			swrm_master_init(swrm);
+			swrm_cmd_fifo_wr_cmd(swrm, 0x4, 0xF, 0x0,
+						SWRS_SCP_INT_STATUS_MASK_1);
+
 		} else {
 			/*wake up from clock stop*/
 			swr_master_write(swrm, SWRM_MCP_BUS_CTRL_ADDR, 0x2);
 			usleep_range(100, 105);
 		}
-		swr_master_write(swrm, SWRM_COMP_SW_RESET, 0x01);
-		swr_master_write(swrm, SWRM_COMP_SW_RESET, 0x01);
-		swrm_master_init(swrm);
+		swrm->state = SWR_MSTR_UP;
 	}
 exit:
 	pm_runtime_set_autosuspend_delay(&pdev->dev, auto_suspend_timer);
@@ -1932,8 +1950,7 @@ static int swrm_runtime_suspend(struct device *dev)
 	mutex_lock(&swrm->force_down_lock);
 	current_state = swrm->state;
 	mutex_unlock(&swrm->force_down_lock);
-	if ((current_state == SWR_MSTR_RESUME) ||
-	    (current_state == SWR_MSTR_UP) ||
+	if ((current_state == SWR_MSTR_UP) ||
 	    (current_state == SWR_MSTR_SSR)) {
 
 		if ((current_state != SWR_MSTR_SSR) &&
@@ -1942,7 +1959,7 @@ static int swrm_runtime_suspend(struct device *dev)
 			ret = -EBUSY;
 			goto exit;
 		}
-		if (!swrm->clk_stop_mode0_supp) {
+		if (!swrm->clk_stop_mode0_supp || swrm->state == SWR_MSTR_SSR) {
 			swrm_clk_pause(swrm);
 			swr_master_write(swrm, SWRM_COMP_CFG_ADDR, 0x00);
 			list_for_each_entry(swr_dev, &mstr->devices, dev_list) {
@@ -1967,6 +1984,9 @@ static int swrm_runtime_suspend(struct device *dev)
 		}
 		swrm_clk_request(swrm, false);
 	}
+	/* Retain  SSR state until resume */
+	if (current_state != SWR_MSTR_SSR)
+		swrm->state = SWR_MSTR_DOWN;
 exit:
 	mutex_unlock(&swrm->reslock);
 	return ret;
@@ -2036,6 +2056,9 @@ int swrm_wcd_notify(struct platform_device *pdev, u32 id, void *data)
 		mutex_lock(&swrm->devlock);
 		swrm->dev_up = false;
 		mutex_unlock(&swrm->devlock);
+		mutex_lock(&swrm->reslock);
+		swrm->state = SWR_MSTR_SSR;
+		mutex_unlock(&swrm->reslock);
 		break;
 	case SWR_DEVICE_SSR_UP:
 		mutex_lock(&swrm->devlock);
@@ -2045,8 +2068,7 @@ int swrm_wcd_notify(struct platform_device *pdev, u32 id, void *data)
 	case SWR_DEVICE_DOWN:
 		dev_dbg(swrm->dev, "%s: swr master down called\n", __func__);
 		mutex_lock(&swrm->mlock);
-		if ((swrm->state == SWR_MSTR_PAUSE) ||
-		    (swrm->state == SWR_MSTR_DOWN))
+		if (swrm->state == SWR_MSTR_DOWN)
 			dev_dbg(swrm->dev, "%s:SWR master is already Down:%d\n",
 				__func__, swrm->state);
 		else
@@ -2057,8 +2079,7 @@ int swrm_wcd_notify(struct platform_device *pdev, u32 id, void *data)
 		dev_dbg(swrm->dev, "%s: swr master up called\n", __func__);
 		mutex_lock(&swrm->mlock);
 		mutex_lock(&swrm->reslock);
-		if ((swrm->state == SWR_MSTR_RESUME) ||
-		    (swrm->state == SWR_MSTR_UP)) {
+		if (swrm->state == SWR_MSTR_UP) {
 			dev_dbg(swrm->dev, "%s: SWR master is already UP: %d\n",
 				__func__, swrm->state);
 			list_for_each_entry(swr_dev, &mstr->devices, dev_list)