1 #include <linux/kernel.h>
2 #include <linux/clk-provider.h>
3 #include <linux/of_address.h>
4 #include <linux/init.h>
7 static struct clk
*out
[2];
8 static struct clk_onecell_data clk_data
= { out
, 2 };
10 #define SYSCLK_CTRL 0x20
11 #define CPUCLK_CTRL 0x24
12 #define LEGACY_DIV 0x3c
14 #define PLL_N(val) (((val) >> 0) & 0x7f)
15 #define PLL_K(val) (((val) >> 13) & 0x7)
16 #define PLL_M(val) (((val) >> 16) & 0x7)
17 #define DIV_INDEX(val) (((val) >> 8) & 0xf)
19 static void __init
make_pll(int idx
, const char *parent
, void __iomem
*base
)
24 sprintf(name
, "pll%d", idx
);
25 val
= readl_relaxed(base
+ idx
*8);
27 div
= (PLL_M(val
) + 1) << PLL_K(val
);
28 clk_register_fixed_factor(NULL
, name
, parent
, 0, mul
, div
);
31 static int __init
get_div(void __iomem
*base
)
33 u8 sysclk_tab
[16] = { 2, 4, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4 };
34 int idx
= DIV_INDEX(readl_relaxed(base
+ LEGACY_DIV
));
36 return sysclk_tab
[idx
];
39 static void __init
tango4_clkgen_setup(struct device_node
*np
)
42 void __iomem
*base
= of_iomap(np
, 0);
43 const char *parent
= of_clk_get_parent_name(np
, 0);
46 panic("%s: invalid address\n", np
->full_name
);
48 make_pll(0, parent
, base
);
49 make_pll(1, parent
, base
);
51 out
[0] = clk_register_divider(NULL
, "cpuclk", "pll0", 0,
52 base
+ CPUCLK_CTRL
, 8, 8, CLK_DIVIDER_ONE_BASED
, NULL
);
54 div
= readl_relaxed(base
+ SYSCLK_CTRL
) & BIT(23) ? get_div(base
) : 4;
55 out
[1] = clk_register_fixed_factor(NULL
, "sysclk", "pll1", 0, 1, div
);
57 ret
= of_clk_add_provider(np
, of_clk_src_onecell_get
, &clk_data
);
58 if (IS_ERR(out
[0]) || IS_ERR(out
[1]) || ret
< 0)
59 panic("%s: clk registration failed\n", np
->full_name
);
61 CLK_OF_DECLARE(tango4_clkgen
, "sigma,tango4-clkgen", tango4_clkgen_setup
);