2015-02-26 19:42:07 +03:00
/*
* r8a7778 Core CPG Clocks
*
* Copyright ( C ) 2014 Ulrich Hecht
*
* 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 ; version 2 of the License .
*/
# include <linux/clk-provider.h>
2016-03-08 03:42:07 +03:00
# include <linux/clk/renesas.h>
2015-02-26 19:42:07 +03:00
# include <linux/of_address.h>
2015-06-23 16:09:27 +03:00
# include <linux/slab.h>
2016-06-01 15:46:01 +03:00
# include <linux/soc/renesas/rcar-rst.h>
2015-02-26 19:42:07 +03:00
struct r8a7778_cpg {
struct clk_onecell_data data ;
spinlock_t lock ;
void __iomem * reg ;
} ;
/* PLL multipliers per bits 11, 12, and 18 of MODEMR */
2015-10-16 18:14:55 +03:00
static const struct {
2015-02-26 19:42:07 +03:00
unsigned long plla_mult ;
unsigned long pllb_mult ;
2015-10-16 18:14:55 +03:00
} r8a7778_rates [ ] __initconst = {
2015-02-26 19:42:07 +03:00
[ 0 ] = { 21 , 21 } ,
[ 1 ] = { 24 , 24 } ,
[ 2 ] = { 28 , 28 } ,
[ 3 ] = { 32 , 32 } ,
[ 5 ] = { 24 , 21 } ,
[ 6 ] = { 28 , 21 } ,
[ 7 ] = { 32 , 24 } ,
} ;
/* Clock dividers per bits 1 and 2 of MODEMR */
2015-10-16 18:14:55 +03:00
static const struct {
2015-02-26 19:42:07 +03:00
const char * name ;
unsigned int div [ 4 ] ;
2015-10-16 18:14:55 +03:00
} r8a7778_divs [ 6 ] __initconst = {
2015-02-26 19:42:07 +03:00
{ " b " , { 12 , 12 , 16 , 18 } } ,
{ " out " , { 12 , 12 , 16 , 18 } } ,
{ " p " , { 16 , 12 , 16 , 12 } } ,
{ " s " , { 4 , 3 , 4 , 3 } } ,
{ " s1 " , { 8 , 6 , 8 , 6 } } ,
} ;
static u32 cpg_mode_rates __initdata ;
static u32 cpg_mode_divs __initdata ;
static struct clk * __init
r8a7778_cpg_register_clock ( struct device_node * np , struct r8a7778_cpg * cpg ,
const char * name )
{
if ( ! strcmp ( name , " plla " ) ) {
return clk_register_fixed_factor ( NULL , " plla " ,
of_clk_get_parent_name ( np , 0 ) , 0 ,
r8a7778_rates [ cpg_mode_rates ] . plla_mult , 1 ) ;
} else if ( ! strcmp ( name , " pllb " ) ) {
return clk_register_fixed_factor ( NULL , " pllb " ,
of_clk_get_parent_name ( np , 0 ) , 0 ,
r8a7778_rates [ cpg_mode_rates ] . pllb_mult , 1 ) ;
} else {
unsigned int i ;
for ( i = 0 ; i < ARRAY_SIZE ( r8a7778_divs ) ; i + + ) {
if ( ! strcmp ( name , r8a7778_divs [ i ] . name ) ) {
return clk_register_fixed_factor ( NULL ,
r8a7778_divs [ i ] . name ,
" plla " , 0 , 1 ,
r8a7778_divs [ i ] . div [ cpg_mode_divs ] ) ;
}
}
}
return ERR_PTR ( - EINVAL ) ;
}
static void __init r8a7778_cpg_clocks_init ( struct device_node * np )
{
struct r8a7778_cpg * cpg ;
struct clk * * clks ;
unsigned int i ;
int num_clks ;
2016-06-01 15:46:01 +03:00
u32 mode ;
if ( rcar_rst_read_mode_pins ( & mode ) )
return ;
BUG_ON ( ! ( mode & BIT ( 19 ) ) ) ;
cpg_mode_rates = ( ! ! ( mode & BIT ( 18 ) ) < < 2 ) |
( ! ! ( mode & BIT ( 12 ) ) < < 1 ) |
( ! ! ( mode & BIT ( 11 ) ) ) ;
cpg_mode_divs = ( ! ! ( mode & BIT ( 2 ) ) < < 1 ) |
( ! ! ( mode & BIT ( 1 ) ) ) ;
2015-02-26 19:42:07 +03:00
num_clks = of_property_count_strings ( np , " clock-output-names " ) ;
if ( num_clks < 0 ) {
pr_err ( " %s: failed to count clocks \n " , __func__ ) ;
return ;
}
cpg = kzalloc ( sizeof ( * cpg ) , GFP_KERNEL ) ;
clks = kcalloc ( num_clks , sizeof ( * clks ) , GFP_KERNEL ) ;
if ( cpg = = NULL | | clks = = NULL ) {
/* We're leaking memory on purpose, there's no point in cleaning
* up as the system won ' t boot anyway .
*/
return ;
}
spin_lock_init ( & cpg - > lock ) ;
cpg - > data . clks = clks ;
cpg - > data . clk_num = num_clks ;
cpg - > reg = of_iomap ( np , 0 ) ;
if ( WARN_ON ( cpg - > reg = = NULL ) )
return ;
for ( i = 0 ; i < num_clks ; + + i ) {
const char * name ;
struct clk * clk ;
of_property_read_string_index ( np , " clock-output-names " , i ,
& name ) ;
clk = r8a7778_cpg_register_clock ( np , cpg , name ) ;
if ( IS_ERR ( clk ) )
pr_err ( " %s: failed to register %s %s clock (%ld) \n " ,
__func__ , np - > name , name , PTR_ERR ( clk ) ) ;
else
cpg - > data . clks [ i ] = clk ;
}
of_clk_add_provider ( np , of_clk_src_onecell_get , & cpg - > data ) ;
2015-08-04 15:28:03 +03:00
cpg_mstp_add_clk_domain ( np ) ;
2015-02-26 19:42:07 +03:00
}
CLK_OF_DECLARE ( r8a7778_cpg_clks , " renesas,r8a7778-cpg-clocks " ,
r8a7778_cpg_clocks_init ) ;