linux/arch/mips/bcm63xx/clk.c
<<
>>
Prefs
   1/*
   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
   4 * for more details.
   5 *
   6 * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
   7 */
   8
   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>
  17
  18static DEFINE_MUTEX(clocks_mutex);
  19
  20
  21static void clk_enable_unlocked(struct clk *clk)
  22{
  23        if (clk->set && (clk->usage++) == 0)
  24                clk->set(clk, 1);
  25}
  26
  27static void clk_disable_unlocked(struct clk *clk)
  28{
  29        if (clk->set && (--clk->usage) == 0)
  30                clk->set(clk, 0);
  31}
  32
  33static void bcm_hwclock_set(u32 mask, int enable)
  34{
  35        u32 reg;
  36
  37        reg = bcm_perf_readl(PERF_CKCTL_REG);
  38        if (enable)
  39                reg |= mask;
  40        else
  41                reg &= ~mask;
  42        bcm_perf_writel(reg, PERF_CKCTL_REG);
  43}
  44
  45/*
  46 * Ethernet MAC "misc" clock: dma clocks and main clock on 6348
  47 */
  48static void enet_misc_set(struct clk *clk, int enable)
  49{
  50        u32 mask;
  51
  52        if (BCMCPU_IS_6338())
  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;
  58        else
  59                /* BCMCPU_IS_6358 */
  60                mask = CKCTL_6358_EMUSB_EN;
  61        bcm_hwclock_set(mask, enable);
  62}
  63
  64static struct clk clk_enet_misc = {
  65        .set    = enet_misc_set,
  66};
  67
  68/*
  69 * Ethernet MAC clocks: only revelant on 6358, silently enable misc
  70 * clocks
  71 */
  72static void enetx_set(struct clk *clk, int enable)
  73{
  74        if (enable)
  75                clk_enable_unlocked(&clk_enet_misc);
  76        else
  77                clk_disable_unlocked(&clk_enet_misc);
  78
  79        if (BCMCPU_IS_6358()) {
  80                u32 mask;
  81
  82                if (clk->id == 0)
  83                        mask = CKCTL_6358_ENET0_EN;
  84                else
  85                        mask = CKCTL_6358_ENET1_EN;
  86                bcm_hwclock_set(mask, enable);
  87        }
  88}
  89
  90static struct clk clk_enet0 = {
  91        .id     = 0,
  92        .set    = enetx_set,
  93};
  94
  95static struct clk clk_enet1 = {
  96        .id     = 1,
  97        .set    = enetx_set,
  98};
  99
 100/*
 101 * Ethernet PHY clock
 102 */
 103static void ephy_set(struct clk *clk, int enable)
 104{
 105        if (!BCMCPU_IS_6358())
 106                return;
 107        bcm_hwclock_set(CKCTL_6358_EPHY_EN, enable);
 108}
 109
 110
 111static struct clk clk_ephy = {
 112        .set    = ephy_set,
 113};
 114
 115/*
 116 * PCM clock
 117 */
 118static void pcm_set(struct clk *clk, int enable)
 119{
 120        if (!BCMCPU_IS_6358())
 121                return;
 122        bcm_hwclock_set(CKCTL_6358_PCM_EN, enable);
 123}
 124
 125static struct clk clk_pcm = {
 126        .set    = pcm_set,
 127};
 128
 129/*
 130 * USB host clock
 131 */
 132static void usbh_set(struct clk *clk, int enable)
 133{
 134        if (!BCMCPU_IS_6348())
 135                return;
 136        bcm_hwclock_set(CKCTL_6348_USBH_EN, enable);
 137}
 138
 139static struct clk clk_usbh = {
 140        .set    = usbh_set,
 141};
 142
 143/*
 144 * SPI clock
 145 */
 146static void spi_set(struct clk *clk, int enable)
 147{
 148        u32 mask;
 149
 150        if (BCMCPU_IS_6338())
 151                mask = CKCTL_6338_SPI_EN;
 152        else if (BCMCPU_IS_6348())
 153                mask = CKCTL_6348_SPI_EN;
 154        else
 155                /* BCMCPU_IS_6358 */
 156                mask = CKCTL_6358_SPI_EN;
 157        bcm_hwclock_set(mask, enable);
 158}
 159
 160static struct clk clk_spi = {
 161        .set    = spi_set,
 162};
 163
 164/*
 165 * Internal peripheral clock
 166 */
 167static struct clk clk_periph = {
 168        .rate   = (50 * 1000 * 1000),
 169};
 170
 171
 172/*
 173 * Linux clock API implementation
 174 */
 175int clk_enable(struct clk *clk)
 176{
 177        mutex_lock(&clocks_mutex);
 178        clk_enable_unlocked(clk);
 179        mutex_unlock(&clocks_mutex);
 180        return 0;
 181}
 182
 183EXPORT_SYMBOL(clk_enable);
 184
 185void clk_disable(struct clk *clk)
 186{
 187        mutex_lock(&clocks_mutex);
 188        clk_disable_unlocked(clk);
 189        mutex_unlock(&clocks_mutex);
 190}
 191
 192EXPORT_SYMBOL(clk_disable);
 193
 194unsigned long clk_get_rate(struct clk *clk)
 195{
 196        return clk->rate;
 197}
 198
 199EXPORT_SYMBOL(clk_get_rate);
 200
 201struct clk *clk_get(struct device *dev, const char *id)
 202{
 203        if (!strcmp(id, "enet0"))
 204                return &clk_enet0;
 205        if (!strcmp(id, "enet1"))
 206                return &clk_enet1;
 207        if (!strcmp(id, "ephy"))
 208                return &clk_ephy;
 209        if (!strcmp(id, "usbh"))
 210                return &clk_usbh;
 211        if (!strcmp(id, "spi"))
 212                return &clk_spi;
 213        if (!strcmp(id, "periph"))
 214                return &clk_periph;
 215        if (BCMCPU_IS_6358() && !strcmp(id, "pcm"))
 216                return &clk_pcm;
 217        return ERR_PTR(-ENOENT);
 218}
 219
 220EXPORT_SYMBOL(clk_get);
 221
 222void clk_put(struct clk *clk)
 223{
 224}
 225
 226EXPORT_SYMBOL(clk_put);
 227