2013-04-09 12:46:26 +04:00
/*
* Copyright 2013 Freescale Semiconductor , Inc .
*
* 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 .
*
2015-01-15 09:03:41 +03:00
* clock driver for Freescale QorIQ SoCs .
2013-04-09 12:46:26 +04:00
*/
2015-01-21 13:03:29 +03:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2013-04-09 12:46:26 +04:00
# include <linux/clk-provider.h>
# include <linux/io.h>
# include <linux/kernel.h>
# include <linux/module.h>
2013-11-11 09:19:08 +04:00
# include <linux/of_address.h>
2013-04-09 12:46:26 +04:00
# include <linux/of_platform.h>
# include <linux/of.h>
# include <linux/slab.h>
struct cmux_clk {
struct clk_hw hw ;
void __iomem * reg ;
2015-01-15 09:03:40 +03:00
unsigned int clk_per_pll ;
2013-04-09 12:46:26 +04:00
u32 flags ;
} ;
# define PLL_KILL BIT(31)
# define CLKSEL_SHIFT 27
# define CLKSEL_ADJUST BIT(0)
# define to_cmux_clk(p) container_of(p, struct cmux_clk, hw)
static int cmux_set_parent ( struct clk_hw * hw , u8 idx )
{
struct cmux_clk * clk = to_cmux_clk ( hw ) ;
u32 clksel ;
2015-01-15 09:03:40 +03:00
clksel = ( ( idx / clk - > clk_per_pll ) < < 2 ) + idx % clk - > clk_per_pll ;
2013-04-09 12:46:26 +04:00
if ( clk - > flags & CLKSEL_ADJUST )
clksel + = 8 ;
clksel = ( clksel & 0xf ) < < CLKSEL_SHIFT ;
iowrite32be ( clksel , clk - > reg ) ;
return 0 ;
}
static u8 cmux_get_parent ( struct clk_hw * hw )
{
struct cmux_clk * clk = to_cmux_clk ( hw ) ;
u32 clksel ;
clksel = ioread32be ( clk - > reg ) ;
clksel = ( clksel > > CLKSEL_SHIFT ) & 0xf ;
if ( clk - > flags & CLKSEL_ADJUST )
clksel - = 8 ;
2015-01-15 09:03:40 +03:00
clksel = ( clksel > > 2 ) * clk - > clk_per_pll + clksel % 4 ;
2013-04-09 12:46:26 +04:00
return clksel ;
}
2015-01-21 13:03:27 +03:00
static const struct clk_ops cmux_ops = {
2013-04-09 12:46:26 +04:00
. get_parent = cmux_get_parent ,
. set_parent = cmux_set_parent ,
} ;
static void __init core_mux_init ( struct device_node * np )
{
struct clk * clk ;
struct clk_init_data init ;
struct cmux_clk * cmux_clk ;
struct device_node * node ;
int rc , count , i ;
u32 offset ;
const char * clk_name ;
const char * * parent_names ;
2015-01-15 09:03:40 +03:00
struct of_phandle_args clkspec ;
2013-04-09 12:46:26 +04:00
rc = of_property_read_u32 ( np , " reg " , & offset ) ;
if ( rc ) {
pr_err ( " %s: could not get reg property \n " , np - > name ) ;
return ;
}
/* get the input clock source count */
count = of_property_count_strings ( np , " clock-names " ) ;
if ( count < 0 ) {
pr_err ( " %s: get clock count error \n " , np - > name ) ;
return ;
}
2015-01-21 13:03:24 +03:00
parent_names = kcalloc ( count , sizeof ( char * ) , GFP_KERNEL ) ;
2015-01-21 13:03:26 +03:00
if ( ! parent_names )
2013-04-09 12:46:26 +04:00
return ;
for ( i = 0 ; i < count ; i + + )
parent_names [ i ] = of_clk_get_parent_name ( np , i ) ;
2015-01-21 13:03:25 +03:00
cmux_clk = kzalloc ( sizeof ( * cmux_clk ) , GFP_KERNEL ) ;
2015-01-21 13:03:26 +03:00
if ( ! cmux_clk )
2013-04-09 12:46:26 +04:00
goto err_name ;
2015-01-21 13:03:26 +03:00
2014-01-21 05:32:45 +04:00
cmux_clk - > reg = of_iomap ( np , 0 ) ;
if ( ! cmux_clk - > reg ) {
pr_err ( " %s: could not map register \n " , __func__ ) ;
goto err_clk ;
}
2013-04-09 12:46:26 +04:00
2015-01-15 09:03:40 +03:00
rc = of_parse_phandle_with_args ( np , " clocks " , " #clock-cells " , 0 ,
& clkspec ) ;
if ( rc ) {
pr_err ( " %s: parse clock node error \n " , __func__ ) ;
goto err_clk ;
}
cmux_clk - > clk_per_pll = of_property_count_strings ( clkspec . np ,
" clock-output-names " ) ;
of_node_put ( clkspec . np ) ;
2013-04-09 12:46:26 +04:00
node = of_find_compatible_node ( NULL , NULL , " fsl,p4080-clockgen " ) ;
if ( node & & ( offset > = 0x80 ) )
cmux_clk - > flags = CLKSEL_ADJUST ;
rc = of_property_read_string_index ( np , " clock-output-names " ,
2015-01-21 13:03:23 +03:00
0 , & clk_name ) ;
2013-04-09 12:46:26 +04:00
if ( rc ) {
pr_err ( " %s: read clock names error \n " , np - > name ) ;
goto err_clk ;
}
init . name = clk_name ;
init . ops = & cmux_ops ;
init . parent_names = parent_names ;
init . num_parents = count ;
init . flags = 0 ;
cmux_clk - > hw . init = & init ;
clk = clk_register ( NULL , & cmux_clk - > hw ) ;
if ( IS_ERR ( clk ) ) {
pr_err ( " %s: could not register clock \n " , clk_name ) ;
goto err_clk ;
}
rc = of_clk_add_provider ( np , of_clk_src_simple_get , clk ) ;
if ( rc ) {
pr_err ( " Could not register clock provider for node:%s \n " ,
2015-01-21 13:03:23 +03:00
np - > name ) ;
2013-04-09 12:46:26 +04:00
goto err_clk ;
}
goto err_name ;
err_clk :
kfree ( cmux_clk ) ;
err_name :
/* free *_names because they are reallocated when registered */
kfree ( parent_names ) ;
}
static void __init core_pll_init ( struct device_node * np )
{
2014-01-21 05:32:45 +04:00
u32 mult ;
2013-04-09 12:46:26 +04:00
int i , rc , count ;
const char * clk_name , * parent_name ;
struct clk_onecell_data * onecell_data ;
struct clk * * subclks ;
2014-01-21 05:32:45 +04:00
void __iomem * base ;
2013-04-09 12:46:26 +04:00
2014-01-21 05:32:45 +04:00
base = of_iomap ( np , 0 ) ;
if ( ! base ) {
2015-01-21 13:03:29 +03:00
pr_err ( " iomap error \n " ) ;
2013-04-09 12:46:26 +04:00
return ;
}
/* get the multiple of PLL */
2014-01-21 05:32:45 +04:00
mult = ioread32be ( base ) ;
2013-04-09 12:46:26 +04:00
/* check if this PLL is disabled */
if ( mult & PLL_KILL ) {
pr_debug ( " PLL:%s is disabled \n " , np - > name ) ;
2014-01-21 05:32:45 +04:00
goto err_map ;
2013-04-09 12:46:26 +04:00
}
mult = ( mult > > 1 ) & 0x3f ;
parent_name = of_clk_get_parent_name ( np , 0 ) ;
if ( ! parent_name ) {
pr_err ( " PLL: %s must have a parent \n " , np - > name ) ;
2014-01-21 05:32:45 +04:00
goto err_map ;
2013-04-09 12:46:26 +04:00
}
count = of_property_count_strings ( np , " clock-output-names " ) ;
if ( count < 0 | | count > 4 ) {
pr_err ( " %s: clock is not supported \n " , np - > name ) ;
2014-01-21 05:32:45 +04:00
goto err_map ;
2013-04-09 12:46:26 +04:00
}
2015-01-21 13:03:24 +03:00
subclks = kcalloc ( count , sizeof ( struct clk * ) , GFP_KERNEL ) ;
2015-01-21 13:03:26 +03:00
if ( ! subclks )
2014-01-21 05:32:45 +04:00
goto err_map ;
2013-04-09 12:46:26 +04:00
2015-01-21 13:03:28 +03:00
onecell_data = kmalloc ( sizeof ( * onecell_data ) , GFP_KERNEL ) ;
2015-01-21 13:03:26 +03:00
if ( ! onecell_data )
2013-04-09 12:46:26 +04:00
goto err_clks ;
for ( i = 0 ; i < count ; i + + ) {
rc = of_property_read_string_index ( np , " clock-output-names " ,
2015-01-21 13:03:23 +03:00
i , & clk_name ) ;
2013-04-09 12:46:26 +04:00
if ( rc ) {
pr_err ( " %s: could not get clock names \n " , np - > name ) ;
goto err_cell ;
}
/*
* when count = = 4 , there are 4 output clocks :
* / 1 , / 2 , / 3 , / 4 respectively
* when count < 4 , there are at least 2 output clocks :
* / 1 , / 2 , ( / 4 , if count = = 3 ) respectively .
*/
if ( count = = 4 )
subclks [ i ] = clk_register_fixed_factor ( NULL , clk_name ,
parent_name , 0 , mult , 1 + i ) ;
else
subclks [ i ] = clk_register_fixed_factor ( NULL , clk_name ,
parent_name , 0 , mult , 1 < < i ) ;
if ( IS_ERR ( subclks [ i ] ) ) {
pr_err ( " %s: could not register clock \n " , clk_name ) ;
goto err_cell ;
}
}
onecell_data - > clks = subclks ;
onecell_data - > clk_num = count ;
rc = of_clk_add_provider ( np , of_clk_src_onecell_get , onecell_data ) ;
if ( rc ) {
pr_err ( " Could not register clk provider for node:%s \n " ,
2015-01-21 13:03:23 +03:00
np - > name ) ;
2013-04-09 12:46:26 +04:00
goto err_cell ;
}
2014-01-21 05:32:45 +04:00
iounmap ( base ) ;
2013-04-09 12:46:26 +04:00
return ;
err_cell :
kfree ( onecell_data ) ;
err_clks :
kfree ( subclks ) ;
2014-01-21 05:32:45 +04:00
err_map :
iounmap ( base ) ;
}
static void __init sysclk_init ( struct device_node * node )
{
struct clk * clk ;
const char * clk_name = node - > name ;
struct device_node * np = of_get_parent ( node ) ;
u32 rate ;
if ( ! np ) {
2015-01-21 13:03:29 +03:00
pr_err ( " could not get parent node \n " ) ;
2014-01-21 05:32:45 +04:00
return ;
}
if ( of_property_read_u32 ( np , " clock-frequency " , & rate ) ) {
of_node_put ( node ) ;
return ;
}
of_property_read_string ( np , " clock-output-names " , & clk_name ) ;
clk = clk_register_fixed_rate ( NULL , clk_name , NULL , CLK_IS_ROOT , rate ) ;
if ( ! IS_ERR ( clk ) )
of_clk_add_provider ( np , of_clk_src_simple_get , clk ) ;
2013-04-09 12:46:26 +04:00
}
clk: ppc-corenet: fix section mismatch warning
In order to fix the following section mismatch warning:
WARNING: drivers/clk/built-in.o(.data+0xe4): Section mismatch in reference from the variable ppc_corenet_clk_driver to the function .init.text:ppc_corenet_clk_probe()
The variable ppc_corenet_clk_driver references
the function __init ppc_corenet_clk_probe()
If the reference is valid then annotate the
variable with __init* or __refdata (see linux/init.h) or name the variable:
*_template, *_timer, *_sht, *_ops, *_probe, *_probe_one, *_console
WARNING: drivers/clk/built-in.o(.data+0x10c): Section mismatch in reference from the variable ppc_corenet_clk_driver to the variable .init.rodata:ppc_clk_ids
The variable ppc_corenet_clk_driver references
the variable __initconst ppc_clk_ids
If the reference is valid then annotate the
variable with __init* or __refdata (see linux/init.h) or name the variable:
*_template, *_timer, *_sht, *_ops, *_probe, *_probe_one, *_console
We can't just add the __init annotation to ppc_corenet_clk_driver or
remove the __init from ppc_corenet_clk_probe() and ppc_clk_ids.
So choose to use CLK_OF_DECLARE to scan and init the clock devices.
Signed-off-by: Kevin Hao <haokexin@gmail.com>
Acked-by: Scott Wood <scottwood@freescale.com>
Acked-by: Michael Turquette <mturquette@linaro.org>
Signed-off-by: Michael Turquette <mturquette@linaro.org>
2014-12-03 11:53:53 +03:00
CLK_OF_DECLARE ( qoriq_sysclk_1 , " fsl,qoriq-sysclk-1.0 " , sysclk_init ) ;
CLK_OF_DECLARE ( qoriq_sysclk_2 , " fsl,qoriq-sysclk-2.0 " , sysclk_init ) ;
CLK_OF_DECLARE ( qoriq_core_pll_1 , " fsl,qoriq-core-pll-1.0 " , core_pll_init ) ;
CLK_OF_DECLARE ( qoriq_core_pll_2 , " fsl,qoriq-core-pll-2.0 " , core_pll_init ) ;
CLK_OF_DECLARE ( qoriq_core_mux_1 , " fsl,qoriq-core-mux-1.0 " , core_mux_init ) ;
CLK_OF_DECLARE ( qoriq_core_mux_2 , " fsl,qoriq-core-mux-2.0 " , core_mux_init ) ;