2005-04-16 15:20:36 -07:00
/*
* linux / arch / arm / mach - pxa / pxa25x . c
*
* Author : Nicolas Pitre
* Created : Jun 15 , 2001
* Copyright : MontaVista Software Inc .
*
* Code specific to PXA21x / 25 x / 26 x variants .
*
* 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 .
*
* Since this file should be linked before any other machine specific file ,
* the __initcall ( ) here will be executed first . This serves as default
* initialization stuff for PXA machines which can be overridden later if
* need be .
*/
2005-06-13 22:35:41 +01:00
# include <linux/config.h>
2005-04-16 15:20:36 -07:00
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/pm.h>
# include <asm/hardware.h>
# include <asm/arch/pxa-regs.h>
# include "generic.h"
/*
* Various clock factors driven by the CCCR register .
*/
/* Crystal Frequency to Memory Frequency Multiplier (L) */
static unsigned char L_clk_mult [ 32 ] = { 0 , 27 , 32 , 36 , 40 , 45 , 0 , } ;
/* Memory Frequency to Run Mode Frequency Multiplier (M) */
static unsigned char M_clk_mult [ 4 ] = { 0 , 1 , 2 , 4 } ;
/* Run Mode Frequency to Turbo Mode Frequency Multiplier (N) */
/* Note: we store the value N * 2 here. */
static unsigned char N2_clk_mult [ 8 ] = { 0 , 0 , 2 , 3 , 4 , 0 , 6 , 0 } ;
/* Crystal clock */
# define BASE_CLK 3686400
/*
* Get the clock frequency as reflected by CCCR and the turbo flag .
* We assume these values have been applied via a fcs .
* If info is not 0 we also display the current settings .
*/
unsigned int get_clk_frequency_khz ( int info )
{
unsigned long cccr , turbo ;
unsigned int l , L , m , M , n2 , N ;
cccr = CCCR ;
asm ( " mrc \t p14, 0, %0, c6, c0, 0 " : " =r " ( turbo ) ) ;
l = L_clk_mult [ ( cccr > > 0 ) & 0x1f ] ;
m = M_clk_mult [ ( cccr > > 5 ) & 0x03 ] ;
n2 = N2_clk_mult [ ( cccr > > 7 ) & 0x07 ] ;
L = l * BASE_CLK ;
M = m * L ;
N = n2 * M / 2 ;
if ( info )
{
L + = 5000 ;
printk ( KERN_INFO " Memory clock: %d.%02dMHz (*%d) \n " ,
L / 1000000 , ( L % 1000000 ) / 10000 , l ) ;
M + = 5000 ;
printk ( KERN_INFO " Run Mode clock: %d.%02dMHz (*%d) \n " ,
M / 1000000 , ( M % 1000000 ) / 10000 , m ) ;
N + = 5000 ;
printk ( KERN_INFO " Turbo Mode clock: %d.%02dMHz (*%d.%d, %sactive) \n " ,
N / 1000000 , ( N % 1000000 ) / 10000 , n2 / 2 , ( n2 % 2 ) * 5 ,
( turbo & 1 ) ? " " : " in " ) ;
}
return ( turbo & 1 ) ? ( N / 1000 ) : ( M / 1000 ) ;
}
EXPORT_SYMBOL ( get_clk_frequency_khz ) ;
/*
* Return the current memory clock frequency in units of 10 kHz
*/
unsigned int get_memclk_frequency_10khz ( void )
{
return L_clk_mult [ ( CCCR > > 0 ) & 0x1f ] * BASE_CLK / 10000 ;
}
EXPORT_SYMBOL ( get_memclk_frequency_10khz ) ;
/*
* Return the current LCD clock frequency in units of 10 kHz
*/
unsigned int get_lcdclk_frequency_10khz ( void )
{
return get_memclk_frequency_10khz ( ) ;
}
EXPORT_SYMBOL ( get_lcdclk_frequency_10khz ) ;
2005-06-03 20:52:27 +01:00
2005-06-13 22:35:41 +01:00
# ifdef CONFIG_PM
2005-06-03 20:52:27 +01:00
int pxa_cpu_pm_prepare ( suspend_state_t state )
{
switch ( state ) {
case PM_SUSPEND_MEM :
break ;
default :
return - EINVAL ;
}
return 0 ;
}
void pxa_cpu_pm_enter ( suspend_state_t state )
{
extern void pxa_cpu_suspend ( unsigned int ) ;
extern void pxa_cpu_resume ( void ) ;
CKEN = 0 ;
switch ( state ) {
case PM_SUSPEND_MEM :
/* set resume return address */
PSPR = virt_to_phys ( pxa_cpu_resume ) ;
2005-10-28 16:25:01 +01:00
pxa_cpu_suspend ( PWRMODE_SLEEP ) ;
2005-06-03 20:52:27 +01:00
break ;
}
}
2005-06-13 22:35:41 +01:00
# endif