[PATCH RFC 5/8] PM / devfreq: exynos5250: migrate to common-clock
Abhilash Kesavan
a.kesavan at samsung.com
Sat Apr 26 13:38:45 PDT 2014
From: Andrew Bresticker <abrestic at chromium.org>
Use the common-clock framework to scale frequencies for the various
peripheral clocks on the Exynos5250.
Signed-off-by: Andrew Bresticker <abrestic at chromium.org>
Signed-off-by: Abhilash Kesavan <a.kesavan at samsung.com>
---
drivers/devfreq/exynos/exynos5_bus.c | 131 +++++++++++++++++++++++++++++++----
1 file changed, 119 insertions(+), 12 deletions(-)
diff --git a/drivers/devfreq/exynos/exynos5_bus.c b/drivers/devfreq/exynos/exynos5_bus.c
index ab54a69..d4b8a68 100644
--- a/drivers/devfreq/exynos/exynos5_bus.c
+++ b/drivers/devfreq/exynos/exynos5_bus.c
@@ -57,7 +57,6 @@ struct busfreq_data_int {
struct notifier_block pm_notifier;
struct mutex lock;
struct pm_qos_request int_req;
- struct clk *int_clk;
};
struct int_bus_opp_table {
@@ -66,6 +65,17 @@ struct int_bus_opp_table {
unsigned long volt;
};
+struct int_clk_table {
+ unsigned int idx;
+ unsigned long freq;
+};
+
+struct int_clk {
+ const char *clk_name;
+ struct clk *clk;
+ struct int_clk_table *freq_table;
+};
+
static struct int_bus_opp_table exynos5_int_opp_table[] = {
{LV_0, 266000, 1025000},
{LV_1, 200000, 1025000},
@@ -75,6 +85,98 @@ static struct int_bus_opp_table exynos5_int_opp_table[] = {
{0, 0, 0},
};
+static struct int_clk_table aclk_166[] = {
+ {LV_0, 167000},
+ {LV_1, 111000},
+ {LV_2, 84000},
+ {LV_3, 84000},
+ {LV_4, 42000},
+};
+
+static struct int_clk_table aclk_200[] = {
+ {LV_0, 200000},
+ {LV_1, 160000},
+ {LV_2, 160000},
+ {LV_3, 134000},
+ {LV_4, 100000},
+};
+
+static struct int_clk_table aclk_266[] = {
+ {LV_0, 267000},
+ {LV_1, 200000},
+ {LV_2, 160000},
+ {LV_3, 134000},
+ {LV_4, 100000},
+};
+
+static struct int_clk_table aclk_333[] = {
+ {LV_0, 333000},
+ {LV_1, 167000},
+ {LV_2, 111000},
+ {LV_3, 111000},
+ {LV_4, 42000},
+};
+
+static struct int_clk_table aclk_300_disp1[] = {
+ {LV_0, 267000},
+ {LV_1, 267000},
+ {LV_2, 267000},
+ {LV_3, 267000},
+ {LV_4, 200000},
+};
+
+static struct int_clk_table aclk_300_gscl[] = {
+ {LV_0, 267000},
+ {LV_1, 267000},
+ {LV_2, 267000},
+ {LV_3, 200000},
+ {LV_4, 100000},
+};
+
+#define EXYNOS5_INT_CLK(name, tbl) { \
+ .clk_name = name, \
+ .freq_table = tbl, \
+}
+
+static struct int_clk exynos5_int_clks[] = {
+ EXYNOS5_INT_CLK("aclk166_d", aclk_166),
+ EXYNOS5_INT_CLK("aclk200_d", aclk_200),
+ EXYNOS5_INT_CLK("aclk266_d", aclk_266),
+ EXYNOS5_INT_CLK("aclk333_d", aclk_333),
+ EXYNOS5_INT_CLK("aclk300_disp1_d", aclk_300_disp1),
+ EXYNOS5_INT_CLK("aclk300_gscl_d", aclk_300_gscl),
+};
+
+static int exynos5_int_set_rate(struct busfreq_data_int *data,
+ unsigned long rate)
+{
+ int index, i;
+
+ for (index = 0; index < ARRAY_SIZE(exynos5_int_opp_table); index++) {
+ if (exynos5_int_opp_table[index].clk == rate)
+ break;
+ }
+
+ if (index >= _LV_END)
+ return -EINVAL;
+
+ /* Change the system clock divider values */
+ for (i = 0; i < ARRAY_SIZE(exynos5_int_clks); i++) {
+ struct int_clk *clk_info = &exynos5_int_clks[i];
+ int ret;
+
+ ret = clk_set_rate(clk_info->clk,
+ clk_info->freq_table[index].freq * 1000);
+ if (ret) {
+ dev_err(data->dev, "Failed to set %s rate: %d\n",
+ clk_info->clk_name, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static int exynos5_int_setvolt(struct busfreq_data_int *data,
unsigned long volt)
{
@@ -126,7 +228,7 @@ static int exynos5_busfreq_int_target(struct device *dev, unsigned long *_freq,
if (err)
goto out;
- err = clk_set_rate(data->int_clk, freq * 1000);
+ err = exynos5_int_set_rate(data, freq);
if (err)
goto out;
@@ -229,7 +331,7 @@ static int exynos5_busfreq_int_pm_notifier_event(struct notifier_block *this,
if (err)
goto unlock;
- err = clk_set_rate(data->int_clk, freq * 1000);
+ err = exynos5_int_set_rate(data, freq);
if (err)
goto unlock;
@@ -309,10 +411,15 @@ static int exynos5_busfreq_int_probe(struct platform_device *pdev)
return PTR_ERR(data->vdd_int);
}
- data->int_clk = devm_clk_get(dev, "int_clk");
- if (IS_ERR(data->int_clk)) {
- dev_err(dev, "Cannot get clock \"int_clk\"\n");
- return PTR_ERR(data->int_clk);
+ for (i = 0; i < ARRAY_SIZE(exynos5_int_clks); i++) {
+ struct int_clk *clk_info = &exynos5_int_clks[i];
+
+ clk_info->clk = devm_clk_get(dev, clk_info->clk_name);
+ if (IS_ERR(clk_info->clk)) {
+ dev_err(dev, "Failed to get clock %s\n",
+ clk_info->clk_name);
+ return PTR_ERR(clk_info->clk);
+ }
}
rcu_read_lock();
@@ -329,16 +436,16 @@ static int exynos5_busfreq_int_probe(struct platform_device *pdev)
rcu_read_unlock();
data->curr_freq = initial_freq;
- err = clk_set_rate(data->int_clk, initial_freq * 1000);
+ err = exynos5_int_setvolt(data, initial_volt);
+ if (err)
+ return err;
+
+ err = exynos5_int_set_rate(data, initial_freq);
if (err) {
dev_err(dev, "Failed to set initial frequency\n");
return err;
}
- err = exynos5_int_setvolt(data, initial_volt);
- if (err)
- return err;
-
platform_set_drvdata(pdev, data);
busfreq_mon_reset(ppmu_data);
--
1.8.3.2
More information about the linux-arm-kernel
mailing list