linux-pm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Amit Daniel Kachhap <amit.daniel@samsung.com>
To: linux-arm-kernel@lists.infradead.org, linux-samsung-soc@vger.kernel.org
Cc: kgene.kim@samsung.com, linux-kernel@vger.kernel.org,
	s.nawrocki@samsung.com, pankaj.dubey@samsung.com,
	ulf.hansson@linaro.org, khilman@kernel.org,
	linux-pm@vger.kernel.org, geert@linux-m68k.org,
	rjw@rjwysocki.net, devicetree@vger.kernel.org,
	Amit Daniel Kachhap <amit.daniel@samsung.com>
Subject: [PATCH RFC v2 09/12] drivers: soc: pm_domain: Modify the parent clocks bindings
Date: Mon, 24 Nov 2014 18:34:13 +0530	[thread overview]
Message-ID: <1416834256-11225-9-git-send-email-amit.daniel@samsung.com> (raw)
In-Reply-To: <1416834256-11225-1-git-send-email-amit.daniel@samsung.com>

This patch updates the parent clock bindings to make it more generic.
The current bindings limits the transient parent clocks to just one
clock as "oscclk". This patch extends it to allow any clock as
intermediate parent clock.
The reparent clock sets are of form tclkX, pclkX, clkX where X:0-9.
Because of this change only exynos5420 SoC DT bindings are affected.
The complete example is shown in the DT documentation section.

Signed-off-by: Amit Daniel Kachhap <amit.daniel@samsung.com>
---
 .../bindings/arm/exynos/power_domain.txt           |   18 +-
 drivers/soc/samsung/pm_domains.c                   |  199 +++++++++++++-------
 2 files changed, 145 insertions(+), 72 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/exynos/power_domain.txt b/Documentation/devicetree/bindings/arm/exynos/power_domain.txt
index 0160bdc..8d913b9 100644
--- a/Documentation/devicetree/bindings/arm/exynos/power_domain.txt
+++ b/Documentation/devicetree/bindings/arm/exynos/power_domain.txt
@@ -13,17 +13,17 @@ Required Properties:
 
 Optional Properties:
 - compatible: This is a second compatible name and gives the complete Power
-	Domain name like "samsung,exynos7-pd-mfc".
-- clocks: List of clock handles. The parent clocks of the input clocks to the
-	devices in this power domain are set to oscclk before power gating
+	Domain name like "samsung,exynos7-pd-mfc"
+- pd-parent-clocks: List of clock handles. The parent clocks of the input clocks to
+	the devices in this power domain are set to tclk before power gating
 	and restored back after powering on a domain. This is required for
 	all domains which are powered on and off and not required for unused
 	domains.
-- clock-names: The following clocks can be specified:
-	- oscclk: Oscillator clock.
+- pd-parent-clock-names: The following clocks can be specified:
+	- tclkN: Transient/Temporary parent clock.
 	- pclkN, clkN: Pairs of parent of input clock and input clock to the
-		devices in this power domain. Maximum of 4 pairs (N = 0 to 3)
-		are supported currently.
+	devices in this power domain.
+	Maximum of 10 sets (N = 0 to 9) are supported.
 - parents: phandle of parent power domains.
 
 Node of a device using power domains must have a samsung,power-domain property
@@ -40,9 +40,9 @@ Example:
 	mfc_pd: power-domain@10044060 {
 		compatible = "samsung,exynos4210-pd";
 		reg = <0x10044060 0x20>;
-		clocks = <&clock CLK_FIN_PLL>, <&clock CLK_MOUT_SW_ACLK333>,
+		pd-parent-clocks = <&clock CLK_FIN_PLL>, <&clock CLK_MOUT_SW_ACLK333>,
 			<&clock CLK_MOUT_USER_ACLK333>;
-		clock-names = "oscclk", "pclk0", "clk0";
+		pd-parent-clock-names = "tclk0", "pclk0", "clk0";
 		#power-domain-cells = <0>;
 	};
 
diff --git a/drivers/soc/samsung/pm_domains.c b/drivers/soc/samsung/pm_domains.c
index 89e2fd5..96196f8 100644
--- a/drivers/soc/samsung/pm_domains.c
+++ b/drivers/soc/samsung/pm_domains.c
@@ -24,11 +24,18 @@
 #include <linux/sched.h>
 #include <linux/soc/samsung/exynos-pmu.h>
 
