owl-divider.c (2493B)
1// SPDX-License-Identifier: GPL-2.0+ 2// 3// OWL divider clock driver 4// 5// Copyright (c) 2014 Actions Semi Inc. 6// Author: David Liu <liuwei@actions-semi.com> 7// 8// Copyright (c) 2018 Linaro Ltd. 9// Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> 10 11#include <linux/clk-provider.h> 12#include <linux/regmap.h> 13 14#include "owl-divider.h" 15 16long owl_divider_helper_round_rate(struct owl_clk_common *common, 17 const struct owl_divider_hw *div_hw, 18 unsigned long rate, 19 unsigned long *parent_rate) 20{ 21 return divider_round_rate(&common->hw, rate, parent_rate, 22 div_hw->table, div_hw->width, 23 div_hw->div_flags); 24} 25 26static long owl_divider_round_rate(struct clk_hw *hw, unsigned long rate, 27 unsigned long *parent_rate) 28{ 29 struct owl_divider *div = hw_to_owl_divider(hw); 30 31 return owl_divider_helper_round_rate(&div->common, &div->div_hw, 32 rate, parent_rate); 33} 34 35unsigned long owl_divider_helper_recalc_rate(struct owl_clk_common *common, 36 const struct owl_divider_hw *div_hw, 37 unsigned long parent_rate) 38{ 39 unsigned long val; 40 unsigned int reg; 41 42 regmap_read(common->regmap, div_hw->reg, ®); 43 val = reg >> div_hw->shift; 44 val &= (1 << div_hw->width) - 1; 45 46 return divider_recalc_rate(&common->hw, parent_rate, 47 val, div_hw->table, 48 div_hw->div_flags, 49 div_hw->width); 50} 51 52static unsigned long owl_divider_recalc_rate(struct clk_hw *hw, 53 unsigned long parent_rate) 54{ 55 struct owl_divider *div = hw_to_owl_divider(hw); 56 57 return owl_divider_helper_recalc_rate(&div->common, 58 &div->div_hw, parent_rate); 59} 60 61int owl_divider_helper_set_rate(const struct owl_clk_common *common, 62 const struct owl_divider_hw *div_hw, 63 unsigned long rate, 64 unsigned long parent_rate) 65{ 66 unsigned long val; 67 unsigned int reg; 68 69 val = divider_get_val(rate, parent_rate, div_hw->table, 70 div_hw->width, 0); 71 72 regmap_read(common->regmap, div_hw->reg, ®); 73 reg &= ~GENMASK(div_hw->width + div_hw->shift - 1, div_hw->shift); 74 75 regmap_write(common->regmap, div_hw->reg, 76 reg | (val << div_hw->shift)); 77 78 return 0; 79} 80 81static int owl_divider_set_rate(struct clk_hw *hw, unsigned long rate, 82 unsigned long parent_rate) 83{ 84 struct owl_divider *div = hw_to_owl_divider(hw); 85 86 return owl_divider_helper_set_rate(&div->common, &div->div_hw, 87 rate, parent_rate); 88} 89 90const struct clk_ops owl_divider_ops = { 91 .recalc_rate = owl_divider_recalc_rate, 92 .round_rate = owl_divider_round_rate, 93 .set_rate = owl_divider_set_rate, 94};