All of lore.kernel.org
 help / color / mirror / Atom feed
From: Todor Tomov <todor.tomov@linaro.org>
To: mchehab@kernel.org, sakari.ailus@linux.intel.com,
	hans.verkuil@cisco.com,
	laurent.pinchart+renesas@ideasonboard.com,
	linux-media@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, Todor Tomov <todor.tomov@linaro.org>
Subject: [PATCH v2 17/34] media: camss: Add basic runtime PM support
Date: Thu,  5 Jul 2018 16:32:48 +0300	[thread overview]
Message-ID: <1530797585-8555-18-git-send-email-todor.tomov@linaro.org> (raw)
In-Reply-To: <1530797585-8555-1-git-send-email-todor.tomov@linaro.org>

There is a PM domain for each of the VFE hardware modules. Add
support for basic runtime PM support to be able to control the
PM domains. When a PM domain needs to be powered on - a device
link is created. When a PM domain needs to be powered off -
its device link is removed. This allows separate and
independent control of the PM domains.

Suspend/Resume is still not supported.

Signed-off-by: Todor Tomov <todor.tomov@linaro.org>
---
 drivers/media/platform/qcom/camss/camss-csid.c   |  4 ++
 drivers/media/platform/qcom/camss/camss-csiphy.c |  5 ++
 drivers/media/platform/qcom/camss/camss-ispif.c  | 19 ++++++-
 drivers/media/platform/qcom/camss/camss-vfe.c    | 13 +++++
 drivers/media/platform/qcom/camss/camss.c        | 63 ++++++++++++++++++++++++
 drivers/media/platform/qcom/camss/camss.h        | 11 +++++
 6 files changed, 113 insertions(+), 2 deletions(-)

diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c
index 627ef44..ea2b0ba 100644
--- a/drivers/media/platform/qcom/camss/camss-csid.c
+++ b/drivers/media/platform/qcom/camss/camss-csid.c
@@ -13,6 +13,7 @@
 #include <linux/kernel.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
 #include <media/media-entity.h>
 #include <media/v4l2-device.h>
@@ -316,6 +317,8 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)
 	if (on) {
 		u32 hw_version;
 
+		pm_runtime_get_sync(dev);
+
 		ret = regulator_enable(csid->vdda);
 		if (ret < 0)
 			return ret;
@@ -348,6 +351,7 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)
 		disable_irq(csid->irq);
 		camss_disable_clocks(csid->nclocks, csid->clock);
 		ret = regulator_disable(csid->vdda);
+		pm_runtime_put_sync(dev);
 	}
 
 	return ret;
diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c
index 0383e94..2db78791 100644
--- a/drivers/media/platform/qcom/camss/camss-csiphy.c
+++ b/drivers/media/platform/qcom/camss/camss-csiphy.c
@@ -13,6 +13,7 @@
 #include <linux/kernel.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <media/media-entity.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-subdev.h>
@@ -240,6 +241,8 @@ static int csiphy_set_power(struct v4l2_subdev *sd, int on)
 		u8 hw_version;
 		int ret;
 
+		pm_runtime_get_sync(dev);
+
 		ret = csiphy_set_clock_rates(csiphy);
 		if (ret < 0)
 			return ret;
@@ -259,6 +262,8 @@ static int csiphy_set_power(struct v4l2_subdev *sd, int on)
 		disable_irq(csiphy->irq);
 
 		camss_disable_clocks(csiphy->nclocks, csiphy->clock);
+
+		pm_runtime_put_sync(dev);
 	}
 
 	return 0;
diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c
index ed50cc5..8b04f8a 100644
--- a/drivers/media/platform/qcom/camss/camss-ispif.c
+++ b/drivers/media/platform/qcom/camss/camss-ispif.c
@@ -14,6 +14,7 @@
 #include <linux/kernel.h>
 #include <linux/mutex.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <media/media-entity.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-subdev.h>
@@ -169,6 +170,14 @@ static int ispif_reset(struct ispif_device *ispif)
 	u32 val;
 	int ret;
 
+	ret = camss_pm_domain_on(to_camss(ispif), PM_DOMAIN_VFE0);
+	if (ret < 0)
+		return ret;
+
+	ret = camss_pm_domain_on(to_camss(ispif), PM_DOMAIN_VFE1);
+	if (ret < 0)
+		return ret;
+
 	ret = camss_enable_clocks(ispif->nclocks_for_reset,
 				  ispif->clock_for_reset,
 				  to_device(ispif));
