summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChanwoo Choi <cw00.choi@samsung.com>2015-04-22 22:23:50 +0900
committerSeung-Woo Kim <sw0312.kim@samsung.com>2016-12-14 13:44:40 +0900
commit119fc9b4ac190e17cd53d280c68241cf975a4bcc (patch)
tree6b8a81f17c2004995fc8b31dacffff3c07747803
parent36b67be6bc51d8e5e540642f1d4c81425129cd88 (diff)
soc: samsung: Add the support of power domain for Exynos SoC
This patch moves the power domain driver of Exynos SoC to support both 32-bit Exynos and 64-bit Exynos. Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
-rw-r--r--arch/arm/mach-exynos/Makefile1
-rw-r--r--drivers/soc/samsung/Makefile1
-rw-r--r--drivers/soc/samsung/pm_domains.c (renamed from arch/arm/mach-exynos/pm_domains.c)75
3 files changed, 36 insertions, 41 deletions
diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile
index bcefb5473ee4..d5fafa91c094 100644
--- a/arch/arm/mach-exynos/Makefile
+++ b/arch/arm/mach-exynos/Makefile
@@ -13,7 +13,6 @@ obj-$(CONFIG_ARCH_EXYNOS) += exynos.o pmu.o exynos-smc.o firmware.o
obj-$(CONFIG_EXYNOS_CPU_SUSPEND) += pm.o sleep.o
obj-$(CONFIG_PM_SLEEP) += suspend.o
-obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o
obj-$(CONFIG_SMP) += platsmp.o headsmp.o
diff --git a/drivers/soc/samsung/Makefile b/drivers/soc/samsung/Makefile
index acaae9fc80bb..65da30682592 100644
--- a/drivers/soc/samsung/Makefile
+++ b/drivers/soc/samsung/Makefile
@@ -2,3 +2,4 @@ obj-$(CONFIG_EXYNOS_PMU) += exynos-pmu.o
obj-$(CONFIG_EXYNOS5433_PMU) += exynos5433-pmu.o
obj-$(CONFIG_EXYNOS_PM) += exynos-pm.o
obj-$(CONFIG_EXYNOS5433_PM) += exynos5433-pm.o
+obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o
diff --git a/arch/arm/mach-exynos/pm_domains.c b/drivers/soc/samsung/pm_domains.c
index 6864178e21b9..623c422a636b 100644
--- a/arch/arm/mach-exynos/pm_domains.c
+++ b/drivers/soc/samsung/pm_domains.c
@@ -23,21 +23,22 @@
#include <linux/of_platform.h>
#include <linux/sched.h>
-#define INT_LOCAL_PWR_EN 0x7
-#define MAX_CLK_PER_DOMAIN 4
+#define INT_LOCAL_PWR_EN 0xF
/*
* Exynos specific wrapper around the generic power domain
*/
struct exynos_pm_domain {
+ struct generic_pm_domain pd;
void __iomem *base;
char const *name;
bool is_off;
- struct generic_pm_domain pd;
+ int nr_reparent_clks;
struct clk *oscclk;
- struct clk *clk[MAX_CLK_PER_DOMAIN];
- struct clk *pclk[MAX_CLK_PER_DOMAIN];
- struct clk *asb_clk[MAX_CLK_PER_DOMAIN];
+ struct clk **clk;
+ struct clk **pclk;
+ int nr_asb_clks;
+ struct clk **asb_clk;
};
static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on)
@@ -51,7 +52,7 @@ static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on)
pd = container_of(domain, struct exynos_pm_domain, pd);
base = pd->base;
- for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) {
+ for (i = 0; i < pd->nr_asb_clks; i++) {
if (IS_ERR(pd->asb_clk[i]))
break;
clk_prepare_enable(pd->asb_clk[i]);
@@ -59,7 +60,7 @@ static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on)
/* Set oscclk before powering off a domain*/
if (!power_on) {
- for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) {
+ for (i = 0; i < pd->nr_reparent_clks; i++) {
if (IS_ERR(pd->clk[i]))
break;
if (clk_set_parent(pd->clk[i], pd->oscclk))
@@ -72,7 +73,7 @@ static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on)
__raw_writel(pwr, base);
/* Wait max 1ms */
- timeout = 10;
+ timeout = 100;
while ((__raw_readl(base + 0x4) & INT_LOCAL_PWR_EN) != pwr) {
if (!timeout) {
@@ -87,7 +88,7 @@ static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on)
/* Restore clocks after powering on a domain*/
if (power_on) {
- for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) {
+ for (i = 0; i < pd->nr_reparent_clks; i++) {
if (IS_ERR(pd->clk[i]))
break;
if (clk_set_parent(pd->clk[i], pd->pclk[i]))
@@ -96,7 +97,7 @@ static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on)
}
}
- for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) {
+ for (i = 0; i < pd->nr_asb_clks; i++) {
if (IS_ERR(pd->asb_clk[i]))
break;
clk_disable_unprepare(pd->asb_clk[i]);
@@ -118,6 +119,7 @@ static int exynos_pd_power_off(struct generic_pm_domain *domain)
static __init int exynos4_pm_init_power_domain(void)
{
struct device_node *np;
+ int nr_clks;
for_each_compatible_node(np, NULL, "samsung,exynos4210-pd") {
struct exynos_pm_domain *pd;
@@ -130,46 +132,39 @@ static __init int exynos4_pm_init_power_domain(void)
return -ENOMEM;
}
- pd->pd.name = kstrdup_const(strrchr(np->full_name, '/') + 1,
- GFP_KERNEL);
+ pd->pd.name = kstrdup(np->name, GFP_KERNEL);
pd->name = pd->pd.name;
pd->base = of_iomap(np, 0);
pd->pd.power_off = exynos_pd_power_off;
pd->pd.power_on = exynos_pd_power_on;
- for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) {
- char clk_name[8];
+ nr_clks = of_count_phandle_with_args(np, "clocks","#clock-cells");
+ if (nr_clks > 0 && !(nr_clks % 2)) {
+ nr_clks /= 2;
- snprintf(clk_name, sizeof(clk_name), "asb%d", i);
- pd->asb_clk[i] = of_clk_get_by_name(np, clk_name);
- if (IS_ERR(pd->asb_clk[i]))
+ pd->oscclk = clk_get(NULL, "xxti");
+ if (IS_ERR(pd->oscclk))
break;
- }
-
- 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;
+ pd->clk = kcalloc(sizeof(struct clk *),
+ nr_clks, GFP_KERNEL);
+ pd->pclk = kcalloc(sizeof(struct clk *),
+ nr_clks, GFP_KERNEL);
+ for (i = 0; i < nr_clks; i++) {
+ pd->clk[i] = of_clk_get(np, i);
+ if (IS_ERR(pd->clk[i]))
+ break;
+ pd->pclk[i] = of_clk_get(np, i + 1);
+ 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);
+ pd->nr_reparent_clks = nr_clks;
+ }
-no_clk:
on = __raw_readl(pd->base + 0x4) & INT_LOCAL_PWR_EN;
pm_genpd_init(&pd->pd, NULL, !on);