1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2014, The Linux Foundation. All rights reserved. 4 */ 5 6 #include <linux/kernel.h> 7 #include <linux/bitops.h> 8 #include <linux/regmap.h> 9 #include <linux/export.h> 10 11 #include "clk-regmap-divider.h" 12 13 static inline struct clk_regmap_div *to_clk_regmap_div(struct clk_hw *hw) 14 { 15 return container_of(to_clk_regmap(hw), struct clk_regmap_div, clkr); 16 } 17 18 static int div_ro_determine_rate(struct clk_hw *hw, 19 struct clk_rate_request *req) 20 { 21 struct clk_regmap_div *divider = to_clk_regmap_div(hw); 22 struct clk_regmap *clkr = ÷r->clkr; 23 u32 val; 24 25 regmap_read(clkr->regmap, divider->reg, &val); 26 val >>= divider->shift; 27 val &= BIT(divider->width) - 1; 28 29 return divider_ro_determine_rate(hw, req, NULL, divider->width, 30 CLK_DIVIDER_ROUND_CLOSEST, val); 31 } 32 33 static int div_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) 34 { 35 struct clk_regmap_div *divider = to_clk_regmap_div(hw); 36 37 return divider_determine_rate(hw, req, NULL, divider->width, 38 CLK_DIVIDER_ROUND_CLOSEST); 39 } 40 41 static int div_set_rate(struct clk_hw *hw, unsigned long rate, 42 unsigned long parent_rate) 43 { 44 struct clk_regmap_div *divider = to_clk_regmap_div(hw); 45 struct clk_regmap *clkr = ÷r->clkr; 46 u32 div; 47 48 div = divider_get_val(rate, parent_rate, NULL, divider->width, 49 CLK_DIVIDER_ROUND_CLOSEST); 50 51 return regmap_update_bits(clkr->regmap, divider->reg, 52 (BIT(divider->width) - 1) << divider->shift, 53 div << divider->shift); 54 } 55 56 static unsigned long div_recalc_rate(struct clk_hw *hw, 57 unsigned long parent_rate) 58 { 59 struct clk_regmap_div *divider = to_clk_regmap_div(hw); 60 struct clk_regmap *clkr = ÷r->clkr; 61 u32 div; 62 63 regmap_read(clkr->regmap, divider->reg, &div); 64 div >>= divider->shift; 65 div &= BIT(divider->width) - 1; 66 67 return divider_recalc_rate(hw, parent_rate, div, NULL, 68 CLK_DIVIDER_ROUND_CLOSEST, divider->width); 69 } 70 71 const struct clk_ops clk_regmap_div_ops = { 72 .determine_rate = div_determine_rate, 73 .set_rate = div_set_rate, 74 .recalc_rate = div_recalc_rate, 75 }; 76 EXPORT_SYMBOL_GPL(clk_regmap_div_ops); 77 78 const struct clk_ops clk_regmap_div_ro_ops = { 79 .determine_rate = div_ro_determine_rate, 80 .recalc_rate = div_recalc_rate, 81 }; 82 EXPORT_SYMBOL_GPL(clk_regmap_div_ro_ops); 83