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 <bcm63xx_cpu.h>
14 #include <bcm63xx_io.h>
15 #include <bcm63xx_regs.h>
16 #include <bcm63xx_clk.h>
18 DEFINE_MUTEX(clocks_mutex);
21 static void clk_enable_unlocked(struct clk *clk)
23 if (clk->set && (clk->usage++) == 0)
27 static void clk_disable_unlocked(struct clk *clk)
29 if (clk->set && (--clk->usage) == 0)
33 static void bcm_hwclock_set(u32 mask, int enable)
37 reg = bcm_perf_readl(PERF_CKCTL_REG);
42 bcm_perf_writel(reg, PERF_CKCTL_REG);
46 * Ethernet MAC "misc" clock: dma clocks and main clock on 6348
48 static void enet_misc_set(struct clk *clk, int enable)
53 mask = CKCTL_6338_ENET_EN;
54 else if (BCMCPU_IS_6345())
55 mask = CKCTL_6345_ENET_EN;
56 else if (BCMCPU_IS_6348())
57 mask = CKCTL_6348_ENET_EN;
60 mask = CKCTL_6358_EMUSB_EN;
61 bcm_hwclock_set(mask, enable);
64 static struct clk clk_enet_misc = {
69 * Ethernet MAC clocks: only revelant on 6358, silently enable misc
72 static void enetx_set(struct clk *clk, int enable)
75 clk_enable_unlocked(&clk_enet_misc);
77 clk_disable_unlocked(&clk_enet_misc);
79 if (BCMCPU_IS_6358()) {
83 mask = CKCTL_6358_ENET0_EN;
85 mask = CKCTL_6358_ENET1_EN;
86 bcm_hwclock_set(mask, enable);
90 static struct clk clk_enet0 = {
95 static struct clk clk_enet1 = {
103 static void ephy_set(struct clk *clk, int enable)
105 if (!BCMCPU_IS_6358())
107 bcm_hwclock_set(CKCTL_6358_EPHY_EN, enable);
111 static struct clk clk_ephy = {
118 static void pcm_set(struct clk *clk, int enable)
120 if (!BCMCPU_IS_6358())
122 bcm_hwclock_set(CKCTL_6358_PCM_EN, enable);
125 static struct clk clk_pcm = {
132 static void usbh_set(struct clk *clk, int enable)
134 if (!BCMCPU_IS_6348())
136 bcm_hwclock_set(CKCTL_6348_USBH_EN, enable);
139 static struct clk clk_usbh = {
146 static void usbs_set(struct clk *clk, int enable)
150 switch(bcm63xx_get_cpu_id()) {
151 case BCM6338_CPU_ID: mask = CKCTL_6338_USBS_EN; break;
152 case BCM6348_CPU_ID: mask = CKCTL_6348_USBS_EN; break;
156 bcm_hwclock_set(mask, enable);
159 static struct clk clk_usbs = {
166 static void spi_set(struct clk *clk, int enable)
170 if (BCMCPU_IS_6338())
171 mask = CKCTL_6338_SPI_EN;
172 else if (BCMCPU_IS_6348())
173 mask = CKCTL_6348_SPI_EN;
176 mask = CKCTL_6358_SPI_EN;
177 bcm_hwclock_set(mask, enable);
180 static struct clk clk_spi = {
185 * Internal peripheral clock
187 static struct clk clk_periph = {
188 .rate = (50 * 1000 * 1000),
193 * Linux clock API implementation
195 int clk_enable(struct clk *clk)
197 mutex_lock(&clocks_mutex);
198 clk_enable_unlocked(clk);
199 mutex_unlock(&clocks_mutex);
203 EXPORT_SYMBOL(clk_enable);
205 void clk_disable(struct clk *clk)
207 mutex_lock(&clocks_mutex);
208 clk_disable_unlocked(clk);
209 mutex_unlock(&clocks_mutex);
212 EXPORT_SYMBOL(clk_disable);
214 unsigned long clk_get_rate(struct clk *clk)
219 EXPORT_SYMBOL(clk_get_rate);
221 struct clk *clk_get(struct device *dev, const char *id)
223 if (!strcmp(id, "enet0"))
225 if (!strcmp(id, "enet1"))
227 if (!strcmp(id, "ephy"))
229 if (!strcmp(id, "usbh"))
231 if (!strcmp(id, "usbs"))
233 if (!strcmp(id, "spi"))
235 if (!strcmp(id, "periph"))
237 if (BCMCPU_IS_6358() && !strcmp(id, "pcm"))
239 return ERR_PTR(-ENOENT);
242 EXPORT_SYMBOL(clk_get);
244 void clk_put(struct clk *clk)
248 EXPORT_SYMBOL(clk_put);