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