-#define MAX_CLK_PER_DOMAIN	4
+#define MAX_CLK_PER_DOMAIN	30
 #define MAX_PARENT_POWER_DOMAIN	10
 
 static struct exynos_pmu_pd_ops *pd_ops;
 
+struct clk_parent_list {
+	struct clk **clks;
+	struct clk **parent_clks;
+	struct clk **trans_clks;
+	unsigned int count;
+};
+
 /*
  * Exynos specific wrapper around the generic power domain
  */
@@ -37,65 +44,152 @@ struct exynos_pm_domain {
 	char const *name;
 	bool is_off;
 	struct generic_pm_domain pd;
-	struct clk *oscclk;
-	struct clk *clk[MAX_CLK_PER_DOMAIN];
-	struct clk *pclk[MAX_CLK_PER_DOMAIN];
+	struct clk_parent_list *clk_parent;
 };
 
-static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on)
+static struct clk *exynos_pd_clk_get(struct device_node *np,
+			char *initial_property,	char *clk_name)
 {
-	struct exynos_pm_domain *pd;
-	void __iomem *base;
-	int ret = 0;
+	struct of_phandle_args clkspec;
+	struct clk *clk;
+	int rc, index;
+	char name[32];
+
+	sprintf(name, "%s-clock-names", initial_property);
+	index = of_property_match_string(np, name, clk_name);
+	if (index < 0)
+		return ERR_PTR(-EINVAL);
+
+	sprintf(name, "%s-clocks", initial_property);
+
+	rc = of_parse_phandle_with_args(np, name, "#clock-cells", index,
+					&clkspec);
+	if (rc)
+		return ERR_PTR(rc);
+
+	clk = of_clk_get_from_provider(&clkspec);
+	of_node_put(clkspec.np);
+	return clk;
+}
 
