summaryrefslogtreecommitdiff
path: root/drivers/mailbox
diff options
context:
space:
mode:
authorAnson Huang <Anson.Huang@nxp.com>2020-04-13 14:52:41 +0800
committerAnson Huang <Anson.Huang@nxp.com>2020-04-17 17:07:18 +0800
commit0201b77acc9238cc341a1c08fbddab4adb3fc4c9 (patch)
treeabfa1a86693353d1a85567011a89c409a410e40b /drivers/mailbox
parentf823973c35a9911ed87b79d8b053bc974602303a (diff)
MLK-23780 mailbox: imx: Support runtime PM
Some power hungry sub-systems like VPU has its own MUs which also use mailbox driver, current mailbox driver uses platform driver model and MU's power will be ON after driver probed and left ON there, it may cause the whole sub-system can NOT enter lower power mode, take VPU driver for example, it has runtime PM support, but due to its MU always ON, the VPU sub-system will be always ON and consume many power during kernel idle. To save power in kernel idle, mailbox driver needs to support runtime PM in order to power off MU when it is unused. However, the runtime suspend/resume can ONLY be implemented in mailbox's .shutdown/.startup callback, so its consumer needs to call mbox_request_channel()/mbox_free_channel() in consumer driver's runtime PM callback, then the MU's power will be ON/OFF along with consumer's runtime PM status. For those consumers never call mbox_free_channel(), MU's power will be still ON always, if there is obvious power increase observed, we will request the consumer to free mailbox channel to save power. Signed-off-by: Anson Huang <Anson.Huang@nxp.com> Reviewed-by: Jacky Bai <ping.bai@nxp.com>
Diffstat (limited to 'drivers/mailbox')
-rw-r--r--drivers/mailbox/imx-mailbox.c27
1 files changed, 26 insertions, 1 deletions
diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c
index 87a6ec95e005..c711165e3207 100644
--- a/drivers/mailbox/imx-mailbox.c
+++ b/drivers/mailbox/imx-mailbox.c
@@ -11,6 +11,7 @@
#include <linux/mailbox_controller.h>
#include <linux/module.h>
#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
#include <linux/slab.h>
#define IMX_MU_xSR_GIPn(x) BIT(28 + (3 - (x)))
@@ -384,6 +385,7 @@ static int imx_mu_startup(struct mbox_chan *chan)
struct imx_mu_con_priv *cp = chan->con_priv;
int ret;
+ pm_runtime_get_sync(priv->dev);
if (cp->type == IMX_MU_TYPE_TXDB) {
/* Tx doorbell don't have ACK support */
tasklet_init(&cp->txdb_tasklet, imx_mu_txdb_tasklet,
@@ -420,6 +422,7 @@ static void imx_mu_shutdown(struct mbox_chan *chan)
if (cp->type == IMX_MU_TYPE_TXDB) {
tasklet_kill(&cp->txdb_tasklet);
+ pm_runtime_put_sync(priv->dev);
return;
}
@@ -438,6 +441,7 @@ static void imx_mu_shutdown(struct mbox_chan *chan)
}
free_irq(priv->irq, chan);
+ pm_runtime_put_sync(priv->dev);
}
static const struct mbox_chan_ops imx_mu_ops = {
@@ -578,7 +582,27 @@ static int imx_mu_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, priv);
- return devm_mbox_controller_register(dev, &priv->mbox);
+ ret = devm_mbox_controller_register(dev, &priv->mbox);
+ if (ret)
+ return ret;
+
+ pm_runtime_enable(dev);
+
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0) {
+ pm_runtime_put_noidle(dev);
+ goto disable_runtime_pm;
+ }
+
+ ret = pm_runtime_put_sync(dev);
+ if (ret < 0)
+ goto disable_runtime_pm;
+
+ return 0;
+
+disable_runtime_pm:
+ pm_runtime_disable(dev);
+ return ret;
}
static int imx_mu_remove(struct platform_device *pdev)
@@ -586,6 +610,7 @@ static int imx_mu_remove(struct platform_device *pdev)
struct imx_mu_priv *priv = platform_get_drvdata(pdev);
clk_disable_unprepare(priv->clk);
+ pm_runtime_disable(priv->dev);
return 0;
}