2012-03-16 10:11:20 +04:00
/*
* Copyright ( C ) 2010 - 2011 Canonical Ltd < jeremy . kerr @ canonical . com >
* Copyright ( C ) 2011 - 2012 Mike Turquette , Linaro Ltd < mturquette @ linaro . org >
*
* 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 .
*
* Fixed rate clock implementation
*/
# include <linux/clk-provider.h>
# include <linux/module.h>
# include <linux/slab.h>
# include <linux/io.h>
# include <linux/err.h>
2012-04-08 06:39:39 +04:00
# include <linux/of.h>
2016-07-05 19:23:34 +03:00
# include <linux/platform_device.h>
2012-03-16 10:11:20 +04:00
/*
* DOC : basic fixed - rate clock that cannot gate
*
* Traits of this clock :
* prepare - clk_ ( un ) prepare only ensures parents are prepared
* enable - clk_enable only ensures parents are enabled
* rate - rate is always a fixed value . No clk_set_rate support
* parent - fixed parent . No clk_set_parent support
*/
static unsigned long clk_fixed_rate_recalc_rate ( struct clk_hw * hw ,
unsigned long parent_rate )
{
return to_clk_fixed_rate ( hw ) - > fixed_rate ;
}
2013-12-21 13:34:48 +04:00
static unsigned long clk_fixed_rate_recalc_accuracy ( struct clk_hw * hw ,
unsigned long parent_accuracy )
{
return to_clk_fixed_rate ( hw ) - > fixed_accuracy ;
}
2012-03-27 11:23:22 +04:00
const struct clk_ops clk_fixed_rate_ops = {
2012-03-16 10:11:20 +04:00
. recalc_rate = clk_fixed_rate_recalc_rate ,
2013-12-21 13:34:48 +04:00
. recalc_accuracy = clk_fixed_rate_recalc_accuracy ,
2012-03-16 10:11:20 +04:00
} ;
EXPORT_SYMBOL_GPL ( clk_fixed_rate_ops ) ;
2012-03-27 04:51:03 +04:00
/**
2016-02-07 11:34:13 +03:00
* clk_hw_register_fixed_rate_with_accuracy - register fixed - rate clock with
* the clock framework
2012-03-27 04:51:03 +04:00
* @ dev : device that is registering this clock
* @ name : name of this clock
* @ parent_name : name of clock ' s parent
* @ flags : framework - specific flags
* @ fixed_rate : non - adjustable clock rate
2013-12-21 13:34:48 +04:00
* @ fixed_accuracy : non - adjustable clock rate
2012-03-27 04:51:03 +04:00
*/
2016-02-07 11:34:13 +03:00
struct clk_hw * clk_hw_register_fixed_rate_with_accuracy ( struct device * dev ,
2013-12-21 13:34:48 +04:00
const char * name , const char * parent_name , unsigned long flags ,
unsigned long fixed_rate , unsigned long fixed_accuracy )
2012-03-16 10:11:20 +04:00
{
struct clk_fixed_rate * fixed ;
2016-02-07 11:34:13 +03:00
struct clk_hw * hw ;
2012-04-26 09:58:56 +04:00
struct clk_init_data init ;
2016-02-07 11:34:13 +03:00
int ret ;
2012-03-16 10:11:20 +04:00
2012-03-27 04:51:03 +04:00
/* allocate fixed-rate clock */
2015-05-15 02:47:10 +03:00
fixed = kzalloc ( sizeof ( * fixed ) , GFP_KERNEL ) ;
if ( ! fixed )
2012-03-16 10:11:20 +04:00
return ERR_PTR ( - ENOMEM ) ;
2012-04-26 09:58:56 +04:00
init . name = name ;
init . ops = & clk_fixed_rate_ops ;
2012-06-01 12:32:47 +04:00
init . flags = flags | CLK_IS_BASIC ;
2012-04-26 09:58:56 +04:00
init . parent_names = ( parent_name ? & parent_name : NULL ) ;
init . num_parents = ( parent_name ? 1 : 0 ) ;
2012-03-16 10:11:20 +04:00
/* struct clk_fixed_rate assignments */
fixed - > fixed_rate = fixed_rate ;
2013-12-21 13:34:48 +04:00
fixed - > fixed_accuracy = fixed_accuracy ;
2012-04-26 09:58:56 +04:00
fixed - > hw . init = & init ;
2012-03-16 10:11:20 +04:00
2012-03-27 04:51:03 +04:00
/* register the clock */
2016-02-07 11:34:13 +03:00
hw = & fixed - > hw ;
ret = clk_hw_register ( dev , hw ) ;
if ( ret ) {
2012-03-27 04:51:03 +04:00
kfree ( fixed ) ;
2016-02-07 11:34:13 +03:00
hw = ERR_PTR ( ret ) ;
}
2012-03-27 04:51:03 +04:00
2016-02-07 11:34:13 +03:00
return hw ;
}
EXPORT_SYMBOL_GPL ( clk_hw_register_fixed_rate_with_accuracy ) ;
struct clk * clk_register_fixed_rate_with_accuracy ( struct device * dev ,
const char * name , const char * parent_name , unsigned long flags ,
unsigned long fixed_rate , unsigned long fixed_accuracy )
{
struct clk_hw * hw ;
hw = clk_hw_register_fixed_rate_with_accuracy ( dev , name , parent_name ,
flags , fixed_rate , fixed_accuracy ) ;
if ( IS_ERR ( hw ) )
return ERR_CAST ( hw ) ;
return hw - > clk ;
2012-03-16 10:11:20 +04:00
}
2013-12-21 13:34:48 +04:00
EXPORT_SYMBOL_GPL ( clk_register_fixed_rate_with_accuracy ) ;
/**
2016-02-07 11:34:13 +03:00
* clk_hw_register_fixed_rate - register fixed - rate clock with the clock
* framework
2013-12-21 13:34:48 +04:00
* @ dev : device that is registering this clock
* @ name : name of this clock
* @ parent_name : name of clock ' s parent
* @ flags : framework - specific flags
* @ fixed_rate : non - adjustable clock rate
*/
2016-02-07 11:34:13 +03:00
struct clk_hw * clk_hw_register_fixed_rate ( struct device * dev , const char * name ,
const char * parent_name , unsigned long flags ,
unsigned long fixed_rate )
{
return clk_hw_register_fixed_rate_with_accuracy ( dev , name , parent_name ,
flags , fixed_rate , 0 ) ;
}
EXPORT_SYMBOL_GPL ( clk_hw_register_fixed_rate ) ;
2013-12-21 13:34:48 +04:00
struct clk * clk_register_fixed_rate ( struct device * dev , const char * name ,
const char * parent_name , unsigned long flags ,
unsigned long fixed_rate )
{
return clk_register_fixed_rate_with_accuracy ( dev , name , parent_name ,
flags , fixed_rate , 0 ) ;
}
2013-07-25 04:43:29 +04:00
EXPORT_SYMBOL_GPL ( clk_register_fixed_rate ) ;
2012-04-08 06:39:39 +04:00
2016-01-06 07:25:10 +03:00
void clk_unregister_fixed_rate ( struct clk * clk )
{
struct clk_hw * hw ;
hw = __clk_get_hw ( clk ) ;
if ( ! hw )
return ;
clk_unregister ( clk ) ;
kfree ( to_clk_fixed_rate ( hw ) ) ;
}
EXPORT_SYMBOL_GPL ( clk_unregister_fixed_rate ) ;
2016-05-22 08:33:35 +03:00
void clk_hw_unregister_fixed_rate ( struct clk_hw * hw )
{
struct clk_fixed_rate * fixed ;
fixed = to_clk_fixed_rate ( hw ) ;
clk_hw_unregister ( hw ) ;
kfree ( fixed ) ;
}
EXPORT_SYMBOL_GPL ( clk_hw_unregister_fixed_rate ) ;
2012-04-08 06:39:39 +04:00
# ifdef CONFIG_OF
2016-07-05 19:23:34 +03:00
static struct clk * _of_fixed_clk_setup ( struct device_node * node )
2012-04-08 06:39:39 +04:00
{
struct clk * clk ;
const char * clk_name = node - > name ;
u32 rate ;
2013-12-21 13:34:48 +04:00
u32 accuracy = 0 ;
2016-07-05 19:23:34 +03:00
int ret ;
2012-04-08 06:39:39 +04:00
if ( of_property_read_u32 ( node , " clock-frequency " , & rate ) )
2016-07-05 19:23:34 +03:00
return ERR_PTR ( - EIO ) ;
2012-04-08 06:39:39 +04:00
2013-12-21 13:34:48 +04:00
of_property_read_u32 ( node , " clock-accuracy " , & accuracy ) ;
2012-04-08 06:39:39 +04:00
of_property_read_string ( node , " clock-output-names " , & clk_name ) ;
2013-12-21 13:34:48 +04:00
clk = clk_register_fixed_rate_with_accuracy ( NULL , clk_name , NULL ,
2016-03-01 22:00:12 +03:00
0 , rate , accuracy ) ;
2016-07-05 19:23:34 +03:00
if ( IS_ERR ( clk ) )
return clk ;
ret = of_clk_add_provider ( node , of_clk_src_simple_get , clk ) ;
if ( ret ) {
clk_unregister ( clk ) ;
return ERR_PTR ( ret ) ;
}
return clk ;
}
/**
* of_fixed_clk_setup ( ) - Setup function for simple fixed rate clock
*/
2016-08-13 04:50:23 +03:00
void __init of_fixed_clk_setup ( struct device_node * node )
2016-07-05 19:23:34 +03:00
{
_of_fixed_clk_setup ( node ) ;
2012-04-08 06:39:39 +04:00
}
2013-01-04 11:00:52 +04:00
CLK_OF_DECLARE ( fixed_clk , " fixed-clock " , of_fixed_clk_setup ) ;
2016-07-05 19:23:34 +03:00
static int of_fixed_clk_remove ( struct platform_device * pdev )
{
struct clk * clk = platform_get_drvdata ( pdev ) ;
clk_unregister_fixed_rate ( clk ) ;
return 0 ;
}
static int of_fixed_clk_probe ( struct platform_device * pdev )
{
struct clk * clk ;
/*
* This function is not executed when of_fixed_clk_setup
* succeeded .
*/
clk = _of_fixed_clk_setup ( pdev - > dev . of_node ) ;
if ( IS_ERR ( clk ) )
return PTR_ERR ( clk ) ;
platform_set_drvdata ( pdev , clk ) ;
return 0 ;
}
static const struct of_device_id of_fixed_clk_ids [ ] = {
{ . compatible = " fixed-clock " } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , of_fixed_clk_ids ) ;
static struct platform_driver of_fixed_clk_driver = {
. driver = {
. name = " of_fixed_clk " ,
. of_match_table = of_fixed_clk_ids ,
} ,
. probe = of_fixed_clk_probe ,
. remove = of_fixed_clk_remove ,
} ;
builtin_platform_driver ( of_fixed_clk_driver ) ;
2012-04-08 06:39:39 +04:00
# endif