^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) // Spreadtrum 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) 2017 Spreadtrum, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) // Author: Chunyan Zhang <chunyan.zhang@spreadtrum.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/clk-provider.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include "div.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) long sprd_div_helper_round_rate(struct sprd_clk_common *common,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) const struct sprd_div_internal *div,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) unsigned long rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) unsigned long *parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) return divider_round_rate(&common->hw, rate, parent_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) NULL, div->width, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) EXPORT_SYMBOL_GPL(sprd_div_helper_round_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) static long sprd_div_round_rate(struct clk_hw *hw, unsigned long rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) unsigned long *parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) struct sprd_div *cd = hw_to_sprd_div(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) return sprd_div_helper_round_rate(&cd->common, &cd->div,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) rate, parent_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) unsigned long sprd_div_helper_recalc_rate(struct sprd_clk_common *common,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) const struct sprd_div_internal *div,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) unsigned long parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) unsigned long val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) unsigned int reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) regmap_read(common->regmap, common->reg, ®);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) val = reg >> div->shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) val &= (1 << div->width) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) return divider_recalc_rate(&common->hw, parent_rate, val, NULL, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) div->width);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) EXPORT_SYMBOL_GPL(sprd_div_helper_recalc_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) static unsigned long sprd_div_recalc_rate(struct clk_hw *hw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) unsigned long parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) struct sprd_div *cd = hw_to_sprd_div(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) return sprd_div_helper_recalc_rate(&cd->common, &cd->div, parent_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) int sprd_div_helper_set_rate(const struct sprd_clk_common *common,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) const struct sprd_div_internal *div,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) unsigned long rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) unsigned long parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) unsigned long val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) unsigned int reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) val = divider_get_val(rate, parent_rate, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) div->width, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) regmap_read(common->regmap, common->reg, ®);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) reg &= ~GENMASK(div->width + div->shift - 1, div->shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) regmap_write(common->regmap, common->reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) reg | (val << div->shift));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) EXPORT_SYMBOL_GPL(sprd_div_helper_set_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) static int sprd_div_set_rate(struct clk_hw *hw, unsigned long rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) unsigned long parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) struct sprd_div *cd = hw_to_sprd_div(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) return sprd_div_helper_set_rate(&cd->common, &cd->div,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) rate, parent_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) const struct clk_ops sprd_div_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) .recalc_rate = sprd_div_recalc_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) .round_rate = sprd_div_round_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) .set_rate = sprd_div_set_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) EXPORT_SYMBOL_GPL(sprd_div_ops);