return xom;
}
-static void __init exynos4_clk_register_finpll(unsigned long xom)
+static void __init exynos4_clk_register_finpll(struct samsung_clk_provider *ctx,
+ unsigned long xom)
{
struct samsung_fixed_rate_clock fclk;
struct clk *clk;
fclk.parent_name = NULL;
fclk.flags = CLK_IS_ROOT;
fclk.fixed_rate = finpll_f;
- samsung_clk_register_fixed_rate(&fclk, 1);
+ samsung_clk_register_fixed_rate(ctx, &fclk, 1);
}
* xxti and xusbxti clocks. These clocks are then registered with the specified
* clock speed.
*/
-void __init exynos4_clk_register_fixed_ext(unsigned long xxti_f,
+void __init exynos4_clk_register_fixed_ext(struct samsung_clk_provider *ctx,
+ unsigned long xxti_f,
unsigned long xusbxti_f)
{
exynos4_fixed_rate_ext_clks[0].fixed_rate = xxti_f;
exynos4_fixed_rate_ext_clks[1].fixed_rate = xusbxti_f;
- samsung_clk_register_fixed_rate(exynos4_fixed_rate_ext_clks,
+ samsung_clk_register_fixed_rate(ctx, exynos4_fixed_rate_ext_clks,
ARRAY_SIZE(exynos4_fixed_rate_ext_clks));
}
void __init exynos4_clk_init(struct device_node *np, enum exynos4_soc exynos4_soc, void __iomem *reg_base, unsigned long xom)
{
struct clk *apll, *mpll, *epll, *vpll;
+ struct samsung_clk_provider *ctx;
if (np) {
reg_base = of_iomap(np, 0);
}
if (exynos4_soc == EXYNOS4210)
- samsung_clk_init(np, reg_base, nr_clks,
+ ctx = samsung_clk_init(np, reg_base, nr_clks,
exynos4_clk_regs, ARRAY_SIZE(exynos4_clk_regs),
exynos4210_clk_save, ARRAY_SIZE(exynos4210_clk_save));
else
- samsung_clk_init(np, reg_base, nr_clks,
+ ctx = samsung_clk_init(np, reg_base, nr_clks,
exynos4_clk_regs, ARRAY_SIZE(exynos4_clk_regs),
exynos4x12_clk_save, ARRAY_SIZE(exynos4x12_clk_save));
+ if (!ctx)
+ panic("%s: unable to allocate context.\n", __func__);
if (np)
- samsung_clk_of_register_fixed_ext(exynos4_fixed_rate_ext_clks,
+ samsung_clk_of_register_fixed_ext(ctx,
+ exynos4_fixed_rate_ext_clks,
ARRAY_SIZE(exynos4_fixed_rate_ext_clks),
ext_clk_match);
- exynos4_clk_register_finpll(xom);
- samsung_clk_register_fixed_rate(exynos4_fixed_rate_clks,
+ exynos4_clk_register_finpll(ctx, xom);
+ samsung_clk_register_fixed_rate(ctx, exynos4_fixed_rate_clks,
ARRAY_SIZE(exynos4_fixed_rate_clks));
if (exynos4_soc == EXYNOS4210) {
- samsung_clk_register_mux(exynos4210_mux_clks,
+ samsung_clk_register_mux(ctx, exynos4210_mux_clks,
ARRAY_SIZE(exynos4210_mux_clks));
apll = samsung_clk_register_pll45xx("fout_apll", "fin_pll",
reg_base + VPLL_LOCK, exynos4_vpll_pms);
}
- samsung_clk_add_lookup(apll, fout_apll);
- samsung_clk_add_lookup(mpll, fout_mpll);
- samsung_clk_add_lookup(epll, fout_epll);
- samsung_clk_add_lookup(vpll, fout_vpll);
+ samsung_clk_add_lookup(ctx, apll, fout_apll);
+ samsung_clk_add_lookup(ctx, mpll, fout_mpll);
+ samsung_clk_add_lookup(ctx, epll, fout_epll);
+ samsung_clk_add_lookup(ctx, vpll, fout_vpll);
- samsung_clk_register_mux(exynos4_mux_clks,
+ samsung_clk_register_mux(ctx, exynos4_mux_clks,
ARRAY_SIZE(exynos4_mux_clks));
- samsung_clk_register_div(exynos4_div_clks,
+ samsung_clk_register_div(ctx, exynos4_div_clks,
ARRAY_SIZE(exynos4_div_clks));
- samsung_clk_register_gate(exynos4_gate_clks,
+ samsung_clk_register_gate(ctx, exynos4_gate_clks,
ARRAY_SIZE(exynos4_gate_clks));
if (exynos4_soc == EXYNOS4210) {
- samsung_clk_register_fixed_rate(exynos4210_fixed_rate_clks,
+ samsung_clk_register_fixed_rate(ctx, exynos4210_fixed_rate_clks,
ARRAY_SIZE(exynos4210_fixed_rate_clks));
- samsung_clk_register_div(exynos4210_div_clks,
+ samsung_clk_register_div(ctx, exynos4210_div_clks,
ARRAY_SIZE(exynos4210_div_clks));
- samsung_clk_register_gate(exynos4210_gate_clks,
+ samsung_clk_register_gate(ctx, exynos4210_gate_clks,
ARRAY_SIZE(exynos4210_gate_clks));
} else {
- samsung_clk_register_mux(exynos4x12_mux_clks,
+ samsung_clk_register_mux(ctx, exynos4x12_mux_clks,
ARRAY_SIZE(exynos4x12_mux_clks));
- samsung_clk_register_div(exynos4x12_div_clks,
+ samsung_clk_register_div(ctx, exynos4x12_div_clks,
ARRAY_SIZE(exynos4x12_div_clks));
- samsung_clk_register_gate(exynos4x12_gate_clks,
+ samsung_clk_register_gate(ctx, exynos4x12_gate_clks,
ARRAY_SIZE(exynos4x12_gate_clks));
}
goto clkout_fail;
}
- samsung_clk_add_lookup(clk, mout_clkout);
+ samsung_clk_add_lookup(ctx, clk, mout_clkout);
clk = clk_register_gate(NULL, "clkout", "mout_clkout",
0, clkout_base, 0, CLK_GATE_SET_TO_DISABLE,
goto clkout_fail;
}
- samsung_clk_add_lookup(clk, clkout);
+ samsung_clk_add_lookup(ctx, clk, clkout);
}
clkout_fail:
void __init exynos5250_clk_init(struct device_node *np)
{
void __iomem *reg_base;
+ struct samsung_clk_provider *ctx;
struct clk *apll, *mpll, *epll, *vpll, *bpll, *gpll, *cpll;
if (np) {
panic("%s: unable to determine soc\n", __func__);
}
- samsung_clk_init(np, reg_base, nr_clks,
+ ctx = samsung_clk_init(np, reg_base, nr_clks,
exynos5250_clk_regs, ARRAY_SIZE(exynos5250_clk_regs),
NULL, 0);
- samsung_clk_of_register_fixed_ext(exynos5250_fixed_rate_ext_clks,
+ if (!ctx)
+ panic("%s: unable to allocate context.\n", __func__);
+
+ samsung_clk_of_register_fixed_ext(ctx, exynos5250_fixed_rate_ext_clks,
ARRAY_SIZE(exynos5250_fixed_rate_ext_clks),
ext_clk_match);
vpll = samsung_clk_register_pll36xx("fout_vpll", "mout_vpllsrc",
reg_base + 0x10140);
- samsung_clk_register_fixed_rate(exynos5250_fixed_rate_clks,
+ samsung_clk_register_fixed_rate(ctx, exynos5250_fixed_rate_clks,
ARRAY_SIZE(exynos5250_fixed_rate_clks));
- samsung_clk_register_fixed_factor(exynos5250_fixed_factor_clks,
+ samsung_clk_register_fixed_factor(ctx, exynos5250_fixed_factor_clks,
ARRAY_SIZE(exynos5250_fixed_factor_clks));
- samsung_clk_register_mux(exynos5250_mux_clks,
+ samsung_clk_register_mux(ctx, exynos5250_mux_clks,
ARRAY_SIZE(exynos5250_mux_clks));
- samsung_clk_register_div(exynos5250_div_clks,
+ samsung_clk_register_div(ctx, exynos5250_div_clks,
ARRAY_SIZE(exynos5250_div_clks));
- samsung_clk_register_gate(exynos5250_gate_clks,
+ samsung_clk_register_gate(ctx, exynos5250_gate_clks,
ARRAY_SIZE(exynos5250_gate_clks));
pr_info("Exynos5250: clock setup completed, armclk=%ld\n",
void __init exynos5440_clk_init(struct device_node *np)
{
void __iomem *reg_base;
+ struct samsung_clk_provider *ctx;
reg_base = of_iomap(np, 0);
if (!reg_base) {
return;
}
- samsung_clk_init(np, reg_base, nr_clks, NULL, 0, NULL, 0);
- samsung_clk_of_register_fixed_ext(exynos5440_fixed_rate_ext_clks,
+ ctx = samsung_clk_init(np, reg_base, nr_clks, NULL, 0, NULL, 0);
+ if (!ctx)
+ panic("%s: unable to allocate context.\n", __func__);
+
+ samsung_clk_of_register_fixed_ext(ctx, exynos5440_fixed_rate_ext_clks,
ARRAY_SIZE(exynos5440_fixed_rate_ext_clks), ext_clk_match);
samsung_clk_register_pll2550x("cplla", "xtal", reg_base + 0x1c, 0x10);
samsung_clk_register_pll2550x("cpllb", "xtal", reg_base + 0x20, 0x10);
- samsung_clk_register_fixed_rate(exynos5440_fixed_rate_clks,
+ samsung_clk_register_fixed_rate(ctx, exynos5440_fixed_rate_clks,
ARRAY_SIZE(exynos5440_fixed_rate_clks));
- samsung_clk_register_fixed_factor(exynos5440_fixed_factor_clks,
+ samsung_clk_register_fixed_factor(ctx, exynos5440_fixed_factor_clks,
ARRAY_SIZE(exynos5440_fixed_factor_clks));
- samsung_clk_register_mux(exynos5440_mux_clks,
+ samsung_clk_register_mux(ctx, exynos5440_mux_clks,
ARRAY_SIZE(exynos5440_mux_clks));
- samsung_clk_register_div(exynos5440_div_clks,
+ samsung_clk_register_div(ctx, exynos5440_div_clks,
ARRAY_SIZE(exynos5440_div_clks));
- samsung_clk_register_gate(exynos5440_gate_clks,
+ samsung_clk_register_gate(ctx, exynos5440_gate_clks,
ARRAY_SIZE(exynos5440_gate_clks));
pr_info("Exynos5440: arm_clk = %ldHz\n", _get_rate("armclk"));
#include <linux/syscore_ops.h>
#include "clk.h"
-static DEFINE_SPINLOCK(lock);
-static struct clk **clk_table;
-static void __iomem *reg_base;
-#ifdef CONFIG_OF
-static struct clk_onecell_data clk_data;
-#endif
+static LIST_HEAD(samsung_clk_providers);
#ifdef CONFIG_PM_SLEEP
-static struct samsung_clk_reg_dump *reg_dump;
-static unsigned long nr_reg_dump;
+static void samsung_clk_suspend_provider(struct samsung_clk_provider *ctx)
+{
+ struct samsung_clk_reg_dump *rd = ctx->reg_dump;
+ unsigned long i;
-static int samsung_clk_suspend(void)
+ for (i = 0; i < ctx->nr_reg_dump; i++, rd++)
+ rd->value = __raw_readl(ctx->reg_base + rd->offset);
+}
+
+static void samsung_clk_resume_provider(struct samsung_clk_provider *ctx)
{
- struct samsung_clk_reg_dump *rd = reg_dump;
+ struct samsung_clk_reg_dump *rd = ctx->reg_dump;
unsigned long i;
- for (i = 0; i < nr_reg_dump; i++, rd++)
- rd->value = __raw_readl(reg_base + rd->offset);
+ for (i = 0; i < ctx->nr_reg_dump; i++, rd++)
+ __raw_writel(rd->value, ctx->reg_base + rd->offset);
+}
+
+static int samsung_clk_suspend(void)
+{
+ struct samsung_clk_provider *ctx;
+
+ list_for_each_entry(ctx, &samsung_clk_providers, list)
+ samsung_clk_suspend_provider(ctx);
return 0;
}
static void samsung_clk_resume(void)
{
- struct samsung_clk_reg_dump *rd = reg_dump;
- unsigned long i;
+ struct samsung_clk_provider *ctx;
- for (i = 0; i < nr_reg_dump; i++, rd++)
- __raw_writel(rd->value, reg_base + rd->offset);
+ list_for_each_entry(ctx, &samsung_clk_providers, list)
+ samsung_clk_resume_provider(ctx);
}
static struct syscore_ops samsung_clk_syscore_ops = {
#endif /* CONFIG_PM_SLEEP */
/* setup the essentials required to support clock lookup using ccf */
-void __init samsung_clk_init(struct device_node *np, void __iomem *base,
+struct samsung_clk_provider *__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,
unsigned long nr_soc_rdump)
{
- reg_base = base;
+ struct samsung_clk_provider *ctx;
+
+ ctx = kzalloc(sizeof(struct samsung_clk_provider), GFP_KERNEL);
+ if (!ctx)
+ return NULL;
+
+ ctx->reg_base = base;
#ifdef CONFIG_PM_SLEEP
if (rdump && nr_rdump) {
unsigned int idx;
- reg_dump = kzalloc(sizeof(struct samsung_clk_reg_dump)
+ ctx->reg_dump = kzalloc(sizeof(struct samsung_clk_reg_dump)
* (nr_rdump + nr_soc_rdump), GFP_KERNEL);
- if (!reg_dump) {
+ if (!ctx->reg_dump) {
pr_err("%s: memory alloc for register dump failed\n",
__func__);
- return;
+ kfree(ctx);
+ return NULL;
}
for (idx = 0; idx < nr_rdump; idx++)
- reg_dump[idx].offset = rdump[idx];
+ ctx->reg_dump[idx].offset = rdump[idx];
for (idx = 0; idx < nr_soc_rdump; idx++)
- reg_dump[nr_rdump + idx].offset = soc_rdump[idx];
- nr_reg_dump = nr_rdump + nr_soc_rdump;
- register_syscore_ops(&samsung_clk_syscore_ops);
+ ctx->reg_dump[nr_rdump + idx].offset = soc_rdump[idx];
+ ctx->nr_reg_dump = nr_rdump + nr_soc_rdump;
+
+ if (list_empty(&samsung_clk_providers))
+ register_syscore_ops(&samsung_clk_syscore_ops);
}
#endif
- clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL);
- if (!clk_table)
+ ctx->clk_table = kzalloc(sizeof(struct clk *) * nr_clks,
+ GFP_KERNEL);
+ if (!ctx->clk_table)
panic("could not allocate clock lookup table\n");
+ list_add_tail(&ctx->list, &samsung_clk_providers);
+
if (!np)
- return;
+ return ctx;
#ifdef CONFIG_OF
- clk_data.clks = clk_table;
- clk_data.clk_num = nr_clks;
- of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+ ctx->clk_data.clks = ctx->clk_table;
+ ctx->clk_data.clk_num = nr_clks;
+ of_clk_add_provider(np, of_clk_src_onecell_get, &ctx->clk_data);
#endif
+
+ return ctx;
}
/* add a clock instance to the clock lookup table used for dt based lookup */
-void samsung_clk_add_lookup(struct clk *clk, unsigned int id)
+void samsung_clk_add_lookup(struct samsung_clk_provider *ctx,
+ struct clk *clk, unsigned int id)
{
- if (clk_table && id)
- clk_table[id] = clk;
+ if (ctx->clk_table && id)
+ ctx->clk_table[id] = clk;
}
/* register a list of aliases */
-void __init samsung_clk_register_alias(struct samsung_clock_alias *list,
+void __init samsung_clk_register_alias(struct samsung_clk_provider *ctx,
+ struct samsung_clock_alias *list,
unsigned int nr_clk)
{
struct clk *clk;
unsigned int idx, ret;
- if (!clk_table) {
+ if (!ctx->clk_table) {
pr_err("%s: clock table missing\n", __func__);
return;
}
continue;
}
- clk = clk_table[list->id];
+ clk = ctx->clk_data.clks[list->id];
if (!clk) {
pr_err("%s: failed to find clock %d\n", __func__,
list->id);
}
/* register a list of fixed clocks */
-void __init samsung_clk_register_fixed_rate(
+void __init samsung_clk_register_fixed_rate(struct samsung_clk_provider *ctx,
struct samsung_fixed_rate_clock *list, unsigned int nr_clk)
{
struct clk *clk;
continue;
}
- samsung_clk_add_lookup(clk, list->id);
+ samsung_clk_add_lookup(ctx, clk, list->id);
/*
* Unconditionally add a clock lookup for the fixed rate clocks.
}
/* register a list of fixed factor clocks */
-void __init samsung_clk_register_fixed_factor(
+void __init samsung_clk_register_fixed_factor(struct samsung_clk_provider *ctx,
struct samsung_fixed_factor_clock *list, unsigned int nr_clk)
{
struct clk *clk;
continue;
}
- samsung_clk_add_lookup(clk, list->id);
+ samsung_clk_add_lookup(ctx, clk, list->id);
}
}
/* register a list of mux clocks */
-void __init samsung_clk_register_mux(struct samsung_mux_clock *list,
- unsigned int nr_clk)
+void __init samsung_clk_register_mux(struct samsung_clk_provider *ctx,
+ struct samsung_mux_clock *list,
+ unsigned int nr_clk)
{
struct clk *clk;
unsigned int idx, ret;
for (idx = 0; idx < nr_clk; idx++, list++) {
clk = clk_register_mux(NULL, list->name, list->parent_names,
- list->num_parents, list->flags, reg_base + list->offset,
- list->shift, list->width, list->mux_flags, &lock);
+ list->num_parents, list->flags,
+ ctx->reg_base + list->offset,
+ list->shift, list->width, list->mux_flags, &ctx->lock);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n", __func__,
list->name);
continue;
}
- samsung_clk_add_lookup(clk, list->id);
+ samsung_clk_add_lookup(ctx, clk, list->id);
/* register a clock lookup only if a clock alias is specified */
if (list->alias) {
}
/* register a list of div clocks */
-void __init samsung_clk_register_div(struct samsung_div_clock *list,
- unsigned int nr_clk)
+void __init samsung_clk_register_div(struct samsung_clk_provider *ctx,
+ struct samsung_div_clock *list,
+ unsigned int nr_clk)
{
struct clk *clk;
unsigned int idx, ret;
for (idx = 0; idx < nr_clk; idx++, list++) {
if (list->table)
clk = clk_register_divider_table(NULL, list->name,
- list->parent_name, list->flags,
- reg_base + list->offset, list->shift,
- list->width, list->div_flags,
- list->table, &lock);
+ list->parent_name, list->flags,
+ ctx->reg_base + list->offset,
+ list->shift, list->width, list->div_flags,
+ list->table, &ctx->lock);
else
clk = clk_register_divider(NULL, list->name,
- list->parent_name, list->flags,
- reg_base + list->offset, list->shift,
- list->width, list->div_flags, &lock);
+ list->parent_name, list->flags,
+ ctx->reg_base + list->offset, list->shift,
+ list->width, list->div_flags, &ctx->lock);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n", __func__,
list->name);
continue;
}
- samsung_clk_add_lookup(clk, list->id);
+ samsung_clk_add_lookup(ctx, clk, list->id);
/* register a clock lookup only if a clock alias is specified */
if (list->alias) {
}
/* register a list of gate clocks */
-void __init samsung_clk_register_gate(struct samsung_gate_clock *list,
- unsigned int nr_clk)
+void __init samsung_clk_register_gate(struct samsung_clk_provider *ctx,
+ struct samsung_gate_clock *list,
+ unsigned int nr_clk)
{
struct clk *clk;
unsigned int idx, ret;
for (idx = 0; idx < nr_clk; idx++, list++) {
clk = clk_register_gate(NULL, list->name, list->parent_name,
- list->flags, reg_base + list->offset,
- list->bit_idx, list->gate_flags, &lock);
+ list->flags, ctx->reg_base + list->offset,
+ list->bit_idx, list->gate_flags, &ctx->lock);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n", __func__,
list->name);
__func__, list->alias);
}
- samsung_clk_add_lookup(clk, list->id);
+ samsung_clk_add_lookup(ctx, clk, list->id);
}
}
* tree and register it
*/
#ifdef CONFIG_OF
-void __init samsung_clk_of_register_fixed_ext(
+void __init samsung_clk_of_register_fixed_ext(struct samsung_clk_provider *ctx,
struct samsung_fixed_rate_clock *fixed_rate_clk,
unsigned int nr_fixed_rate_clk,
struct of_device_id *clk_matches)
{
const struct of_device_id *match;
- struct device_node *np;
+ struct device_node *clk_np;
u32 freq;
- for_each_matching_node_and_match(np, clk_matches, &match) {
- if (of_property_read_u32(np, "clock-frequency", &freq))
+ for_each_matching_node_and_match(clk_np, clk_matches, &match) {
+ if (of_property_read_u32(clk_np, "clock-frequency", &freq))
continue;
fixed_rate_clk[(u32)match->data].fixed_rate = freq;
}
- samsung_clk_register_fixed_rate(fixed_rate_clk, nr_fixed_rate_clk);
+ samsung_clk_register_fixed_rate(ctx, fixed_rate_clk, nr_fixed_rate_clk);
}
#endif
#include <linux/of.h>
#include <linux/of_address.h>
+/* Context node which holds information about the clock provider. */
+/**
+ * struct samsung_clk_provider: information about clock plovider
+ * @reg_base: virtual address for the register base.
+ * @clk_data: holds clock related data like clk* and number of clocks.
+ */
+struct samsung_clk_provider {
+ void __iomem *reg_base;
+ struct clk **clk_table;
+ struct clk_onecell_data clk_data;
+ spinlock_t lock;
+ struct samsung_clk_reg_dump *reg_dump;
+ unsigned long nr_reg_dump;
+ struct list_head list;
+};
+
/**
* struct samsung_clock_alias: information about mux clock
* @id: platform specific id of the clock.
u32 value;
};
-extern void __init samsung_clk_init(struct device_node *np, void __iomem *base,
+extern struct samsung_clk_provider *__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,
unsigned long nr_soc_rdump);
extern void __init samsung_clk_of_register_fixed_ext(
+ struct samsung_clk_provider *ctx,
struct samsung_fixed_rate_clock *fixed_rate_clk,
unsigned int nr_fixed_rate_clk,
struct of_device_id *clk_matches);
-extern void samsung_clk_add_lookup(struct clk *clk, unsigned int id);
+extern void samsung_clk_add_lookup(struct samsung_clk_provider *ctx,
+ struct clk *clk, unsigned int id);
-extern void samsung_clk_register_alias(struct samsung_clock_alias *list,
+extern void samsung_clk_register_alias(struct samsung_clk_provider *ctx,
+ struct samsung_clock_alias *list,
unsigned int nr_clk);
extern void __init samsung_clk_register_fixed_rate(
+ struct samsung_clk_provider *ctx,
struct samsung_fixed_rate_clock *clk_list, unsigned int nr_clk);
extern void __init samsung_clk_register_fixed_factor(
+ struct samsung_clk_provider *ctx,
struct samsung_fixed_factor_clock *list, unsigned int nr_clk);
-extern void __init samsung_clk_register_mux(struct samsung_mux_clock *clk_list,
- unsigned int nr_clk);
-extern void __init samsung_clk_register_div(struct samsung_div_clock *clk_list,
- unsigned int nr_clk);
-extern void __init samsung_clk_register_gate(
+extern void __init samsung_clk_register_mux(struct samsung_clk_provider *ctx,
+ struct samsung_mux_clock *clk_list, unsigned int nr_clk);
+extern void __init samsung_clk_register_div(struct samsung_clk_provider *ctx,
+ struct samsung_div_clock *clk_list, unsigned int nr_clk);
+extern void __init samsung_clk_register_gate(struct samsung_clk_provider *ctx,
struct samsung_gate_clock *clk_list, unsigned int nr_clk);
extern unsigned long _get_rate(const char *clk_name);