@@ -172,6 +172,63 @@ static struct clk mstp_clks[] = {
SH_HWBLK_CLK("lcdc0", -1, P_CLK, HWBLK_LCDC, 0),
};
+static int siu_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ struct clk_div_mult_table *table = clk->priv;
+ u32 value;
+ int ret;
+
+ if (!strcmp("pll_clk", parent->name))
+ value = __raw_readl(clk->enable_reg) & ~(1 << 7);
+ else if ((!strcmp("siumcka_clk", parent->name) &&
+ !strcmp("siua_clk", clk->name)) ||
+ (!strcmp("siumckb_clk", parent->name) &&
+ !strcmp("siub_clk", clk->name)))
+ value = __raw_readl(clk->enable_reg) | (1 << 7);
+ else
+ return -EINVAL;
+
+ ret = clk_reparent(clk, parent);
+ if (ret < 0)
+ return ret;
+
+ __raw_writel(value, clk->enable_reg);
+
+ /* Rebiuld the frequency table */
+ clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
+ table, &clk->arch_flags);
+
+ return 0;
+}
+
+static int siu_clk_set_rate(struct clk *clk, unsigned long rate, int algo_id)
+{
+ unsigned long value;
+ int idx = clk_rate_table_find(clk, clk->freq_table, rate);
+ if (idx < 0)
+ return idx;
+
+ value = __raw_readl(clk->enable_reg);
+ value &= ~0xf;
+ value |= idx;
+ __raw_writel(value, clk->enable_reg);
+
+ return 0;
+}
+
+static int siu_clk_enable(struct clk *clk)
+{
+ __raw_writel(__raw_readl(clk->enable_reg) & ~(1 << 8), clk->enable_reg);
+ return 0;
+}
+
+static void siu_clk_disable(struct clk *clk)
+{
+ __raw_writel(__raw_readl(clk->enable_reg) | (1 << 8), clk->enable_reg);
+}
+
+static struct clk_ops siu_ops;
+
int __init arch_clk_init(void)
{
int k, ret = 0;
@@ -187,6 +244,15 @@ int __init arch_clk_init(void)
if (!ret)
ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
+ if (!ret) {
+ siu_ops = *div4_clks[DIV4_SIUA].ops;
+ siu_ops.enable = siu_clk_enable;
+ siu_ops.disable = siu_clk_disable;
+ siu_ops.set_rate = siu_clk_set_rate;
+ siu_ops.set_parent = siu_clk_set_parent;
+ div4_clks[DIV4_SIUA].ops = &siu_ops;
+ div4_clks[DIV4_SIUB].ops = &siu_ops;
+ }
if (!ret)
ret = sh_clk_div6_register(div6_clks, ARRAY_SIZE(div6_clks));