2014-05-07 18:02:15 +02:00
/*
* drivers / clk / at91 / clk - slow . c
*
* Copyright ( C ) 2013 Boris BREZILLON < b . brezillon @ overkiz . com >
*
* 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 ; either version 2 of the License , or
* ( at your option ) any later version .
*
*/
# include <linux/clk-provider.h>
# include <linux/clkdev.h>
# include <linux/clk/at91_pmc.h>
# include <linux/of.h>
2014-09-07 08:14:29 +02:00
# include <linux/mfd/syscon.h>
# include <linux/regmap.h>
2014-05-07 18:02:15 +02:00
# include "pmc.h"
struct clk_sam9260_slow {
struct clk_hw hw ;
2014-09-07 08:14:29 +02:00
struct regmap * regmap ;
2014-05-07 18:02:15 +02:00
} ;
# define to_clk_sam9260_slow(hw) container_of(hw, struct clk_sam9260_slow, hw)
static u8 clk_sam9260_slow_get_parent ( struct clk_hw * hw )
{
struct clk_sam9260_slow * slowck = to_clk_sam9260_slow ( hw ) ;
2014-09-07 08:14:29 +02:00
unsigned int status ;
2014-05-07 18:02:15 +02:00
2014-09-07 08:14:29 +02:00
regmap_read ( slowck - > regmap , AT91_PMC_SR , & status ) ;
return status & AT91_PMC_OSCSEL ? 1 : 0 ;
2014-05-07 18:02:15 +02:00
}
static const struct clk_ops sam9260_slow_ops = {
. get_parent = clk_sam9260_slow_get_parent ,
} ;
2016-06-01 14:31:22 -07:00
static struct clk_hw * __init
2014-09-07 08:14:29 +02:00
at91_clk_register_sam9260_slow ( struct regmap * regmap ,
2014-05-07 18:02:15 +02:00
const char * name ,
const char * * parent_names ,
int num_parents )
{
struct clk_sam9260_slow * slowck ;
2016-06-01 14:31:22 -07:00
struct clk_hw * hw ;
2014-05-07 18:02:15 +02:00
struct clk_init_data init ;
2016-06-01 14:31:22 -07:00
int ret ;
2014-05-07 18:02:15 +02:00
2014-09-07 08:14:29 +02:00
if ( ! name )
2014-05-07 18:02:15 +02:00
return ERR_PTR ( - EINVAL ) ;
if ( ! parent_names | | ! num_parents )
return ERR_PTR ( - EINVAL ) ;
slowck = kzalloc ( sizeof ( * slowck ) , GFP_KERNEL ) ;
if ( ! slowck )
return ERR_PTR ( - ENOMEM ) ;
init . name = name ;
init . ops = & sam9260_slow_ops ;
init . parent_names = parent_names ;
init . num_parents = num_parents ;
init . flags = 0 ;
slowck - > hw . init = & init ;
2014-09-07 08:14:29 +02:00
slowck - > regmap = regmap ;
2014-05-07 18:02:15 +02:00
2016-06-01 14:31:22 -07:00
hw = & slowck - > hw ;
ret = clk_hw_register ( NULL , & slowck - > hw ) ;
if ( ret ) {
2014-05-07 18:02:15 +02:00
kfree ( slowck ) ;
2016-06-01 14:31:22 -07:00
hw = ERR_PTR ( ret ) ;
}
2014-05-07 18:02:15 +02:00
2016-06-01 14:31:22 -07:00
return hw ;
2014-05-07 18:02:15 +02:00
}
2014-09-07 08:14:29 +02:00
static void __init of_at91sam9260_clk_slow_setup ( struct device_node * np )
2014-05-07 18:02:15 +02:00
{
2016-06-01 14:31:22 -07:00
struct clk_hw * hw ;
2014-05-07 18:02:15 +02:00
const char * parent_names [ 2 ] ;
2016-02-19 17:29:17 -08:00
unsigned int num_parents ;
2014-05-07 18:02:15 +02:00
const char * name = np - > name ;
2014-09-07 08:14:29 +02:00
struct regmap * regmap ;
2014-05-07 18:02:15 +02:00
2015-05-29 11:25:45 +02:00
num_parents = of_clk_get_parent_count ( np ) ;
2014-09-02 17:27:51 +02:00
if ( num_parents ! = 2 )
2014-05-07 18:02:15 +02:00
return ;
2015-07-06 22:59:01 -05:00
of_clk_parent_fill ( np , parent_names , num_parents ) ;
2014-09-07 08:14:29 +02:00
regmap = syscon_node_to_regmap ( of_get_parent ( np ) ) ;
if ( IS_ERR ( regmap ) )
return ;
2014-05-07 18:02:15 +02:00
of_property_read_string ( np , " clock-output-names " , & name ) ;
2016-06-01 14:31:22 -07:00
hw = at91_clk_register_sam9260_slow ( regmap , name , parent_names ,
2014-05-07 18:02:15 +02:00
num_parents ) ;
2016-06-01 14:31:22 -07:00
if ( IS_ERR ( hw ) )
2014-05-07 18:02:15 +02:00
return ;
2016-06-01 14:31:22 -07:00
of_clk_add_hw_provider ( np , of_clk_hw_simple_get , hw ) ;
2014-05-07 18:02:15 +02:00
}
2014-09-07 08:14:29 +02:00
CLK_OF_DECLARE ( at91sam9260_clk_slow , " atmel,at91sam9260-clk-slow " ,
of_at91sam9260_clk_slow_setup ) ;