Prechádzať zdrojové kódy

Merge "soc: swr-mstr: add support for hardware wakeup interrupt"

Linux Build Service Account 6 rokov pred
rodič
commit
86a34cd9cc
3 zmenil súbory, kde vykonal 93 pridanie a 16 odobranie
  1. 1 0
      include/soc/swr-wcd.h
  2. 89 14
      soc/swr-mstr-ctrl.c
  3. 3 2
      soc/swr-mstr-ctrl.h

+ 1 - 0
include/soc/swr-wcd.h

@@ -26,6 +26,7 @@ enum {
 	SWR_CLK_FREQ,
 	SWR_DEVICE_SSR_DOWN,
 	SWR_DEVICE_SSR_UP,
+	SWR_REGISTER_WAKE_IRQ,
 };
 
 struct swr_mstr_port {

+ 89 - 14
soc/swr-mstr-ctrl.c

@@ -1421,6 +1421,32 @@ handle_irq:
 	return ret;
 }
 
+static irqreturn_t swrm_wakeup_interrupt(int irq, void *dev)
+{
+	struct swr_mstr_ctrl *swrm = dev;
+	int ret = IRQ_HANDLED;
+
+	if (!swrm || !(swrm->dev)) {
+		pr_err("%s: swrm or dev is null\n", __func__);
+		return IRQ_NONE;
+	}
+	mutex_lock(&swrm->devlock);
+	if (!swrm->dev_up) {
+		if (swrm->wake_irq > 0)
+			disable_irq_nosync(swrm->wake_irq);
+		mutex_unlock(&swrm->devlock);
+		return ret;
+	}
+	mutex_unlock(&swrm->devlock);
+	if (swrm->wake_irq > 0)
+		disable_irq_nosync(swrm->wake_irq);
+	pm_runtime_get_sync(swrm->dev);
+	pm_runtime_mark_last_busy(swrm->dev);
+	pm_runtime_put_autosuspend(swrm->dev);
+
+	return ret;
+}
+
 static void swrm_wakeup_work(struct work_struct *work)
 {
 	struct swr_mstr_ctrl *swrm;
@@ -1592,8 +1618,8 @@ static int swrm_event_notify(struct notifier_block *self,
 		schedule_work(&(swrm->dc_presence_work));
 		break;
 	case SWR_WAKE_IRQ_EVENT:
-		if (swrm->wakeup_req && !swrm->wakeup_triggered) {
-			swrm->wakeup_triggered = true;
+		if (swrm->ipc_wakeup && !swrm->ipc_wakeup_triggered) {
+			swrm->ipc_wakeup_triggered = true;
 			schedule_work(&swrm->wakeup_work);
 		}
 		break;
@@ -1769,6 +1795,8 @@ static int swrm_probe(struct platform_device *pdev)
 	swrm->mclk_freq = MCLK_FREQ;
 	swrm->dev_up = true;
 	swrm->state = SWR_MSTR_UP;
+	swrm->ipc_wakeup = false;
+	swrm->ipc_wakeup_triggered = false;
 	init_completion(&swrm->reset);
 	init_completion(&swrm->broadcast);
 	init_completion(&swrm->clk_off_complete);
@@ -1796,11 +1824,6 @@ static int swrm_probe(struct platform_device *pdev)
 		}
 	}
 
-	if (of_property_read_u32(swrm->dev->of_node,
-			"qcom,swr-wakeup-required", &swrm->wakeup_req)) {
-		swrm->wakeup_req = false;
-	}
-
 	if (swrm->reg_irq) {
 		ret = swrm->reg_irq(swrm->handle, swr_mstr_interrupt, swrm,
 			    SWR_IRQ_REGISTER);
@@ -1910,6 +1933,9 @@ static int swrm_remove(struct platform_device *pdev)
 				swrm, SWR_IRQ_FREE);
 	else if (swrm->irq)
 		free_irq(swrm->irq, swrm);
+	else if (swrm->wake_irq > 0)
+		free_irq(swrm->wake_irq, swrm);
+
 	pm_runtime_disable(&pdev->dev);
 	pm_runtime_set_suspended(&pdev->dev);
 	swr_unregister_master(&swrm->master);
@@ -1951,9 +1977,10 @@ static int swrm_runtime_resume(struct device *dev)
 
 	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->clk_stop_mode0_supp) {
+			if (swrm->ipc_wakeup)
+				msm_aud_evt_blocking_notifier_call_chain(
+					SWR_WAKE_IRQ_DEREGISTER, (void *)swrm);
 		}
 
 		if (swrm_clk_request(swrm, true))
