2018-12-11 20:57:48 +03:00
// SPDX-License-Identifier: GPL-2.0
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 >
*
* 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
*/
2019-08-30 18:09:15 +03:00
# define to_clk_fixed_rate(_hw) container_of(_hw, struct clk_fixed_rate, hw)
2012-03-16 10:11:20 +04:00
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 )
{
2019-08-30 18:09:18 +03:00
struct clk_fixed_rate * fixed = to_clk_fixed_rate ( hw ) ;
if ( fixed - > flags & CLK_FIXED_RATE_PARENT_ACCURACY )
return parent_accuracy ;
return fixed - > fixed_accuracy ;
2013-12-21 13:34:48 +04:00
}
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 ) ;
2022-09-16 09:17:39 +03:00
static void devm_clk_hw_register_fixed_rate_release ( struct device * dev , void * res )
{
struct clk_fixed_rate * fix = res ;
/*
* We can not use clk_hw_unregister_fixed_rate , since it will kfree ( )
* the hw , resulting in double free . Just unregister the hw and let
* devres code kfree ( ) it .
*/
clk_hw_unregister ( & fix - > hw ) ;
}
2019-08-30 18:09:17 +03:00
struct clk_hw * __clk_hw_register_fixed_rate ( struct device * dev ,
struct device_node * np , const char * name ,
const char * parent_name , const struct clk_hw * parent_hw ,
const struct clk_parent_data * parent_data , unsigned long flags ,
unsigned long fixed_rate , unsigned long fixed_accuracy ,
2022-09-16 09:17:39 +03:00
unsigned long clk_fixed_flags , bool devm )
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 ;
2019-11-15 19:28:55 +03:00
struct clk_init_data init = { } ;
2019-08-30 18:09:17 +03:00
int ret = - EINVAL ;
2012-03-16 10:11:20 +04:00
2012-03-27 04:51:03 +04:00
/* allocate fixed-rate clock */
2022-09-16 09:17:39 +03:00
if ( devm )
fixed = devres_alloc ( devm_clk_hw_register_fixed_rate_release ,
sizeof ( * fixed ) , GFP_KERNEL ) ;
else
fixed = kzalloc ( sizeof ( * fixed ) , GFP_KERNEL ) ;
2015-05-15 02:47:10 +03:00
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 ;
2019-04-25 20:57:37 +03:00
init . flags = flags ;
2019-08-30 18:09:17 +03:00
init . parent_names = parent_name ? & parent_name : NULL ;
init . parent_hws = parent_hw ? & parent_hw : NULL ;
init . parent_data = parent_data ;
if ( parent_name | | parent_hw | | parent_data )
init . num_parents = 1 ;
else
init . num_parents = 0 ;
2012-04-26 09:58:56 +04:00
2012-03-16 10:11:20 +04:00
/* struct clk_fixed_rate assignments */
2019-08-30 18:09:17 +03:00
fixed - > flags = clk_fixed_flags ;
2012-03-16 10:11:20 +04:00
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 ;
2019-08-30 18:09:17 +03:00
if ( dev | | ! np )
ret = clk_hw_register ( dev , hw ) ;
2022-05-09 12:21:02 +03:00
else
2019-08-30 18:09:17 +03:00
ret = of_clk_hw_register ( np , hw ) ;
2016-02-07 11:34:13 +03:00
if ( ret ) {
2022-09-16 09:17:39 +03:00
if ( devm )
devres_free ( fixed ) ;
else
kfree ( fixed ) ;
2016-02-07 11:34:13 +03:00
hw = ERR_PTR ( ret ) ;
2022-09-16 09:17:39 +03:00
} else if ( devm )
devres_add ( dev , fixed ) ;
2012-03-27 04:51:03 +04:00
2016-02-07 11:34:13 +03:00
return hw ;
}
2019-08-30 18:09:17 +03:00
EXPORT_SYMBOL_GPL ( __clk_hw_register_fixed_rate ) ;
2016-02-07 11:34:13 +03:00
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 )
{
2019-08-30 18:09:14 +03:00
struct clk_hw * hw ;
hw = clk_hw_register_fixed_rate_with_accuracy ( dev , name , parent_name ,
flags , fixed_rate , 0 ) ;
if ( IS_ERR ( hw ) )
return ERR_CAST ( hw ) ;
return hw - > clk ;
2013-12-21 13:34:48 +04:00
}
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
2019-08-30 18:09:13 +03:00
static struct clk_hw * _of_fixed_clk_setup ( struct device_node * node )
2012-04-08 06:39:39 +04:00
{
2019-08-30 18:09:13 +03:00
struct clk_hw * hw ;
2012-04-08 06:39:39 +04:00
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 ) ;
2019-08-30 18:09:13 +03:00
hw = clk_hw_register_fixed_rate_with_accuracy ( NULL , clk_name , NULL ,
2016-03-01 22:00:12 +03:00
0 , rate , accuracy ) ;
2019-08-30 18:09:13 +03:00
if ( IS_ERR ( hw ) )
return hw ;
2016-07-05 19:23:34 +03:00
2019-08-30 18:09:13 +03:00
ret = of_clk_add_hw_provider ( node , of_clk_hw_simple_get , hw ) ;
2016-07-05 19:23:34 +03:00
if ( ret ) {
2019-08-30 18:09:13 +03:00
clk_hw_unregister_fixed_rate ( hw ) ;
2016-07-05 19:23:34 +03:00
return ERR_PTR ( ret ) ;
}
2019-08-30 18:09:13 +03:00
return hw ;
2016-07-05 19:23:34 +03:00
}
/**
* of_fixed_clk_setup ( ) - Setup function for simple fixed rate clock
2020-09-16 19:17:36 +03:00
* @ node : device node for the clock
2016-07-05 19:23:34 +03:00
*/
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 )
{
2019-08-30 18:09:13 +03:00
struct clk_hw * hw = platform_get_drvdata ( pdev ) ;
2016-07-05 19:23:34 +03:00
2018-10-18 22:54:11 +03:00
of_clk_del_provider ( pdev - > dev . of_node ) ;
2019-08-30 18:09:13 +03:00
clk_hw_unregister_fixed_rate ( hw ) ;
2016-07-05 19:23:34 +03:00
return 0 ;
}
static int of_fixed_clk_probe ( struct platform_device * pdev )
{
2019-08-30 18:09:13 +03:00
struct clk_hw * hw ;
2016-07-05 19:23:34 +03:00
/*
* This function is not executed when of_fixed_clk_setup
* succeeded .
*/
2019-08-30 18:09:13 +03:00
hw = _of_fixed_clk_setup ( pdev - > dev . of_node ) ;
if ( IS_ERR ( hw ) )
return PTR_ERR ( hw ) ;
2016-07-05 19:23:34 +03:00
2019-08-30 18:09:13 +03:00
platform_set_drvdata ( pdev , hw ) ;
2016-07-05 19:23:34 +03:00
return 0 ;
}
static const struct of_device_id of_fixed_clk_ids [ ] = {
{ . compatible = " fixed-clock " } ,
{ }
} ;
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