1*9c92ab61SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 24116076eSJosh Cartwright /* 34116076eSJosh Cartwright * Copyright (c) 2014, The Linux Foundation. All rights reserved. 44116076eSJosh Cartwright */ 54116076eSJosh Cartwright 64116076eSJosh Cartwright #include <linux/kernel.h> 74116076eSJosh Cartwright #include <linux/bitops.h> 84116076eSJosh Cartwright #include <linux/regmap.h> 94116076eSJosh Cartwright #include <linux/export.h> 104116076eSJosh Cartwright 114116076eSJosh Cartwright #include "clk-regmap-divider.h" 124116076eSJosh Cartwright 134116076eSJosh Cartwright static inline struct clk_regmap_div *to_clk_regmap_div(struct clk_hw *hw) 144116076eSJosh Cartwright { 154116076eSJosh Cartwright return container_of(to_clk_regmap(hw), struct clk_regmap_div, clkr); 164116076eSJosh Cartwright } 174116076eSJosh Cartwright 18f933d383SAbhishek Sahu static long div_round_ro_rate(struct clk_hw *hw, unsigned long rate, 19f933d383SAbhishek Sahu unsigned long *prate) 20f933d383SAbhishek Sahu { 21f933d383SAbhishek Sahu struct clk_regmap_div *divider = to_clk_regmap_div(hw); 22f933d383SAbhishek Sahu struct clk_regmap *clkr = ÷r->clkr; 23f5edaefeSJerome Brunet u32 val; 24f933d383SAbhishek Sahu 25f5edaefeSJerome Brunet regmap_read(clkr->regmap, divider->reg, &val); 26f5edaefeSJerome Brunet val >>= divider->shift; 27f5edaefeSJerome Brunet val &= BIT(divider->width) - 1; 28f933d383SAbhishek Sahu 29f5edaefeSJerome Brunet return divider_ro_round_rate(hw, rate, prate, NULL, divider->width, 30f5edaefeSJerome Brunet CLK_DIVIDER_ROUND_CLOSEST, val); 31f933d383SAbhishek Sahu } 32f933d383SAbhishek Sahu 334116076eSJosh Cartwright static long div_round_rate(struct clk_hw *hw, unsigned long rate, 344116076eSJosh Cartwright unsigned long *prate) 354116076eSJosh Cartwright { 364116076eSJosh Cartwright struct clk_regmap_div *divider = to_clk_regmap_div(hw); 374116076eSJosh Cartwright 384116076eSJosh Cartwright return divider_round_rate(hw, rate, prate, NULL, divider->width, 394116076eSJosh Cartwright CLK_DIVIDER_ROUND_CLOSEST); 404116076eSJosh Cartwright } 414116076eSJosh Cartwright 424116076eSJosh Cartwright static int div_set_rate(struct clk_hw *hw, unsigned long rate, 434116076eSJosh Cartwright unsigned long parent_rate) 444116076eSJosh Cartwright { 454116076eSJosh Cartwright struct clk_regmap_div *divider = to_clk_regmap_div(hw); 464116076eSJosh Cartwright struct clk_regmap *clkr = ÷r->clkr; 474116076eSJosh Cartwright u32 div; 484116076eSJosh Cartwright 494116076eSJosh Cartwright div = divider_get_val(rate, parent_rate, NULL, divider->width, 504116076eSJosh Cartwright CLK_DIVIDER_ROUND_CLOSEST); 514116076eSJosh Cartwright 524116076eSJosh Cartwright return regmap_update_bits(clkr->regmap, divider->reg, 534116076eSJosh Cartwright (BIT(divider->width) - 1) << divider->shift, 544116076eSJosh Cartwright div << divider->shift); 554116076eSJosh Cartwright } 564116076eSJosh Cartwright 574116076eSJosh Cartwright static unsigned long div_recalc_rate(struct clk_hw *hw, 584116076eSJosh Cartwright unsigned long parent_rate) 594116076eSJosh Cartwright { 604116076eSJosh Cartwright struct clk_regmap_div *divider = to_clk_regmap_div(hw); 614116076eSJosh Cartwright struct clk_regmap *clkr = ÷r->clkr; 624116076eSJosh Cartwright u32 div; 634116076eSJosh Cartwright 644116076eSJosh Cartwright regmap_read(clkr->regmap, divider->reg, &div); 654116076eSJosh Cartwright div >>= divider->shift; 664116076eSJosh Cartwright div &= BIT(divider->width) - 1; 674116076eSJosh Cartwright 684116076eSJosh Cartwright return divider_recalc_rate(hw, parent_rate, div, NULL, 6912a26c29SJerome Brunet CLK_DIVIDER_ROUND_CLOSEST, divider->width); 704116076eSJosh Cartwright } 714116076eSJosh Cartwright 724116076eSJosh Cartwright const struct clk_ops clk_regmap_div_ops = { 734116076eSJosh Cartwright .round_rate = div_round_rate, 744116076eSJosh Cartwright .set_rate = div_set_rate, 754116076eSJosh Cartwright .recalc_rate = div_recalc_rate, 764116076eSJosh Cartwright }; 774116076eSJosh Cartwright EXPORT_SYMBOL_GPL(clk_regmap_div_ops); 78f933d383SAbhishek Sahu 79f933d383SAbhishek Sahu const struct clk_ops clk_regmap_div_ro_ops = { 80f933d383SAbhishek Sahu .round_rate = div_round_ro_rate, 81f933d383SAbhishek Sahu .recalc_rate = div_recalc_rate, 82f933d383SAbhishek Sahu }; 83f933d383SAbhishek Sahu EXPORT_SYMBOL_GPL(clk_regmap_div_ro_ops); 84