@@ -201,12 +210,15 @@ static int ispif_reset(struct ispif_device *ispif)
 		msecs_to_jiffies(ISPIF_RESET_TIMEOUT_MS));
 	if (!time) {
 		dev_err(to_device(ispif), "ISPIF reset timeout\n");
-		return -EIO;
+		ret = -EIO;
 	}
 
 	camss_disable_clocks(ispif->nclocks_for_reset, ispif->clock_for_reset);
 
-	return 0;
+	camss_pm_domain_off(to_camss(ispif), PM_DOMAIN_VFE0);
+	camss_pm_domain_off(to_camss(ispif), PM_DOMAIN_VFE1);
+
+	return ret;
 }
 
 /*
@@ -232,6 +244,8 @@ static int ispif_set_power(struct v4l2_subdev *sd, int on)
 			goto exit;
 		}
 
+		pm_runtime_get_sync(dev);
+
 		ret = camss_enable_clocks(ispif->nclocks, ispif->clock, dev);
 		if (ret < 0)
 			goto exit;
@@ -252,6 +266,7 @@ static int ispif_set_power(struct v4l2_subdev *sd, int on)
 			goto exit;
 		} else if (ispif->power_count == 1) {
 			camss_disable_clocks(ispif->nclocks, ispif->clock);
+			pm_runtime_put_sync(dev);
 		}
 
 		ispif->power_count--;
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 3f589c4..4afbef8 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -15,6 +15,7 @@
 #include <linux/mutex.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/spinlock_types.h>
 #include <linux/spinlock.h>
 #include <media/media-entity.h>
@@ -1981,6 +1982,12 @@ static int vfe_get(struct vfe_device *vfe)
 	mutex_lock(&vfe->power_lock);
 
 	if (vfe->power_count == 0) {
+		ret = camss_pm_domain_on(vfe->camss, vfe->id);
+		if (ret < 0)
+			goto error_pm_domain;
+
+		pm_runtime_get_sync(vfe->camss->dev);
+
 		ret = vfe_set_clock_rates(vfe);
 		if (ret < 0)
 			goto error_clocks;
@@ -2012,6 +2019,10 @@ static int vfe_get(struct vfe_device *vfe)
 	camss_disable_clocks(vfe->nclocks, vfe->clock);
 
 error_clocks:
+	pm_runtime_put_sync(vfe->camss->dev);
+	camss_pm_domain_off(vfe->camss, vfe->id);
+
+error_pm_domain:
 	mutex_unlock(&vfe->power_lock);
 
 	return ret;
@@ -2034,6 +2045,8 @@ static void vfe_put(struct vfe_device *vfe)
 			vfe_halt(vfe);
 		}
 		camss_disable_clocks(vfe->nclocks, vfe->clock);
+		pm_runtime_put_sync(vfe->camss->dev);
+		camss_pm_domain_off(vfe->camss, vfe->id);
 	}
 
 	vfe->power_count--;
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index 171e2c9..dcc0c30 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -14,6 +14,8 @@
 #include <linux/platform_device.h>
 #include <linux/of.h>
 #include <linux/of_graph.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm_domain.h>
 #include <linux/slab.h>
 #include <linux/videodev2.h>
 
@@ -393,6 +395,26 @@ int camss_get_pixel_clock(struct media_entity *entity, u32 *pixel_clock)
 	return 0;
 }
 
+int camss_pm_domain_on(struct camss *camss, int id)
+{
+	if (camss->version == CAMSS_8x96) {
+		camss->genpd_link[id] = device_link_add(camss->dev,
+				camss->genpd[id], DL_FLAG_STATELESS |
+				DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);
+
+		if (!camss->genpd_link[id])
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+void camss_pm_domain_off(struct camss *camss, int id)
+{
+	if (camss->version == CAMSS_8x96)
+		device_link_del(camss->genpd_link[id]);
+}
+
 /*
  * camss_of_parse_endpoint_node - Parse port endpoint node
  * @dev: Device
@@ -896,6 +918,23 @@ static int camss_probe(struct platform_device *pdev)
 		}
 	}
 
+	if (camss->version == CAMSS_8x96) {
+		camss->genpd[PM_DOMAIN_VFE0] = dev_pm_domain_attach_by_id(
+						camss->dev, PM_DOMAIN_VFE0);
+		if (IS_ERR(camss->genpd[PM_DOMAIN_VFE0]))
+			return PTR_ERR(camss->genpd[PM_DOMAIN_VFE0]);
+
+		camss->genpd[PM_DOMAIN_VFE1] = dev_pm_domain_attach_by_id(
+						camss->dev, PM_DOMAIN_VFE1);
+		if (IS_ERR(camss->genpd[PM_DOMAIN_VFE1])) {
+			dev_pm_domain_detach(camss->genpd[PM_DOMAIN_VFE0],
+					     true);
+			return PTR_ERR(camss->genpd[PM_DOMAIN_VFE1]);
+		}
+	}
+
+	pm_runtime_enable(dev);
+
 	return 0;
 
 err_register_subdevs:
@@ -912,6 +951,13 @@ void camss_delete(struct camss *camss)
 	media_device_unregister(&camss->media_dev);
 	media_device_cleanup(&camss->media_dev);
 
+	pm_runtime_disable(camss->dev);
+
+	if (camss->version == CAMSS_8x96) {
+		dev_pm_domain_detach(camss->genpd[PM_DOMAIN_VFE0], true);
+		dev_pm_domain_detach(camss->genpd[PM_DOMAIN_VFE1], true);
+	}
+
 	kfree(camss);
 }
 
@@ -947,12 +993,29 @@ static const struct of_device_id camss_dt_match[] = {
 
 MODULE_DEVICE_TABLE(of, camss_dt_match);
 
+static int camss_runtime_suspend(struct device *dev)
+{
+	return 0;
+}
+
+static int camss_runtime_resume(struct device *dev)
+{
+	return 0;
+}
+
+static const struct dev_pm_ops camss_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+	SET_RUNTIME_PM_OPS(camss_runtime_suspend, camss_runtime_resume, NULL)
+};
+
 static struct platform_driver qcom_camss_driver = {
 	.probe = camss_probe,
 	.remove = camss_remove,
 	.driver = {
 		.name = "qcom-camss",
 		.of_match_table = camss_dt_match,
+		.pm = &camss_pm_ops,
 	},
 };
 
diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h
index dff1045..418996d 100644
--- a/drivers/media/platform/qcom/camss/camss.h
+++ b/drivers/media/platform/qcom/camss/camss.h
@@ -10,6 +10,7 @@
 #ifndef QC_MSM_CAMSS_H
 #define QC_MSM_CAMSS_H
 
+#include <linux/device.h>
 #include <linux/types.h>
 #include <media/v4l2-async.h>
 #include <media/v4l2-device.h>
@@ -56,6 +57,12 @@ struct resources_ispif {
 	char *interrupt;
 };
 
+enum pm_domain {
+	PM_DOMAIN_VFE0,
+	PM_DOMAIN_VFE1,
+	PM_DOMAIN_COUNT
+};
+
 enum camss_version {
 	CAMSS_8x16,
 	CAMSS_8x96,
@@ -75,6 +82,8 @@ struct camss {
 	int vfe_num;
 	struct vfe_device *vfe;
 	atomic_t ref_count;
+	struct device *genpd[PM_DOMAIN_COUNT];
+	struct device_link *genpd_link[PM_DOMAIN_COUNT];
 };
 
 struct camss_camera_interface {
@@ -99,6 +108,8 @@ int camss_enable_clocks(int nclocks, struct camss_clock *clock,
 			struct device *dev);
 void camss_disable_clocks(int nclocks, struct camss_clock *clock);
 int camss_get_pixel_clock(struct media_entity *entity, u32 *pixel_clock);
+int camss_pm_domain_on(struct camss *camss, int id);
+void camss_pm_domain_off(struct camss *camss, int id);
 void camss_delete(struct camss *camss);
 
 #endif /* QC_MSM_CAMSS_H */
