2011-03-30 09:27:47 +02:00
/*
* 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 .
*
* Copyright ( C ) 2010 Thomas Langer < thomas . langer @ lantiq . com >
* Copyright ( C ) 2010 John Crispin < blogic @ openwrt . org >
*/
# include <linux/io.h>
2011-11-10 21:33:07 +01:00
# include <linux/export.h>
2011-03-30 09:27:47 +02:00
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/types.h>
# include <linux/clk.h>
2012-04-17 15:53:19 +02:00
# include <linux/clkdev.h>
2011-03-30 09:27:47 +02:00
# include <linux/err.h>
# include <linux/list.h>
# include <asm/time.h>
# include <asm/irq.h>
# include <asm/div64.h>
# include <lantiq_soc.h>
# include "clk.h"
2012-04-17 15:53:19 +02:00
# include "prom.h"
2011-03-30 09:27:47 +02:00
2012-04-17 15:53:19 +02:00
/* lantiq socs have 3 static clocks */
2013-01-19 08:54:24 +00:00
static struct clk cpu_clk_generic [ 4 ] ;
2011-03-30 09:27:47 +02:00
2013-01-19 08:54:24 +00:00
void clkdev_add_static ( unsigned long cpu , unsigned long fpi ,
unsigned long io , unsigned long ppe )
2012-04-17 15:53:19 +02:00
{
cpu_clk_generic [ 0 ] . rate = cpu ;
cpu_clk_generic [ 1 ] . rate = fpi ;
cpu_clk_generic [ 2 ] . rate = io ;
2013-01-19 08:54:24 +00:00
cpu_clk_generic [ 3 ] . rate = ppe ;
2012-04-17 15:53:19 +02:00
}
2011-03-30 09:27:47 +02:00
2012-04-17 15:53:19 +02:00
struct clk * clk_get_cpu ( void )
{
return & cpu_clk_generic [ 0 ] ;
}
struct clk * clk_get_fpi ( void )
{
return & cpu_clk_generic [ 1 ] ;
}
EXPORT_SYMBOL_GPL ( clk_get_fpi ) ;
struct clk * clk_get_io ( void )
2011-03-30 09:27:47 +02:00
{
2012-04-17 15:53:19 +02:00
return & cpu_clk_generic [ 2 ] ;
2011-03-30 09:27:47 +02:00
}
2013-01-19 08:54:24 +00:00
struct clk * clk_get_ppe ( void )
{
return & cpu_clk_generic [ 3 ] ;
}
EXPORT_SYMBOL_GPL ( clk_get_ppe ) ;
2011-03-30 09:27:47 +02:00
static inline int clk_good ( struct clk * clk )
{
return clk & & ! IS_ERR ( clk ) ;
}
unsigned long clk_get_rate ( struct clk * clk )
{
if ( unlikely ( ! clk_good ( clk ) ) )
return 0 ;
if ( clk - > rate ! = 0 )
return clk - > rate ;
if ( clk - > get_rate ! = NULL )
return clk - > get_rate ( ) ;
return 0 ;
}
EXPORT_SYMBOL ( clk_get_rate ) ;
2012-04-17 15:53:19 +02:00
int clk_set_rate ( struct clk * clk , unsigned long rate )
2011-03-30 09:27:47 +02:00
{
2012-04-17 15:53:19 +02:00
if ( unlikely ( ! clk_good ( clk ) ) )
return 0 ;
if ( clk - > rates & & * clk - > rates ) {
unsigned long * r = clk - > rates ;
while ( * r & & ( * r ! = rate ) )
r + + ;
if ( ! * r ) {
pr_err ( " clk %s.%s: trying to set invalid rate %ld \n " ,
clk - > cl . dev_id , clk - > cl . con_id , rate ) ;
return - 1 ;
}
}
clk - > rate = rate ;
return 0 ;
2011-03-30 09:27:47 +02:00
}
2012-04-17 15:53:19 +02:00
EXPORT_SYMBOL ( clk_set_rate ) ;
2011-03-30 09:27:47 +02:00
2011-06-09 20:15:21 +02:00
int clk_enable ( struct clk * clk )
{
2012-04-17 15:53:19 +02:00
if ( unlikely ( ! clk_good ( clk ) ) )
return - 1 ;
if ( clk - > enable )
return clk - > enable ( clk ) ;
return - 1 ;
2011-06-09 20:15:21 +02:00
}
EXPORT_SYMBOL ( clk_enable ) ;
void clk_disable ( struct clk * clk )
{
2012-04-17 15:53:19 +02:00
if ( unlikely ( ! clk_good ( clk ) ) )
return ;
if ( clk - > disable )
clk - > disable ( clk ) ;
2011-06-09 20:15:21 +02:00
}
EXPORT_SYMBOL ( clk_disable ) ;
2012-04-17 15:53:19 +02:00
int clk_activate ( struct clk * clk )
{
if ( unlikely ( ! clk_good ( clk ) ) )
return - 1 ;
if ( clk - > activate )
return clk - > activate ( clk ) ;
return - 1 ;
}
EXPORT_SYMBOL ( clk_activate ) ;
void clk_deactivate ( struct clk * clk )
{
if ( unlikely ( ! clk_good ( clk ) ) )
return ;
if ( clk - > deactivate )
clk - > deactivate ( clk ) ;
}
EXPORT_SYMBOL ( clk_deactivate ) ;
2012-07-22 08:56:01 +02:00
struct clk * of_clk_get_from_provider ( struct of_phandle_args * clkspec )
{
return NULL ;
}
2012-04-17 15:53:19 +02:00
static inline u32 get_counter_resolution ( void )
2011-03-30 09:27:47 +02:00
{
u32 res ;
__asm__ __volatile__ (
2013-01-22 12:59:30 +01:00
" .set push \n "
" .set mips32r2 \n "
" rdhwr %0, $3 \n "
2011-03-30 09:27:47 +02:00
" .set pop \n "
: " =&r " ( res )
: /* no input */
: " memory " ) ;
return res ;
}
void __init plat_time_init ( void )
{
struct clk * clk ;
2012-04-17 15:53:19 +02:00
ltq_soc_init ( ) ;
2011-03-30 09:27:47 +02:00
2012-04-17 15:53:19 +02:00
clk = clk_get_cpu ( ) ;
mips_hpt_frequency = clk_get_rate ( clk ) / get_counter_resolution ( ) ;
2011-03-30 09:27:47 +02:00
write_c0_compare ( read_c0_count ( ) ) ;
2012-04-17 15:53:19 +02:00
pr_info ( " CPU Clock: %ldMHz \n " , clk_get_rate ( clk ) / 1000000 ) ;
2011-03-30 09:27:47 +02:00
clk_put ( clk ) ;
}