diff options
author | Srinivas Kandagatla <srinivas.kandagatla@linaro.org> | 2021-10-18 14:09:35 +0100 |
---|---|---|
committer | Srinivas Kandagatla <srinivas.kandagatla@linaro.org> | 2021-12-13 13:52:56 +0000 |
commit | c376a4726b3de68de498558ae26706afe062c6e7 (patch) | |
tree | 56149fd020ccebdf6ff620cba05b9c88e6b6aa06 | |
parent | 0b470ad5a7238f96761805217a61b46414b9bbb4 (diff) |
soundwire: qcom: add wake up support
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
-rw-r--r-- | drivers/soundwire/qcom.c | 76 |
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; } |