From patchwork Fri Jun 22 15:33:26 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Todor Tomov X-Patchwork-Id: 139685 Delivered-To: patch@linaro.org Received: by 2002:a2e:970d:0:0:0:0:0 with SMTP id r13-v6csp1015885lji; Fri, 22 Jun 2018 08:34:18 -0700 (PDT) X-Google-Smtp-Source: ADUXVKLBc5o7jcytT89jotsuKv/tdubKLyPM/ysZAAgRrnhqjZvbuRw/Ucu1KYK20g8fzGFQDbT3 X-Received: by 2002:a63:6c03:: with SMTP id h3-v6mr1862067pgc.28.1529681658842; Fri, 22 Jun 2018 08:34:18 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1529681658; cv=none; d=google.com; s=arc-20160816; b=cIU5I1wGOyTR7ToYyvk40MIrO7mVwKS/a1+ImlvHQ9O7u+In0YjpY02OyZlUBVqk/m 7SD7MQx4DQsTlUC10PsmWFOzDa/J0rJQjyQIiDVtF/YBNzZ+2az7RpRlvklkEouGygmk rOpFewDgEtpQMnSaoqNusADb3pBCM7ikh/c+6qMqzpL63w3YgBCPIGZ2KrVhu95wc47j 4swTQaS/NkQZVxwileobOJWkn8pY6fRjqJFxPUN4nG3GM7U8807QHkLF8D16tz3JzG7D lC1FSqyKFfJ9uk5N3I2AOL1j1+ODkSSDrtNa38R87h7gkVC2SXNE1V+lZjZADOE5zLkb JQ4w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=by1xYfl8QRyBb9bqrA0Xnaw+eCzI0AVbd8do8hcwbBA=; b=T3dKTEOaIcbOiuTjCV9KjZJu8aif+S5lEWnkfA+91X8QRh6sz5rLWL8Wx07uAoA/ww JOCwvXMTaUO7jPukP4Ds7MSZk2Uf4e0IFs8y9I9lcqBSpZo+bs7LrklBh9aK1pLtQrr5 dyGBcPSgd28ZIx/kvEPtMo+SUBbmyZepdaxbrelik/8LXiKoRX5e60TWyjN6WSZ+ypo+ HFK8S91Pv25fvEkYbyyu9k5K1QUk+mnP8vz6nQR90d9h43q2DlHqc6l0oEQZkCxQoYFR UaJUNr9OcoiEGf0hq4aXGg7YLmuvPcH1e7zQZRDlQckUEaVQCwu7wOh3A/TOo+rmB3O0 bVlA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id k22-v6si8032310pll.416.2018.06.22.08.34.17; Fri, 22 Jun 2018 08:34:18 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S934072AbeFVPeP (ORCPT + 31 others); Fri, 22 Jun 2018 11:34:15 -0400 Received: from ns.mm-sol.com ([37.157.136.199]:46399 "EHLO extserv.mm-sol.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933978AbeFVPeI (ORCPT ); Fri, 22 Jun 2018 11:34:08 -0400 Received: from mms-0439.qualcomm.mm-sol.com (unknown [37.157.136.206]) by extserv.mm-sol.com (Postfix) with ESMTPSA id 7AA8DCD3C; Fri, 22 Jun 2018 18:33:59 +0300 (EEST) From: Todor Tomov 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 Subject: [PATCH 17/32] media: camss: Add basic runtime PM support Date: Fri, 22 Jun 2018 18:33:26 +0300 Message-Id: <1529681621-9682-18-git-send-email-todor.tomov@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1529681621-9682-1-git-send-email-todor.tomov@linaro.org> References: <1529681621-9682-1-git-send-email-todor.tomov@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.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 --- 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(-) -- 2.7.4 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 #include #include +#include #include #include #include @@ -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 #include #include +#include #include #include #include @@ -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 #include #include +#include #include #include #include @@ -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 #include #include +#include #include #include #include @@ -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 #include #include +#include +#include #include #include @@ -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 #include #include #include @@ -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 */