@@ -2032,10 +2059,14 @@ static int swrm_runtime_suspend(struct device *dev)
 		}
 		swrm_clk_request(swrm, false);
 
-		if (swrm->clk_stop_mode0_supp && swrm->wakeup_req) {
-			msm_aud_evt_blocking_notifier_call_chain(
-				SWR_WAKE_IRQ_REGISTER, (void *)swrm);
-			swrm->wakeup_triggered = false;
+		if (swrm->clk_stop_mode0_supp) {
+			if (swrm->wake_irq > 0) {
+				enable_irq(swrm->wake_irq);
+			} else if (swrm->ipc_wakeup) {
+				msm_aud_evt_blocking_notifier_call_chain(
+					SWR_WAKE_IRQ_REGISTER, (void *)swrm);
+				swrm->ipc_wakeup_triggered = false;
+			}
 		}
 
 	}
@@ -2071,6 +2102,35 @@ static int swrm_device_down(struct device *dev)
 	return 0;
 }
 
+int swrm_register_wake_irq(struct swr_mstr_ctrl *swrm)
+{
+	int ret = 0;
+
+	if (!swrm->ipc_wakeup) {
+		swrm->wake_irq = platform_get_irq_byname(swrm->pdev,
+					"swr_wake_irq");
+		if (swrm->wake_irq < 0) {
+			dev_err(swrm->dev,
+				"%s() error getting wake irq handle: %d\n",
+				__func__, swrm->wake_irq);
+			return -EINVAL;
+		}
+
+		ret = request_threaded_irq(swrm->wake_irq, NULL,
+					   swrm_wakeup_interrupt,
+					   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+					   "swr_wake_irq", swrm);
+		if (ret) {
+			dev_err(swrm->dev, "%s: Failed to request irq %d\n",
+				__func__, ret);
+			return -EINVAL;
+		}
+		/* Disable wake irq - enable it after clock stop */
+		disable_irq(swrm->wake_irq);
+	}
+	return ret;
+}
+
 /**
  * swrm_wcd_notify - parent device can notify to soundwire master through
  * this function
@@ -2196,6 +2256,21 @@ int swrm_wcd_notify(struct platform_device *pdev, u32 id, void *data)
 			mutex_unlock(&swrm->mlock);
 		}
 		break;
+	case SWR_REGISTER_WAKE_IRQ:
+		if (!data) {
+			dev_err(swrm->dev, "%s: reg wake irq data is NULL\n",
+				__func__);
+			ret = -EINVAL;
+		} else {
+			mutex_lock(&swrm->mlock);
+			swrm->ipc_wakeup = *(u32 *)data;
+			ret = swrm_register_wake_irq(swrm);
+			if (ret)
+				dev_err(swrm->dev, "%s: register wake_irq failed\n",
+					__func__);
+			mutex_unlock(&swrm->mlock);
+		}
+		break;
 	default:
 		dev_err(swrm->dev, "%s: swr master unknown id %d\n",
 			__func__, id);

+ 3 - 2
soc/swr-mstr-ctrl.h

@@ -131,6 +131,7 @@ struct swr_mstr_ctrl {
 	int (*reg_irq)(void *handle, irqreturn_t(*irq_handler)(int irq,
 			void *data), void *swr_handle, int type);
 	int irq;
+	int wake_irq;
 	int version;
 	int mclk_freq;
 	u32 num_dev;
@@ -152,9 +153,9 @@ struct swr_mstr_ctrl {
 	int swr_irq;
 	u32 clk_stop_mode0_supp;
 	struct work_struct wakeup_work;
-	u32 wakeup_req;
+	u32 ipc_wakeup;
 	bool dev_up;
-	bool wakeup_triggered;
+	bool ipc_wakeup_triggered;
 };
 
 #endif /* _SWR_WCD_CTRL_H */