-	pd = container_of(domain, struct exynos_pm_domain, pd);
-	base = pd->base;
+static int pd_init_parent_clocks(struct platform_device *pdev,
+		struct device_node *np, struct exynos_pm_domain *pd)
+{
+	struct clk_parent_list *list;
+	char clk_name[8];
+	int count, i;
+	struct clk *clk = ERR_PTR(-ENOENT);
+
+	list = devm_kzalloc(&pdev->dev, sizeof(*list), GFP_KERNEL);
+	if (!list)
+		return -ENOMEM;
+
+	pd->clk_parent = list;
+
+	/*
+	 * Each clock re-parenting data set contains 3 elements- tclkX, pclkX
+	 * and clkX, where X can vary between 0-9.
+	 */
+	count = of_property_count_strings(np, "pd-parent-clock-names");
+	if (!count || (count % 3) || count > MAX_CLK_PER_DOMAIN)
+		return -EINVAL;
 
-	/* Set oscclk before powering off a domain*/
-	if (!power_on) {
-		int i;
+	list->count = count / 3;
+
+	list->clks = devm_kzalloc(&pdev->dev,
+			sizeof(*list->clks) * list->count, GFP_KERNEL);
+	if (!list->clks)
+		return -ENOMEM;
+
+	list->parent_clks = devm_kzalloc(&pdev->dev,
+			sizeof(*list->parent_clks) * list->count, GFP_KERNEL);
+	if (!list->parent_clks)
+		return -ENOMEM;
+
+	list->trans_clks = devm_kzalloc(&pdev->dev,
+			sizeof(*list->trans_clks) * list->count, GFP_KERNEL);
+	if (!list->trans_clks)
+		return -ENOMEM;
+
+	for (i = 0; i < list->count; i++) {
+		snprintf(clk_name, sizeof(clk_name), "tclk%d", i);
+		clk = exynos_pd_clk_get(np, "pd-parent", clk_name);
+		if (IS_ERR(clk)) {
+			dev_err(&pdev->dev, "%s clock not found\n", clk_name);
+			return -EINVAL;
+		}
+		list->trans_clks[i] = clk;
 
-		for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) {
-			if (IS_ERR(pd->clk[i]))
-				break;
-			if (clk_set_parent(pd->clk[i], pd->oscclk))
-				pr_err("%s: error setting oscclk as parent to clock %d\n",
-						pd->name, i);
+		snprintf(clk_name, sizeof(clk_name), "pclk%d", i);
+		clk = exynos_pd_clk_get(np, "pd-parent", clk_name);
+		if (IS_ERR(clk)) {
+			dev_err(&pdev->dev, "%s clock not found\n", clk_name);
+			return -EINVAL;
 		}
+		list->parent_clks[i] = clk;
+
+		snprintf(clk_name, sizeof(clk_name), "clk%d", i);
+		clk = exynos_pd_clk_get(np, "pd-parent", clk_name);
+		if (IS_ERR(clk)) {
+			dev_err(&pdev->dev, "%s clock not found\n", clk_name);
+			return -EINVAL;
+		}
+		list->clks[i] = clk;
 	}
+	dev_info(&pdev->dev, "pd parent clocks initialised\n");
+	return 0;
+}
 
-	if (power_on)
-		ret = pd_ops->pd_on(domain->name, base);
-	else
-		ret = pd_ops->pd_off(domain->name, base);
+static void exynos_pd_post_poweron(struct exynos_pm_domain *pd)
+{
+	struct clk_parent_list *p_list;
+	int i;
 
-	if (ret)
-		return ret;
+	p_list = pd->clk_parent;
+	if (!p_list)
+		return;
 
-	/* Restore clocks after powering on a domain*/
-	if (power_on) {
-		int i;
+	/* Set the parents clocks correctly */
+	for (i = 0; i < p_list->count; i++)
+		clk_set_parent(p_list->clks[i], p_list->parent_clks[i]);
+}
 
-		for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) {
-			if (IS_ERR(pd->clk[i]))
-				break;
-			if (clk_set_parent(pd->clk[i], pd->pclk[i]))
-				pr_err("%s: error setting parent to clock%d\n",
-						pd->name, i);
-		}
-	}
+static void exynos_pd_poweroff_prepare(struct exynos_pm_domain *pd)
+{
+	struct clk_parent_list *p_list;
+	int i;
 
-	return ret;
+	p_list = pd->clk_parent;
+	if (!p_list)
+		return;
+
+	/* Reparent the clocks to the transient clocks before power off */
+	for (i = 0; i < p_list->count; i++)
+		clk_set_parent(p_list->clks[i], p_list->trans_clks[i]);
 }
 
 static int exynos_pd_power_on(struct generic_pm_domain *domain)
 {
-	return exynos_pd_power(domain, true);
+	int ret = 0;
+	struct exynos_pm_domain *pd;
+
+	pd = container_of(domain, struct exynos_pm_domain, pd);
+	ret = pd_ops->pd_on(domain->name, pd->base);
+	if (ret)
+		return ret;
+	exynos_pd_post_poweron(pd);
+	return ret;
 }
 
 static int exynos_pd_power_off(struct generic_pm_domain *domain)
 {
-	return exynos_pd_power(domain, false);
+	int ret = 0;
+	struct exynos_pm_domain *pd;
+
+	pd = container_of(domain, struct exynos_pm_domain, pd);
+	exynos_pd_poweroff_prepare(pd);
+	ret = pd_ops->pd_off(domain->name, pd->base);
+	return ret;
 }
 
 static int exynos_power_domain_probe(struct platform_device *pdev)
@@ -118,7 +212,6 @@ static int exynos_power_domain_probe(struct platform_device *pdev)
 
 	for_each_compatible_node(np, NULL, "samsung,exynos4210-pd") {
 		struct exynos_pm_domain *pd;
-		int i;
 		bool on;
 		const char *name;
 
@@ -139,30 +232,10 @@ static int exynos_power_domain_probe(struct platform_device *pdev)
 		pd->pd.power_off = exynos_pd_power_off;
 		pd->pd.power_on = exynos_pd_power_on;
 
-		pd->oscclk = of_clk_get_by_name(np, "oscclk");
-		if (IS_ERR(pd->oscclk))
-			goto no_clk;
-
-		for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) {
-			char clk_name[8];
-
-			snprintf(clk_name, sizeof(clk_name), "clk%d", i);
-			pd->clk[i] = of_clk_get_by_name(np, clk_name);
-			if (IS_ERR(pd->clk[i]))
-				break;
-			snprintf(clk_name, sizeof(clk_name), "pclk%d", i);
-			pd->pclk[i] = of_clk_get_by_name(np, clk_name);
-			if (IS_ERR(pd->pclk[i])) {
-				clk_put(pd->clk[i]);
-				pd->clk[i] = ERR_PTR(-EINVAL);
-				break;
-			}
-		}
-
-		if (IS_ERR(pd->clk[0]))
-			clk_put(pd->oscclk);
+		if (of_find_property(np, "pd-parent-clocks", NULL))
+			if (pd_init_parent_clocks(pdev, np, pd))
+				return -EINVAL;
 
