2009-06-23 21:39:56 +09:00
/* linux/arch/arm/plat-s5pc1xx/s5pc100-clock.c
*
* Copyright 2009 Samsung Electronics , Co .
* Byungho Min < bhmin @ samsung . com >
*
* S5PC100 based common clock support
*
* Based on plat - s3c64xx / s3c6400 - clock . c
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/init.h>
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/list.h>
# include <linux/errno.h>
# include <linux/err.h>
# include <linux/clk.h>
# include <linux/sysdev.h>
# include <linux/io.h>
# include <mach/hardware.h>
# include <mach/map.h>
# include <plat/cpu-freq.h>
# include <plat/regs-clock.h>
# include <plat/clock.h>
2010-01-12 12:19:28 +09:00
# include <plat/clock-clksrc.h>
2009-06-23 21:39:56 +09:00
# include <plat/cpu.h>
# include <plat/pll.h>
# include <plat/devs.h>
# include <plat/s5pc100.h>
/* fin_apll, fin_mpll and fin_epll are all the same clock, which we call
* ext_xtal_mux for want of an actual name from the manual .
*/
static struct clk clk_ext_xtal_mux = {
. name = " ext_xtal " ,
. id = - 1 ,
} ;
# define clk_fin_apll clk_ext_xtal_mux
# define clk_fin_mpll clk_ext_xtal_mux
# define clk_fin_epll clk_ext_xtal_mux
# define clk_fin_hpll clk_ext_xtal_mux
# define clk_fout_mpll clk_mpll
2009-11-17 08:41:13 +01:00
# define clk_vclk_54m clk_54m
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
/* APLL */
static struct clk clk_fout_apll = {
. name = " fout_apll " ,
2009-06-23 21:39:56 +09:00
. id = - 1 ,
. rate = 27000000 ,
} ;
2009-11-17 08:41:13 +01:00
static struct clk * clk_src_apll_list [ ] = {
[ 0 ] = & clk_fin_apll ,
[ 1 ] = & clk_fout_apll ,
} ;
2009-06-23 21:39:56 +09:00
2010-01-12 12:19:28 +09:00
static struct clksrc_sources clk_src_apll = {
2009-11-17 08:41:13 +01:00
. sources = clk_src_apll_list ,
. nr_sources = ARRAY_SIZE ( clk_src_apll_list ) ,
} ;
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
static struct clksrc_clk clk_mout_apll = {
. clk = {
. name = " mout_apll " ,
. id = - 1 ,
} ,
. sources = & clk_src_apll ,
2010-01-12 12:19:28 +09:00
. reg_src = { . reg = S5PC100_CLKSRC0 , . shift = 0 , . size = 1 , } ,
2009-11-17 08:41:13 +01:00
} ;
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
static unsigned long s5pc100_clk_dout_apll_get_rate ( struct clk * clk )
{
unsigned long rate = clk_get_rate ( clk - > parent ) ;
unsigned int ratio ;
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
ratio = __raw_readl ( S5PC100_CLKDIV0 ) & S5PC100_CLKDIV0_APLL_MASK ;
ratio > > = S5PC100_CLKDIV0_APLL_SHIFT ;
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
return rate / ( ratio + 1 ) ;
}
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
static struct clk clk_dout_apll = {
. name = " dout_apll " ,
2009-06-23 21:39:56 +09:00
. id = - 1 ,
2009-11-17 08:41:13 +01:00
. parent = & clk_mout_apll . clk ,
2009-12-01 01:24:37 +00:00
. ops = & ( struct clk_ops ) {
. get_rate = s5pc100_clk_dout_apll_get_rate ,
} ,
2009-06-23 21:39:56 +09:00
} ;
2009-11-17 08:41:13 +01:00
static unsigned long s5pc100_clk_arm_get_rate ( struct clk * clk )
{
unsigned long rate = clk_get_rate ( clk - > parent ) ;
unsigned int ratio ;
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
ratio = __raw_readl ( S5PC100_CLKDIV0 ) & S5PC100_CLKDIV0_ARM_MASK ;
ratio > > = S5PC100_CLKDIV0_ARM_SHIFT ;
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
return rate / ( ratio + 1 ) ;
}
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
static unsigned long s5pc100_clk_arm_round_rate ( struct clk * clk ,
unsigned long rate )
2009-06-23 21:39:56 +09:00
{
2009-11-17 08:41:13 +01:00
unsigned long parent = clk_get_rate ( clk - > parent ) ;
u32 div ;
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
if ( parent < rate )
return rate ;
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
div = ( parent / rate ) - 1 ;
if ( div > S5PC100_CLKDIV0_ARM_MASK )
div = S5PC100_CLKDIV0_ARM_MASK ;
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
return parent / ( div + 1 ) ;
2009-06-23 21:39:56 +09:00
}
2009-11-17 08:41:13 +01:00
static int s5pc100_clk_arm_set_rate ( struct clk * clk , unsigned long rate )
2009-06-23 21:39:56 +09:00
{
2009-11-17 08:41:13 +01:00
unsigned long parent = clk_get_rate ( clk - > parent ) ;
u32 div ;
u32 val ;
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
if ( rate < parent / ( S5PC100_CLKDIV0_ARM_MASK + 1 ) )
return - EINVAL ;
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
rate = clk_round_rate ( clk , rate ) ;
div = clk_get_rate ( clk - > parent ) / rate ;
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
val = __raw_readl ( S5PC100_CLKDIV0 ) ;
val & = S5PC100_CLKDIV0_ARM_MASK ;
val | = ( div - 1 ) ;
__raw_writel ( val , S5PC100_CLKDIV0 ) ;
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
return 0 ;
2009-06-23 21:39:56 +09:00
}
2009-11-17 08:41:13 +01:00
static struct clk clk_arm = {
. name = " armclk " ,
. id = - 1 ,
. parent = & clk_dout_apll ,
2009-12-01 01:24:37 +00:00
. ops = & ( struct clk_ops ) {
. get_rate = s5pc100_clk_arm_get_rate ,
. set_rate = s5pc100_clk_arm_set_rate ,
. round_rate = s5pc100_clk_arm_round_rate ,
} ,
2009-11-17 08:41:13 +01:00
} ;
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
static unsigned long s5pc100_clk_dout_d0_bus_get_rate ( struct clk * clk )
2009-06-23 21:39:56 +09:00
{
2009-11-17 08:41:13 +01:00
unsigned long rate = clk_get_rate ( clk - > parent ) ;
unsigned int ratio ;
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
ratio = __raw_readl ( S5PC100_CLKDIV0 ) & S5PC100_CLKDIV0_D0_MASK ;
ratio > > = S5PC100_CLKDIV0_D0_SHIFT ;
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
return rate / ( ratio + 1 ) ;
2009-06-23 21:39:56 +09:00
}
2009-11-17 08:41:13 +01:00
static struct clk clk_dout_d0_bus = {
. name = " dout_d0_bus " ,
. id = - 1 ,
. parent = & clk_arm ,
2009-12-01 01:24:37 +00:00
. ops = & ( struct clk_ops ) {
. get_rate = s5pc100_clk_dout_d0_bus_get_rate ,
} ,
2009-11-17 08:41:13 +01:00
} ;
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
static unsigned long s5pc100_clk_dout_pclkd0_get_rate ( struct clk * clk )
2009-06-23 21:39:56 +09:00
{
2009-11-17 08:41:13 +01:00
unsigned long rate = clk_get_rate ( clk - > parent ) ;
unsigned int ratio ;
ratio = __raw_readl ( S5PC100_CLKDIV0 ) & S5PC100_CLKDIV0_PCLKD0_MASK ;
ratio > > = S5PC100_CLKDIV0_PCLKD0_SHIFT ;
return rate / ( ratio + 1 ) ;
2009-06-23 21:39:56 +09:00
}
2009-11-17 08:41:13 +01:00
static struct clk clk_dout_pclkd0 = {
. name = " dout_pclkd0 " ,
. id = - 1 ,
. parent = & clk_dout_d0_bus ,
2009-12-01 01:24:37 +00:00
. ops = & ( struct clk_ops ) {
. get_rate = s5pc100_clk_dout_pclkd0_get_rate ,
} ,
2009-11-17 08:41:13 +01:00
} ;
static unsigned long s5pc100_clk_dout_apll2_get_rate ( struct clk * clk )
2009-06-23 21:39:56 +09:00
{
2009-11-17 08:41:13 +01:00
unsigned long rate = clk_get_rate ( clk - > parent ) ;
unsigned int ratio ;
ratio = __raw_readl ( S5PC100_CLKDIV1 ) & S5PC100_CLKDIV1_APLL2_MASK ;
ratio > > = S5PC100_CLKDIV1_APLL2_SHIFT ;
return rate / ( ratio + 1 ) ;
2009-06-23 21:39:56 +09:00
}
2009-11-17 08:41:13 +01:00
static struct clk clk_dout_apll2 = {
. name = " dout_apll2 " ,
. id = - 1 ,
. parent = & clk_mout_apll . clk ,
2009-12-01 01:24:37 +00:00
. ops = & ( struct clk_ops ) {
. get_rate = s5pc100_clk_dout_apll2_get_rate ,
} ,
2009-06-23 21:39:56 +09:00
} ;
2009-11-17 08:41:13 +01:00
/* MPLL */
static struct clk * clk_src_mpll_list [ ] = {
[ 0 ] = & clk_fin_mpll ,
[ 1 ] = & clk_fout_mpll ,
} ;
2009-06-23 21:39:56 +09:00
2010-01-12 12:19:28 +09:00
static struct clksrc_sources clk_src_mpll = {
2009-11-17 08:41:13 +01:00
. sources = clk_src_mpll_list ,
. nr_sources = ARRAY_SIZE ( clk_src_mpll_list ) ,
} ;
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
static struct clksrc_clk clk_mout_mpll = {
. clk = {
. name = " mout_mpll " ,
2009-06-23 21:39:56 +09:00
. id = - 1 ,
} ,
2009-11-17 08:41:13 +01:00
. sources = & clk_src_mpll ,
2010-01-12 12:19:28 +09:00
. reg_src = { . reg = S5PC100_CLKSRC0 , . shift = 4 , . size = 1 , } ,
2009-11-17 08:41:13 +01:00
} ;
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
static struct clk * clkset_am_list [ ] = {
[ 0 ] = & clk_mout_mpll . clk ,
[ 1 ] = & clk_dout_apll2 ,
} ;
2009-06-23 21:39:56 +09:00
2010-01-12 12:19:28 +09:00
static struct clksrc_sources clk_src_am = {
2009-11-17 08:41:13 +01:00
. sources = clkset_am_list ,
. nr_sources = ARRAY_SIZE ( clkset_am_list ) ,
} ;
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
static struct clksrc_clk clk_mout_am = {
. clk = {
. name = " mout_am " ,
2009-06-23 21:39:56 +09:00
. id = - 1 ,
} ,
2009-11-17 08:41:13 +01:00
. sources = & clk_src_am ,
2010-01-12 12:19:28 +09:00
. reg_src = { . reg = S5PC100_CLKSRC0 , . shift = 16 , . size = 1 , } ,
2009-11-17 08:41:13 +01:00
} ;
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
static unsigned long s5pc100_clk_dout_d1_bus_get_rate ( struct clk * clk )
{
unsigned long rate = clk_get_rate ( clk - > parent ) ;
unsigned int ratio ;
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
printk ( KERN_DEBUG " %s: parent is %ld \n " , __func__ , rate ) ;
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
ratio = __raw_readl ( S5PC100_CLKDIV1 ) & S5PC100_CLKDIV1_D1_MASK ;
ratio > > = S5PC100_CLKDIV1_D1_SHIFT ;
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
return rate / ( ratio + 1 ) ;
}
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
static struct clk clk_dout_d1_bus = {
. name = " dout_d1_bus " ,
. id = - 1 ,
. parent = & clk_mout_am . clk ,
2009-12-01 01:24:37 +00:00
. ops = & ( struct clk_ops ) {
. get_rate = s5pc100_clk_dout_d1_bus_get_rate ,
} ,
2009-11-17 08:41:13 +01:00
} ;
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
static struct clk * clkset_onenand_list [ ] = {
[ 0 ] = & clk_dout_d0_bus ,
[ 1 ] = & clk_dout_d1_bus ,
} ;
2010-01-12 12:19:28 +09:00
static struct clksrc_sources clk_src_onenand = {
2009-11-17 08:41:13 +01:00
. sources = clkset_onenand_list ,
. nr_sources = ARRAY_SIZE ( clkset_onenand_list ) ,
} ;
static struct clksrc_clk clk_mout_onenand = {
. clk = {
. name = " mout_onenand " ,
2009-06-23 21:39:56 +09:00
. id = - 1 ,
} ,
2009-11-17 08:41:13 +01:00
. sources = & clk_src_onenand ,
2010-01-12 12:19:28 +09:00
. reg_src = { . reg = S5PC100_CLKSRC0 , . shift = 24 , . size = 1 , } ,
2009-06-23 21:39:56 +09:00
} ;
2009-11-17 08:41:13 +01:00
static unsigned long s5pc100_clk_dout_pclkd1_get_rate ( struct clk * clk )
2009-06-23 21:39:56 +09:00
{
2009-11-17 08:41:13 +01:00
unsigned long rate = clk_get_rate ( clk - > parent ) ;
unsigned int ratio ;
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
printk ( KERN_DEBUG " %s: parent is %ld \n " , __func__ , rate ) ;
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
ratio = __raw_readl ( S5PC100_CLKDIV1 ) & S5PC100_CLKDIV1_PCLKD1_MASK ;
ratio > > = S5PC100_CLKDIV1_PCLKD1_SHIFT ;
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
return rate / ( ratio + 1 ) ;
}
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
static struct clk clk_dout_pclkd1 = {
. name = " dout_pclkd1 " ,
. id = - 1 ,
. parent = & clk_dout_d1_bus ,
2009-12-01 01:24:37 +00:00
. ops = & ( struct clk_ops ) {
. get_rate = s5pc100_clk_dout_pclkd1_get_rate ,
} ,
2009-11-17 08:41:13 +01:00
} ;
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
static unsigned long s5pc100_clk_dout_mpll2_get_rate ( struct clk * clk )
{
unsigned long rate = clk_get_rate ( clk - > parent ) ;
unsigned int ratio ;
printk ( KERN_DEBUG " %s: parent is %ld \n " , __func__ , rate ) ;
ratio = __raw_readl ( S5PC100_CLKDIV1 ) & S5PC100_CLKDIV1_MPLL2_MASK ;
ratio > > = S5PC100_CLKDIV1_MPLL2_SHIFT ;
return rate / ( ratio + 1 ) ;
2009-06-23 21:39:56 +09:00
}
2009-11-17 08:41:13 +01:00
static struct clk clk_dout_mpll2 = {
. name = " dout_mpll2 " ,
2009-06-23 21:39:56 +09:00
. id = - 1 ,
2009-11-17 08:41:13 +01:00
. parent = & clk_mout_am . clk ,
2009-12-01 01:24:37 +00:00
. ops = & ( struct clk_ops ) {
. get_rate = s5pc100_clk_dout_mpll2_get_rate ,
} ,
2009-06-23 21:39:56 +09:00
} ;
2009-11-17 08:41:13 +01:00
static unsigned long s5pc100_clk_dout_cam_get_rate ( struct clk * clk )
{
unsigned long rate = clk_get_rate ( clk - > parent ) ;
unsigned int ratio ;
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
printk ( KERN_DEBUG " %s: parent is %ld \n " , __func__ , rate ) ;
ratio = __raw_readl ( S5PC100_CLKDIV1 ) & S5PC100_CLKDIV1_CAM_MASK ;
ratio > > = S5PC100_CLKDIV1_CAM_SHIFT ;
return rate / ( ratio + 1 ) ;
}
static struct clk clk_dout_cam = {
. name = " dout_cam " ,
. id = - 1 ,
. parent = & clk_dout_mpll2 ,
2009-12-01 01:24:37 +00:00
. ops = & ( struct clk_ops ) {
. get_rate = s5pc100_clk_dout_cam_get_rate ,
} ,
2009-06-23 21:39:56 +09:00
} ;
2009-11-17 08:41:13 +01:00
static unsigned long s5pc100_clk_dout_mpll_get_rate ( struct clk * clk )
{
unsigned long rate = clk_get_rate ( clk - > parent ) ;
unsigned int ratio ;
printk ( KERN_DEBUG " %s: parent is %ld \n " , __func__ , rate ) ;
ratio = __raw_readl ( S5PC100_CLKDIV1 ) & S5PC100_CLKDIV1_MPLL_MASK ;
ratio > > = S5PC100_CLKDIV1_MPLL_SHIFT ;
return rate / ( ratio + 1 ) ;
}
static struct clk clk_dout_mpll = {
. name = " dout_mpll " ,
. id = - 1 ,
. parent = & clk_mout_am . clk ,
2009-12-01 01:24:37 +00:00
. ops = & ( struct clk_ops ) {
. get_rate = s5pc100_clk_dout_mpll_get_rate ,
} ,
2009-06-23 21:39:56 +09:00
} ;
2009-11-17 08:41:13 +01:00
/* EPLL */
2009-06-23 21:39:56 +09:00
static struct clk clk_fout_epll = {
. name = " fout_epll " ,
. id = - 1 ,
} ;
static struct clk * clk_src_epll_list [ ] = {
[ 0 ] = & clk_fin_epll ,
[ 1 ] = & clk_fout_epll ,
} ;
2010-01-12 12:19:28 +09:00
static struct clksrc_sources clk_src_epll = {
2009-06-23 21:39:56 +09:00
. sources = clk_src_epll_list ,
. nr_sources = ARRAY_SIZE ( clk_src_epll_list ) ,
} ;
static struct clksrc_clk clk_mout_epll = {
. clk = {
. name = " mout_epll " ,
. id = - 1 ,
} ,
2010-01-12 12:19:28 +09:00
. sources = & clk_src_epll ,
. reg_src = { . reg = S5PC100_CLKSRC0 , . shift = 8 , . size = 1 , } ,
2009-06-23 21:39:56 +09:00
} ;
2009-11-17 08:41:13 +01:00
/* HPLL */
static struct clk clk_fout_hpll = {
. name = " fout_hpll " ,
. id = - 1 ,
2009-06-23 21:39:56 +09:00
} ;
2009-11-17 08:41:13 +01:00
static struct clk * clk_src_hpll_list [ ] = {
[ 0 ] = & clk_27m ,
[ 1 ] = & clk_fout_hpll ,
2009-06-23 21:39:56 +09:00
} ;
2010-01-12 12:19:28 +09:00
static struct clksrc_sources clk_src_hpll = {
2009-11-17 08:41:13 +01:00
. sources = clk_src_hpll_list ,
. nr_sources = ARRAY_SIZE ( clk_src_hpll_list ) ,
} ;
static struct clksrc_clk clk_mout_hpll = {
. clk = {
. name = " mout_hpll " ,
2009-06-23 21:39:56 +09:00
. id = - 1 ,
} ,
2010-01-12 12:19:28 +09:00
. sources = & clk_src_hpll ,
. reg_src = { . reg = S5PC100_CLKSRC0 , . shift = 12 , . size = 1 , } ,
2009-06-23 21:39:56 +09:00
} ;
2009-11-17 08:41:13 +01:00
/* Peripherals */
/*
* The peripheral clocks are all controlled via clocksource followed
* by an optional divider and gate stage . We currently roll this into
* one clock which hides the intermediate clock from the mux .
*
* Note , the JPEG clock can only be an even divider . . .
*
* The scaler and LCD clocks depend on the S5PC100 version , and also
* have a common parent divisor so are not included here .
*/
2009-06-23 21:39:56 +09:00
2010-01-12 12:39:58 +09:00
static struct clk clk_iis_cd0 = {
. name = " iis_cdclk0 " ,
. id = - 1 ,
} ;
static struct clk clk_iis_cd1 = {
. name = " iis_cdclk1 " ,
. id = - 1 ,
} ;
static struct clk clk_iis_cd2 = {
. name = " iis_cdclk2 " ,
. id = - 1 ,
} ;
static struct clk clk_pcm_cd0 = {
. name = " pcm_cdclk0 " ,
. id = - 1 ,
} ;
static struct clk clk_pcm_cd1 = {
. name = " pcm_cdclk1 " ,
. id = - 1 ,
} ;
static struct clk * clkset_audio0_list [ ] = {
& clk_mout_epll . clk ,
& clk_dout_mpll ,
& clk_fin_epll ,
& clk_iis_cd0 ,
& clk_pcm_cd0 ,
& clk_mout_hpll . clk ,
} ;
static struct clksrc_sources clkset_audio0 = {
. sources = clkset_audio0_list ,
. nr_sources = ARRAY_SIZE ( clkset_audio0_list ) ,
} ;
2009-11-17 08:41:13 +01:00
static struct clk * clkset_spi_list [ ] = {
& clk_mout_epll . clk ,
& clk_dout_mpll2 ,
& clk_fin_epll ,
& clk_mout_hpll . clk ,
} ;
2010-01-12 12:19:28 +09:00
static struct clksrc_sources clkset_spi = {
2009-11-17 08:41:13 +01:00
. sources = clkset_spi_list ,
. nr_sources = ARRAY_SIZE ( clkset_spi_list ) ,
} ;
2010-01-12 12:39:58 +09:00
static struct clk * clkset_uart_list [ ] = {
& clk_mout_epll . clk ,
& clk_dout_mpll ,
} ;
static struct clksrc_sources clkset_uart = {
. sources = clkset_uart_list ,
. nr_sources = ARRAY_SIZE ( clkset_uart_list ) ,
} ;
static struct clk * clkset_audio1_list [ ] = {
& clk_mout_epll . clk ,
& clk_dout_mpll ,
& clk_fin_epll ,
& clk_iis_cd1 ,
& clk_pcm_cd1 ,
& clk_mout_hpll . clk ,
} ;
static struct clksrc_sources clkset_audio1 = {
. sources = clkset_audio1_list ,
. nr_sources = ARRAY_SIZE ( clkset_audio1_list ) ,
} ;
static struct clk * clkset_audio2_list [ ] = {
& clk_mout_epll . clk ,
& clk_dout_mpll ,
& clk_fin_epll ,
& clk_iis_cd2 ,
& clk_mout_hpll . clk ,
} ;
static struct clksrc_sources clkset_audio2 = {
. sources = clkset_audio2_list ,
. nr_sources = ARRAY_SIZE ( clkset_audio2_list ) ,
} ;
2010-01-12 12:49:17 +09:00
static struct clksrc_clk clksrc_audio [ ] = {
{
. clk = {
. name = " audio-bus " ,
. id = 0 ,
. ctrlbit = S5PC100_CLKGATE_SCLK1_AUDIO0 ,
. enable = s5pc100_sclk1_ctrl ,
} ,
. sources = & clkset_audio0 ,
. reg_div = { . reg = S5PC100_CLKDIV4 , . shift = 12 , . size = 4 , } ,
. reg_src = { . reg = S5PC100_CLKSRC3 , . shift = 12 , . size = 3 , } ,
} , {
. clk = {
. name = " audio-bus " ,
. id = 1 ,
. ctrlbit = S5PC100_CLKGATE_SCLK1_AUDIO1 ,
. enable = s5pc100_sclk1_ctrl ,
} ,
. sources = & clkset_audio1 ,
. reg_div = { . reg = S5PC100_CLKDIV4 , . shift = 16 , . size = 4 , } ,
. reg_src = { . reg = S5PC100_CLKSRC3 , . shift = 16 , . size = 3 , } ,
} , {
. clk = {
. name = " audio-bus " ,
. id = 2 ,
. ctrlbit = S5PC100_CLKGATE_SCLK1_AUDIO2 ,
. enable = s5pc100_sclk1_ctrl ,
} ,
. sources = & clkset_audio2 ,
. reg_div = { . reg = S5PC100_CLKDIV4 , . shift = 20 , . size = 4 , } ,
. reg_src = { . reg = S5PC100_CLKSRC3 , . shift = 20 , . size = 3 , } ,
} ,
} ;
2010-01-12 12:39:58 +09:00
static struct clk * clkset_spdif_list [ ] = {
2010-01-12 12:49:17 +09:00
& clksrc_audio [ 0 ] . clk ,
& clksrc_audio [ 1 ] . clk ,
& clksrc_audio [ 2 ] . clk ,
2010-01-12 12:39:58 +09:00
} ;
static struct clksrc_sources clkset_spdif = {
. sources = clkset_spdif_list ,
. nr_sources = ARRAY_SIZE ( clkset_spdif_list ) ,
} ;
static struct clk * clkset_lcd_fimc_list [ ] = {
& clk_mout_epll . clk ,
& clk_dout_mpll ,
& clk_mout_hpll . clk ,
& clk_vclk_54m ,
} ;
static struct clksrc_sources clkset_lcd_fimc = {
. sources = clkset_lcd_fimc_list ,
. nr_sources = ARRAY_SIZE ( clkset_lcd_fimc_list ) ,
} ;
static struct clk * clkset_mmc_list [ ] = {
& clk_mout_epll . clk ,
& clk_dout_mpll ,
& clk_fin_epll ,
& clk_mout_hpll . clk ,
} ;
static struct clksrc_sources clkset_mmc = {
. sources = clkset_mmc_list ,
. nr_sources = ARRAY_SIZE ( clkset_mmc_list ) ,
} ;
static struct clk * clkset_usbhost_list [ ] = {
& clk_mout_epll . clk ,
& clk_dout_mpll ,
& clk_mout_hpll . clk ,
& clk_48m ,
} ;
static struct clksrc_sources clkset_usbhost = {
. sources = clkset_usbhost_list ,
. nr_sources = ARRAY_SIZE ( clkset_usbhost_list ) ,
} ;
2010-01-12 12:49:17 +09:00
static struct clksrc_clk clksrc_clks [ ] = {
{
. clk = {
. name = " spi_bus " ,
. id = 0 ,
. ctrlbit = S5PC100_CLKGATE_SCLK0_SPI0 ,
. enable = s5pc100_sclk0_ctrl ,
} ,
. sources = & clkset_spi ,
. reg_div = { . reg = S5PC100_CLKDIV2 , . shift = 4 , . size = 4 , } ,
. reg_src = { . reg = S5PC100_CLKSRC1 , . shift = 4 , . size = 2 , } ,
} , {
. clk = {
. name = " spi_bus " ,
. id = 1 ,
. ctrlbit = S5PC100_CLKGATE_SCLK0_SPI1 ,
. enable = s5pc100_sclk0_ctrl ,
} ,
. sources = & clkset_spi ,
. reg_div = { . reg = S5PC100_CLKDIV2 , . shift = 8 , . size = 4 , } ,
. reg_src = { . reg = S5PC100_CLKSRC1 , . shift = 8 , . size = 2 , } ,
} , {
. clk = {
. name = " spi_bus " ,
. id = 2 ,
. ctrlbit = S5PC100_CLKGATE_SCLK0_SPI2 ,
. enable = s5pc100_sclk0_ctrl ,
} ,
. sources = & clkset_spi ,
. reg_div = { . reg = S5PC100_CLKDIV2 , . shift = 12 , . size = 4 , } ,
. reg_src = { . reg = S5PC100_CLKSRC1 , . shift = 12 , . size = 2 , } ,
} , {
. clk = {
. name = " uclk1 " ,
. id = - 1 ,
. ctrlbit = S5PC100_CLKGATE_SCLK0_UART ,
. enable = s5pc100_sclk0_ctrl ,
} ,
. sources = & clkset_uart ,
. reg_div = { . reg = S5PC100_CLKDIV2 , . shift = 0 , . size = 3 , } ,
. reg_src = { . reg = S5PC100_CLKSRC1 , . shift = 0 , . size = 1 , } ,
} , {
. clk = {
. name = " spdif " ,
. id = - 1 ,
} ,
. sources = & clkset_spdif ,
. reg_src = { . reg = S5PC100_CLKSRC3 , . shift = 24 , . size = 2 , } ,
} , {
. clk = {
. name = " lcd " ,
. id = - 1 ,
. ctrlbit = S5PC100_CLKGATE_SCLK1_LCD ,
. enable = s5pc100_sclk1_ctrl ,
} ,
. sources = & clkset_lcd_fimc ,
. reg_div = { . reg = S5PC100_CLKDIV3 , . shift = 12 , . size = 4 , } ,
. reg_src = { . reg = S5PC100_CLKSRC2 , . shift = 12 , . size = 2 , } ,
} , {
. clk = {
. name = " fimc " ,
. id = 0 ,
. ctrlbit = S5PC100_CLKGATE_SCLK1_FIMC0 ,
. enable = s5pc100_sclk1_ctrl ,
} ,
. sources = & clkset_lcd_fimc ,
. reg_div = { . reg = S5PC100_CLKDIV3 , . shift = 16 , . size = 4 , } ,
. reg_src = { . reg = S5PC100_CLKSRC2 , . shift = 16 , . size = 2 , } ,
} , {
. clk = {
. name = " fimc " ,
. id = 1 ,
. ctrlbit = S5PC100_CLKGATE_SCLK1_FIMC1 ,
. enable = s5pc100_sclk1_ctrl ,
} ,
. sources = & clkset_lcd_fimc ,
. reg_div = { . reg = S5PC100_CLKDIV3 , . shift = 20 , . size = 4 , } ,
. reg_src = { . reg = S5PC100_CLKSRC2 , . shift = 20 , . size = 2 , } ,
} , {
. clk = {
. name = " fimc " ,
. id = 2 ,
. ctrlbit = S5PC100_CLKGATE_SCLK1_FIMC2 ,
. enable = s5pc100_sclk1_ctrl ,
} ,
. sources = & clkset_lcd_fimc ,
. reg_div = { . reg = S5PC100_CLKDIV3 , . shift = 24 , . size = 4 , } ,
. reg_src = { . reg = S5PC100_CLKSRC2 , . shift = 24 , . size = 2 , } ,
} , {
. clk = {
. name = " mmc_bus " ,
. id = 0 ,
. ctrlbit = S5PC100_CLKGATE_SCLK0_MMC0 ,
. enable = s5pc100_sclk0_ctrl ,
} ,
. sources = & clkset_mmc ,
. reg_div = { . reg = S5PC100_CLKDIV3 , . shift = 0 , . size = 4 , } ,
. reg_src = { . reg = S5PC100_CLKSRC2 , . shift = 0 , . size = 2 , } ,
} , {
. clk = {
. name = " mmc_bus " ,
. id = 1 ,
. ctrlbit = S5PC100_CLKGATE_SCLK0_MMC1 ,
. enable = s5pc100_sclk0_ctrl ,
} ,
. sources = & clkset_mmc ,
. reg_div = { . reg = S5PC100_CLKDIV3 , . shift = 4 , . size = 4 , } ,
. reg_src = { . reg = S5PC100_CLKSRC2 , . shift = 4 , . size = 2 , } ,
} , {
. clk = {
. name = " mmc_bus " ,
. id = 2 ,
. ctrlbit = S5PC100_CLKGATE_SCLK0_MMC2 ,
. enable = s5pc100_sclk0_ctrl ,
} ,
. sources = & clkset_mmc ,
. reg_div = { . reg = S5PC100_CLKDIV3 , . shift = 8 , . size = 4 , } ,
. reg_src = { . reg = S5PC100_CLKSRC2 , . shift = 8 , . size = 2 , } ,
} , {
. clk = {
. name = " usbhost " ,
. id = - 1 ,
. ctrlbit = S5PC100_CLKGATE_SCLK0_USBHOST ,
. enable = s5pc100_sclk0_ctrl ,
} ,
. sources = & clkset_usbhost ,
. reg_div = { . reg = S5PC100_CLKDIV2 , . shift = 20 , . size = 4 , } ,
. reg_src = { . reg = S5PC100_CLKSRC1 , . shift = 20 , . size = 2 , } ,
}
2009-11-17 08:41:13 +01:00
} ;
2009-06-23 21:39:56 +09:00
/* Clock initialisation code */
static struct clksrc_clk * init_parents [ ] = {
& clk_mout_apll ,
& clk_mout_mpll ,
2009-11-17 08:41:13 +01:00
& clk_mout_am ,
& clk_mout_onenand ,
& clk_mout_epll ,
& clk_mout_hpll ,
2009-06-23 21:39:56 +09:00
} ;
# define GET_DIV(clk, field) ((((clk) & field##_MASK) >> field##_SHIFT) + 1)
void __init_or_cpufreq s5pc100_setup_clocks ( void )
{
struct clk * xtal_clk ;
unsigned long xtal ;
unsigned long armclk ;
unsigned long hclkd0 ;
unsigned long hclk ;
unsigned long pclkd0 ;
unsigned long pclk ;
2009-11-17 08:41:13 +01:00
unsigned long apll , mpll , epll , hpll ;
2009-06-23 21:39:56 +09:00
unsigned int ptr ;
u32 clkdiv0 , clkdiv1 ;
printk ( KERN_DEBUG " %s: registering clocks \n " , __func__ ) ;
2009-11-17 08:41:12 +01:00
clkdiv0 = __raw_readl ( S5PC100_CLKDIV0 ) ;
clkdiv1 = __raw_readl ( S5PC100_CLKDIV1 ) ;
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:13 +01:00
printk ( KERN_DEBUG " %s: clkdiv0 = %08x, clkdiv1 = %08x \n " , __func__ , clkdiv0 , clkdiv1 ) ;
2009-06-23 21:39:56 +09:00
xtal_clk = clk_get ( NULL , " xtal " ) ;
BUG_ON ( IS_ERR ( xtal_clk ) ) ;
xtal = clk_get_rate ( xtal_clk ) ;
clk_put ( xtal_clk ) ;
printk ( KERN_DEBUG " %s: xtal is %ld \n " , __func__ , xtal ) ;
2009-11-17 08:41:12 +01:00
apll = s5pc1xx_get_pll ( xtal , __raw_readl ( S5PC100_APLL_CON ) ) ;
mpll = s5pc1xx_get_pll ( xtal , __raw_readl ( S5PC100_MPLL_CON ) ) ;
epll = s5pc1xx_get_pll ( xtal , __raw_readl ( S5PC100_EPLL_CON ) ) ;
2009-06-23 21:39:56 +09:00
hpll = s5pc1xx_get_pll ( xtal , __raw_readl ( S5PC100_HPLL_CON ) ) ;
2009-11-17 08:41:13 +01:00
printk ( KERN_INFO " S5PC100: Apll=%ld.%03ld Mhz, Mpll=%ld.%03ld Mhz "
" , Epll=%ld.%03ld Mhz, Hpll=%ld.%03ld Mhz \n " ,
print_mhz ( apll ) , print_mhz ( mpll ) ,
print_mhz ( epll ) , print_mhz ( hpll ) ) ;
2009-06-23 21:39:56 +09:00
2009-11-17 08:41:12 +01:00
armclk = apll / GET_DIV ( clkdiv0 , S5PC100_CLKDIV0_APLL ) ;
2009-06-23 21:39:56 +09:00
armclk = armclk / GET_DIV ( clkdiv0 , S5PC100_CLKDIV0_ARM ) ;
hclkd0 = armclk / GET_DIV ( clkdiv0 , S5PC100_CLKDIV0_D0 ) ;
pclkd0 = hclkd0 / GET_DIV ( clkdiv0 , S5PC100_CLKDIV0_PCLKD0 ) ;
hclk = mpll / GET_DIV ( clkdiv1 , S5PC100_CLKDIV1_D1 ) ;
pclk = hclk / GET_DIV ( clkdiv1 , S5PC100_CLKDIV1_PCLKD1 ) ;
2009-11-17 08:41:13 +01:00
printk ( KERN_INFO " S5PC100: ARMCLK=%ld.%03ld MHz, HCLKD0=%ld.%03ld MHz, "
" PCLKD0=%ld.%03ld MHz \n , HCLK=%ld.%03ld MHz, "
" PCLK=%ld.%03ld MHz \n " ,
print_mhz ( armclk ) , print_mhz ( hclkd0 ) ,
print_mhz ( pclkd0 ) , print_mhz ( hclk ) , print_mhz ( pclk ) ) ;
2009-06-23 21:39:56 +09:00
clk_fout_apll . rate = apll ;
clk_fout_mpll . rate = mpll ;
clk_fout_epll . rate = epll ;
2009-11-17 08:41:13 +01:00
clk_fout_hpll . rate = hpll ;
2009-06-23 21:39:56 +09:00
clk_h . rate = hclk ;
clk_p . rate = pclk ;
2009-11-17 08:41:13 +01:00
clk_f . rate = armclk ;
2009-06-23 21:39:56 +09:00
for ( ptr = 0 ; ptr < ARRAY_SIZE ( init_parents ) ; ptr + + )
2010-01-12 12:19:28 +09:00
s3c_set_clksrc ( init_parents [ ptr ] , true ) ;
2010-01-12 12:49:17 +09:00
for ( ptr = 0 ; ptr < ARRAY_SIZE ( clksrc_audio ) ; ptr + + )
s3c_set_clksrc ( clksrc_audio + ptr , true ) ;
for ( ptr = 0 ; ptr < ARRAY_SIZE ( clksrc_clks ) ; ptr + + )
s3c_set_clksrc ( clksrc_clks + ptr , true ) ;
2009-06-23 21:39:56 +09:00
}
static struct clk * clks [ ] __initdata = {
& clk_ext_xtal_mux ,
2009-11-17 08:41:13 +01:00
& clk_dout_apll ,
& clk_dout_d0_bus ,
& clk_dout_pclkd0 ,
& clk_dout_apll2 ,
2010-01-12 12:49:17 +09:00
& clk_mout_apll . clk ,
& clk_mout_mpll . clk ,
& clk_mout_epll . clk ,
& clk_mout_hpll . clk ,
2009-11-17 08:41:13 +01:00
& clk_mout_am . clk ,
& clk_dout_d1_bus ,
2010-01-12 12:49:17 +09:00
& clk_mout_onenand . clk ,
2009-11-17 08:41:13 +01:00
& clk_dout_pclkd1 ,
& clk_dout_mpll2 ,
& clk_dout_cam ,
2009-06-23 21:39:56 +09:00
& clk_dout_mpll ,
2009-11-17 08:41:13 +01:00
& clk_fout_epll ,
& clk_iis_cd0 ,
& clk_iis_cd1 ,
& clk_iis_cd2 ,
& clk_pcm_cd0 ,
& clk_pcm_cd1 ,
& clk_arm ,
2009-06-23 21:39:56 +09:00
} ;
void __init s5pc100_register_clocks ( void )
{
struct clk * clkp ;
int ret ;
int ptr ;
for ( ptr = 0 ; ptr < ARRAY_SIZE ( clks ) ; ptr + + ) {
clkp = clks [ ptr ] ;
ret = s3c24xx_register_clock ( clkp ) ;
if ( ret < 0 ) {
printk ( KERN_ERR " Failed to register clock %s (%d) \n " ,
clkp - > name , ret ) ;
}
}
2010-01-12 12:19:28 +09:00
2010-01-12 12:49:17 +09:00
s3c_register_clksrc ( clksrc_audio , ARRAY_SIZE ( clksrc_audio ) ) ;
s3c_register_clksrc ( clksrc_clks , ARRAY_SIZE ( clksrc_clks ) ) ;
2009-06-23 21:39:56 +09:00
}