-- 
2.7.4


  parent reply	other threads:[~2018-07-05 13:37 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-07-05 13:32 [PATCH v2 00/34] Qualcomm Camera Subsystem driver - 8x96 support Todor Tomov
2018-07-05 13:32 ` [PATCH v2 01/34] doc-rst: Add packed Bayer raw14 pixel formats Todor Tomov
2018-07-05 13:32 ` [PATCH v2 02/34] media: v4l: Add new 2X8 10-bit grayscale media bus code Todor Tomov
2018-07-05 13:32 ` [PATCH v2 03/34] media: v4l: Add new 10-bit packed grayscale format Todor Tomov
2018-07-05 13:32 ` [PATCH v2 04/34] media: Rename CAMSS driver path Todor Tomov
2018-07-05 13:32 ` [PATCH v2 05/34] media: camss: Use SPDX license headers Todor Tomov
2018-07-05 13:32 ` [PATCH v2 06/34] media: camss: Fix OF node usage Todor Tomov
2018-07-05 13:32 ` [PATCH v2 07/34] media: camss: csiphy: Ensure clock mux config is done before the rest Todor Tomov
2018-07-05 13:32 ` [PATCH v2 08/34] media: camss: Unify the clock names Todor Tomov
2018-07-11 16:07   ` Rob Herring
2018-07-16  8:53     ` Todor Tomov
2018-07-16 14:00       ` Rob Herring
2018-07-05 13:32 ` [PATCH v2 09/34] media: camss: csiphy: Update settle count calculation Todor Tomov
2018-07-05 13:32 ` [PATCH v2 10/34] media: camss: csid: Configure data type and decode format properly Todor Tomov
2018-07-05 13:32 ` [PATCH v2 11/34] media: camss: vfe: Fix to_vfe() macro member name Todor Tomov
2018-07-05 13:32 ` [PATCH v2 12/34] media: camss: vfe: Get line pointer as container of video_out Todor Tomov
2018-07-05 13:32 ` [PATCH v2 13/34] media: camss: vfe: Do not disable CAMIF when clearing its status Todor Tomov
2018-07-05 13:32 ` [PATCH v2 14/34] media: dt-bindings: media: qcom,camss: Fix whitespaces Todor Tomov
2018-07-05 13:32 ` [PATCH v2 15/34] media: dt-bindings: media: qcom,camss: Add 8996 bindings Todor Tomov
2018-07-05 13:32 ` [PATCH v2 16/34] media: camss: Add 8x96 resources Todor Tomov
2018-07-05 13:32 ` Todor Tomov [this message]
2018-07-05 13:32 ` [PATCH v2 18/34] media: camss: csiphy: Split to hardware dependent and independent parts Todor Tomov
2018-07-05 13:32 ` [PATCH v2 19/34] media: camss: csiphy: Unify lane handling Todor Tomov
2018-07-05 13:32 ` [PATCH v2 20/34] media: camss: csiphy: Add support for 8x96 Todor Tomov
2018-07-05 13:32 ` [PATCH v2 21/34] media: camss: csid: " Todor Tomov
2018-07-05 13:32 ` [PATCH v2 22/34] media: camss: ispif: " Todor Tomov
2018-07-05 13:32 ` [PATCH v2 23/34] media: camss: vfe: Split to hardware dependent and independent parts Todor Tomov
2018-07-05 13:32 ` [PATCH v2 24/34] media: camss: vfe: Add support for 8x96 Todor Tomov
2018-07-05 13:32 ` [PATCH v2 25/34] media: camss: Format configuration per hardware version Todor Tomov
2018-07-05 13:32 ` [PATCH v2 26/34] media: camss: vfe: Different format support on source pad Todor Tomov
2018-07-05 13:32 ` [PATCH v2 27/34] media: camss: vfe: Add support for UYVY output from VFE on 8x96 Todor Tomov
2018-07-05 13:32 ` [PATCH v2 28/34] media: camss: csid: Different format support on source pad Todor Tomov
2018-07-05 13:33 ` [PATCH v2 29/34] media: camss: csid: MIPI10 to Plain16 format conversion Todor Tomov
2018-07-05 13:33 ` [PATCH v2 30/34] media: camss: Add support for RAW MIPI14 on 8x96 Todor Tomov
2018-07-05 13:33 ` [PATCH v2 31/34] media: camss: Add support for 10-bit grayscale formats Todor Tomov
2018-07-05 13:33 ` [PATCH v2 32/34] media: doc: media/v4l-drivers: Update Qualcomm CAMSS driver document for 8x96 Todor Tomov
2018-07-05 13:33 ` [PATCH v2 33/34] media: camss: csid: Add support for events triggered by user controls Todor Tomov
2018-07-05 13:33 ` [PATCH v2 34/34] media: v4l2-ioctl: Add format descriptions for packed Bayer raw14 pixel formats Todor Tomov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1530797585-8555-18-git-send-email-todor.tomov@linaro.org \
    --to=todor.tomov@linaro.org \
    --cc=hans.verkuil@cisco.com \
    --cc=laurent.pinchart+renesas@ideasonboard.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=mchehab@kernel.org \
    --cc=sakari.ailus@linux.intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.