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_reset.h>
20 void (*set)(struct clk *, int);
26 static DEFINE_MUTEX(clocks_mutex);
29 static void clk_enable_unlocked(struct clk *clk)
31 if (clk->set && (clk->usage++) == 0)
35 static void clk_disable_unlocked(struct clk *clk)
37 if (clk->set && (--clk->usage) == 0)
41 static void bcm_hwclock_set(u32 mask, int enable)
45 reg = bcm_perf_readl(PERF_CKCTL_REG);
50 bcm_perf_writel(reg, PERF_CKCTL_REG);
54 * Ethernet MAC "misc" clock: dma clocks and main clock on 6348
56 static void enet_misc_set(struct clk *clk, int enable)
61 mask = CKCTL_6338_ENET_EN;
62 else if (BCMCPU_IS_6345())
63 mask = CKCTL_6345_ENET_EN;
64 else if (BCMCPU_IS_6348())
65 mask = CKCTL_6348_ENET_EN;
68 mask = CKCTL_6358_EMUSB_EN;
69 bcm_hwclock_set(mask, enable);
72 static struct clk clk_enet_misc = {
77 * Ethernet MAC clocks: only revelant on 6358, silently enable misc
80 static void enetx_set(struct clk *clk, int enable)
83 clk_enable_unlocked(&clk_enet_misc);
85 clk_disable_unlocked(&clk_enet_misc);
87 if (BCMCPU_IS_6358()) {
91 mask = CKCTL_6358_ENET0_EN;
93 mask = CKCTL_6358_ENET1_EN;
94 bcm_hwclock_set(mask, enable);
98 static struct clk clk_enet0 = {
103 static struct clk clk_enet1 = {
111 static void ephy_set(struct clk *clk, int enable)
113 if (!BCMCPU_IS_6358())
115 bcm_hwclock_set(CKCTL_6358_EPHY_EN, enable);
119 static struct clk clk_ephy = {
124 * Ethernet switch clock
126 static void enetsw_set(struct clk *clk, int enable)
128 if (BCMCPU_IS_6328())
129 bcm_hwclock_set(CKCTL_6328_ROBOSW_EN, enable);
130 else if (BCMCPU_IS_6362())
131 bcm_hwclock_set(CKCTL_6362_ROBOSW_EN, enable);
132 else if (BCMCPU_IS_6368())
133 bcm_hwclock_set(CKCTL_6368_ROBOSW_EN |
134 CKCTL_6368_SWPKT_USB_EN |
135 CKCTL_6368_SWPKT_SAR_EN,
141 /* reset switch core afer clock change */
142 bcm63xx_core_set_reset(BCM63XX_RESET_ENETSW, 1);
144 bcm63xx_core_set_reset(BCM63XX_RESET_ENETSW, 0);
149 static struct clk clk_enetsw = {
156 static void pcm_set(struct clk *clk, int enable)
158 if (!BCMCPU_IS_6358())
160 bcm_hwclock_set(CKCTL_6358_PCM_EN, enable);
163 static struct clk clk_pcm = {
170 static void usbh_set(struct clk *clk, int enable)
172 if (BCMCPU_IS_6328())
173 bcm_hwclock_set(CKCTL_6328_USBH_EN, enable);
174 else if (BCMCPU_IS_6348())
175 bcm_hwclock_set(CKCTL_6348_USBH_EN, enable);
176 else if (BCMCPU_IS_6362())
177 bcm_hwclock_set(CKCTL_6362_USBH_EN, enable);
178 else if (BCMCPU_IS_6368())
179 bcm_hwclock_set(CKCTL_6368_USBH_EN, enable);
182 static struct clk clk_usbh = {
189 static void usbd_set(struct clk *clk, int enable)
191 if (BCMCPU_IS_6328())
192 bcm_hwclock_set(CKCTL_6328_USBD_EN, enable);
193 else if (BCMCPU_IS_6362())
194 bcm_hwclock_set(CKCTL_6362_USBD_EN, enable);
195 else if (BCMCPU_IS_6368())
196 bcm_hwclock_set(CKCTL_6368_USBD_EN, enable);
199 static struct clk clk_usbd = {
206 static void spi_set(struct clk *clk, int enable)
210 if (BCMCPU_IS_6338())
211 mask = CKCTL_6338_SPI_EN;
212 else if (BCMCPU_IS_6348())
213 mask = CKCTL_6348_SPI_EN;
214 else if (BCMCPU_IS_6358())
215 mask = CKCTL_6358_SPI_EN;
216 else if (BCMCPU_IS_6362())
217 mask = CKCTL_6362_SPI_EN;
220 mask = CKCTL_6368_SPI_EN;
221 bcm_hwclock_set(mask, enable);
224 static struct clk clk_spi = {
231 static void xtm_set(struct clk *clk, int enable)
233 if (!BCMCPU_IS_6368())
236 bcm_hwclock_set(CKCTL_6368_SAR_EN |
237 CKCTL_6368_SWPKT_SAR_EN, enable);
240 /* reset sar core afer clock change */
241 bcm63xx_core_set_reset(BCM63XX_RESET_SAR, 1);
243 bcm63xx_core_set_reset(BCM63XX_RESET_SAR, 0);
249 static struct clk clk_xtm = {
256 static void ipsec_set(struct clk *clk, int enable)
258 if (BCMCPU_IS_6362())
259 bcm_hwclock_set(CKCTL_6362_IPSEC_EN, enable);
260 else if (BCMCPU_IS_6368())
261 bcm_hwclock_set(CKCTL_6368_IPSEC_EN, enable);
264 static struct clk clk_ipsec = {
272 static void pcie_set(struct clk *clk, int enable)
274 if (BCMCPU_IS_6328())
275 bcm_hwclock_set(CKCTL_6328_PCIE_EN, enable);
276 else if (BCMCPU_IS_6362())
277 bcm_hwclock_set(CKCTL_6362_PCIE_EN, enable);
280 static struct clk clk_pcie = {
285 * Internal peripheral clock
287 static struct clk clk_periph = {
288 .rate = (50 * 1000 * 1000),
293 * Linux clock API implementation
295 int clk_enable(struct clk *clk)
297 mutex_lock(&clocks_mutex);
298 clk_enable_unlocked(clk);
299 mutex_unlock(&clocks_mutex);
303 EXPORT_SYMBOL(clk_enable);
305 void clk_disable(struct clk *clk)
307 mutex_lock(&clocks_mutex);
308 clk_disable_unlocked(clk);
309 mutex_unlock(&clocks_mutex);
312 EXPORT_SYMBOL(clk_disable);
314 unsigned long clk_get_rate(struct clk *clk)
319 EXPORT_SYMBOL(clk_get_rate);
321 struct clk *clk_get(struct device *dev, const char *id)
323 if (!strcmp(id, "enet0"))
325 if (!strcmp(id, "enet1"))
327 if (!strcmp(id, "enetsw"))
329 if (!strcmp(id, "ephy"))
331 if (!strcmp(id, "usbh"))
333 if (!strcmp(id, "usbd"))
335 if (!strcmp(id, "spi"))
337 if (!strcmp(id, "xtm"))
339 if (!strcmp(id, "periph"))
341 if (BCMCPU_IS_6358() && !strcmp(id, "pcm"))
343 if ((BCMCPU_IS_6362() || BCMCPU_IS_6368()) && !strcmp(id, "ipsec"))
345 if ((BCMCPU_IS_6328() || BCMCPU_IS_6362()) && !strcmp(id, "pcie"))
347 return ERR_PTR(-ENOENT);
350 EXPORT_SYMBOL(clk_get);
352 void clk_put(struct clk *clk)
356 EXPORT_SYMBOL(clk_put);