2008-01-28 13:01:34 +01:00
/* linux/arch/arm/plat-s3c24xx/s3c24xx-clock.c
*
2009-11-13 22:54:14 +00:00
* Copyright ( c ) 2004 - 2008 Simtec Electronics
2008-01-28 13:01:34 +01:00
* http : //armlinux.simtec.co.uk/
* Ben Dooks < ben @ simtec . co . uk >
*
* S3C2440 / S3C2442 Common clock 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>
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/list.h>
# include <linux/errno.h>
# include <linux/err.h>
# include <linux/device.h>
# include <linux/interrupt.h>
# include <linux/ioport.h>
# include <linux/clk.h>
2008-09-06 12:10:45 +01:00
# include <linux/io.h>
2008-01-28 13:01:34 +01:00
2008-08-05 16:14:15 +01:00
# include <mach/hardware.h>
2011-07-26 16:09:06 -07:00
# include <linux/atomic.h>
2008-01-28 13:01:34 +01:00
# include <asm/irq.h>
2008-08-05 16:14:15 +01:00
# include <mach/regs-clock.h>
2008-01-28 13:01:34 +01:00
2008-10-07 23:09:51 +01:00
# include <plat/clock.h>
2008-10-07 22:26:09 +01:00
# include <plat/cpu.h>
2008-01-28 13:01:34 +01:00
2008-01-28 13:01:35 +01:00
static int s3c2440_setparent_armclk ( struct clk * clk , struct clk * parent )
{
unsigned long camdivn ;
unsigned long dvs ;
if ( parent = = & clk_f )
dvs = 0 ;
else if ( parent = = & clk_h )
dvs = S3C2440_CAMDIVN_DVSEN ;
else
return - EINVAL ;
clk - > parent = parent ;
camdivn = __raw_readl ( S3C2440_CAMDIVN ) ;
camdivn & = ~ S3C2440_CAMDIVN_DVSEN ;
camdivn | = dvs ;
__raw_writel ( camdivn , S3C2440_CAMDIVN ) ;
return 0 ;
}
static struct clk clk_arm = {
. name = " armclk " ,
. id = - 1 ,
2009-12-01 01:24:37 +00:00
. ops = & ( struct clk_ops ) {
. set_parent = s3c2440_setparent_armclk ,
} ,
2008-01-28 13:01:35 +01:00
} ;
2012-01-27 15:35:25 +09:00
static int s3c244x_clk_add ( struct device * dev , struct subsys_interface * sif )
2008-01-28 13:01:34 +01:00
{
unsigned long camdivn = __raw_readl ( S3C2440_CAMDIVN ) ;
unsigned long clkdivn ;
struct clk * clock_upll ;
2008-01-28 13:01:35 +01:00
int ret ;
2008-01-28 13:01:34 +01:00
printk ( " S3C244X: Clock Support, DVS %s \n " ,
( camdivn & S3C2440_CAMDIVN_DVSEN ) ? " on " : " off " ) ;
2008-01-28 13:01:35 +01:00
clk_arm . parent = ( camdivn & S3C2440_CAMDIVN_DVSEN ) ? & clk_h : & clk_f ;
ret = s3c24xx_register_clock ( & clk_arm ) ;
if ( ret < 0 ) {
printk ( KERN_ERR " S3C24XX: Failed to add armclk (%d) \n " , ret ) ;
return ret ;
}
2008-01-28 13:01:34 +01:00
clock_upll = clk_get ( NULL , " upll " ) ;
if ( IS_ERR ( clock_upll ) ) {
printk ( KERN_ERR " S3C244X: Failed to get upll clock \n " ) ;
return - ENOENT ;
}
/* check rate of UPLL, and if it is near 96MHz, then change
* to using half the UPLL rate for the system */
if ( clk_get_rate ( clock_upll ) > ( 94 * MHZ ) ) {
clk_usb_bus . rate = clk_get_rate ( clock_upll ) / 2 ;
2008-10-21 14:06:37 +01:00
spin_lock ( & clocks_lock ) ;
2008-01-28 13:01:34 +01:00
clkdivn = __raw_readl ( S3C2410_CLKDIVN ) ;
clkdivn | = S3C2440_CLKDIVN_UCLK ;
__raw_writel ( clkdivn , S3C2410_CLKDIVN ) ;
2008-10-21 14:06:37 +01:00
spin_unlock ( & clocks_lock ) ;
2008-01-28 13:01:34 +01:00
}
return 0 ;
}
2011-12-21 16:01:38 -08:00
static struct subsys_interface s3c2440_clk_interface = {
. name = " s3c2440_clk " ,
. subsys = & s3c2440_subsys ,
. add_dev = s3c244x_clk_add ,
2008-01-28 13:01:34 +01:00
} ;
static int s3c2440_clk_init ( void )
{
2011-12-21 16:01:38 -08:00
return subsys_interface_register ( & s3c2440_clk_interface ) ;
2008-01-28 13:01:34 +01:00
}
arch_initcall ( s3c2440_clk_init ) ;
2011-12-21 16:01:38 -08:00
static struct subsys_interface s3c2442_clk_interface = {
. name = " s3c2442_clk " ,
. subsys = & s3c2442_subsys ,
. add_dev = s3c244x_clk_add ,
2008-01-28 13:01:34 +01:00
} ;
static int s3c2442_clk_init ( void )
{
2011-12-21 16:01:38 -08:00
return subsys_interface_register ( & s3c2442_clk_interface ) ;
2008-01-28 13:01:34 +01:00
}
arch_initcall ( s3c2442_clk_init ) ;