2007-02-16 14:12:31 +03:00
/* linux/arch/arm/mach-s3c2443/clock.c
*
2010-01-30 11:25:49 +03:00
* Copyright ( c ) 2007 , 2010 Simtec Electronics
2007-02-16 14:12:31 +03:00
* Ben Dooks < ben @ simtec . co . uk >
*
* S3C2443 Clock control support
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include <linux/init.h>
2010-04-28 13:03:57 +04:00
2007-02-16 14:12:31 +03:00
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/list.h>
# include <linux/errno.h>
# include <linux/err.h>
2011-12-22 04:26:03 +04:00
# include <linux/device.h>
2007-02-16 14:12:31 +03:00
# include <linux/clk.h>
# include <linux/mutex.h>
# include <linux/serial_core.h>
2008-09-06 15:10:45 +04:00
# include <linux/io.h>
2007-02-16 14:12:31 +03:00
# include <asm/mach/map.h>
2008-08-05 19:14:15 +04:00
# include <mach/hardware.h>
2007-02-16 14:12:31 +03:00
2008-08-05 19:14:15 +04:00
# include <mach/regs-s3c2443-clock.h>
2007-02-16 14:12:31 +03:00
2008-10-21 17:06:38 +04:00
# include <plat/cpu-freq.h>
2008-10-08 02:09:51 +04:00
# include <plat/clock.h>
2010-01-30 10:19:59 +03:00
# include <plat/clock-clksrc.h>
2008-10-08 01:26:09 +04:00
# include <plat/cpu.h>
2007-02-16 14:12:31 +03:00
/* We currently have to assume that the system is running
* from the XTPll input , and that all * * * REFCLKs are being
* fed from it , as we cannot read the state of OM [ 4 ] from
* software .
*
* It would be possible for each board initialisation to
* set the correct muxing at initialisation
*/
/* clock selections */
2008-07-07 21:12:39 +04:00
/* armdiv
*
* this clock is sourced from msysclk and can have a number of
* divider values applied to it to then be fed into armclk .
2011-10-14 10:08:56 +04:00
* The real clock definition is done in s3c2443 - clock . c ,
* only the armdiv divisor table must be defined here .
2008-07-07 21:12:39 +04:00
*/
2010-01-30 12:14:14 +03:00
static unsigned int armdiv [ 16 ] = {
[ S3C2443_CLKDIV0_ARMDIV_1 > > S3C2443_CLKDIV0_ARMDIV_SHIFT ] = 1 ,
[ S3C2443_CLKDIV0_ARMDIV_2 > > S3C2443_CLKDIV0_ARMDIV_SHIFT ] = 2 ,
[ S3C2443_CLKDIV0_ARMDIV_3 > > S3C2443_CLKDIV0_ARMDIV_SHIFT ] = 3 ,
[ S3C2443_CLKDIV0_ARMDIV_4 > > S3C2443_CLKDIV0_ARMDIV_SHIFT ] = 4 ,
[ S3C2443_CLKDIV0_ARMDIV_6 > > S3C2443_CLKDIV0_ARMDIV_SHIFT ] = 6 ,
[ S3C2443_CLKDIV0_ARMDIV_8 > > S3C2443_CLKDIV0_ARMDIV_SHIFT ] = 8 ,
[ S3C2443_CLKDIV0_ARMDIV_12 > > S3C2443_CLKDIV0_ARMDIV_SHIFT ] = 12 ,
[ S3C2443_CLKDIV0_ARMDIV_16 > > S3C2443_CLKDIV0_ARMDIV_SHIFT ] = 16 ,
} ;
2007-02-16 14:12:31 +03:00
/* hsspi
*
* high - speed spi clock , sourced from esysclk
*/
2010-01-30 10:19:59 +03:00
static struct clksrc_clk clk_hsspi = {
. clk = {
2011-09-27 03:45:23 +04:00
. name = " hsspi-if " ,
2010-01-30 11:25:49 +03:00
. parent = & clk_esysclk . clk ,
2010-01-30 10:19:59 +03:00
. ctrlbit = S3C2443_SCLKCON_HSSPICLK ,
. enable = s3c2443_clkcon_enable_s ,
2009-12-01 04:24:37 +03:00
} ,
2010-01-30 10:19:59 +03:00
. reg_div = { . reg = S3C2443_CLKDIV1 , . size = 2 , . shift = 4 } ,
2007-02-16 14:12:31 +03:00
} ;
/* clk_hsmcc_div
*
* this clock is sourced from epll , and is fed through a divider ,
* to a mux controlled by sclkcon where either it or a extclk can
* be fed to the hsmmc block
*/
2010-01-30 10:19:59 +03:00
static struct clksrc_clk clk_hsmmc_div = {
. clk = {
. name = " hsmmc-div " ,
2011-06-14 14:12:26 +04:00
. devname = " s3c-sdhci.1 " ,
2010-01-30 11:25:49 +03:00
. parent = & clk_esysclk . clk ,
2009-12-01 04:24:37 +03:00
} ,
2010-01-30 10:19:59 +03:00
. reg_div = { . reg = S3C2443_CLKDIV1 , . size = 2 , . shift = 6 } ,
2007-02-16 14:12:31 +03:00
} ;
static int s3c2443_setparent_hsmmc ( struct clk * clk , struct clk * parent )
{
unsigned long clksrc = __raw_readl ( S3C2443_SCLKCON ) ;
clksrc & = ~ ( S3C2443_SCLKCON_HSMMCCLK_EXT |
S3C2443_SCLKCON_HSMMCCLK_EPLL ) ;
if ( parent = = & clk_epll )
clksrc | = S3C2443_SCLKCON_HSMMCCLK_EPLL ;
else if ( parent = = & clk_ext )
clksrc | = S3C2443_SCLKCON_HSMMCCLK_EXT ;
else
return - EINVAL ;
if ( clk - > usage > 0 ) {
__raw_writel ( clksrc , S3C2443_SCLKCON ) ;
}
clk - > parent = parent ;
return 0 ;
}
static int s3c2443_enable_hsmmc ( struct clk * clk , int enable )
{
return s3c2443_setparent_hsmmc ( clk , clk - > parent ) ;
}
static struct clk clk_hsmmc = {
. name = " hsmmc-if " ,
2011-06-14 14:12:26 +04:00
. devname = " s3c-sdhci.1 " ,
2010-01-30 10:19:59 +03:00
. parent = & clk_hsmmc_div . clk ,
2007-02-16 14:12:31 +03:00
. enable = s3c2443_enable_hsmmc ,
2009-12-01 04:24:37 +03:00
. ops = & ( struct clk_ops ) {
. set_parent = s3c2443_setparent_hsmmc ,
} ,
2007-02-16 14:12:31 +03:00
} ;
/* standard clock definitions */
2010-04-28 07:58:13 +04:00
static struct clk init_clocks_off [ ] = {
2007-02-16 14:12:31 +03:00
{
. name = " sdi " ,
. parent = & clk_p ,
. enable = s3c2443_clkcon_enable_p ,
. ctrlbit = S3C2443_PCLKCON_SDI ,
} , {
. name = " spi " ,
2011-06-14 14:12:26 +04:00
. devname = " s3c2410-spi.0 " ,
2007-02-16 14:12:31 +03:00
. parent = & clk_p ,
. enable = s3c2443_clkcon_enable_p ,
. ctrlbit = S3C2443_PCLKCON_SPI1 ,
}
} ;
/* clocks to add straight away */
2010-01-30 10:19:59 +03:00
static struct clksrc_clk * clksrcs [ ] __initdata = {
2007-02-16 14:12:31 +03:00
& clk_hsspi ,
& clk_hsmmc_div ,
2010-01-30 10:19:59 +03:00
} ;
static struct clk * clks [ ] __initdata = {
2007-02-16 14:12:31 +03:00
& clk_hsmmc ,
} ;
2012-04-25 05:06:49 +04:00
static struct clk_lookup s3c2443_clk_lookup [ ] = {
CLKDEV_INIT ( " s3c-sdhci.1 " , " mmc_busclk.2 " , & clk_hsmmc ) ,
2012-07-13 02:15:14 +04:00
CLKDEV_INIT ( " s3c2443-spi.0 " , " spi_busclk2 " , & clk_hsspi . clk ) ,
2012-04-25 05:06:49 +04:00
} ;
2008-10-21 17:06:38 +04:00
void __init s3c2443_init_clocks ( int xtal )
{
unsigned long epllcon = __raw_readl ( S3C2443_EPLLCON ) ;
int ptr ;
2010-04-28 13:03:57 +04:00
clk_epll . rate = s3c2443_get_epll ( epllcon , xtal ) ;
clk_epll . parent = & clk_epllref . clk ;
2011-10-14 10:08:57 +04:00
s3c2443_common_init_clocks ( xtal , s3c2443_get_mpll ,
2011-10-14 10:08:56 +04:00
armdiv , ARRAY_SIZE ( armdiv ) ,
S3C2443_CLKDIV0_ARMDIV_MASK ) ;
2008-10-21 17:06:38 +04:00
2010-04-28 07:58:13 +04:00
s3c24xx_register_clocks ( clks , ARRAY_SIZE ( clks ) ) ;
2007-02-16 14:12:31 +03:00
2010-01-30 10:19:59 +03:00
for ( ptr = 0 ; ptr < ARRAY_SIZE ( clksrcs ) ; ptr + + )
s3c_register_clksrc ( clksrcs [ ptr ] , 1 ) ;
2007-02-16 14:12:31 +03:00
/* We must be careful disabling the clocks we are not intending to
2007-10-20 01:10:43 +04:00
* be using at boot time , as subsystems such as the LCD which do
2007-02-16 14:12:31 +03:00
* their own DMA requests to the bus can cause the system to lockup
* if they where in the middle of requesting bus access .
*
* Disabling the LCD clock if the LCD is active is very dangerous ,
* and therefore the bootloader should be careful to not enable
* the LCD clock if it is not needed .
*/
/* install (and disable) the clocks we do not need immediately */
2010-04-28 07:58:13 +04:00
s3c_register_clocks ( init_clocks_off , ARRAY_SIZE ( init_clocks_off ) ) ;
s3c_disable_clocks ( init_clocks_off , ARRAY_SIZE ( init_clocks_off ) ) ;
2012-04-25 05:06:49 +04:00
clkdev_add_table ( s3c2443_clk_lookup , ARRAY_SIZE ( s3c2443_clk_lookup ) ) ;
2008-11-21 13:36:05 +03:00
s3c_pwmclk_init ( ) ;
2007-02-16 14:12:31 +03:00
}