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>
20 #define MHZ (KHZ * KHZ)
23 unsigned long (*get_rate
)(struct clk
*clk
);
24 int (*set_rate
)(struct clk
*clk
, unsigned long rate
);
25 struct clk
*(*get_parent
)(struct clk
*clk
);
26 int (*enable
)(struct clk
*clk
, int enable
);
30 struct clk
*parent
; /* parent clk */
31 unsigned long rate
; /* clock rate in Hz */
32 unsigned long divider
; /* clock divider */
33 u32 usecount
; /* reference count */
34 struct clk_ops
*ops
; /* clock operation */
35 void __iomem
*enable_reg
; /* clock enable register */
36 u32 enable_mask
; /* clock enable mask */
39 static unsigned long clk_divide_parent(struct clk
*clk
)
41 if (clk
->parent
&& clk
->divider
)
42 return clk_get_rate(clk
->parent
) / clk
->divider
;
47 static int clk_local_onoff_enable(struct clk
*clk
, int enable
)
51 /* no enable_reg means the clock is always enabled */
55 tmp
= __raw_readl(clk
->enable_reg
);
57 tmp
&= ~clk
->enable_mask
;
59 tmp
|= clk
->enable_mask
;
61 __raw_writel(tmp
, clk
->enable_reg
);
66 static struct clk_ops default_clk_ops
= {
67 .get_rate
= clk_divide_parent
,
68 .enable
= clk_local_onoff_enable
,
71 static DEFINE_SPINLOCK(clocks_lock
);
73 static const unsigned long cpu_freq_table
[] = {
92 static struct clk clk_cpu
;
94 /* System clock is fixed at 50Mhz */
95 static struct clk clk_sys
= {
99 static struct clk clk_sdram
;
101 static struct clk clk_timer0
= {
102 .parent
= &clk_sdram
,
104 .ops
= &default_clk_ops
,
107 static struct clk clk_timer1_2
= {
111 /* Watchdog clock is system clock / 128 */
112 static struct clk clk_wdt
= {
115 .ops
= &default_clk_ops
,
118 static struct clk clk_emac
= {
119 .ops
= &default_clk_ops
,
120 .enable_reg
= (void __iomem
*)(_CONFADDR_SYSDBG
+ SYSDBG_SYSCTL
),
121 .enable_mask
= SYSCTL_EMAC
,
124 static struct clk clk_ephy
= {
125 .ops
= &default_clk_ops
,
126 .enable_reg
= (void __iomem
*)(_CONFADDR_SYSDBG
+ SYSDBG_PLL_CTL
),
127 .enable_mask
= ~(1 << 0),
130 static struct clk clk_cipher
= {
131 .ops
= &default_clk_ops
,
132 .enable_reg
= (void __iomem
*)(_CONFADDR_SYSDBG
+ SYSDBG_SYSCTL
),
133 .enable_mask
= SYSCTL_CIPHER
,
136 #define CLK(_dev, _con, _clk) \
137 { .dev_id = (_dev), .con_id = (_con), .clk = (_clk) },
139 static struct clk_lookup mcs814x_chip_clks
[] = {
140 CLK("cpu", NULL
, &clk_cpu
)
141 CLK("sys", NULL
, &clk_sys
)
142 CLK("sdram", NULL
, &clk_sdram
)
144 CLK("timer0", NULL
, &clk_timer0
)
146 CLK("timer1", NULL
, &clk_timer1_2
)
147 /* 64-bits timer2, same as timer 1 */
148 CLK("timer2", NULL
, &clk_timer1_2
)
149 CLK(NULL
, "wdt", &clk_wdt
)
150 CLK(NULL
, "emac", &clk_emac
)
151 CLK(NULL
, "ephy", &clk_ephy
)
152 CLK(NULL
, "cipher", &clk_cipher
)
155 static void local_clk_disable(struct clk
*clk
)
157 WARN_ON(!clk
->usecount
);
159 if (clk
->usecount
> 0) {
162 if ((clk
->usecount
== 0) && (clk
->ops
->enable
))
163 clk
->ops
->enable(clk
, 0);
166 local_clk_disable(clk
->parent
);
170 static int local_clk_enable(struct clk
*clk
)
175 ret
= local_clk_enable(clk
->parent
);
180 if ((clk
->usecount
== 0) && (clk
->ops
->enable
))
181 ret
= clk
->ops
->enable(clk
, 1);
185 else if (clk
->parent
&& clk
->parent
->ops
->enable
)
186 local_clk_disable(clk
->parent
);
191 int clk_enable(struct clk
*clk
)
196 spin_lock_irqsave(&clocks_lock
, flags
);
197 ret
= local_clk_enable(clk
);
198 spin_unlock_irqrestore(&clocks_lock
, flags
);
202 EXPORT_SYMBOL(clk_enable
);
204 void clk_disable(struct clk
*clk
)
208 spin_lock_irqsave(&clocks_lock
, flags
);
209 local_clk_disable(clk
);
210 spin_unlock_irqrestore(&clocks_lock
, flags
);
212 EXPORT_SYMBOL(clk_disable
);
214 unsigned long clk_get_rate(struct clk
*clk
)
216 if (unlikely(IS_ERR_OR_NULL(clk
)))
222 if (clk
->ops
&& clk
->ops
->get_rate
)
223 return clk
->ops
->get_rate(clk
);
225 return clk_get_rate(clk
->parent
);
227 EXPORT_SYMBOL(clk_get_rate
);
229 struct clk
*clk_get_parent(struct clk
*clk
)
233 if (unlikely(IS_ERR_OR_NULL(clk
)))
236 if (!clk
->ops
|| !clk
->ops
->get_parent
)
239 spin_lock_irqsave(&clocks_lock
, flags
);
240 clk
->parent
= clk
->ops
->get_parent(clk
);
241 spin_unlock_irqrestore(&clocks_lock
, flags
);
245 EXPORT_SYMBOL(clk_get_parent
);
247 void __init
mcs814x_clk_init(void)
252 clkdev_add_table(mcs814x_chip_clks
, ARRAY_SIZE(mcs814x_chip_clks
));
254 /* read the bootstrap registers to know the exact clocking scheme */
255 bs1
= __raw_readl(_CONFADDR_SYSDBG
+ SYSDBG_BS1
);
256 cpu_freq
= (bs1
>> CPU_FREQ_SHIFT
) & CPU_FREQ_MASK
;
258 pr_info("CPU frequency: %lu (kHz)\n", cpu_freq_table
[cpu_freq
]);
259 clk_cpu
.rate
= cpu_freq
* KHZ
;
261 /* read SDRAM frequency */
262 if (bs1
& SDRAM_FREQ_BIT
)
263 clk_sdram
.rate
= 100 * MHZ
;
265 clk_sdram
.rate
= 133 * MHZ
;
267 pr_info("SDRAM frequency: %lu (MHz)\n", clk_sdram
.rate
/ MHZ
);