summaryrefslogtreecommitdiff
path: root/drivers/media/platform/imx8
diff options
context:
space:
mode:
authorGuoniu.Zhou <guoniu.zhou@nxp.com>2017-11-15 19:10:38 +0800
committerLeonard Crestez <leonard.crestez@nxp.com>2018-08-24 12:41:33 +0300
commitcd087464cbe7daa77096066b13c5b4011b8e4baa (patch)
tree2e46235dad9403095b0698111a0711c798a06547 /drivers/media/platform/imx8
parentc722ce7fea3b3e7d50075e8ec59169466c6cc002 (diff)
MLK-16823-1: mipi_csi: Add runtime suspend/resume
Add runtime suspend/resume features support for mipi csi. For saving power, the mipi_csi turn off it's power domain and clock after probe. In order to share code with system pm suspend/resume, I change system suspend/resume in this patch. Reviewed-by: Sandor Yu <sandor.yu@nxp.com> Signed-off-by: Guoniu.Zhou <guoniu.zhou@nxp.com> (cherry picked from commit f88f4ac99b23e03b1cc1d87209875d6001dbbbe5)
Diffstat (limited to 'drivers/media/platform/imx8')
-rw-r--r--drivers/media/platform/imx8/mxc-mipi-csi2.c97
-rw-r--r--drivers/media/platform/imx8/mxc-mipi-csi2.h3
2 files changed, 76 insertions, 24 deletions
diff --git a/drivers/media/platform/imx8/mxc-mipi-csi2.c b/drivers/media/platform/imx8/mxc-mipi-csi2.c
index 4778a015434f..18bee2002eda 100644
--- a/drivers/media/platform/imx8/mxc-mipi-csi2.c
+++ b/drivers/media/platform/imx8/mxc-mipi-csi2.c
@@ -351,6 +351,7 @@ static int mipi_csi2_clk_enable(struct mxc_mipi_csi2_dev *csi2dev)
dev_err(dev, "%s, prepare clk_pxl error\n", __func__);
return ret;
}
+
return ret;
}
@@ -413,12 +414,14 @@ static int mipi_csi2_s_power(struct v4l2_subdev *sd, int on)
static int mipi_csi2_s_stream(struct v4l2_subdev *sd, int enable)
{
struct mxc_mipi_csi2_dev *csi2dev = sd_to_mxc_mipi_csi2_dev(sd);
+ struct device *dev = &csi2dev->pdev->dev;
int ret = 0;
dev_dbg(&csi2dev->pdev->dev, "%s: %d, csi2dev: 0x%x\n",
__func__, enable, csi2dev->flags);
if (enable) {
+ pm_runtime_get_sync(dev);
if (!csi2dev->running) {
mxc_csi2_get_sensor_fmt(csi2dev);
mxc_mipi_csi2_hc_config(csi2dev);
@@ -428,12 +431,12 @@ static int mipi_csi2_s_stream(struct v4l2_subdev *sd, int enable)
mxc_mipi_csi2_reg_dump(csi2dev);
}
csi2dev->running++;
-
} else {
if (csi2dev->running)
mxc_mipi_csi2_disable(csi2dev);
csi2dev->running--;
+ pm_runtime_put(dev);
}
return ret;
@@ -525,6 +528,7 @@ static int mipi_csi2_probe(struct platform_device *pdev)
return -ENOMEM;
csi2dev->pdev = pdev;
+ mutex_init(&csi2dev->lock);
ret = mipi_csi2_parse_dt(csi2dev);
if (ret < 0)
@@ -581,15 +585,20 @@ static int mipi_csi2_probe(struct platform_device *pdev)
mipi_sc_fw_init(csi2dev, 1);
+ csi2dev->running = 0;
+ csi2dev->flags = MXC_MIPI_CSI2_PM_POWERED;
+
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_get_sync(dev);
+
ret = mipi_csi2_clk_enable(csi2dev);
if (ret < 0)
goto e_clkdis;
dev_info(&pdev->dev, "lanes: %d, name: %s\n",
csi2dev->num_lanes, csi2dev->sd.name);
-
- csi2dev->running = 0;
- csi2dev->flags = MXC_MIPI_CSI2_PM_POWERED;
+ pm_runtime_put_sync(dev);
return 0;
@@ -603,55 +612,95 @@ static int mipi_csi2_remove(struct platform_device *pdev)
struct v4l2_subdev *sd = platform_get_drvdata(pdev);
struct mxc_mipi_csi2_dev *csi2dev = sd_to_mxc_mipi_csi2_dev(sd);
+ pm_runtime_get_sync(&pdev->dev);
mipi_sc_fw_init(csi2dev, 0);
media_entity_cleanup(&csi2dev->sd.entity);
- mipi_csi2_clk_disable(csi2dev);
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
return 0;
}
-static int mipi_csi2_pm_suspend(struct device *dev)
+static int mipi_csi2_suspend(struct device *dev, bool runtime)
{
struct mxc_mipi_csi2_dev *csi2dev = dev_get_drvdata(dev);
struct v4l2_subdev *sd = &csi2dev->sd;
- if (csi2dev->flags & MXC_MIPI_CSI2_PM_SUSPENDED)
- return 0;
+ mutex_lock(&csi2dev->lock);
+ if (csi2dev->flags & MXC_MIPI_CSI2_PM_POWERED) {
+ if (csi2dev->running)
+ mipi_csi2_s_stream(sd, false);
- if (csi2dev->running)
- mipi_csi2_s_stream(sd, false);
- mipi_csi2_clk_disable(csi2dev);
- csi2dev->flags &= ~MXC_MIPI_CSI2_PM_POWERED;
- csi2dev->flags |= MXC_MIPI_CSI2_PM_SUSPENDED;
+ mipi_csi2_clk_disable(csi2dev);
+ csi2dev->flags &= ~MXC_MIPI_CSI2_PM_POWERED;
+ if (runtime)
+ csi2dev->flags |= MXC_MIPI_CSI2_RUNTIME_SUSPENDED;
+ else
+ csi2dev->flags |= MXC_MIPI_CSI2_PM_SUSPENDED;
+ }
+ mutex_unlock(&csi2dev->lock);
return 0;
}
-static int mipi_csi2_pm_resume(struct device *dev)
+static int mipi_csi2_resume(struct device *dev, bool runtime)
{
struct mxc_mipi_csi2_dev *csi2dev = dev_get_drvdata(dev);
struct v4l2_subdev *sd = &csi2dev->sd;
int ret;
- if (csi2dev->flags & MXC_MIPI_CSI2_PM_POWERED)
+ mutex_lock(&csi2dev->lock);
+ if (!(csi2dev->flags & MXC_MIPI_CSI2_RUNTIME_SUSPENDED) &&
+ !(csi2dev->flags & MXC_MIPI_CSI2_PM_SUSPENDED)) {
+ mutex_unlock(&csi2dev->lock);
return 0;
-
- ret = mipi_csi2_clk_enable(csi2dev);
- if (ret < 0) {
- dev_info(dev, "%s:%d fail\n", __func__, __LINE__);
- return -EAGAIN;
}
- if (csi2dev->running)
- mipi_csi2_s_stream(sd, true);
- csi2dev->flags |= MXC_MIPI_CSI2_PM_POWERED;
- csi2dev->flags &= ~MXC_MIPI_CSI2_PM_SUSPENDED;
+ if (!(csi2dev->flags & MXC_MIPI_CSI2_PM_POWERED)) {
+ ret = mipi_csi2_clk_enable(csi2dev);
+ if (ret < 0) {
+ mutex_unlock(&csi2dev->lock);
+ dev_err(dev, "%s:%d fail\n", __func__, __LINE__);
+ return -EAGAIN;
+ }
+
+ if (csi2dev->running)
+ mipi_csi2_s_stream(sd, true);
+ csi2dev->flags |= MXC_MIPI_CSI2_PM_POWERED;
+ if (runtime)
+ csi2dev->flags &= ~MXC_MIPI_CSI2_RUNTIME_SUSPENDED;
+ else
+ csi2dev->flags &= ~MXC_MIPI_CSI2_PM_SUSPENDED;
+ }
+ mutex_unlock(&csi2dev->lock);
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int mipi_csi2_pm_suspend(struct device *dev)
+{
+ return mipi_csi2_suspend(dev, false);
+}
+
+static int mipi_csi2_pm_resume(struct device *dev)
+{
+ return mipi_csi2_resume(dev, false);
+}
+#endif
+
+static int mipi_csi2_runtime_suspend(struct device *dev)
+{
+ return mipi_csi2_suspend(dev, true);
+}
+static int mipi_csi2_runtime_resume(struct device *dev)
+{
+ return mipi_csi2_resume(dev, true);
+}
+
static const struct dev_pm_ops mipi_csi_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(mipi_csi2_pm_suspend, mipi_csi2_pm_resume)
+ SET_RUNTIME_PM_OPS(mipi_csi2_runtime_suspend, mipi_csi2_runtime_resume, NULL)
};
static const struct of_device_id mipi_csi2_of_match[] = {
diff --git a/drivers/media/platform/imx8/mxc-mipi-csi2.h b/drivers/media/platform/imx8/mxc-mipi-csi2.h
index e9af8ea42c1d..72e741e75d62 100644
--- a/drivers/media/platform/imx8/mxc-mipi-csi2.h
+++ b/drivers/media/platform/imx8/mxc-mipi-csi2.h
@@ -259,6 +259,8 @@ struct mxc_mipi_csi2_dev {
struct v4l2_async_notifier subdev_notifier;
struct v4l2_async_subdev *async_subdevs[2];
+ struct mutex lock;
+
int id;
u32 hs_settle;
u32 num_lanes;
@@ -270,6 +272,7 @@ struct mxc_mipi_csi2_dev {
enum mxc_mipi_csi2_pm_state {
MXC_MIPI_CSI2_PM_POWERED = 0x1,
MXC_MIPI_CSI2_PM_SUSPENDED = 0x2,
+ MXC_MIPI_CSI2_RUNTIME_SUSPENDED = 0x4,
};
#endif