2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
6 * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
9 #include <linux/module.h>
10 #include <linux/mutex.h>
11 #include <linux/err.h>
12 #include <linux/clk.h>
13 #include <linux/delay.h>
14 #include <bcm63xx_cpu.h>
15 #include <bcm63xx_io.h>
16 #include <bcm63xx_regs.h>
17 #include <bcm63xx_clk.h>
19 static DEFINE_MUTEX(clocks_mutex);
22 static void clk_enable_unlocked(struct clk *clk)
24 if (clk->set && (clk->usage++) == 0)
28 static void clk_disable_unlocked(struct clk *clk)
30 if (clk->set && (--clk->usage) == 0)
34 static void bcm_hwclock_set(u32 mask, int enable)
38 reg = bcm_perf_readl(PERF_CKCTL_REG);
43 bcm_perf_writel(reg, PERF_CKCTL_REG);
47 * Ethernet MAC "misc" clock: dma clocks and main clock on 6348
49 static void enet_misc_set(struct clk *clk, int enable)
54 mask = CKCTL_6338_ENET_EN;
55 else if (BCMCPU_IS_6345())
56 mask = CKCTL_6345_ENET_EN;
57 else if (BCMCPU_IS_6348())
58 mask = CKCTL_6348_ENET_EN;
61 mask = CKCTL_6358_EMUSB_EN;
62 bcm_hwclock_set(mask, enable);
65 static struct clk clk_enet_misc = {
70 * Ethernet MAC clocks: only revelant on 6358, silently enable misc
73 static void enetx_set(struct clk *clk, int enable)
76 clk_enable_unlocked(&clk_enet_misc);
78 clk_disable_unlocked(&clk_enet_misc);
80 if (BCMCPU_IS_6358()) {
84 mask = CKCTL_6358_ENET0_EN;
86 mask = CKCTL_6358_ENET1_EN;
87 bcm_hwclock_set(mask, enable);
91 static struct clk clk_enet0 = {
96 static struct clk clk_enet1 = {
104 static void ephy_set(struct clk *clk, int enable)
106 if (!BCMCPU_IS_6358())
108 bcm_hwclock_set(CKCTL_6358_EPHY_EN, enable);
112 static struct clk clk_ephy = {
117 * Ethernet switch clock
119 static void enetsw_set(struct clk *clk, int enable)
121 if (!BCMCPU_IS_6368())
123 bcm_hwclock_set(CKCTL_6368_ROBOSW_EN |
124 CKCTL_6368_SWPKT_USB_EN |
125 CKCTL_6368_SWPKT_SAR_EN, enable);
129 /* reset switch core afer clock change */
130 val = bcm_perf_readl(PERF_SOFTRESET_6368_REG);
131 val &= ~SOFTRESET_6368_ENETSW_MASK;
132 bcm_perf_writel(val, PERF_SOFTRESET_6368_REG);
134 val |= SOFTRESET_6368_ENETSW_MASK;
135 bcm_perf_writel(val, PERF_SOFTRESET_6368_REG);
140 static struct clk clk_enetsw = {
147 static void pcm_set(struct clk *clk, int enable)
149 if (!BCMCPU_IS_6358())
151 bcm_hwclock_set(CKCTL_6358_PCM_EN, enable);
154 static struct clk clk_pcm = {
161 static void usbh_set(struct clk *clk, int enable)
163 if (BCMCPU_IS_6328())
164 bcm_hwclock_set(CKCTL_6328_USBH_EN, enable);
165 else if (BCMCPU_IS_6348())
166 bcm_hwclock_set(CKCTL_6348_USBH_EN, enable);
167 else if (BCMCPU_IS_6368())
168 bcm_hwclock_set(CKCTL_6368_USBH_EN, enable);
171 static struct clk clk_usbh = {
178 static void usbd_set(struct clk *clk, int enable)
180 if (BCMCPU_IS_6328())
181 bcm_hwclock_set(CKCTL_6328_USBD_EN, enable);
182 else if (BCMCPU_IS_6368())
183 bcm_hwclock_set(CKCTL_6368_USBD_EN, enable);
186 static struct clk clk_usbd = {
193 static void spi_set(struct clk *clk, int enable)
197 if (BCMCPU_IS_6338())
198 mask = CKCTL_6338_SPI_EN;
199 else if (BCMCPU_IS_6348())
200 mask = CKCTL_6348_SPI_EN;
201 else if (BCMCPU_IS_6358())
202 mask = CKCTL_6358_SPI_EN;
205 mask = CKCTL_6368_SPI_EN;
206 bcm_hwclock_set(mask, enable);
209 static struct clk clk_spi = {
216 static void xtm_set(struct clk *clk, int enable)
218 if (!BCMCPU_IS_6368())
221 bcm_hwclock_set(CKCTL_6368_SAR_EN |
222 CKCTL_6368_SWPKT_SAR_EN, enable);
227 /* reset sar core afer clock change */
228 val = bcm_perf_readl(PERF_SOFTRESET_6368_REG);
229 val &= ~SOFTRESET_6368_SAR_MASK;
230 bcm_perf_writel(val, PERF_SOFTRESET_6368_REG);
232 val |= SOFTRESET_6368_SAR_MASK;
233 bcm_perf_writel(val, PERF_SOFTRESET_6368_REG);
239 static struct clk clk_xtm = {
246 static void ipsec_set(struct clk *clk, int enable)
248 bcm_hwclock_set(CKCTL_6368_IPSEC_EN, enable);
251 static struct clk clk_ipsec = {
259 static void pcie_set(struct clk *clk, int enable)
261 bcm_hwclock_set(CKCTL_6328_PCIE_EN, enable);
264 static struct clk clk_pcie = {
269 * Internal peripheral clock
271 static struct clk clk_periph = {
272 .rate = (50 * 1000 * 1000),
277 * Linux clock API implementation
279 int clk_enable(struct clk *clk)
281 mutex_lock(&clocks_mutex);
282 clk_enable_unlocked(clk);
283 mutex_unlock(&clocks_mutex);
287 EXPORT_SYMBOL(clk_enable);
289 void clk_disable(struct clk *clk)
291 mutex_lock(&clocks_mutex);
292 clk_disable_unlocked(clk);
293 mutex_unlock(&clocks_mutex);
296 EXPORT_SYMBOL(clk_disable);
298 unsigned long clk_get_rate(struct clk *clk)
303 EXPORT_SYMBOL(clk_get_rate);
305 struct clk *clk_get(struct device *dev, const char *id)
307 if (!strcmp(id, "enet0"))
309 if (!strcmp(id, "enet1"))
311 if (!strcmp(id, "enetsw"))
313 if (!strcmp(id, "ephy"))
315 if (!strcmp(id, "usbh"))
317 if (!strcmp(id, "usbd"))
319 if (!strcmp(id, "spi"))
321 if (!strcmp(id, "xtm"))
323 if (!strcmp(id, "periph"))
325 if (BCMCPU_IS_6358() && !strcmp(id, "pcm"))
327 if (BCMCPU_IS_6368() && !strcmp(id, "ipsec"))
329 if (BCMCPU_IS_6328() && !strcmp(id, "pcie"))
331 return ERR_PTR(-ENOENT);
334 EXPORT_SYMBOL(clk_get);
336 void clk_put(struct clk *clk)
340 EXPORT_SYMBOL(clk_put);