[PATCH 2/6] clk: samsung: add infrastructure to register CPU clocks

Thomas Abraham ta.omasab at gmail.com
Thu Jan 9 10:59:21 EST 2014


The CPU clock provider supplies the clock to the CPU clock domain. The
composition and organization of the CPU clock provider could vary among
Exynos SoCs. A CPU clock provider can be composed of clock mux, dividers
and gates. This patch defines a new clock type for CPU clock provider and
adds infrastructure to register the CPU clock providers for Samsung
platforms.

Signed-off-by: Thomas Abraham <thomas.ab at samsung.com>
---
 drivers/clk/samsung/clk.c |   71 +++++++++++++++++++++++++++++++++++++++++++++
 drivers/clk/samsung/clk.h |   37 +++++++++++++++++++++++-
 2 files changed, 107 insertions(+), 1 deletions(-)

diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c
index f503f32..9ac9056 100644
--- a/drivers/clk/samsung/clk.c
+++ b/drivers/clk/samsung/clk.c
@@ -316,3 +316,74 @@ unsigned long _get_rate(const char *clk_name)
 
 	return clk_get_rate(clk);
 }
+
+/*
+ * On most platform, the core clock rate is equal to the clock rate of
+ * parent pll. This is a simple helper function to support recalc_rate
+ * callback for such platforms.
+ */
+unsigned long samsung_core_clock_recalc_rate(struct clk_hw *hw,
+				unsigned long parent_rate)
+{
+	/*
+	 * Assuming that the output of the parent pll is the output clock
+	 * frequency of the core clock.
+	 */
+	return parent_rate;
+}
+
+/* This is a helper function to perform clock rounding for core clocks. */
+long samsung_core_clk_round_rate(struct clk_hw *hw,
+			unsigned long drate, unsigned long *prate)
+{
+	struct samsung_core_clock *core_clk;
+	const struct samsung_core_clock_freq_table *freq_tbl;
+	int i;
+
+	core_clk = container_of(hw, struct samsung_core_clock, hw);
+	freq_tbl = core_clk->freq_table;
+	drate /= 1000;
+
+	for (i = 0; i < freq_tbl->freq_count; i++) {
+		if (drate >= freq_tbl->freq[i])
+			return freq_tbl->freq[i] * 1000;
+	}
+	return freq_tbl->freq[i - 1] * 1000;
+}
+
+/* helper function to register a core clock */
+void __init samsung_coreclk_register(const char *name, const char **parents,
+			unsigned int num_parents, const char *pllclk,
+			const struct clk_ops *clk_ops, unsigned int lookup_id,
+			const struct samsung_core_clock_freq_table *freq_tbl)
+{
+	struct samsung_core_clock *coreclk;
+	struct clk_init_data init;
+	struct clk *clk;
+
+	coreclk = kzalloc(sizeof(*coreclk), GFP_KERNEL);
+	if (!coreclk) {
+		pr_err("%s: could not allocate memory for coreclk %s\n",
+					__func__, name);
+		return;
+	}
+
+	init.name = name;
+	init.flags = CLK_GET_RATE_NOCACHE;
+	init.parent_names = parents;
+	init.num_parents = num_parents;
+	init.ops = clk_ops;
+
+	coreclk->hw.init = &init;
+	coreclk->ctrl_base = reg_base;
+	coreclk->fout_pll = __clk_lookup(pllclk);
+	coreclk->freq_table = freq_tbl;
+
+	clk = clk_register(NULL, &coreclk->hw);
+	if (IS_ERR(clk)) {
+		pr_err("%s: could not register coreclk %s\n", __func__,	name);
+		kfree(coreclk);
+		return;
+	}
+	samsung_clk_add_lookup(clk, lookup_id);
+}
diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h
index 31b4174..0e43023 100644
--- a/drivers/clk/samsung/clk.h
+++ b/drivers/clk/samsung/clk.h
@@ -312,6 +312,37 @@ struct samsung_pll_clock {
 	__PLL(_typ, _id, NULL, _name, _pname, CLK_GET_RATE_NOCACHE,	\
 		_lock, _con, _rtable, _alias)
 
+/**
+ * struct samsung_core_clock_freq_table: table of frequency supported by
+ * a core clock and associated data if any.
+ * @freq: points to a table of supported frequencies (in KHz)
+ * @freq_count: number of entries in the frequency table
+ * @data: core clock specific data, if any
+ */
+struct samsung_core_clock_freq_table {
+	const unsigned long	*freq;       /* in KHz */
+	unsigned long		freq_count;
+	const void		*data;
+};
+
+/**
+ * struct samsung_core_clock: information about clock supplied to a CPU core.
+ * @hw: handle between ccf and core clock.
+ * @ctrl_base: base address of the clock controller.
+ * @fout_pll: clock handle representing the clock output of the associated PLL.
+ */
+struct samsung_core_clock {
+	struct clk_hw		hw;
+	void __iomem		*ctrl_base;
+	struct clk		*fout_pll;
+	const struct samsung_core_clock_freq_table *freq_table;
+};
+
+extern unsigned long samsung_core_clock_recalc_rate(struct clk_hw *hw,
+				unsigned long parent_rate);
+extern long samsung_core_clk_round_rate(struct clk_hw *hw,
+			unsigned long drate, unsigned long *prate);
+
 extern void __init samsung_clk_init(struct device_node *np, void __iomem *base,
 		unsigned long nr_clks, unsigned long *rdump,
 		unsigned long nr_rdump, unsigned long *soc_rdump,
@@ -337,7 +368,11 @@ extern void __init samsung_clk_register_gate(
 		struct samsung_gate_clock *clk_list, unsigned int nr_clk);
 extern void __init samsung_clk_register_pll(struct samsung_pll_clock *pll_list,
 		unsigned int nr_clk, void __iomem *base);
-
+extern void __init samsung_coreclk_register(const char *coreclk,
+		const char **parents, unsigned int num_parents,
+		const char *pllclk, const struct clk_ops *clk_ops,
+		unsigned int lookup_id,
+		const struct samsung_core_clock_freq_table *freq_tbl);
 extern unsigned long _get_rate(const char *clk_name);
 
 #endif /* __SAMSUNG_CLK_H */
-- 
1.6.6.rc2




More information about the linux-arm-kernel mailing list