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...@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

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to