2018-12-11 09:57:48 -08:00
// SPDX-License-Identifier: GPL-2.0
2013-03-20 17:30:34 +05:30
/*
* Copyright ( c ) 2013 NVIDIA CORPORATION . All rights reserved .
*/
# include <linux/clk-provider.h>
2020-11-05 20:27:45 +01:00
# include <linux/device.h>
2013-03-20 17:30:34 +05:30
# include <linux/err.h>
# include <linux/slab.h>
static u8 clk_composite_get_parent ( struct clk_hw * hw )
{
struct clk_composite * composite = to_clk_composite ( hw ) ;
const struct clk_ops * mux_ops = composite - > mux_ops ;
struct clk_hw * mux_hw = composite - > mux_hw ;
2015-02-12 14:58:30 +01:00
__clk_hw_set_clk ( mux_hw , hw ) ;
2013-03-20 17:30:34 +05:30
return mux_ops - > get_parent ( mux_hw ) ;
}
static int clk_composite_set_parent ( struct clk_hw * hw , u8 index )
{
struct clk_composite * composite = to_clk_composite ( hw ) ;
const struct clk_ops * mux_ops = composite - > mux_ops ;
struct clk_hw * mux_hw = composite - > mux_hw ;
2015-02-12 14:58:30 +01:00
__clk_hw_set_clk ( mux_hw , hw ) ;
2013-03-20 17:30:34 +05:30
return mux_ops - > set_parent ( mux_hw , index ) ;
}
static unsigned long clk_composite_recalc_rate ( struct clk_hw * hw ,
unsigned long parent_rate )
{
struct clk_composite * composite = to_clk_composite ( hw ) ;
2013-04-11 11:31:36 -07:00
const struct clk_ops * rate_ops = composite - > rate_ops ;
struct clk_hw * rate_hw = composite - > rate_hw ;
2013-03-20 17:30:34 +05:30
2015-02-12 14:58:30 +01:00
__clk_hw_set_clk ( rate_hw , hw ) ;
2013-03-20 17:30:34 +05:30
2013-04-11 11:31:36 -07:00
return rate_ops - > recalc_rate ( rate_hw , parent_rate ) ;
2013-03-20 17:30:34 +05:30
}
2021-10-16 12:50:22 +02:00
static int clk_composite_determine_rate_for_parent ( struct clk_hw * rate_hw ,
struct clk_rate_request * req ,
struct clk_hw * parent_hw ,
const struct clk_ops * rate_ops )
{
long rate ;
req - > best_parent_hw = parent_hw ;
req - > best_parent_rate = clk_hw_get_rate ( parent_hw ) ;
if ( rate_ops - > determine_rate )
return rate_ops - > determine_rate ( rate_hw , req ) ;
rate = rate_ops - > round_rate ( rate_hw , req - > rate ,
& req - > best_parent_rate ) ;
if ( rate < 0 )
return rate ;
req - > rate = rate ;
return 0 ;
}
2015-07-07 20:48:08 +02:00
static int clk_composite_determine_rate ( struct clk_hw * hw ,
struct clk_rate_request * req )
2013-09-14 21:37:59 -03:00
{
struct clk_composite * composite = to_clk_composite ( hw ) ;
const struct clk_ops * rate_ops = composite - > rate_ops ;
const struct clk_ops * mux_ops = composite - > mux_ops ;
struct clk_hw * rate_hw = composite - > rate_hw ;
struct clk_hw * mux_hw = composite - > mux_hw ;
2015-07-30 17:20:57 -07:00
struct clk_hw * parent ;
2014-07-03 01:56:45 +02:00
unsigned long rate_diff ;
unsigned long best_rate_diff = ULONG_MAX ;
2021-10-16 12:50:22 +02:00
unsigned long best_rate = 0 ;
int i , ret ;
2013-09-14 21:37:59 -03:00
2021-10-16 12:50:22 +02:00
if ( rate_hw & & rate_ops & &
( rate_ops - > determine_rate | | rate_ops - > round_rate ) & &
2021-10-16 12:50:21 +02:00
mux_hw & & mux_ops & & mux_ops - > set_parent ) {
2015-07-07 20:48:08 +02:00
req - > best_parent_hw = NULL ;
2014-07-03 01:56:45 +02:00
2015-06-29 16:56:30 -07:00
if ( clk_hw_get_flags ( hw ) & CLK_SET_RATE_NO_REPARENT ) {
2021-10-16 12:50:22 +02:00
struct clk_rate_request tmp_req = * req ;
2015-07-30 17:20:57 -07:00
parent = clk_hw_get_parent ( mux_hw ) ;
2014-07-03 01:56:45 +02:00
2021-10-16 12:50:22 +02:00
ret = clk_composite_determine_rate_for_parent ( rate_hw ,
& tmp_req ,
parent ,
rate_ops ) ;
if ( ret )
return ret ;
req - > rate = tmp_req . rate ;
2021-11-03 13:24:41 +01:00
req - > best_parent_hw = tmp_req . best_parent_hw ;
2021-10-16 12:50:22 +02:00
req - > best_parent_rate = tmp_req . best_parent_rate ;
2015-07-07 20:48:08 +02:00
return 0 ;
2014-07-03 01:56:45 +02:00
}
2015-06-25 16:53:23 -07:00
for ( i = 0 ; i < clk_hw_get_num_parents ( mux_hw ) ; i + + ) {
2021-10-16 12:50:22 +02:00
struct clk_rate_request tmp_req = * req ;
2015-07-30 17:20:57 -07:00
parent = clk_hw_get_parent_by_index ( mux_hw , i ) ;
2014-07-03 01:56:45 +02:00
if ( ! parent )
continue ;
2021-10-16 12:50:22 +02:00
ret = clk_composite_determine_rate_for_parent ( rate_hw ,
& tmp_req ,
parent ,
rate_ops ) ;
if ( ret )
2014-07-03 01:56:45 +02:00
continue ;
2021-10-16 12:50:22 +02:00
rate_diff = abs ( req - > rate - tmp_req . rate ) ;
2014-07-03 01:56:45 +02:00
2015-07-07 20:48:08 +02:00
if ( ! rate_diff | | ! req - > best_parent_hw
2014-07-03 01:56:45 +02:00
| | best_rate_diff > rate_diff ) {
2015-07-30 17:20:57 -07:00
req - > best_parent_hw = parent ;
2021-10-16 12:50:22 +02:00
req - > best_parent_rate = tmp_req . best_parent_rate ;
2014-07-03 01:56:45 +02:00
best_rate_diff = rate_diff ;
2021-10-16 12:50:22 +02:00
best_rate = tmp_req . rate ;
2014-07-03 01:56:45 +02:00
}
if ( ! rate_diff )
2015-07-07 20:48:08 +02:00
return 0 ;
2014-07-03 01:56:45 +02:00
}
2015-07-07 20:48:08 +02:00
req - > rate = best_rate ;
return 0 ;
2021-10-16 12:50:21 +02:00
} else if ( rate_hw & & rate_ops & & rate_ops - > determine_rate ) {
__clk_hw_set_clk ( rate_hw , hw ) ;
return rate_ops - > determine_rate ( rate_hw , req ) ;
2013-09-14 21:37:59 -03:00
} else if ( mux_hw & & mux_ops & & mux_ops - > determine_rate ) {
2015-02-12 14:58:30 +01:00
__clk_hw_set_clk ( mux_hw , hw ) ;
2015-07-07 20:48:08 +02:00
return mux_ops - > determine_rate ( mux_hw , req ) ;
2013-09-14 21:37:59 -03:00
} else {
pr_err ( " clk: clk_composite_determine_rate function called, but no mux or rate callback set! \n " ) ;
2015-07-09 22:39:38 +02:00
return - EINVAL ;
2013-09-14 21:37:59 -03:00
}
}
2013-03-20 17:30:34 +05:30
static long clk_composite_round_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long * prate )
{
struct clk_composite * composite = to_clk_composite ( hw ) ;
2013-04-11 11:31:36 -07:00
const struct clk_ops * rate_ops = composite - > rate_ops ;
struct clk_hw * rate_hw = composite - > rate_hw ;
2013-03-20 17:30:34 +05:30
2015-02-12 14:58:30 +01:00
__clk_hw_set_clk ( rate_hw , hw ) ;
2013-03-20 17:30:34 +05:30
2013-04-11 11:31:36 -07:00
return rate_ops - > round_rate ( rate_hw , rate , prate ) ;
2013-03-20 17:30:34 +05:30
}
static int clk_composite_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long parent_rate )
{
struct clk_composite * composite = to_clk_composite ( hw ) ;
2013-04-11 11:31:36 -07:00
const struct clk_ops * rate_ops = composite - > rate_ops ;
struct clk_hw * rate_hw = composite - > rate_hw ;
2013-03-20 17:30:34 +05:30
2015-02-12 14:58:30 +01:00
__clk_hw_set_clk ( rate_hw , hw ) ;
2013-03-20 17:30:34 +05:30
2013-04-11 11:31:36 -07:00
return rate_ops - > set_rate ( rate_hw , rate , parent_rate ) ;
2013-03-20 17:30:34 +05:30
}
2016-04-12 16:43:39 +08:00
static int clk_composite_set_rate_and_parent ( struct clk_hw * hw ,
unsigned long rate ,
unsigned long parent_rate ,
u8 index )
{
struct clk_composite * composite = to_clk_composite ( hw ) ;
const struct clk_ops * rate_ops = composite - > rate_ops ;
const struct clk_ops * mux_ops = composite - > mux_ops ;
struct clk_hw * rate_hw = composite - > rate_hw ;
struct clk_hw * mux_hw = composite - > mux_hw ;
unsigned long temp_rate ;
__clk_hw_set_clk ( rate_hw , hw ) ;
__clk_hw_set_clk ( mux_hw , hw ) ;
temp_rate = rate_ops - > recalc_rate ( rate_hw , parent_rate ) ;
if ( temp_rate > rate ) {
rate_ops - > set_rate ( rate_hw , rate , parent_rate ) ;
mux_ops - > set_parent ( mux_hw , index ) ;
} else {
mux_ops - > set_parent ( mux_hw , index ) ;
rate_ops - > set_rate ( rate_hw , rate , parent_rate ) ;
}
return 0 ;
}
2013-03-20 17:30:34 +05:30
static int clk_composite_is_enabled ( struct clk_hw * hw )
{
struct clk_composite * composite = to_clk_composite ( hw ) ;
const struct clk_ops * gate_ops = composite - > gate_ops ;
struct clk_hw * gate_hw = composite - > gate_hw ;
2015-02-12 14:58:30 +01:00
__clk_hw_set_clk ( gate_hw , hw ) ;
2013-03-20 17:30:34 +05:30
return gate_ops - > is_enabled ( gate_hw ) ;
}
static int clk_composite_enable ( struct clk_hw * hw )
{
struct clk_composite * composite = to_clk_composite ( hw ) ;
const struct clk_ops * gate_ops = composite - > gate_ops ;
struct clk_hw * gate_hw = composite - > gate_hw ;
2015-02-12 14:58:30 +01:00
__clk_hw_set_clk ( gate_hw , hw ) ;
2013-03-20 17:30:34 +05:30
return gate_ops - > enable ( gate_hw ) ;
}
static void clk_composite_disable ( struct clk_hw * hw )
{
struct clk_composite * composite = to_clk_composite ( hw ) ;
const struct clk_ops * gate_ops = composite - > gate_ops ;
struct clk_hw * gate_hw = composite - > gate_hw ;
2015-02-12 14:58:30 +01:00
__clk_hw_set_clk ( gate_hw , hw ) ;
2013-03-20 17:30:34 +05:30
gate_ops - > disable ( gate_hw ) ;
}
2020-01-03 00:10:59 +01:00
static struct clk_hw * __clk_hw_register_composite ( struct device * dev ,
const char * name , const char * const * parent_names ,
const struct clk_parent_data * pdata , int num_parents ,
2013-03-20 17:30:34 +05:30
struct clk_hw * mux_hw , const struct clk_ops * mux_ops ,
2013-04-11 11:31:36 -07:00
struct clk_hw * rate_hw , const struct clk_ops * rate_ops ,
2013-03-20 17:30:34 +05:30
struct clk_hw * gate_hw , const struct clk_ops * gate_ops ,
unsigned long flags )
{
2016-02-07 00:20:31 -08:00
struct clk_hw * hw ;
2019-11-15 21:58:55 +05:30
struct clk_init_data init = { } ;
2013-03-20 17:30:34 +05:30
struct clk_composite * composite ;
struct clk_ops * clk_composite_ops ;
2016-02-07 00:20:31 -08:00
int ret ;
2013-03-20 17:30:34 +05:30
composite = kzalloc ( sizeof ( * composite ) , GFP_KERNEL ) ;
2015-05-14 16:47:10 -07:00
if ( ! composite )
2013-03-20 17:30:34 +05:30
return ERR_PTR ( - ENOMEM ) ;
init . name = name ;
2019-04-25 10:57:37 -07:00
init . flags = flags ;
2020-01-03 00:10:59 +01:00
if ( parent_names )
init . parent_names = parent_names ;
else
init . parent_data = pdata ;
2013-03-20 17:30:34 +05:30
init . num_parents = num_parents ;
2016-02-07 00:20:31 -08:00
hw = & composite - > hw ;
2013-03-20 17:30:34 +05:30
clk_composite_ops = & composite - > ops ;
if ( mux_hw & & mux_ops ) {
2014-07-03 01:57:30 +02:00
if ( ! mux_ops - > get_parent ) {
2016-02-07 00:20:31 -08:00
hw = ERR_PTR ( - EINVAL ) ;
2013-03-20 17:30:34 +05:30
goto err ;
}
composite - > mux_hw = mux_hw ;
composite - > mux_ops = mux_ops ;
clk_composite_ops - > get_parent = clk_composite_get_parent ;
2014-07-03 01:57:30 +02:00
if ( mux_ops - > set_parent )
clk_composite_ops - > set_parent = clk_composite_set_parent ;
2013-09-14 21:37:59 -03:00
if ( mux_ops - > determine_rate )
clk_composite_ops - > determine_rate = clk_composite_determine_rate ;
2013-03-20 17:30:34 +05:30
}
2013-04-11 11:31:36 -07:00
if ( rate_hw & & rate_ops ) {
2013-04-11 11:31:37 -07:00
if ( ! rate_ops - > recalc_rate ) {
2016-02-07 00:20:31 -08:00
hw = ERR_PTR ( - EINVAL ) ;
2013-03-20 17:30:34 +05:30
goto err ;
}
2014-07-03 01:58:14 +02:00
clk_composite_ops - > recalc_rate = clk_composite_recalc_rate ;
2013-03-20 17:30:34 +05:30
2014-07-03 01:58:14 +02:00
if ( rate_ops - > determine_rate )
clk_composite_ops - > determine_rate =
clk_composite_determine_rate ;
else if ( rate_ops - > round_rate )
clk_composite_ops - > round_rate =
clk_composite_round_rate ;
/* .set_rate requires either .round_rate or .determine_rate */
if ( rate_ops - > set_rate ) {
if ( rate_ops - > determine_rate | | rate_ops - > round_rate )
clk_composite_ops - > set_rate =
clk_composite_set_rate ;
else
WARN ( 1 , " %s: missing round_rate op is required \n " ,
__func__ ) ;
2013-04-11 11:31:37 -07:00
}
2013-04-11 11:31:36 -07:00
composite - > rate_hw = rate_hw ;
composite - > rate_ops = rate_ops ;
2013-03-20 17:30:34 +05:30
}
2016-04-12 16:43:39 +08:00
if ( mux_hw & & mux_ops & & rate_hw & & rate_ops ) {
if ( mux_ops - > set_parent & & rate_ops - > set_rate )
clk_composite_ops - > set_rate_and_parent =
clk_composite_set_rate_and_parent ;
}
2013-03-20 17:30:34 +05:30
if ( gate_hw & & gate_ops ) {
if ( ! gate_ops - > is_enabled | | ! gate_ops - > enable | |
! gate_ops - > disable ) {
2016-02-07 00:20:31 -08:00
hw = ERR_PTR ( - EINVAL ) ;
2013-03-20 17:30:34 +05:30
goto err ;
}
composite - > gate_hw = gate_hw ;
composite - > gate_ops = gate_ops ;
clk_composite_ops - > is_enabled = clk_composite_is_enabled ;
clk_composite_ops - > enable = clk_composite_enable ;
clk_composite_ops - > disable = clk_composite_disable ;
}
init . ops = clk_composite_ops ;
composite - > hw . init = & init ;
2016-02-07 00:20:31 -08:00
ret = clk_hw_register ( dev , hw ) ;
if ( ret ) {
hw = ERR_PTR ( ret ) ;
2013-03-20 17:30:34 +05:30
goto err ;
2016-02-07 00:20:31 -08:00
}
2013-03-20 17:30:34 +05:30
if ( composite - > mux_hw )
2016-02-07 00:20:31 -08:00
composite - > mux_hw - > clk = hw - > clk ;
2013-03-20 17:30:34 +05:30
2013-04-11 11:31:36 -07:00
if ( composite - > rate_hw )
2016-02-07 00:20:31 -08:00
composite - > rate_hw - > clk = hw - > clk ;
2013-03-20 17:30:34 +05:30
if ( composite - > gate_hw )
2016-02-07 00:20:31 -08:00
composite - > gate_hw - > clk = hw - > clk ;
2013-03-20 17:30:34 +05:30
2016-02-07 00:20:31 -08:00
return hw ;
2013-03-20 17:30:34 +05:30
err :
kfree ( composite ) ;
2016-02-07 00:20:31 -08:00
return hw ;
}
2020-01-03 00:10:59 +01:00
struct clk_hw * clk_hw_register_composite ( struct device * dev , const char * name ,
const char * const * parent_names , int num_parents ,
struct clk_hw * mux_hw , const struct clk_ops * mux_ops ,
struct clk_hw * rate_hw , const struct clk_ops * rate_ops ,
struct clk_hw * gate_hw , const struct clk_ops * gate_ops ,
unsigned long flags )
{
return __clk_hw_register_composite ( dev , name , parent_names , NULL ,
num_parents , mux_hw , mux_ops ,
rate_hw , rate_ops , gate_hw ,
gate_ops , flags ) ;
}
2020-07-30 09:22:50 +08:00
EXPORT_SYMBOL_GPL ( clk_hw_register_composite ) ;
2020-01-03 00:10:59 +01:00
struct clk_hw * clk_hw_register_composite_pdata ( struct device * dev ,
const char * name ,
const struct clk_parent_data * parent_data ,
int num_parents ,
struct clk_hw * mux_hw , const struct clk_ops * mux_ops ,
struct clk_hw * rate_hw , const struct clk_ops * rate_ops ,
struct clk_hw * gate_hw , const struct clk_ops * gate_ops ,
unsigned long flags )
{
return __clk_hw_register_composite ( dev , name , NULL , parent_data ,
num_parents , mux_hw , mux_ops ,
rate_hw , rate_ops , gate_hw ,
gate_ops , flags ) ;
}
2016-02-07 00:20:31 -08:00
struct clk * clk_register_composite ( struct device * dev , const char * name ,
const char * const * parent_names , int num_parents ,
struct clk_hw * mux_hw , const struct clk_ops * mux_ops ,
struct clk_hw * rate_hw , const struct clk_ops * rate_ops ,
struct clk_hw * gate_hw , const struct clk_ops * gate_ops ,
unsigned long flags )
{
struct clk_hw * hw ;
hw = clk_hw_register_composite ( dev , name , parent_names , num_parents ,
mux_hw , mux_ops , rate_hw , rate_ops , gate_hw , gate_ops ,
flags ) ;
if ( IS_ERR ( hw ) )
return ERR_CAST ( hw ) ;
return hw - > clk ;
2013-03-20 17:30:34 +05:30
}
2021-09-02 06:25:24 +08:00
EXPORT_SYMBOL_GPL ( clk_register_composite ) ;
2016-03-23 17:38:24 +01:00
2020-01-03 00:10:59 +01:00
struct clk * clk_register_composite_pdata ( struct device * dev , const char * name ,
const struct clk_parent_data * parent_data ,
int num_parents ,
struct clk_hw * mux_hw , const struct clk_ops * mux_ops ,
struct clk_hw * rate_hw , const struct clk_ops * rate_ops ,
struct clk_hw * gate_hw , const struct clk_ops * gate_ops ,
unsigned long flags )
{
struct clk_hw * hw ;
hw = clk_hw_register_composite_pdata ( dev , name , parent_data ,
num_parents , mux_hw , mux_ops , rate_hw , rate_ops ,
gate_hw , gate_ops , flags ) ;
if ( IS_ERR ( hw ) )
return ERR_CAST ( hw ) ;
return hw - > clk ;
}
2016-03-23 17:38:24 +01:00
void clk_unregister_composite ( struct clk * clk )
{
struct clk_composite * composite ;
struct clk_hw * hw ;
hw = __clk_get_hw ( clk ) ;
if ( ! hw )
return ;
composite = to_clk_composite ( hw ) ;
clk_unregister ( clk ) ;
kfree ( composite ) ;
}
2019-11-15 21:58:56 +05:30
void clk_hw_unregister_composite ( struct clk_hw * hw )
{
struct clk_composite * composite ;
composite = to_clk_composite ( hw ) ;
clk_hw_unregister ( hw ) ;
kfree ( composite ) ;
}
EXPORT_SYMBOL_GPL ( clk_hw_unregister_composite ) ;
2020-11-05 20:27:45 +01:00
static void devm_clk_hw_release_composite ( struct device * dev , void * res )
{
clk_hw_unregister_composite ( * ( struct clk_hw * * ) res ) ;
}
static struct clk_hw * __devm_clk_hw_register_composite ( struct device * dev ,
const char * name , const char * const * parent_names ,
const struct clk_parent_data * pdata , int num_parents ,
struct clk_hw * mux_hw , const struct clk_ops * mux_ops ,
struct clk_hw * rate_hw , const struct clk_ops * rate_ops ,
struct clk_hw * gate_hw , const struct clk_ops * gate_ops ,
unsigned long flags )
{
struct clk_hw * * ptr , * hw ;
ptr = devres_alloc ( devm_clk_hw_release_composite , sizeof ( * ptr ) ,
GFP_KERNEL ) ;
if ( ! ptr )
return ERR_PTR ( - ENOMEM ) ;
hw = __clk_hw_register_composite ( dev , name , parent_names , pdata ,
num_parents , mux_hw , mux_ops , rate_hw ,
rate_ops , gate_hw , gate_ops , flags ) ;
if ( ! IS_ERR ( hw ) ) {
* ptr = hw ;
devres_add ( dev , ptr ) ;
} else {
devres_free ( ptr ) ;
}
return hw ;
}
struct clk_hw * devm_clk_hw_register_composite_pdata ( struct device * dev ,
const char * name ,
const struct clk_parent_data * parent_data ,
int num_parents ,
struct clk_hw * mux_hw , const struct clk_ops * mux_ops ,
struct clk_hw * rate_hw , const struct clk_ops * rate_ops ,
struct clk_hw * gate_hw , const struct clk_ops * gate_ops ,
unsigned long flags )
{
return __devm_clk_hw_register_composite ( dev , name , NULL , parent_data ,
num_parents , mux_hw , mux_ops ,
rate_hw , rate_ops , gate_hw ,
gate_ops , flags ) ;
}