^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) * Copyright (c) 2019 Rockchip Electronics Co. Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Base on code in drivers/clk/clk-fractional-divider.c.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * See clk-fractional-divider.c for further copyright information.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/rational.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include "clk-regmap.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #define to_clk_regmap_fractional_divider(_hw) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) container_of(_hw, struct clk_regmap_fractional_divider, hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) static unsigned long
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) clk_regmap_fractional_divider_recalc_rate(struct clk_hw *hw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) unsigned long parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) struct clk_regmap_fractional_divider *fd =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) to_clk_regmap_fractional_divider(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) unsigned long m, n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) u64 ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) regmap_read(fd->regmap, fd->reg, &val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) m = (val & fd->mmask) >> fd->mshift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) n = (val & fd->nmask) >> fd->nshift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) if (!n || !m)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) return parent_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) ret = (u64)parent_rate * m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) do_div(ret, n);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static void clk_regmap_fractional_divider_approximation(struct clk_hw *hw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) unsigned long rate, unsigned long *parent_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) unsigned long *m, unsigned long *n)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) struct clk_regmap_fractional_divider *fd =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) to_clk_regmap_fractional_divider(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) unsigned long p_rate, p_parent_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) struct clk_hw *p_parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) unsigned long scale;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) p_rate = clk_hw_get_rate(clk_hw_get_parent(hw));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) if ((rate * 20 > p_rate) && (p_rate % rate != 0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) p_parent = clk_hw_get_parent(clk_hw_get_parent(hw));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) p_parent_rate = clk_hw_get_rate(p_parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) *parent_rate = p_parent_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * Get rate closer to *parent_rate to guarantee there is no overflow
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * for m and n. In the result it will be the nearest rate left shifted
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * by (scale - fd->nwidth) bits.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) scale = fls_long(*parent_rate / rate - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) if (scale > fd->nwidth)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) rate <<= scale - fd->nwidth;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) rational_best_approximation(rate, *parent_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) GENMASK(fd->mwidth - 1, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) GENMASK(fd->nwidth - 1, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) m, n);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) static long
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) clk_regmap_fractional_divider_round_rate(struct clk_hw *hw, unsigned long rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) unsigned long *parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) unsigned long m, n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) u64 ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) if (!rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) return *parent_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) if (rate >= *parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) return *parent_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) clk_regmap_fractional_divider_approximation(hw, rate, parent_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) &m, &n);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) ret = (u64)*parent_rate * m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) do_div(ret, n);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) clk_regmap_fractional_divider_set_rate(struct clk_hw *hw, unsigned long rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) unsigned long parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) struct clk_regmap_fractional_divider *fd =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) to_clk_regmap_fractional_divider(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) unsigned long m, n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) rational_best_approximation(rate, parent_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) &m, &n);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) dev_dbg(fd->dev, "%s: parent_rate=%ld, m=%ld, n=%ld, rate=%ld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) clk_hw_get_name(hw), parent_rate, m, n, rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) regmap_read(fd->regmap, fd->reg, &val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) val &= ~(fd->mmask | fd->nmask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) val |= (m << fd->mshift) | (n << fd->nshift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) return regmap_write(fd->regmap, fd->reg, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) const struct clk_ops clk_regmap_fractional_divider_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) .recalc_rate = clk_regmap_fractional_divider_recalc_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) .round_rate = clk_regmap_fractional_divider_round_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) .set_rate = clk_regmap_fractional_divider_set_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) EXPORT_SYMBOL_GPL(clk_regmap_fractional_divider_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) struct clk *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) devm_clk_regmap_register_fractional_divider(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) const char *name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) const char *parent_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) struct regmap *regmap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) u32 reg, unsigned long flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) struct clk_regmap_fractional_divider *fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) struct clk_init_data init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) fd = devm_kzalloc(dev, sizeof(*fd), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) if (!fd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) init.name = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) init.ops = &clk_regmap_fractional_divider_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) init.flags = flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) init.parent_names = (parent_name ? &parent_name : NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) init.num_parents = (parent_name ? 1 : 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) fd->dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) fd->regmap = regmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) fd->reg = reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) fd->mshift = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) fd->mwidth = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) fd->mmask = GENMASK(fd->mwidth - 1, 0) << fd->mshift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) fd->nshift = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) fd->nwidth = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) fd->nmask = GENMASK(fd->nwidth - 1, 0) << fd->nshift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) fd->hw.init = &init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) return devm_clk_register(dev, &fd->hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) EXPORT_SYMBOL_GPL(devm_clk_regmap_register_fractional_divider);