-no_clk:
 		on = pd_ops->pd_status(pd->base);
 
 		pm_genpd_init(&pd->pd, NULL, !on);
-- 
1.7.9.5

  parent reply	other threads:[~2014-11-24 13:04 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-11-24 12:52 [PATCH RFC v2 00/12] soc: samsung: Modify and enhance power domain driver Amit Daniel Kachhap
2014-11-24 13:04 ` [PATCH RFC v2 01/12] arm: exynos: Add platform driver support for " Amit Daniel Kachhap
2014-11-24 13:04   ` [PATCH RFC v2 02/12] soc: exynos: Move exynos power domain file to driver/soc/samsung folder Amit Daniel Kachhap
2014-11-24 13:04   ` [PATCH RFC v2 03/12] soc: samsung: exynos-pmu: Register exynos pd driver as a mfd client Amit Daniel Kachhap
2014-11-24 13:04   ` [PATCH RFC v2 04/12] soc: samsung: Re-structure PMU driver to create pd on/off handlers Amit Daniel Kachhap
2014-11-24 13:04   ` [PATCH RFC v2 05/12] soc: samsung: pm_domain: Use unique compatible name for power domain Amit Daniel Kachhap
2014-11-24 13:04   ` [PATCH RFC v2 06/12] driver: soc: exynos-pmu: Add exynos7 power domain on/off ops Amit Daniel Kachhap
     [not found]     ` <1416834256-11225-6-git-send-email-amit.daniel-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2014-11-25  7:30       ` Ulf Hansson
2014-11-25  8:33         ` amit daniel kachhap
2014-11-24 13:04   ` [PATCH RFC v2 07/12] PM / Domains: export pm_genpd_lookup_name Amit Daniel Kachhap
2014-11-25  7:35     ` Ulf Hansson
2014-11-25  8:48       ` amit daniel kachhap
2014-11-27 14:20         ` Ulf Hansson
2014-11-28  8:52           ` amit daniel kachhap
2014-11-24 13:04   ` [PATCH RFC v2 08/12] soc: samsung: pm_domain: Add support for parent power domain Amit Daniel Kachhap
2014-11-25  7:59     ` Ulf Hansson
     [not found]       ` <CAPDyKFoBnViXQF=wDYp0x4gaOO4ht3a8KBeY6=k6_Zkkav28pQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-11-25  8:57         ` amit daniel kachhap
2014-11-25  9:19           ` Geert Uytterhoeven
2014-12-03  8:36             ` Marek Szyprowski
2014-11-24 13:04   ` Amit Daniel Kachhap [this message]
2014-11-24 13:04   ` [PATCH RFC v2 10/12] drivers: soc: samsung: Add support for clock enabling in " Amit Daniel Kachhap
     [not found]   ` <1416834256-11225-1-git-send-email-amit.daniel-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2014-11-24 13:04     ` [PATCH RFC v2 11/12] drivers: soc: samsung: Add support for clock rate save/restore " Amit Daniel Kachhap
2014-11-24 13:04   ` [PATCH RFC v2 12/12] arm64: Kconfig: Enable PM_GENERIC_DOMAINS for exynos7 Amit Daniel Kachhap

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=1416834256-11225-9-git-send-email-amit.daniel@samsung.com \
    --to=amit.daniel@samsung.com \
    --cc=devicetree@vger.kernel.org \
    --cc=geert@linux-m68k.org \
    --cc=kgene.kim@samsung.com \
    --cc=khilman@kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pm@vger.kernel.org \
    --cc=linux-samsung-soc@vger.kernel.org \
    --cc=pankaj.dubey@samsung.com \
    --cc=rjw@rjwysocki.net \
    --cc=s.nawrocki@samsung.com \
    --cc=ulf.hansson@linaro.org \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).