Lines Matching +full:fractional +full:- +full:n
1 // SPDX-License-Identifier: GPL-2.0
5 * Adjustable fractional divider clock implementation.
10 * rate = (m / n) * parent_rate (1)
13 * m (numerator) and n (denominator) values to be provided to satisfy
16 * Since m and n have the limitation by a range, e.g.
18 * n >= 1, n < N_width, where N_width = 2^nwidth (2)
32 * scale = floor(log2(parent_rate / rate)) - nwidth (5)
34 * and assume that the IP, that needs m and n, has also its own
37 * at the same time a much better result of m and n than simple
49 #include <linux/clk-provider.h>
51 #include "clk-fractional-divider.h"
55 if (fd->flags & CLK_FRAC_DIVIDER_BIG_ENDIAN) in clk_fd_readl()
56 return ioread32be(fd->reg); in clk_fd_readl()
58 return readl(fd->reg); in clk_fd_readl()
63 if (fd->flags & CLK_FRAC_DIVIDER_BIG_ENDIAN) in clk_fd_writel()
64 iowrite32be(val, fd->reg); in clk_fd_writel()
66 writel(val, fd->reg); in clk_fd_writel()
73 unsigned long m, n; in clk_fd_get_div() local
77 if (fd->lock) in clk_fd_get_div()
78 spin_lock_irqsave(fd->lock, flags); in clk_fd_get_div()
80 __acquire(fd->lock); in clk_fd_get_div()
84 if (fd->lock) in clk_fd_get_div()
85 spin_unlock_irqrestore(fd->lock, flags); in clk_fd_get_div()
87 __release(fd->lock); in clk_fd_get_div()
89 mmask = GENMASK(fd->mwidth - 1, 0) << fd->mshift; in clk_fd_get_div()
90 nmask = GENMASK(fd->nwidth - 1, 0) << fd->nshift; in clk_fd_get_div()
92 m = (val & mmask) >> fd->mshift; in clk_fd_get_div()
93 n = (val & nmask) >> fd->nshift; in clk_fd_get_div()
95 if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) { in clk_fd_get_div()
97 n++; in clk_fd_get_div()
100 fract->numerator = m; in clk_fd_get_div()
101 fract->denominator = n; in clk_fd_get_div()
123 unsigned long *m, unsigned long *n) in clk_fractional_divider_general_approximation() argument
130 * for m and n. In the result it will be the nearest rate left shifted in clk_fractional_divider_general_approximation()
131 * by (scale - fd->nwidth) bits. in clk_fractional_divider_general_approximation()
135 if (fd->flags & CLK_FRAC_DIVIDER_POWER_OF_TWO_PS) { in clk_fractional_divider_general_approximation()
136 unsigned long scale = fls_long(*parent_rate / rate - 1); in clk_fractional_divider_general_approximation()
138 if (scale > fd->nwidth) in clk_fractional_divider_general_approximation()
139 rate <<= scale - fd->nwidth; in clk_fractional_divider_general_approximation()
142 if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) { in clk_fractional_divider_general_approximation()
143 max_m = BIT(fd->mwidth); in clk_fractional_divider_general_approximation()
144 max_n = BIT(fd->nwidth); in clk_fractional_divider_general_approximation()
146 max_m = GENMASK(fd->mwidth - 1, 0); in clk_fractional_divider_general_approximation()
147 max_n = GENMASK(fd->nwidth - 1, 0); in clk_fractional_divider_general_approximation()
150 rational_best_approximation(rate, *parent_rate, max_m, max_n, m, n); in clk_fractional_divider_general_approximation()
158 unsigned long m, n; in clk_fd_round_rate() local
164 if (fd->approximation) in clk_fd_round_rate()
165 fd->approximation(hw, rate, parent_rate, &m, &n); in clk_fd_round_rate()
167 clk_fractional_divider_general_approximation(hw, rate, parent_rate, &m, &n); in clk_fd_round_rate()
170 do_div(ret, n); in clk_fd_round_rate()
180 unsigned long m, n, max_m, max_n; in clk_fd_set_rate() local
184 if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) { in clk_fd_set_rate()
185 max_m = BIT(fd->mwidth); in clk_fd_set_rate()
186 max_n = BIT(fd->nwidth); in clk_fd_set_rate()
188 max_m = GENMASK(fd->mwidth - 1, 0); in clk_fd_set_rate()
189 max_n = GENMASK(fd->nwidth - 1, 0); in clk_fd_set_rate()
191 rational_best_approximation(rate, parent_rate, max_m, max_n, &m, &n); in clk_fd_set_rate()
193 if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) { in clk_fd_set_rate()
194 m--; in clk_fd_set_rate()
195 n--; in clk_fd_set_rate()
198 mmask = GENMASK(fd->mwidth - 1, 0) << fd->mshift; in clk_fd_set_rate()
199 nmask = GENMASK(fd->nwidth - 1, 0) << fd->nshift; in clk_fd_set_rate()
201 if (fd->lock) in clk_fd_set_rate()
202 spin_lock_irqsave(fd->lock, flags); in clk_fd_set_rate()
204 __acquire(fd->lock); in clk_fd_set_rate()
208 val |= (m << fd->mshift) | (n << fd->nshift); in clk_fd_set_rate()
211 if (fd->lock) in clk_fd_set_rate()
212 spin_unlock_irqrestore(fd->lock, flags); in clk_fd_set_rate()
214 __release(fd->lock); in clk_fd_set_rate()
230 DEFINE_DEBUGFS_ATTRIBUTE(clk_fd_numerator_fops, clk_fd_numerator_get, NULL, "%llu\n");
242 DEFINE_DEBUGFS_ATTRIBUTE(clk_fd_denominator_fops, clk_fd_denominator_get, NULL, "%llu\n");
273 return ERR_PTR(-ENOMEM); in clk_hw_register_fractional_divider()
281 fd->reg = reg; in clk_hw_register_fractional_divider()
282 fd->mshift = mshift; in clk_hw_register_fractional_divider()
283 fd->mwidth = mwidth; in clk_hw_register_fractional_divider()
284 fd->nshift = nshift; in clk_hw_register_fractional_divider()
285 fd->nwidth = nwidth; in clk_hw_register_fractional_divider()
286 fd->flags = clk_divider_flags; in clk_hw_register_fractional_divider()
287 fd->lock = lock; in clk_hw_register_fractional_divider()
288 fd->hw.init = &init; in clk_hw_register_fractional_divider()
290 hw = &fd->hw; in clk_hw_register_fractional_divider()
313 return hw->clk; in clk_register_fractional_divider()