2019-05-29 07:17:56 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2015-01-19 18:05:30 -08:00
/*
* Copyright ( c ) 2014 , The Linux Foundation . All rights reserved .
*/
# include <linux/kernel.h>
# include <linux/bitops.h>
# include <linux/regmap.h>
# include <linux/export.h>
# include "clk-regmap-divider.h"
static inline struct clk_regmap_div * to_clk_regmap_div ( struct clk_hw * hw )
{
return container_of ( to_clk_regmap ( hw ) , struct clk_regmap_div , clkr ) ;
}
2017-12-13 19:55:32 +05:30
static long div_round_ro_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long * prate )
{
struct clk_regmap_div * divider = to_clk_regmap_div ( hw ) ;
struct clk_regmap * clkr = & divider - > clkr ;
2018-02-14 14:43:40 +01:00
u32 val ;
2017-12-13 19:55:32 +05:30
2018-02-14 14:43:40 +01:00
regmap_read ( clkr - > regmap , divider - > reg , & val ) ;
val > > = divider - > shift ;
val & = BIT ( divider - > width ) - 1 ;
2017-12-13 19:55:32 +05:30
2018-02-14 14:43:40 +01:00
return divider_ro_round_rate ( hw , rate , prate , NULL , divider - > width ,
CLK_DIVIDER_ROUND_CLOSEST , val ) ;
2017-12-13 19:55:32 +05:30
}
2015-01-19 18:05:30 -08:00
static long div_round_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long * prate )
{
struct clk_regmap_div * divider = to_clk_regmap_div ( hw ) ;
return divider_round_rate ( hw , rate , prate , NULL , divider - > width ,
CLK_DIVIDER_ROUND_CLOSEST ) ;
}
static int div_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long parent_rate )
{
struct clk_regmap_div * divider = to_clk_regmap_div ( hw ) ;
struct clk_regmap * clkr = & divider - > clkr ;
u32 div ;
div = divider_get_val ( rate , parent_rate , NULL , divider - > width ,
CLK_DIVIDER_ROUND_CLOSEST ) ;
return regmap_update_bits ( clkr - > regmap , divider - > reg ,
( BIT ( divider - > width ) - 1 ) < < divider - > shift ,
div < < divider - > shift ) ;
}
static unsigned long div_recalc_rate ( struct clk_hw * hw ,
unsigned long parent_rate )
{
struct clk_regmap_div * divider = to_clk_regmap_div ( hw ) ;
struct clk_regmap * clkr = & divider - > clkr ;
u32 div ;
regmap_read ( clkr - > regmap , divider - > reg , & div ) ;
div > > = divider - > shift ;
div & = BIT ( divider - > width ) - 1 ;
return divider_recalc_rate ( hw , parent_rate , div , NULL ,
2017-12-21 17:30:54 +01:00
CLK_DIVIDER_ROUND_CLOSEST , divider - > width ) ;
2015-01-19 18:05:30 -08:00
}
const struct clk_ops clk_regmap_div_ops = {
. round_rate = div_round_rate ,
. set_rate = div_set_rate ,
. recalc_rate = div_recalc_rate ,
} ;
EXPORT_SYMBOL_GPL ( clk_regmap_div_ops ) ;
2017-12-13 19:55:32 +05:30
const struct clk_ops clk_regmap_div_ro_ops = {
. round_rate = div_round_ro_rate ,
. recalc_rate = div_recalc_rate ,
} ;
EXPORT_SYMBOL_GPL ( clk_regmap_div_ro_ops ) ;