aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSrinivas Kandagatla <srinivas.kandagatla@linaro.org>2021-10-18 14:09:35 +0100
committerSrinivas Kandagatla <srinivas.kandagatla@linaro.org>2021-12-13 13:52:56 +0000
commitc376a4726b3de68de498558ae26706afe062c6e7 (patch)
tree56149fd020ccebdf6ff620cba05b9c88e6b6aa06
parent0b470ad5a7238f96761805217a61b46414b9bbb4 (diff)
soundwire: qcom: add wake up support
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
-rw-r--r--drivers/soundwire/qcom.c76
1 files changed, 76 insertions, 0 deletions
diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index 1fbc75874438..45df9db44f2d 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -14,6 +14,7 @@
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/slab.h>
+#include <linux/pm_wakeirq.h>
#include <linux/slimbus.h>
#include <linux/soundwire/sdw.h>
#include <linux/soundwire/sdw_registers.h>
@@ -152,6 +153,7 @@ struct qcom_swrm_ctrl {
u8 rd_cmd_id;
int irq;
unsigned int version;
+ int wake_irq;
int num_din_ports;
int num_dout_ports;
int cols_index;
@@ -521,6 +523,48 @@ static int qcom_swrm_enumerate(struct sdw_bus *bus)
return 0;
}
+static irqreturn_t qcom_swrm_wake_irq_handler(int irq, void *dev_id)
+{
+ struct qcom_swrm_ctrl *swrm = dev_id;
+ int ret = IRQ_HANDLED;
+ struct sdw_slave *slave;
+
+ clk_prepare_enable(swrm->hclk);
+
+ if (swrm->wake_irq > 0) {
+ if (unlikely(!irq_get_irq_data(swrm->wake_irq))) {
+ ret = IRQ_NONE;
+ goto err;
+ }
+ if (!irqd_irq_disabled(irq_get_irq_data(swrm->wake_irq)))
+ disable_irq_nosync(swrm->wake_irq);
+ }
+
+ /*
+ * resume all the slaves which must have potentially generated this
+ * interrupt, this should also wake the controller at the same time
+ */
+ list_for_each_entry(slave, &swrm->bus.slaves, node) {
+ ret = pm_runtime_get_sync(&slave->dev);
+ if (ret < 0 && ret != -EACCES) {
+ dev_err_ratelimited(swrm->dev,
+ "pm_runtime_get_sync failed in %s, ret %d\n", __func__, ret);
+ pm_runtime_put_noidle(&slave->dev);
+ ret = IRQ_NONE;
+ goto err;
+ }
+ }
+
+ list_for_each_entry(slave, &swrm->bus.slaves, node) {
+ pm_runtime_mark_last_busy(&slave->dev);
+ pm_runtime_put_autosuspend(&slave->dev);
+ }
+err:
+ clk_disable_unprepare(swrm->hclk);
+ return IRQ_HANDLED;
+}
+
+
static irqreturn_t qcom_swrm_irq_handler(int irq, void *dev_id)
{
struct qcom_swrm_ctrl *swrm = dev_id;
@@ -1349,6 +1393,24 @@ static int qcom_swrm_probe(struct platform_device *pdev)
goto err_clk;
}
+ ctrl->wake_irq = of_irq_get(dev->of_node, 1);
+ if (ctrl->wake_irq < 0) {
+ dev_err(dev, "No wake irq\n");
+ } else {
+ ret = devm_request_threaded_irq(dev, ctrl->wake_irq, NULL,
+ qcom_swrm_wake_irq_handler,
+ IRQF_TRIGGER_HIGH |
+ IRQF_ONESHOT,
+ "swr_wake_irq", ctrl);
+ if (ret) {
+ dev_err(dev, "Failed to request soundwire wake irq\n");
+ goto err_init;
+ }
+ dev_pm_set_wake_irq(dev,ctrl->wake_irq);
+ irq_set_irq_wake(ctrl->wake_irq, 1);
+ }
+
+
ret = sdw_bus_master_add(&ctrl->bus, dev, dev->fwnode);
if (ret) {
dev_err(dev, "Failed to register Soundwire controller (%d)\n",
@@ -1413,6 +1475,15 @@ static int swrm_runtime_resume(struct device *dev)
struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dev);
int ret;
+ if (ctrl->wake_irq > 0) {
+ if (unlikely(!irq_get_irq_data(ctrl->wake_irq))) {
+ pr_err("%s: irq data is NULL\n", __func__);
+ return IRQ_NONE;
+ }
+ if (!irqd_irq_disabled(irq_get_irq_data(ctrl->wake_irq)))
+ disable_irq_nosync(ctrl->wake_irq);
+ }
+
clk_prepare_enable(ctrl->hclk);
if (ctrl->clk_stop_bus_reset) {
@@ -1468,6 +1539,11 @@ static int __maybe_unused swrm_runtime_suspend(struct device *dev)
usleep_range(300, 305);
+ if (ctrl->wake_irq > 0) {
+ if (irqd_irq_disabled(irq_get_irq_data(ctrl->wake_irq)))
+ enable_irq(ctrl->wake_irq);
+ }
+
return 0;
}