linux/arch/arm/mach-s3c24xx/clock-s3c2443.c
<<
>>
Prefs
   1/* linux/arch/arm/mach-s3c2443/clock.c
   2 *
   3 * Copyright (c) 2007, 2010 Simtec Electronics
   4 *      Ben Dooks <ben@simtec.co.uk>
   5 *
   6 * S3C2443 Clock control support
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License as published by
  10 * the Free Software Foundation; either version 2 of the License, or
  11 * (at your option) any later version.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU General Public License
  19 * along with this program; if not, write to the Free Software
  20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  21*/
  22
  23#include <linux/init.h>
  24
  25#include <linux/module.h>
  26#include <linux/kernel.h>
  27#include <linux/list.h>
  28#include <linux/errno.h>
  29#include <linux/err.h>
  30#include <linux/device.h>
  31#include <linux/clk.h>
  32#include <linux/mutex.h>
  33#include <linux/serial_core.h>
  34#include <linux/io.h>
  35
  36#include <asm/mach/map.h>
  37
  38#include <mach/hardware.h>
  39
  40#include <mach/regs-s3c2443-clock.h>
  41
  42#include <plat/cpu-freq.h>
  43
  44#include <plat/clock.h>
  45#include <plat/clock-clksrc.h>
  46#include <plat/cpu.h>
  47
  48/* We currently have to assume that the system is running
  49 * from the XTPll input, and that all ***REFCLKs are being
  50 * fed from it, as we cannot read the state of OM[4] from
  51 * software.
  52 *
  53 * It would be possible for each board initialisation to
  54 * set the correct muxing at initialisation
  55*/
  56
  57/* clock selections */
  58
  59/* armdiv
  60 *
  61 * this clock is sourced from msysclk and can have a number of
  62 * divider values applied to it to then be fed into armclk.
  63 * The real clock definition is done in s3c2443-clock.c,
  64 * only the armdiv divisor table must be defined here.
  65*/
  66
  67static unsigned int armdiv[16] = {
  68        [S3C2443_CLKDIV0_ARMDIV_1 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 1,
  69        [S3C2443_CLKDIV0_ARMDIV_2 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 2,
  70        [S3C2443_CLKDIV0_ARMDIV_3 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 3,
  71        [S3C2443_CLKDIV0_ARMDIV_4 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 4,
  72        [S3C2443_CLKDIV0_ARMDIV_6 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 6,
  73        [S3C2443_CLKDIV0_ARMDIV_8 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 8,
  74        [S3C2443_CLKDIV0_ARMDIV_12 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]     = 12,
  75        [S3C2443_CLKDIV0_ARMDIV_16 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]     = 16,
  76};
  77
  78/* hsspi
  79 *
  80 * high-speed spi clock, sourced from esysclk
  81*/
  82
  83static struct clksrc_clk clk_hsspi = {
  84        .clk    = {
  85                .name           = "hsspi-if",
  86                .parent         = &clk_esysclk.clk,
  87                .ctrlbit        = S3C2443_SCLKCON_HSSPICLK,
  88                .enable         = s3c2443_clkcon_enable_s,
  89        },
  90        .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 },
  91};
  92
  93
  94/* clk_hsmcc_div
  95 *
  96 * this clock is sourced from epll, and is fed through a divider,
  97 * to a mux controlled by sclkcon where either it or a extclk can
  98 * be fed to the hsmmc block
  99*/
 100
 101static struct clksrc_clk clk_hsmmc_div = {
 102        .clk    = {
 103                .name           = "hsmmc-div",
 104                .devname        = "s3c-sdhci.1",
 105                .parent         = &clk_esysclk.clk,
 106        },
 107        .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 6 },
 108};
 109
 110static int s3c2443_setparent_hsmmc(struct clk *clk, struct clk *parent)
 111{
 112        unsigned long clksrc = __raw_readl(S3C2443_SCLKCON);
 113
 114        clksrc &= ~(S3C2443_SCLKCON_HSMMCCLK_EXT |
 115                    S3C2443_SCLKCON_HSMMCCLK_EPLL);
 116
 117        if (parent == &clk_epll)
 118                clksrc |= S3C2443_SCLKCON_HSMMCCLK_EPLL;
 119        else if (parent == &clk_ext)
 120                clksrc |= S3C2443_SCLKCON_HSMMCCLK_EXT;
 121        else
 122                return -EINVAL;
 123
 124        if (clk->usage > 0) {
 125                __raw_writel(clksrc, S3C2443_SCLKCON);
 126        }
 127
 128        clk->parent = parent;
 129        return 0;
 130}
 131
 132static int s3c2443_enable_hsmmc(struct clk *clk, int enable)
 133{
 134        return s3c2443_setparent_hsmmc(clk, clk->parent);
 135}
 136
 137static struct clk clk_hsmmc = {
 138        .name           = "hsmmc-if",
 139        .devname        = "s3c-sdhci.1",
 140        .parent         = &clk_hsmmc_div.clk,
 141        .enable         = s3c2443_enable_hsmmc,
 142        .ops            = &(struct clk_ops) {
 143                .set_parent     = s3c2443_setparent_hsmmc,
 144        },
 145};
 146
 147/* standard clock definitions */
 148
 149static struct clk init_clocks_off[] = {
 150        {
 151                .name           = "sdi",
 152                .parent         = &clk_p,
 153                .enable         = s3c2443_clkcon_enable_p,
 154                .ctrlbit        = S3C2443_PCLKCON_SDI,
 155        }, {
 156                .name           = "spi",
 157                .devname        = "s3c2410-spi.0",
 158                .parent         = &clk_p,
 159                .enable         = s3c2443_clkcon_enable_p,
 160                .ctrlbit        = S3C2443_PCLKCON_SPI1,
 161        }
 162};
 163
 164/* clocks to add straight away */
 165
 166static struct clksrc_clk *clksrcs[] __initdata = {
 167        &clk_hsspi,
 168        &clk_hsmmc_div,
 169};
 170
 171static struct clk *clks[] __initdata = {
 172        &clk_hsmmc,
 173};
 174
 175static struct clk_lookup s3c2443_clk_lookup[] = {
 176        CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &clk_hsmmc),
 177        CLKDEV_INIT("s3c2443-spi.0", "spi_busclk2", &clk_hsspi.clk),
 178};
 179
 180void __init s3c2443_init_clocks(int xtal)
 181{
 182        unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
 183        int ptr;
 184
 185        clk_epll.rate = s3c2443_get_epll(epllcon, xtal);
 186        clk_epll.parent = &clk_epllref.clk;
 187
 188        s3c2443_common_init_clocks(xtal, s3c2443_get_mpll,
 189                                   armdiv, ARRAY_SIZE(armdiv),
 190                                   S3C2443_CLKDIV0_ARMDIV_MASK);
 191
 192        s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
 193
 194        for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
 195                s3c_register_clksrc(clksrcs[ptr], 1);
 196
 197        /* We must be careful disabling the clocks we are not intending to
 198         * be using at boot time, as subsystems such as the LCD which do
 199         * their own DMA requests to the bus can cause the system to lockup
 200         * if they where in the middle of requesting bus access.
 201         *
 202         * Disabling the LCD clock if the LCD is active is very dangerous,
 203         * and therefore the bootloader should be careful to not enable
 204         * the LCD clock if it is not needed.
 205        */
 206
 207        /* install (and disable) the clocks we do not need immediately */
 208
 209        s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
 210        s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
 211        clkdev_add_table(s3c2443_clk_lookup, ARRAY_SIZE(s3c2443_clk_lookup));
 212}
 213