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_6348())
55 mask = CKCTL_6348_ENET_EN;
58 mask = CKCTL_6358_EMUSB_EN;
59 bcm_hwclock_set(mask, enable);
62 static struct clk clk_enet_misc = {
67 * Ethernet MAC clocks: only revelant on 6358, silently enable misc
70 static void enetx_set(struct clk *clk, int enable)
73 clk_enable_unlocked(&clk_enet_misc);
75 clk_disable_unlocked(&clk_enet_misc);
77 if (BCMCPU_IS_6358()) {
81 mask = CKCTL_6358_ENET0_EN;
83 mask = CKCTL_6358_ENET1_EN;
84 bcm_hwclock_set(mask, enable);
88 static struct clk clk_enet0 = {
93 static struct clk clk_enet1 = {
101 static void ephy_set(struct clk *clk, int enable)
103 if (!BCMCPU_IS_6358())
105 bcm_hwclock_set(CKCTL_6358_EPHY_EN, enable);
109 static struct clk clk_ephy = {
116 static void pcm_set(struct clk *clk, int enable)
118 if (!BCMCPU_IS_6358())
120 bcm_hwclock_set(CKCTL_6358_PCM_EN, enable);
123 static struct clk clk_pcm = {
130 static void usbh_set(struct clk *clk, int enable)
132 if (!BCMCPU_IS_6348())
134 bcm_hwclock_set(CKCTL_6348_USBH_EN, enable);
137 static struct clk clk_usbh = {
144 static void usbs_set(struct clk *clk, int enable)
148 switch(bcm63xx_get_cpu_id()) {
149 case BCM6338_CPU_ID: mask = CKCTL_6338_USBS_EN; break;
150 case BCM6348_CPU_ID: mask = CKCTL_6348_USBS_EN; break;
154 bcm_hwclock_set(mask, enable);
157 static struct clk clk_usbs = {
164 static void spi_set(struct clk *clk, int enable)
168 if (BCMCPU_IS_6338())
169 mask = CKCTL_6338_SPI_EN;
170 else if (BCMCPU_IS_6348())
171 mask = CKCTL_6348_SPI_EN;
174 mask = CKCTL_6358_SPI_EN;
175 bcm_hwclock_set(mask, enable);
178 static struct clk clk_spi = {
183 * Internal peripheral clock
185 static struct clk clk_periph = {
186 .rate = (50 * 1000 * 1000),
191 * Linux clock API implementation
193 int clk_enable(struct clk *clk)
195 mutex_lock(&clocks_mutex);
196 clk_enable_unlocked(clk);
197 mutex_unlock(&clocks_mutex);
201 EXPORT_SYMBOL(clk_enable);
203 void clk_disable(struct clk *clk)
205 mutex_lock(&clocks_mutex);
206 clk_disable_unlocked(clk);
207 mutex_unlock(&clocks_mutex);
210 EXPORT_SYMBOL(clk_disable);
212 unsigned long clk_get_rate(struct clk *clk)
217 EXPORT_SYMBOL(clk_get_rate);
219 struct clk *clk_get(struct device *dev, const char *id)
221 if (!strcmp(id, "enet0"))
223 if (!strcmp(id, "enet1"))
225 if (!strcmp(id, "ephy"))
227 if (!strcmp(id, "usbh"))
229 if (!strcmp(id, "usbs"))
231 if (!strcmp(id, "spi"))
233 if (!strcmp(id, "periph"))
235 if (BCMCPU_IS_6358() && !strcmp(id, "pcm"))
237 return ERR_PTR(-ENOENT);
240 EXPORT_SYMBOL(clk_get);
242 void clk_put(struct clk *clk)
246 EXPORT_SYMBOL(clk_put);