2018-12-11 20:57:48 +03:00
// SPDX-License-Identifier: GPL-2.0
2012-05-03 14:06:14 +04:00
/*
* Copyright ( C ) 2011 Sascha Hauer , Pengutronix < s . hauer @ pengutronix . de >
*/
# include <linux/module.h>
# include <linux/clk-provider.h>
# include <linux/slab.h>
# include <linux/err.h>
2013-04-12 15:57:44 +04:00
# include <linux/of.h>
2016-07-05 19:23:33 +03:00
# include <linux/platform_device.h>
2012-05-03 14:06:14 +04:00
/*
* DOC : basic fixed multiplier and divider clock that cannot gate
*
* Traits of this clock :
* prepare - clk_prepare only ensures that parents are prepared
* enable - clk_enable only ensures that parents are enabled
* rate - rate is fixed . clk - > rate = parent - > rate / div * mult
* parent - fixed parent . No clk_set_parent support
*/
static unsigned long clk_factor_recalc_rate ( struct clk_hw * hw ,
unsigned long parent_rate )
{
struct clk_fixed_factor * fix = to_clk_fixed_factor ( hw ) ;
2012-12-03 12:14:37 +04:00
unsigned long long int rate ;
2012-05-03 14:06:14 +04:00
2012-12-03 12:14:37 +04:00
rate = ( unsigned long long int ) parent_rate * fix - > mult ;
do_div ( rate , fix - > div ) ;
return ( unsigned long ) rate ;
2012-05-03 14:06:14 +04:00
}
static long clk_factor_round_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long * prate )
{
struct clk_fixed_factor * fix = to_clk_fixed_factor ( hw ) ;
2015-06-30 02:56:30 +03:00
if ( clk_hw_get_flags ( hw ) & CLK_SET_RATE_PARENT ) {
2012-05-03 14:06:14 +04:00
unsigned long best_parent ;
best_parent = ( rate / fix - > mult ) * fix - > div ;
2015-07-31 03:20:57 +03:00
* prate = clk_hw_round_rate ( clk_hw_get_parent ( hw ) , best_parent ) ;
2012-05-03 14:06:14 +04:00
}
return ( * prate / fix - > div ) * fix - > mult ;
}
static int clk_factor_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long parent_rate )
{
2015-06-10 23:04:54 +03:00
/*
* We must report success but we can do so unconditionally because
* clk_factor_round_rate returns values that ensure this call is a
* nop .
*/
2012-05-03 14:06:14 +04:00
return 0 ;
}
2024-02-21 21:22:09 +03:00
static unsigned long clk_factor_recalc_accuracy ( struct clk_hw * hw ,
unsigned long parent_accuracy )
{
struct clk_fixed_factor * fix = to_clk_fixed_factor ( hw ) ;
if ( fix - > flags & CLK_FIXED_FACTOR_FIXED_ACCURACY )
return fix - > acc ;
return parent_accuracy ;
}
2015-06-10 23:04:54 +03:00
const struct clk_ops clk_fixed_factor_ops = {
2012-05-03 14:06:14 +04:00
. round_rate = clk_factor_round_rate ,
. set_rate = clk_factor_set_rate ,
. recalc_rate = clk_factor_recalc_rate ,
2024-02-21 21:22:09 +03:00
. recalc_accuracy = clk_factor_recalc_accuracy ,
2012-05-03 14:06:14 +04:00
} ;
EXPORT_SYMBOL_GPL ( clk_fixed_factor_ops ) ;
2021-02-11 08:22:02 +03:00
static void devm_clk_hw_register_fixed_factor_release ( struct device * dev , void * res )
{
2021-04-07 02:06:06 +03:00
struct clk_fixed_factor * fix = res ;
/*
* We can not use clk_hw_unregister_fixed_factor , 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 ) ;
2021-02-11 08:22:02 +03:00
}
2019-04-12 21:31:50 +03:00
static struct clk_hw *
__clk_hw_register_fixed_factor ( struct device * dev , struct device_node * np ,
2022-06-30 01:53:23 +03:00
const char * name , const char * parent_name ,
2024-02-21 21:22:10 +03:00
const struct clk_hw * parent_hw , const struct clk_parent_data * pdata ,
2021-02-11 08:22:02 +03:00
unsigned long flags , unsigned int mult , unsigned int div ,
2024-02-21 21:22:09 +03:00
unsigned long acc , unsigned int fixflags , bool devm )
2012-05-03 14:06:14 +04:00
{
struct clk_fixed_factor * fix ;
2019-04-23 20:46:51 +03:00
struct clk_init_data init = { } ;
2016-02-07 11:11:06 +03:00
struct clk_hw * hw ;
int ret ;
2012-05-03 14:06:14 +04:00
2021-02-11 08:22:02 +03:00
/* You can't use devm without a dev */
if ( devm & & ! dev )
return ERR_PTR ( - EINVAL ) ;
if ( devm )
fix = devres_alloc ( devm_clk_hw_register_fixed_factor_release ,
sizeof ( * fix ) , GFP_KERNEL ) ;
else
fix = kmalloc ( sizeof ( * fix ) , GFP_KERNEL ) ;
2015-05-15 02:47:10 +03:00
if ( ! fix )
2012-05-03 14:06:14 +04:00
return ERR_PTR ( - ENOMEM ) ;
/* struct clk_fixed_factor assignments */
fix - > mult = mult ;
fix - > div = div ;
fix - > hw . init = & init ;
2024-02-21 21:22:09 +03:00
fix - > acc = acc ;
fix - > flags = fixflags ;
2012-05-03 14:06:14 +04:00
init . name = name ;
init . ops = & clk_fixed_factor_ops ;
2019-04-25 20:57:37 +03:00
init . flags = flags ;
2019-04-12 21:31:50 +03:00
if ( parent_name )
init . parent_names = & parent_name ;
2022-06-30 01:53:23 +03:00
else if ( parent_hw )
init . parent_hws = & parent_hw ;
2019-04-12 21:31:50 +03:00
else
2024-02-21 21:22:10 +03:00
init . parent_data = pdata ;
2012-05-03 14:06:14 +04:00
init . num_parents = 1 ;
2016-02-07 11:11:06 +03:00
hw = & fix - > hw ;
2019-04-12 21:31:50 +03:00
if ( dev )
ret = clk_hw_register ( dev , hw ) ;
else
ret = of_clk_hw_register ( np , hw ) ;
2016-02-07 11:11:06 +03:00
if ( ret ) {
2021-02-11 08:22:02 +03:00
if ( devm )
devres_free ( fix ) ;
else
kfree ( fix ) ;
2016-02-07 11:11:06 +03:00
hw = ERR_PTR ( ret ) ;
2021-02-11 08:22:02 +03:00
} else if ( devm )
devres_add ( dev , fix ) ;
2012-05-03 14:06:14 +04:00
2016-02-07 11:11:06 +03:00
return hw ;
}
2019-04-12 21:31:50 +03:00
2022-02-26 07:07:22 +03:00
/**
* devm_clk_hw_register_fixed_factor_index - Register a fixed factor clock with
* parent from DT index
* @ dev : device that is registering this clock
* @ name : name of this clock
* @ index : index of phandle in @ dev ' clocks ' property
* @ flags : fixed factor flags
* @ mult : multiplier
* @ div : divider
*
* Return : Pointer to fixed factor clk_hw structure that was registered or
* an error pointer .
*/
struct clk_hw * devm_clk_hw_register_fixed_factor_index ( struct device * dev ,
const char * name , unsigned int index , unsigned long flags ,
unsigned int mult , unsigned int div )
{
2024-02-21 21:22:10 +03:00
const struct clk_parent_data pdata = { . index = index } ;
return __clk_hw_register_fixed_factor ( dev , NULL , name , NULL , NULL , & pdata ,
2024-02-21 21:22:09 +03:00
flags , mult , div , 0 , 0 , true ) ;
2022-02-26 07:07:22 +03:00
}
EXPORT_SYMBOL_GPL ( devm_clk_hw_register_fixed_factor_index ) ;
2022-06-30 01:53:23 +03:00
/**
* devm_clk_hw_register_fixed_factor_parent_hw - Register a fixed factor clock with
* pointer to parent clock
* @ dev : device that is registering this clock
* @ name : name of this clock
* @ parent_hw : pointer to parent clk
* @ flags : fixed factor flags
* @ mult : multiplier
* @ div : divider
*
* Return : Pointer to fixed factor clk_hw structure that was registered or
* an error pointer .
*/
struct clk_hw * devm_clk_hw_register_fixed_factor_parent_hw ( struct device * dev ,
const char * name , const struct clk_hw * parent_hw ,
unsigned long flags , unsigned int mult , unsigned int div )
{
2024-02-21 21:22:10 +03:00
const struct clk_parent_data pdata = { . index = - 1 } ;
2022-06-30 01:53:23 +03:00
return __clk_hw_register_fixed_factor ( dev , NULL , name , NULL , parent_hw ,
2024-02-21 21:22:10 +03:00
& pdata , flags , mult , div , 0 , 0 , true ) ;
2022-06-30 01:53:23 +03:00
}
EXPORT_SYMBOL_GPL ( devm_clk_hw_register_fixed_factor_parent_hw ) ;
struct clk_hw * clk_hw_register_fixed_factor_parent_hw ( struct device * dev ,
const char * name , const struct clk_hw * parent_hw ,
unsigned long flags , unsigned int mult , unsigned int div )
{
2024-02-21 21:22:10 +03:00
const struct clk_parent_data pdata = { . index = - 1 } ;
return __clk_hw_register_fixed_factor ( dev , NULL , name , NULL , parent_hw ,
& pdata , flags , mult , div , 0 , 0 , false ) ;
2022-06-30 01:53:23 +03:00
}
EXPORT_SYMBOL_GPL ( clk_hw_register_fixed_factor_parent_hw ) ;
2019-04-12 21:31:50 +03:00
struct clk_hw * clk_hw_register_fixed_factor ( struct device * dev ,
const char * name , const char * parent_name , unsigned long flags ,
unsigned int mult , unsigned int div )
{
2024-02-21 21:22:10 +03:00
const struct clk_parent_data pdata = { . index = - 1 } ;
return __clk_hw_register_fixed_factor ( dev , NULL , name , parent_name , NULL ,
& pdata , flags , mult , div , 0 , 0 , false ) ;
2019-04-12 21:31:50 +03:00
}
2016-02-07 11:11:06 +03:00
EXPORT_SYMBOL_GPL ( clk_hw_register_fixed_factor ) ;
2024-02-21 21:22:10 +03:00
struct clk_hw * clk_hw_register_fixed_factor_fwname ( struct device * dev ,
struct device_node * np , const char * name , const char * fw_name ,
unsigned long flags , unsigned int mult , unsigned int div )
{
const struct clk_parent_data pdata = { . index = - 1 , . fw_name = fw_name } ;
return __clk_hw_register_fixed_factor ( dev , np , name , NULL , NULL ,
& pdata , flags , mult , div , 0 , 0 , false ) ;
}
EXPORT_SYMBOL_GPL ( clk_hw_register_fixed_factor_fwname ) ;
struct clk_hw * clk_hw_register_fixed_factor_with_accuracy_fwname ( struct device * dev ,
struct device_node * np , const char * name , const char * fw_name ,
unsigned long flags , unsigned int mult , unsigned int div ,
unsigned long acc )
{
const struct clk_parent_data pdata = { . index = - 1 , . fw_name = fw_name } ;
return __clk_hw_register_fixed_factor ( dev , np , name , NULL , NULL ,
& pdata , flags , mult , div , acc ,
CLK_FIXED_FACTOR_FIXED_ACCURACY , false ) ;
}
EXPORT_SYMBOL_GPL ( clk_hw_register_fixed_factor_with_accuracy_fwname ) ;
2016-02-07 11:11:06 +03:00
struct clk * clk_register_fixed_factor ( struct device * dev , const char * name ,
const char * parent_name , unsigned long flags ,
unsigned int mult , unsigned int div )
{
struct clk_hw * hw ;
hw = clk_hw_register_fixed_factor ( dev , name , parent_name , flags , mult ,
div ) ;
if ( IS_ERR ( hw ) )
return ERR_CAST ( hw ) ;
return hw - > clk ;
2012-05-03 14:06:14 +04:00
}
2013-08-16 06:06:29 +04:00
EXPORT_SYMBOL_GPL ( clk_register_fixed_factor ) ;
2016-01-06 07:25:09 +03:00
void clk_unregister_fixed_factor ( struct clk * clk )
{
struct clk_hw * hw ;
hw = __clk_get_hw ( clk ) ;
if ( ! hw )
return ;
clk_unregister ( clk ) ;
kfree ( to_clk_fixed_factor ( hw ) ) ;
}
EXPORT_SYMBOL_GPL ( clk_unregister_fixed_factor ) ;
2016-02-07 11:11:06 +03:00
void clk_hw_unregister_fixed_factor ( struct clk_hw * hw )
{
struct clk_fixed_factor * fix ;
fix = to_clk_fixed_factor ( hw ) ;
clk_hw_unregister ( hw ) ;
kfree ( fix ) ;
}
EXPORT_SYMBOL_GPL ( clk_hw_unregister_fixed_factor ) ;
2013-08-16 06:06:29 +04:00
2021-02-11 08:22:02 +03:00
struct clk_hw * devm_clk_hw_register_fixed_factor ( struct device * dev ,
const char * name , const char * parent_name , unsigned long flags ,
unsigned int mult , unsigned int div )
{
2024-02-21 21:22:10 +03:00
const struct clk_parent_data pdata = { . index = - 1 } ;
return __clk_hw_register_fixed_factor ( dev , NULL , name , parent_name , NULL ,
& pdata , flags , mult , div , 0 , 0 , true ) ;
2021-02-11 08:22:02 +03:00
}
EXPORT_SYMBOL_GPL ( devm_clk_hw_register_fixed_factor ) ;
2024-02-21 21:22:10 +03:00
struct clk_hw * devm_clk_hw_register_fixed_factor_fwname ( struct device * dev ,
struct device_node * np , const char * name , const char * fw_name ,
unsigned long flags , unsigned int mult , unsigned int div )
{
const struct clk_parent_data pdata = { . index = - 1 , . fw_name = fw_name } ;
return __clk_hw_register_fixed_factor ( dev , np , name , NULL , NULL ,
& pdata , flags , mult , div , 0 , 0 , true ) ;
}
EXPORT_SYMBOL_GPL ( devm_clk_hw_register_fixed_factor_fwname ) ;
struct clk_hw * devm_clk_hw_register_fixed_factor_with_accuracy_fwname ( struct device * dev ,
struct device_node * np , const char * name , const char * fw_name ,
unsigned long flags , unsigned int mult , unsigned int div ,
unsigned long acc )
{
const struct clk_parent_data pdata = { . index = - 1 , . fw_name = fw_name } ;
return __clk_hw_register_fixed_factor ( dev , np , name , NULL , NULL ,
& pdata , flags , mult , div , acc ,
CLK_FIXED_FACTOR_FIXED_ACCURACY , true ) ;
}
EXPORT_SYMBOL_GPL ( devm_clk_hw_register_fixed_factor_with_accuracy_fwname ) ;
2013-04-12 15:57:44 +04:00
# ifdef CONFIG_OF
2019-04-12 21:31:50 +03:00
static struct clk_hw * _of_fixed_factor_clk_setup ( struct device_node * node )
2013-04-12 15:57:44 +04:00
{
2019-04-12 21:31:50 +03:00
struct clk_hw * hw ;
2013-04-12 15:57:44 +04:00
const char * clk_name = node - > name ;
2024-02-21 21:22:10 +03:00
const struct clk_parent_data pdata = { . index = 0 } ;
2013-04-12 15:57:44 +04:00
u32 div , mult ;
2016-07-05 19:23:33 +03:00
int ret ;
2013-04-12 15:57:44 +04:00
if ( of_property_read_u32 ( node , " clock-div " , & div ) ) {
2018-08-28 18:44:29 +03:00
pr_err ( " %s Fixed factor clock <%pOFn> must have a clock-div property \n " ,
__func__ , node ) ;
2016-07-05 19:23:33 +03:00
return ERR_PTR ( - EIO ) ;
2013-04-12 15:57:44 +04:00
}
if ( of_property_read_u32 ( node , " clock-mult " , & mult ) ) {
2018-08-28 18:44:29 +03:00
pr_err ( " %s Fixed factor clock <%pOFn> must have a clock-mult property \n " ,
__func__ , node ) ;
2016-07-05 19:23:33 +03:00
return ERR_PTR ( - EIO ) ;
2013-04-12 15:57:44 +04:00
}
of_property_read_string ( node , " clock-output-names " , & clk_name ) ;
2024-02-21 21:22:10 +03:00
hw = __clk_hw_register_fixed_factor ( NULL , node , clk_name , NULL , NULL ,
& pdata , 0 , mult , div , 0 , 0 , false ) ;
2019-04-12 21:31:50 +03:00
if ( IS_ERR ( hw ) ) {
2018-07-17 16:17:00 +03:00
/*
* Clear OF_POPULATED flag so that clock registration can be
* attempted again from probe function .
*/
of_node_clear_flag ( node , OF_POPULATED ) ;
2019-04-12 21:31:50 +03:00
return ERR_CAST ( hw ) ;
2018-07-17 16:17:00 +03:00
}
2016-07-05 19:23:33 +03:00
2019-04-12 21:31:50 +03:00
ret = of_clk_add_hw_provider ( node , of_clk_hw_simple_get , hw ) ;
2016-07-05 19:23:33 +03:00
if ( ret ) {
2019-04-12 21:31:50 +03:00
clk_hw_unregister_fixed_factor ( hw ) ;
2016-07-05 19:23:33 +03:00
return ERR_PTR ( ret ) ;
}
2019-04-12 21:31:50 +03:00
return hw ;
2016-07-05 19:23:33 +03:00
}
/**
* of_fixed_factor_clk_setup ( ) - Setup function for simple fixed factor clock
2020-09-16 19:17:36 +03:00
* @ node : device node for the clock
2016-07-05 19:23:33 +03:00
*/
void __init of_fixed_factor_clk_setup ( struct device_node * node )
{
_of_fixed_factor_clk_setup ( node ) ;
2013-04-12 15:57:44 +04:00
}
CLK_OF_DECLARE ( fixed_factor_clk , " fixed-factor-clock " ,
of_fixed_factor_clk_setup ) ;
2016-07-05 19:23:33 +03:00
2023-03-12 19:14:50 +03:00
static void of_fixed_factor_clk_remove ( struct platform_device * pdev )
2016-07-05 19:23:33 +03:00
{
2019-04-12 21:31:50 +03:00
struct clk_hw * clk = platform_get_drvdata ( pdev ) ;
2016-07-05 19:23:33 +03:00
2018-11-01 16:15:49 +03:00
of_clk_del_provider ( pdev - > dev . of_node ) ;
2019-04-12 21:31:50 +03:00
clk_hw_unregister_fixed_factor ( clk ) ;
2016-07-05 19:23:33 +03:00
}
static int of_fixed_factor_clk_probe ( struct platform_device * pdev )
{
2019-04-12 21:31:50 +03:00
struct clk_hw * clk ;
2016-07-05 19:23:33 +03:00
/*
* This function is not executed when of_fixed_factor_clk_setup
* succeeded .
*/
clk = _of_fixed_factor_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_factor_clk_ids [ ] = {
{ . compatible = " fixed-factor-clock " } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , of_fixed_factor_clk_ids ) ;
static struct platform_driver of_fixed_factor_clk_driver = {
. driver = {
. name = " of_fixed_factor_clk " ,
. of_match_table = of_fixed_factor_clk_ids ,
} ,
. probe = of_fixed_factor_clk_probe ,
2023-03-12 19:14:50 +03:00
. remove_new = of_fixed_factor_clk_remove ,
2016-07-05 19:23:33 +03:00
} ;
builtin_platform_driver ( of_fixed_factor_clk_driver ) ;
2013-04-12 15:57:44 +04:00
# endif