@@ -100,4 +100,20 @@ enum clk_sh_algo_id {
IP_N1,
};
+struct clk_cpg_div {
+ struct clk clk;
+ int id;
+};
+
+struct clk_cpg_div_group {
+ int *multipliers;
+ int *divisors;
+ int nr_entries;
+ int (*get_index)(struct clk_cpg_div *div);
+ void (*set_index)(struct clk_cpg_div *div, int index);
+};
+
+int clk_cpg_div_register(struct clk_cpg_div *div,
+ struct clk_cpg_div_group *group);
+
#endif /* __ASM_SH_CLOCK_H */
@@ -2,6 +2,38 @@
#include <linux/compiler.h>
#include <asm/clock.h>
+static unsigned long clk_cpg_div_recalc(struct clk *clk)
+{
+ struct clk_cpg_div_group *group = clk->priv;
+ struct clk_cpg_div *div;
+ unsigned long multiplier, divisor;
+ int index;
+
+ div = (void *)((char *)clk - offsetof(struct clk_cpg_div, clk));
+ index = group->get_index(div);
+
+ BUG_ON(index >= group->nr_entries);
+
+ multiplier = group->multipliers[index];
+ divisor = group->divisors[index];
+
+ BUG_ON(!multiplier || !divisor);
+
+ return clk->parent->rate * multiplier / divisor;
+}
+
+static struct clk_ops clk_cpg_div_ops = {
+ .recalc = clk_cpg_div_recalc,
+};
+
+int clk_cpg_div_register(struct clk_cpg_div *div,
+ struct clk_cpg_div_group *group)
+{
+ div->clk.ops = &clk_cpg_div_ops;
+ div->clk.priv = group;
+ return clk_register(&div->clk);
+}
+
#ifndef CONFIG_SH_CLK_DISABLE_LEGACY
static struct clk master_clk = {