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
to_clk_regmap_div(struct clk_hw * hw)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
div_round_ro_rate(struct clk_hw * hw,unsigned long rate,unsigned long * prate)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
div_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * prate)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
div_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)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
div_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)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