1e7300d04SMaxime Bizon /* 2e7300d04SMaxime Bizon * This file is subject to the terms and conditions of the GNU General Public 3e7300d04SMaxime Bizon * License. See the file "COPYING" in the main directory of this archive 4e7300d04SMaxime Bizon * for more details. 5e7300d04SMaxime Bizon * 6e7300d04SMaxime Bizon * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> 7e7300d04SMaxime Bizon */ 8e7300d04SMaxime Bizon 9e7300d04SMaxime Bizon #include <linux/module.h> 10e7300d04SMaxime Bizon #include <linux/mutex.h> 11e7300d04SMaxime Bizon #include <linux/err.h> 12e7300d04SMaxime Bizon #include <linux/clk.h> 1304712f3fSMaxime Bizon #include <linux/delay.h> 14e7300d04SMaxime Bizon #include <bcm63xx_cpu.h> 15e7300d04SMaxime Bizon #include <bcm63xx_io.h> 16e7300d04SMaxime Bizon #include <bcm63xx_regs.h> 17*ba00e2e5SJonas Gorski #include <bcm63xx_reset.h> 18e7300d04SMaxime Bizon #include <bcm63xx_clk.h> 19e7300d04SMaxime Bizon 20e7300d04SMaxime Bizon static DEFINE_MUTEX(clocks_mutex); 21e7300d04SMaxime Bizon 22e7300d04SMaxime Bizon 23e7300d04SMaxime Bizon static void clk_enable_unlocked(struct clk *clk) 24e7300d04SMaxime Bizon { 25e7300d04SMaxime Bizon if (clk->set && (clk->usage++) == 0) 26e7300d04SMaxime Bizon clk->set(clk, 1); 27e7300d04SMaxime Bizon } 28e7300d04SMaxime Bizon 29e7300d04SMaxime Bizon static void clk_disable_unlocked(struct clk *clk) 30e7300d04SMaxime Bizon { 31e7300d04SMaxime Bizon if (clk->set && (--clk->usage) == 0) 32e7300d04SMaxime Bizon clk->set(clk, 0); 33e7300d04SMaxime Bizon } 34e7300d04SMaxime Bizon 35e7300d04SMaxime Bizon static void bcm_hwclock_set(u32 mask, int enable) 36e7300d04SMaxime Bizon { 37e7300d04SMaxime Bizon u32 reg; 38e7300d04SMaxime Bizon 39e7300d04SMaxime Bizon reg = bcm_perf_readl(PERF_CKCTL_REG); 40e7300d04SMaxime Bizon if (enable) 41e7300d04SMaxime Bizon reg |= mask; 42e7300d04SMaxime Bizon else 43e7300d04SMaxime Bizon reg &= ~mask; 44e7300d04SMaxime Bizon bcm_perf_writel(reg, PERF_CKCTL_REG); 45e7300d04SMaxime Bizon } 46e7300d04SMaxime Bizon 47e7300d04SMaxime Bizon /* 48e7300d04SMaxime Bizon * Ethernet MAC "misc" clock: dma clocks and main clock on 6348 49e7300d04SMaxime Bizon */ 50e7300d04SMaxime Bizon static void enet_misc_set(struct clk *clk, int enable) 51e7300d04SMaxime Bizon { 52e7300d04SMaxime Bizon u32 mask; 53e7300d04SMaxime Bizon 54e7300d04SMaxime Bizon if (BCMCPU_IS_6338()) 55e7300d04SMaxime Bizon mask = CKCTL_6338_ENET_EN; 56e7300d04SMaxime Bizon else if (BCMCPU_IS_6345()) 57e7300d04SMaxime Bizon mask = CKCTL_6345_ENET_EN; 58e7300d04SMaxime Bizon else if (BCMCPU_IS_6348()) 59e7300d04SMaxime Bizon mask = CKCTL_6348_ENET_EN; 60e7300d04SMaxime Bizon else 61e7300d04SMaxime Bizon /* BCMCPU_IS_6358 */ 62e7300d04SMaxime Bizon mask = CKCTL_6358_EMUSB_EN; 63e7300d04SMaxime Bizon bcm_hwclock_set(mask, enable); 64e7300d04SMaxime Bizon } 65e7300d04SMaxime Bizon 66e7300d04SMaxime Bizon static struct clk clk_enet_misc = { 67e7300d04SMaxime Bizon .set = enet_misc_set, 68e7300d04SMaxime Bizon }; 69e7300d04SMaxime Bizon 70e7300d04SMaxime Bizon /* 71e7300d04SMaxime Bizon * Ethernet MAC clocks: only revelant on 6358, silently enable misc 72e7300d04SMaxime Bizon * clocks 73e7300d04SMaxime Bizon */ 74e7300d04SMaxime Bizon static void enetx_set(struct clk *clk, int enable) 75e7300d04SMaxime Bizon { 76e7300d04SMaxime Bizon if (enable) 77e7300d04SMaxime Bizon clk_enable_unlocked(&clk_enet_misc); 78e7300d04SMaxime Bizon else 79e7300d04SMaxime Bizon clk_disable_unlocked(&clk_enet_misc); 80e7300d04SMaxime Bizon 81e7300d04SMaxime Bizon if (BCMCPU_IS_6358()) { 82e7300d04SMaxime Bizon u32 mask; 83e7300d04SMaxime Bizon 84e7300d04SMaxime Bizon if (clk->id == 0) 85e7300d04SMaxime Bizon mask = CKCTL_6358_ENET0_EN; 86e7300d04SMaxime Bizon else 87e7300d04SMaxime Bizon mask = CKCTL_6358_ENET1_EN; 88e7300d04SMaxime Bizon bcm_hwclock_set(mask, enable); 89e7300d04SMaxime Bizon } 90e7300d04SMaxime Bizon } 91e7300d04SMaxime Bizon 92e7300d04SMaxime Bizon static struct clk clk_enet0 = { 93e7300d04SMaxime Bizon .id = 0, 94e7300d04SMaxime Bizon .set = enetx_set, 95e7300d04SMaxime Bizon }; 96e7300d04SMaxime Bizon 97e7300d04SMaxime Bizon static struct clk clk_enet1 = { 98e7300d04SMaxime Bizon .id = 1, 99e7300d04SMaxime Bizon .set = enetx_set, 100e7300d04SMaxime Bizon }; 101e7300d04SMaxime Bizon 102e7300d04SMaxime Bizon /* 103e7300d04SMaxime Bizon * Ethernet PHY clock 104e7300d04SMaxime Bizon */ 105e7300d04SMaxime Bizon static void ephy_set(struct clk *clk, int enable) 106e7300d04SMaxime Bizon { 107e7300d04SMaxime Bizon if (!BCMCPU_IS_6358()) 108e7300d04SMaxime Bizon return; 109e7300d04SMaxime Bizon bcm_hwclock_set(CKCTL_6358_EPHY_EN, enable); 110e7300d04SMaxime Bizon } 111e7300d04SMaxime Bizon 112e7300d04SMaxime Bizon 113e7300d04SMaxime Bizon static struct clk clk_ephy = { 114e7300d04SMaxime Bizon .set = ephy_set, 115e7300d04SMaxime Bizon }; 116e7300d04SMaxime Bizon 117e7300d04SMaxime Bizon /* 11804712f3fSMaxime Bizon * Ethernet switch clock 11904712f3fSMaxime Bizon */ 12004712f3fSMaxime Bizon static void enetsw_set(struct clk *clk, int enable) 12104712f3fSMaxime Bizon { 12204712f3fSMaxime Bizon if (!BCMCPU_IS_6368()) 12304712f3fSMaxime Bizon return; 124d9831a41SFlorian Fainelli bcm_hwclock_set(CKCTL_6368_ROBOSW_EN | 12504712f3fSMaxime Bizon CKCTL_6368_SWPKT_USB_EN | 12604712f3fSMaxime Bizon CKCTL_6368_SWPKT_SAR_EN, enable); 12704712f3fSMaxime Bizon if (enable) { 12804712f3fSMaxime Bizon /* reset switch core afer clock change */ 129*ba00e2e5SJonas Gorski bcm63xx_core_set_reset(BCM63XX_RESET_ENETSW, 1); 13004712f3fSMaxime Bizon msleep(10); 131*ba00e2e5SJonas Gorski bcm63xx_core_set_reset(BCM63XX_RESET_ENETSW, 0); 13204712f3fSMaxime Bizon msleep(10); 13304712f3fSMaxime Bizon } 13404712f3fSMaxime Bizon } 13504712f3fSMaxime Bizon 13604712f3fSMaxime Bizon static struct clk clk_enetsw = { 13704712f3fSMaxime Bizon .set = enetsw_set, 13804712f3fSMaxime Bizon }; 13904712f3fSMaxime Bizon 14004712f3fSMaxime Bizon /* 141e7300d04SMaxime Bizon * PCM clock 142e7300d04SMaxime Bizon */ 143e7300d04SMaxime Bizon static void pcm_set(struct clk *clk, int enable) 144e7300d04SMaxime Bizon { 145e7300d04SMaxime Bizon if (!BCMCPU_IS_6358()) 146e7300d04SMaxime Bizon return; 147e7300d04SMaxime Bizon bcm_hwclock_set(CKCTL_6358_PCM_EN, enable); 148e7300d04SMaxime Bizon } 149e7300d04SMaxime Bizon 150e7300d04SMaxime Bizon static struct clk clk_pcm = { 151e7300d04SMaxime Bizon .set = pcm_set, 152e7300d04SMaxime Bizon }; 153e7300d04SMaxime Bizon 154e7300d04SMaxime Bizon /* 155e7300d04SMaxime Bizon * USB host clock 156e7300d04SMaxime Bizon */ 157e7300d04SMaxime Bizon static void usbh_set(struct clk *clk, int enable) 158e7300d04SMaxime Bizon { 159dd89d60cSKevin Cernekee if (BCMCPU_IS_6328()) 160dd89d60cSKevin Cernekee bcm_hwclock_set(CKCTL_6328_USBH_EN, enable); 161dd89d60cSKevin Cernekee else if (BCMCPU_IS_6348()) 162e7300d04SMaxime Bizon bcm_hwclock_set(CKCTL_6348_USBH_EN, enable); 16304712f3fSMaxime Bizon else if (BCMCPU_IS_6368()) 164d9831a41SFlorian Fainelli bcm_hwclock_set(CKCTL_6368_USBH_EN, enable); 165e7300d04SMaxime Bizon } 166e7300d04SMaxime Bizon 167e7300d04SMaxime Bizon static struct clk clk_usbh = { 168e7300d04SMaxime Bizon .set = usbh_set, 169e7300d04SMaxime Bizon }; 170e7300d04SMaxime Bizon 171e7300d04SMaxime Bizon /* 172dd89d60cSKevin Cernekee * USB device clock 173dd89d60cSKevin Cernekee */ 174dd89d60cSKevin Cernekee static void usbd_set(struct clk *clk, int enable) 175dd89d60cSKevin Cernekee { 176dd89d60cSKevin Cernekee if (BCMCPU_IS_6328()) 177dd89d60cSKevin Cernekee bcm_hwclock_set(CKCTL_6328_USBD_EN, enable); 178dd89d60cSKevin Cernekee else if (BCMCPU_IS_6368()) 179dd89d60cSKevin Cernekee bcm_hwclock_set(CKCTL_6368_USBD_EN, enable); 180dd89d60cSKevin Cernekee } 181dd89d60cSKevin Cernekee 182dd89d60cSKevin Cernekee static struct clk clk_usbd = { 183dd89d60cSKevin Cernekee .set = usbd_set, 184dd89d60cSKevin Cernekee }; 185dd89d60cSKevin Cernekee 186dd89d60cSKevin Cernekee /* 187e7300d04SMaxime Bizon * SPI clock 188e7300d04SMaxime Bizon */ 189e7300d04SMaxime Bizon static void spi_set(struct clk *clk, int enable) 190e7300d04SMaxime Bizon { 191e7300d04SMaxime Bizon u32 mask; 192e7300d04SMaxime Bizon 193e7300d04SMaxime Bizon if (BCMCPU_IS_6338()) 194e7300d04SMaxime Bizon mask = CKCTL_6338_SPI_EN; 195e7300d04SMaxime Bizon else if (BCMCPU_IS_6348()) 196e7300d04SMaxime Bizon mask = CKCTL_6348_SPI_EN; 19719372b24SFlorian Fainelli else if (BCMCPU_IS_6358()) 198e7300d04SMaxime Bizon mask = CKCTL_6358_SPI_EN; 19919372b24SFlorian Fainelli else 20019372b24SFlorian Fainelli /* BCMCPU_IS_6368 */ 20119372b24SFlorian Fainelli mask = CKCTL_6368_SPI_EN; 202e7300d04SMaxime Bizon bcm_hwclock_set(mask, enable); 203e7300d04SMaxime Bizon } 204e7300d04SMaxime Bizon 205e7300d04SMaxime Bizon static struct clk clk_spi = { 206e7300d04SMaxime Bizon .set = spi_set, 207e7300d04SMaxime Bizon }; 208e7300d04SMaxime Bizon 209e7300d04SMaxime Bizon /* 21004712f3fSMaxime Bizon * XTM clock 21104712f3fSMaxime Bizon */ 21204712f3fSMaxime Bizon static void xtm_set(struct clk *clk, int enable) 21304712f3fSMaxime Bizon { 21404712f3fSMaxime Bizon if (!BCMCPU_IS_6368()) 21504712f3fSMaxime Bizon return; 21604712f3fSMaxime Bizon 217d9831a41SFlorian Fainelli bcm_hwclock_set(CKCTL_6368_SAR_EN | 21804712f3fSMaxime Bizon CKCTL_6368_SWPKT_SAR_EN, enable); 21904712f3fSMaxime Bizon 22004712f3fSMaxime Bizon if (enable) { 22104712f3fSMaxime Bizon /* reset sar core afer clock change */ 222*ba00e2e5SJonas Gorski bcm63xx_core_set_reset(BCM63XX_RESET_SAR, 1); 22304712f3fSMaxime Bizon mdelay(1); 224*ba00e2e5SJonas Gorski bcm63xx_core_set_reset(BCM63XX_RESET_SAR, 0); 22504712f3fSMaxime Bizon mdelay(1); 22604712f3fSMaxime Bizon } 22704712f3fSMaxime Bizon } 22804712f3fSMaxime Bizon 22904712f3fSMaxime Bizon 23004712f3fSMaxime Bizon static struct clk clk_xtm = { 23104712f3fSMaxime Bizon .set = xtm_set, 23204712f3fSMaxime Bizon }; 23304712f3fSMaxime Bizon 23404712f3fSMaxime Bizon /* 2350b55561bSFlorian Fainelli * IPsec clock 2360b55561bSFlorian Fainelli */ 2370b55561bSFlorian Fainelli static void ipsec_set(struct clk *clk, int enable) 2380b55561bSFlorian Fainelli { 2390b55561bSFlorian Fainelli bcm_hwclock_set(CKCTL_6368_IPSEC_EN, enable); 2400b55561bSFlorian Fainelli } 2410b55561bSFlorian Fainelli 2420b55561bSFlorian Fainelli static struct clk clk_ipsec = { 2430b55561bSFlorian Fainelli .set = ipsec_set, 2440b55561bSFlorian Fainelli }; 2450b55561bSFlorian Fainelli 2460b55561bSFlorian Fainelli /* 247f2d1035eSJonas Gorski * PCIe clock 248f2d1035eSJonas Gorski */ 249f2d1035eSJonas Gorski 250f2d1035eSJonas Gorski static void pcie_set(struct clk *clk, int enable) 251f2d1035eSJonas Gorski { 252f2d1035eSJonas Gorski bcm_hwclock_set(CKCTL_6328_PCIE_EN, enable); 253f2d1035eSJonas Gorski } 254f2d1035eSJonas Gorski 255f2d1035eSJonas Gorski static struct clk clk_pcie = { 256f2d1035eSJonas Gorski .set = pcie_set, 257f2d1035eSJonas Gorski }; 258f2d1035eSJonas Gorski 259f2d1035eSJonas Gorski /* 260e7300d04SMaxime Bizon * Internal peripheral clock 261e7300d04SMaxime Bizon */ 262e7300d04SMaxime Bizon static struct clk clk_periph = { 263e7300d04SMaxime Bizon .rate = (50 * 1000 * 1000), 264e7300d04SMaxime Bizon }; 265e7300d04SMaxime Bizon 266e7300d04SMaxime Bizon 267e7300d04SMaxime Bizon /* 268e7300d04SMaxime Bizon * Linux clock API implementation 269e7300d04SMaxime Bizon */ 270e7300d04SMaxime Bizon int clk_enable(struct clk *clk) 271e7300d04SMaxime Bizon { 272e7300d04SMaxime Bizon mutex_lock(&clocks_mutex); 273e7300d04SMaxime Bizon clk_enable_unlocked(clk); 274e7300d04SMaxime Bizon mutex_unlock(&clocks_mutex); 275e7300d04SMaxime Bizon return 0; 276e7300d04SMaxime Bizon } 277e7300d04SMaxime Bizon 278e7300d04SMaxime Bizon EXPORT_SYMBOL(clk_enable); 279e7300d04SMaxime Bizon 280e7300d04SMaxime Bizon void clk_disable(struct clk *clk) 281e7300d04SMaxime Bizon { 282e7300d04SMaxime Bizon mutex_lock(&clocks_mutex); 283e7300d04SMaxime Bizon clk_disable_unlocked(clk); 284e7300d04SMaxime Bizon mutex_unlock(&clocks_mutex); 285e7300d04SMaxime Bizon } 286e7300d04SMaxime Bizon 287e7300d04SMaxime Bizon EXPORT_SYMBOL(clk_disable); 288e7300d04SMaxime Bizon 289e7300d04SMaxime Bizon unsigned long clk_get_rate(struct clk *clk) 290e7300d04SMaxime Bizon { 291e7300d04SMaxime Bizon return clk->rate; 292e7300d04SMaxime Bizon } 293e7300d04SMaxime Bizon 294e7300d04SMaxime Bizon EXPORT_SYMBOL(clk_get_rate); 295e7300d04SMaxime Bizon 296e7300d04SMaxime Bizon struct clk *clk_get(struct device *dev, const char *id) 297e7300d04SMaxime Bizon { 298e7300d04SMaxime Bizon if (!strcmp(id, "enet0")) 299e7300d04SMaxime Bizon return &clk_enet0; 300e7300d04SMaxime Bizon if (!strcmp(id, "enet1")) 301e7300d04SMaxime Bizon return &clk_enet1; 30204712f3fSMaxime Bizon if (!strcmp(id, "enetsw")) 30304712f3fSMaxime Bizon return &clk_enetsw; 304e7300d04SMaxime Bizon if (!strcmp(id, "ephy")) 305e7300d04SMaxime Bizon return &clk_ephy; 306e7300d04SMaxime Bizon if (!strcmp(id, "usbh")) 307e7300d04SMaxime Bizon return &clk_usbh; 308dd89d60cSKevin Cernekee if (!strcmp(id, "usbd")) 309dd89d60cSKevin Cernekee return &clk_usbd; 310e7300d04SMaxime Bizon if (!strcmp(id, "spi")) 311e7300d04SMaxime Bizon return &clk_spi; 31204712f3fSMaxime Bizon if (!strcmp(id, "xtm")) 31304712f3fSMaxime Bizon return &clk_xtm; 314e7300d04SMaxime Bizon if (!strcmp(id, "periph")) 315e7300d04SMaxime Bizon return &clk_periph; 316e7300d04SMaxime Bizon if (BCMCPU_IS_6358() && !strcmp(id, "pcm")) 317e7300d04SMaxime Bizon return &clk_pcm; 3180b55561bSFlorian Fainelli if (BCMCPU_IS_6368() && !strcmp(id, "ipsec")) 3190b55561bSFlorian Fainelli return &clk_ipsec; 320f2d1035eSJonas Gorski if (BCMCPU_IS_6328() && !strcmp(id, "pcie")) 321f2d1035eSJonas Gorski return &clk_pcie; 322e7300d04SMaxime Bizon return ERR_PTR(-ENOENT); 323e7300d04SMaxime Bizon } 324e7300d04SMaxime Bizon 325e7300d04SMaxime Bizon EXPORT_SYMBOL(clk_get); 326e7300d04SMaxime Bizon 327e7300d04SMaxime Bizon void clk_put(struct clk *clk) 328e7300d04SMaxime Bizon { 329e7300d04SMaxime Bizon } 330e7300d04SMaxime Bizon 331e7300d04SMaxime Bizon EXPORT_SYMBOL(clk_put); 332