Received: by 2002:ac0:a5a7:0:0:0:0:0 with SMTP id m36-v6csp997592imm; Wed, 25 Jul 2018 09:40:36 -0700 (PDT) X-Google-Smtp-Source: AAOMgpekcan+DknWfvCfcanw3emV86uRGOVVCKTxEIBOX4TeQjVnVOEBmrme37+O0Y0qaUTVmqIm X-Received: by 2002:a62:2459:: with SMTP id r86-v6mr17670367pfj.31.1532536836237; Wed, 25 Jul 2018 09:40:36 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1532536836; cv=none; d=google.com; s=arc-20160816; b=voMbjieEQZ/9YAWBB3Xw2ZQWS9KRGghwHGXdQ8BbzBZLKMcT2vfl7VXIjxOjaHdL0Q 45ZOdvayUtDNBy2PmgTN+G4m18TMUpTR3jQP6EjJ7BUrH5fozbKQRA41PUgbEr3lFxvS vdnaqI10EA7Bjo9SCkRF5B6OYZmHHAPSwiHwLlL/XNahI+Zl6qBArqmdEbJJEEnBRlVt B5q/JqSaABH7HEG+we5jvVkLW4xx8m1LuZG3F2KyxIhKkgD+6gNoOiDR7PYYfG5v1tTl biD8r8UOlX6eFG1JzTmRizd308z4VCGAjuJkJhOBR6/JGZ1xArXx0gwnFBwKjfS+yyzI dcZg== 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=PF3VRthiGMYMuNzMwXovX7Yan/p405Z1hrf15g5jQsU=; b=G0eCyWM7Eie+2jY6/Z5aKim2FQJyfvyYSbC0SeGSG95jHmBO39b8Em4kWNLKoFB2O4 uELdUzjPRNjv8c5Ili/85HKCMkDDu2IflCehLWAO7LBYmhGZHYuI/kSQOLYAyK0Wf4mi N3BTO0qNJSJ+Ec6TkijsmhoPZ/RCpIzYK5mTv1RkrKQ7UKgggrB5yqIpG6KtHpdLdg9n idYusl9LWEq81+vo25nUkI2VzzeUECsms08SjuRQ7iz5BwUYWDcO2hkUWPbigugMiOCb HQp35+QsSILseGbDmeMbJDWXSrVIqO9O1/gOo1RNJ3kgYl41+81PipenkVuJ/qNSHw9t WnJA== 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 66-v6si3064282plb.428.2018.07.25.09.40.20; Wed, 25 Jul 2018 09:40:36 -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 S1731212AbeGYRva (ORCPT + 99 others); Wed, 25 Jul 2018 13:51:30 -0400 Received: from ns.mm-sol.com ([37.157.136.199]:35590 "EHLO extserv.mm-sol.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729184AbeGYRv1 (ORCPT ); Wed, 25 Jul 2018 13:51:27 -0400 Received: from mms-0439.qualcomm.mm-sol.com (unknown [37.157.136.206]) by extserv.mm-sol.com (Postfix) with ESMTPSA id 4DF6FCD64; Wed, 25 Jul 2018 19:38:54 +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 v4 18/34] media: camss: Add basic runtime PM support Date: Wed, 25 Jul 2018 19:38:27 +0300 Message-Id: <1532536723-19062-19-git-send-email-todor.tomov@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1532536723-19062-1-git-send-email-todor.tomov@linaro.org> References: <1532536723-19062-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 | 13 ++++- drivers/media/platform/qcom/camss/camss-csiphy.c | 15 +++++- drivers/media/platform/qcom/camss/camss-ispif.c | 26 ++++++++-- drivers/media/platform/qcom/camss/camss-vfe.c | 17 +++++++ drivers/media/platform/qcom/camss/camss.c | 63 ++++++++++++++++++++++++ drivers/media/platform/qcom/camss/camss.h | 11 +++++ 6 files changed, 139 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c index 627ef44..3ba087f 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,19 +317,27 @@ static int csid_set_power(struct v4l2_subdev *sd, int on) if (on) { u32 hw_version; - ret = regulator_enable(csid->vdda); + ret = pm_runtime_get_sync(dev); if (ret < 0) return ret; + ret = regulator_enable(csid->vdda); + if (ret < 0) { + pm_runtime_put_sync(dev); + return ret; + } + ret = csid_set_clock_rates(csid); if (ret < 0) { regulator_disable(csid->vdda); + pm_runtime_put_sync(dev); return ret; } ret = camss_enable_clocks(csid->nclocks, csid->clock, dev); if (ret < 0) { regulator_disable(csid->vdda); + pm_runtime_put_sync(dev); return ret; } @@ -339,6 +348,7 @@ static int csid_set_power(struct v4l2_subdev *sd, int on) disable_irq(csid->irq); camss_disable_clocks(csid->nclocks, csid->clock); regulator_disable(csid->vdda); + pm_runtime_put_sync(dev); return ret; } @@ -348,6 +358,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..4aeaedb 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,13 +241,21 @@ static int csiphy_set_power(struct v4l2_subdev *sd, int on) u8 hw_version; int ret; - ret = csiphy_set_clock_rates(csiphy); + ret = pm_runtime_get_sync(dev); if (ret < 0) return ret; + ret = csiphy_set_clock_rates(csiphy); + if (ret < 0) { + pm_runtime_put_sync(dev); + return ret; + } + ret = camss_enable_clocks(csiphy->nclocks, csiphy->clock, dev); - if (ret < 0) + if (ret < 0) { + pm_runtime_put_sync(dev); return ret; + } enable_irq(csiphy->irq); @@ -259,6 +268,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..2c6c0d2 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,12 +244,19 @@ static int ispif_set_power(struct v4l2_subdev *sd, int on) goto exit; } - ret = camss_enable_clocks(ispif->nclocks, ispif->clock, dev); + ret = pm_runtime_get_sync(dev); if (ret < 0) goto exit; + ret = camss_enable_clocks(ispif->nclocks, ispif->clock, dev); + if (ret < 0) { + pm_runtime_put_sync(dev); + goto exit; + } + ret = ispif_reset(ispif); if (ret < 0) { + pm_runtime_put_sync(dev); camss_disable_clocks(ispif->nclocks, ispif->clock); goto exit; } @@ -252,6 +271,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..474e1dd 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,14 @@ 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; + + ret = pm_runtime_get_sync(vfe->camss->dev); + if (ret < 0) + goto error_pm_runtime_get; + ret = vfe_set_clock_rates(vfe); if (ret < 0) goto error_clocks; @@ -2012,6 +2021,12 @@ static int vfe_get(struct vfe_device *vfe) camss_disable_clocks(vfe->nclocks, vfe->clock); error_clocks: + pm_runtime_put_sync(vfe->camss->dev); + +error_pm_runtime_get: + camss_pm_domain_off(vfe->camss, vfe->id); + +error_pm_domain: mutex_unlock(&vfe->power_lock); return ret; @@ -2034,6 +2049,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 */ -- 2.7.4