2 * Moschip MCS814x clock routines
4 * Copyright (C) 2012, Florian Fainelli <florian@openwrt.org>
8 #include <linux/kernel.h>
9 #include <linux/init.h>
10 #include <linux/export.h>
11 #include <linux/spinlock.h>
12 #include <linux/err.h>
14 #include <linux/clkdev.h>
15 #include <linux/clk.h>
17 #include <mach/mcs814x.h>
19 /* System configuration registers offsets */
20 #define SYSDBG_BS1 0x00
21 #define SYSDBG_SYSCTL 0x08
22 #define SYSCTL_EMAC (1 << 0)
23 #define SYSCTL_CIPHER (1 << 16)
24 #define SYSDBG_PLL_CTL 0x3C
26 #define CPU_FREQ_SHIFT 27
27 #define CPU_FREQ_MASK 0x0F
28 #define SDRAM_FREQ_BIT (1 << 22)
31 #define MHZ (KHZ * KHZ)
34 unsigned long (*get_rate)(struct clk *clk);
35 int (*set_rate)(struct clk *clk, unsigned long rate);
36 struct clk *(*get_parent)(struct clk *clk);
37 int (*enable)(struct clk *clk, int enable);
41 struct clk *parent; /* parent clk */
42 unsigned long rate; /* clock rate in Hz */
43 unsigned long divider; /* clock divider */
44 u32 usecount; /* reference count */
45 struct clk_ops *ops; /* clock operation */
46 void __iomem *enable_reg; /* clock enable register */
47 u32 enable_mask; /* clock enable mask */
50 static unsigned long clk_divide_parent(struct clk *clk)
52 if (clk->parent && clk->divider)
53 return clk_get_rate(clk->parent) / clk->divider;
58 static int clk_local_onoff_enable(struct clk *clk, int enable)
62 /* no enable_reg means the clock is always enabled */
66 tmp = __raw_readl(clk->enable_reg);
68 tmp &= ~clk->enable_mask;
70 tmp |= clk->enable_mask;
72 __raw_writel(tmp, clk->enable_reg);
77 static struct clk_ops default_clk_ops = {
78 .get_rate = clk_divide_parent,
79 .enable = clk_local_onoff_enable,
82 static DEFINE_SPINLOCK(clocks_lock);
84 static const unsigned long cpu_freq_table[] = {
103 static struct clk clk_cpu;
105 /* System clock is fixed at 50Mhz */
106 static struct clk clk_sys = {
110 static struct clk clk_sdram;
112 static struct clk clk_timer0 = {
113 .parent = &clk_sdram,
115 .ops = &default_clk_ops,
118 static struct clk clk_timer1_2 = {
122 /* Watchdog clock is system clock / 128 */
123 static struct clk clk_wdt = {
126 .ops = &default_clk_ops,
129 static struct clk clk_emac = {
130 .ops = &default_clk_ops,
131 .enable_reg = (void __iomem *)(_CONFADDR_SYSDBG + SYSDBG_SYSCTL),
132 .enable_mask = SYSCTL_EMAC,
135 static struct clk clk_ephy = {
136 .ops = &default_clk_ops,
137 .enable_reg = (void __iomem *)(_CONFADDR_SYSDBG + SYSDBG_PLL_CTL),
138 .enable_mask = ~(1 << 0),
141 static struct clk clk_cipher = {
142 .ops = &default_clk_ops,
143 .enable_reg = (void __iomem *)(_CONFADDR_SYSDBG + SYSDBG_SYSCTL),
144 .enable_mask = SYSCTL_CIPHER,
147 #define CLK(_dev, _con, _clk) \
148 { .dev_id = (_dev), .con_id = (_con), .clk = (_clk) },
150 static struct clk_lookup mcs814x_chip_clks[] = {
151 CLK("cpu", NULL, &clk_cpu)
152 CLK("sys", NULL, &clk_sys)
153 CLK("sdram", NULL, &clk_sdram)
155 CLK("timer0", NULL, &clk_timer0)
157 CLK("timer1", NULL, &clk_timer1_2)
158 /* 64-bits timer2, same as timer 1 */
159 CLK("timer2", NULL, &clk_timer1_2)
160 CLK(NULL, "wdt", &clk_wdt)
161 CLK(NULL, "emac", &clk_emac)
162 CLK(NULL, "ephy", &clk_ephy)
163 CLK(NULL, "cipher", &clk_cipher)
166 static void local_clk_disable(struct clk *clk)
168 WARN_ON(!clk->usecount);
170 if (clk->usecount > 0) {
173 if ((clk->usecount == 0) && (clk->ops->enable))
174 clk->ops->enable(clk, 0);
177 local_clk_disable(clk->parent);
181 static int local_clk_enable(struct clk *clk)
186 ret = local_clk_enable(clk->parent);
191 if ((clk->usecount == 0) && (clk->ops->enable))
192 ret = clk->ops->enable(clk, 1);
196 else if (clk->parent && clk->parent->ops->enable)
197 local_clk_disable(clk->parent);
202 int clk_enable(struct clk *clk)
207 spin_lock_irqsave(&clocks_lock, flags);
208 ret = local_clk_enable(clk);
209 spin_unlock_irqrestore(&clocks_lock, flags);
213 EXPORT_SYMBOL(clk_enable);
215 void clk_disable(struct clk *clk)
219 spin_lock_irqsave(&clocks_lock, flags);
220 local_clk_disable(clk);
221 spin_unlock_irqrestore(&clocks_lock, flags);
223 EXPORT_SYMBOL(clk_disable);
225 unsigned long clk_get_rate(struct clk *clk)
227 if (unlikely(IS_ERR_OR_NULL(clk)))
233 if (clk->ops && clk->ops->get_rate)
234 return clk->ops->get_rate(clk);
236 return clk_get_rate(clk->parent);
238 EXPORT_SYMBOL(clk_get_rate);
240 struct clk *clk_get_parent(struct clk *clk)
244 if (unlikely(IS_ERR_OR_NULL(clk)))
247 if (!clk->ops || !clk->ops->get_parent)
250 spin_lock_irqsave(&clocks_lock, flags);
251 clk->parent = clk->ops->get_parent(clk);
252 spin_unlock_irqrestore(&clocks_lock, flags);
256 EXPORT_SYMBOL(clk_get_parent);
258 void __init mcs814x_clk_init(void)
263 clkdev_add_table(mcs814x_chip_clks, ARRAY_SIZE(mcs814x_chip_clks));
265 /* read the bootstrap registers to know the exact clocking scheme */
266 bs1 = __raw_readl(_CONFADDR_SYSDBG + SYSDBG_BS1);
267 cpu_freq = (bs1 >> CPU_FREQ_SHIFT) & CPU_FREQ_MASK;
269 pr_info("CPU frequency: %lu (kHz)\n", cpu_freq_table[cpu_freq]);
270 clk_cpu.rate = cpu_freq * KHZ;
272 /* read SDRAM frequency */
273 if (bs1 & SDRAM_FREQ_BIT)
274 clk_sdram.rate = 100 * MHZ;
276 clk_sdram.rate = 133 * MHZ;
278 pr_info("SDRAM frequency: %lu (MHz)\n", clk_sdram.rate / MHZ);