2007-02-11 20:31:01 +03:00
/* linux/arch/arm/mach-s3c2442/s3c2442.c
2006-06-19 02:06:41 +04:00
*
2010-01-26 10:13:35 +03:00
* Copyright ( c ) 2004 - 2005 Simtec Electronics
* http : //armlinux.simtec.co.uk/
* Ben Dooks < ben @ simtec . co . uk >
2006-06-19 02:06:41 +04:00
*
2010-01-26 10:13:35 +03:00
* S3C2442 core and lock support
2006-06-19 02:06:41 +04:00
*
* This program is free software ; you can redistribute it and / or modify
2010-01-26 10:13:35 +03:00
* 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
2006-06-19 02:06:41 +04:00
*/
2010-01-26 10:13:35 +03:00
# include <linux/init.h>
# include <linux/module.h>
2006-06-19 02:06:41 +04:00
# include <linux/kernel.h>
# include <linux/list.h>
2010-01-26 10:13:35 +03:00
# include <linux/errno.h>
# include <linux/err.h>
# include <linux/device.h>
2006-06-19 02:06:41 +04:00
# include <linux/sysdev.h>
2011-04-23 00:03:21 +04:00
# include <linux/syscore_ops.h>
2010-01-26 10:13:35 +03:00
# include <linux/interrupt.h>
# include <linux/ioport.h>
# include <linux/mutex.h>
2010-12-01 09:29:23 +03:00
# include <linux/gpio.h>
2010-01-26 10:13:35 +03:00
# include <linux/clk.h>
# include <linux/io.h>
2006-06-19 02:06:41 +04:00
2010-01-26 10:13:35 +03:00
# include <mach/hardware.h>
2011-07-27 03:09:06 +04:00
# include <linux/atomic.h>
2010-01-26 10:13:35 +03:00
# include <asm/irq.h>
# include <mach/regs-clock.h>
# include <plat/clock.h>
2008-10-08 01:26:09 +04:00
# include <plat/cpu.h>
2010-12-01 09:29:23 +03:00
# include <plat/s3c244x.h>
2011-04-23 00:03:21 +04:00
# include <plat/pm.h>
2010-12-01 09:29:23 +03:00
# include <plat/gpio-core.h>
# include <plat/gpio-cfg.h>
# include <plat/gpio-cfg-helpers.h>
2006-06-19 02:06:41 +04:00
2010-01-26 10:13:35 +03:00
/* S3C2442 extended clock support */
static unsigned long s3c2442_camif_upll_round ( struct clk * clk ,
unsigned long rate )
{
unsigned long parent_rate = clk_get_rate ( clk - > parent ) ;
int div ;
if ( rate > parent_rate )
return parent_rate ;
div = parent_rate / rate ;
if ( div = = 3 )
return parent_rate / 3 ;
/* note, we remove the +/- 1 calculations for the divisor */
div / = 2 ;
if ( div < 1 )
div = 1 ;
else if ( div > 16 )
div = 16 ;
return parent_rate / ( div * 2 ) ;
}
static int s3c2442_camif_upll_setrate ( struct clk * clk , unsigned long rate )
{
unsigned long parent_rate = clk_get_rate ( clk - > parent ) ;
unsigned long camdivn = __raw_readl ( S3C2440_CAMDIVN ) ;
rate = s3c2442_camif_upll_round ( clk , rate ) ;
camdivn & = ~ S3C2442_CAMDIVN_CAMCLK_DIV3 ;
if ( rate = = parent_rate ) {
camdivn & = ~ S3C2440_CAMDIVN_CAMCLK_SEL ;
} else if ( ( parent_rate / rate ) = = 3 ) {
camdivn | = S3C2440_CAMDIVN_CAMCLK_SEL ;
camdivn | = S3C2442_CAMDIVN_CAMCLK_DIV3 ;
} else {
camdivn & = ~ S3C2440_CAMDIVN_CAMCLK_MASK ;
camdivn | = S3C2440_CAMDIVN_CAMCLK_SEL ;
camdivn | = ( ( ( parent_rate / rate ) / 2 ) - 1 ) ;
}
__raw_writel ( camdivn , S3C2440_CAMDIVN ) ;
return 0 ;
}
/* Extra S3C2442 clocks */
static struct clk s3c2442_clk_cam = {
. name = " camif " ,
. id = - 1 ,
. enable = s3c2410_clkcon_enable ,
. ctrlbit = S3C2440_CLKCON_CAMERA ,
} ;
static struct clk s3c2442_clk_cam_upll = {
. name = " camif-upll " ,
. id = - 1 ,
. ops = & ( struct clk_ops ) {
. set_rate = s3c2442_camif_upll_setrate ,
. round_rate = s3c2442_camif_upll_round ,
} ,
} ;
static int s3c2442_clk_add ( struct sys_device * sysdev )
{
struct clk * clock_upll ;
struct clk * clock_h ;
struct clk * clock_p ;
clock_p = clk_get ( NULL , " pclk " ) ;
clock_h = clk_get ( NULL , " hclk " ) ;
clock_upll = clk_get ( NULL , " upll " ) ;
if ( IS_ERR ( clock_p ) | | IS_ERR ( clock_h ) | | IS_ERR ( clock_upll ) ) {
printk ( KERN_ERR " S3C2442: Failed to get parent clocks \n " ) ;
return - EINVAL ;
}
s3c2442_clk_cam . parent = clock_h ;
s3c2442_clk_cam_upll . parent = clock_upll ;
s3c24xx_register_clock ( & s3c2442_clk_cam ) ;
s3c24xx_register_clock ( & s3c2442_clk_cam_upll ) ;
clk_disable ( & s3c2442_clk_cam ) ;
return 0 ;
}
static struct sysdev_driver s3c2442_clk_driver = {
. add = s3c2442_clk_add ,
} ;
static __init int s3c2442_clk_init ( void )
{
return sysdev_driver_register ( & s3c2442_sysclass , & s3c2442_clk_driver ) ;
}
arch_initcall ( s3c2442_clk_init ) ;
2006-06-19 02:06:41 +04:00
static struct sys_device s3c2442_sysdev = {
. cls = & s3c2442_sysclass ,
} ;
int __init s3c2442_init ( void )
{
printk ( " S3C2442: Initialising architecture \n " ) ;
2011-04-23 00:03:21 +04:00
register_syscore_ops ( & s3c2410_pm_syscore_ops ) ;
register_syscore_ops ( & s3c244x_pm_syscore_ops ) ;
register_syscore_ops ( & s3c24xx_irq_syscore_ops ) ;
2006-06-19 02:06:41 +04:00
return sysdev_register ( & s3c2442_sysdev ) ;
}
2010-12-01 09:29:23 +03:00
void __init s3c2442_map_io ( void )
{
s3c244x_map_io ( ) ;
s3c24xx_gpiocfg_default . set_pull = s3c_gpio_setpull_1down ;
s3c24xx_gpiocfg_default . get_pull = s3c_gpio_getpull_1down ;
}