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@xxxxxxxxxxx> --- 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 majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html