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 BCM6345_CPU_ID: mask = CKCTL_6345_USBS_EN; break;
153 case BCM6348_CPU_ID: mask = CKCTL_6348_USBS_EN; break;
157 bcm_hwclock_set(mask, enable);
160 static struct clk clk_usbs = {
167 static void spi_set(struct clk *clk, int enable)
171 if (BCMCPU_IS_6338())
172 mask = CKCTL_6338_SPI_EN;
173 else if (BCMCPU_IS_6348())
174 mask = CKCTL_6348_SPI_EN;
177 mask = CKCTL_6358_SPI_EN;
178 bcm_hwclock_set(mask, enable);
181 static struct clk clk_spi = {
186 * Internal peripheral clock
188 static struct clk clk_periph = {
189 .rate = (50 * 1000 * 1000),
194 * Linux clock API implementation
196 int clk_enable(struct clk *clk)
198 mutex_lock(&clocks_mutex);
199 clk_enable_unlocked(clk);
200 mutex_unlock(&clocks_mutex);
204 EXPORT_SYMBOL(clk_enable);
206 void clk_disable(struct clk *clk)
208 mutex_lock(&clocks_mutex);
209 clk_disable_unlocked(clk);
210 mutex_unlock(&clocks_mutex);
213 EXPORT_SYMBOL(clk_disable);
215 unsigned long clk_get_rate(struct clk *clk)
220 EXPORT_SYMBOL(clk_get_rate);
222 struct clk *clk_get(struct device *dev, const char *id)
224 if (!strcmp(id, "enet0"))
226 if (!strcmp(id, "enet1"))
228 if (!strcmp(id, "ephy"))
230 if (!strcmp(id, "usbh"))
232 if (!strcmp(id, "usbs"))
234 if (!strcmp(id, "spi"))
236 if (!strcmp(id, "periph"))
238 if (BCMCPU_IS_6358() && !strcmp(id, "pcm"))
240 return ERR_PTR(-ENOENT);
243 EXPORT_SYMBOL(clk_get);
245 void clk_put(struct clk *clk)
249 EXPORT_SYMBOL(clk_put);