Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0 2 : : /* 3 : : * Copyright (C) 2014 Intel Corporation 4 : : * 5 : : * Adjustable fractional divider clock implementation. 6 : : * Output rate = (m / n) * parent_rate. 7 : : * Uses rational best approximation algorithm. 8 : : */ 9 : : 10 : : #include <linux/clk-provider.h> 11 : : #include <linux/io.h> 12 : : #include <linux/module.h> 13 : : #include <linux/device.h> 14 : : #include <linux/slab.h> 15 : : #include <linux/rational.h> 16 : : 17 : : static inline u32 clk_fd_readl(struct clk_fractional_divider *fd) 18 : : { 19 : 0 : if (fd->flags & CLK_FRAC_DIVIDER_BIG_ENDIAN) 20 : 0 : return ioread32be(fd->reg); 21 : : 22 : 0 : return readl(fd->reg); 23 : : } 24 : : 25 : : static inline void clk_fd_writel(struct clk_fractional_divider *fd, u32 val) 26 : : { 27 : 0 : if (fd->flags & CLK_FRAC_DIVIDER_BIG_ENDIAN) 28 : 0 : iowrite32be(val, fd->reg); 29 : : else 30 : 0 : writel(val, fd->reg); 31 : : } 32 : : 33 : 0 : static unsigned long clk_fd_recalc_rate(struct clk_hw *hw, 34 : : unsigned long parent_rate) 35 : : { 36 : : struct clk_fractional_divider *fd = to_clk_fd(hw); 37 : : unsigned long flags = 0; 38 : : unsigned long m, n; 39 : : u32 val; 40 : : u64 ret; 41 : : 42 : 0 : if (fd->lock) 43 : 0 : spin_lock_irqsave(fd->lock, flags); 44 : : else 45 : : __acquire(fd->lock); 46 : : 47 : : val = clk_fd_readl(fd); 48 : : 49 : 0 : if (fd->lock) 50 : : spin_unlock_irqrestore(fd->lock, flags); 51 : : else 52 : : __release(fd->lock); 53 : : 54 : 0 : m = (val & fd->mmask) >> fd->mshift; 55 : 0 : n = (val & fd->nmask) >> fd->nshift; 56 : : 57 : 0 : if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) { 58 : 0 : m++; 59 : 0 : n++; 60 : : } 61 : : 62 : 0 : if (!n || !m) 63 : : return parent_rate; 64 : : 65 : 0 : ret = (u64)parent_rate * m; 66 : 0 : do_div(ret, n); 67 : : 68 : 0 : return ret; 69 : : } 70 : : 71 : 0 : static void clk_fd_general_approximation(struct clk_hw *hw, unsigned long rate, 72 : : unsigned long *parent_rate, 73 : : unsigned long *m, unsigned long *n) 74 : : { 75 : : struct clk_fractional_divider *fd = to_clk_fd(hw); 76 : : unsigned long scale; 77 : : 78 : : /* 79 : : * Get rate closer to *parent_rate to guarantee there is no overflow 80 : : * for m and n. In the result it will be the nearest rate left shifted 81 : : * by (scale - fd->nwidth) bits. 82 : : */ 83 : 0 : scale = fls_long(*parent_rate / rate - 1); 84 : 0 : if (scale > fd->nwidth) 85 : 0 : rate <<= scale - fd->nwidth; 86 : : 87 : 0 : rational_best_approximation(rate, *parent_rate, 88 : 0 : GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0), 89 : : m, n); 90 : 0 : } 91 : : 92 : 0 : static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate, 93 : : unsigned long *parent_rate) 94 : : { 95 : : struct clk_fractional_divider *fd = to_clk_fd(hw); 96 : : unsigned long m, n; 97 : : u64 ret; 98 : : 99 : 0 : if (!rate || (!clk_hw_can_set_rate_parent(hw) && rate >= *parent_rate)) 100 : 0 : return *parent_rate; 101 : : 102 : 0 : if (fd->approximation) 103 : 0 : fd->approximation(hw, rate, parent_rate, &m, &n); 104 : : else 105 : 0 : clk_fd_general_approximation(hw, rate, parent_rate, &m, &n); 106 : : 107 : 0 : ret = (u64)*parent_rate * m; 108 : 0 : do_div(ret, n); 109 : : 110 : 0 : return ret; 111 : : } 112 : : 113 : 0 : static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate, 114 : : unsigned long parent_rate) 115 : : { 116 : : struct clk_fractional_divider *fd = to_clk_fd(hw); 117 : : unsigned long flags = 0; 118 : : unsigned long m, n; 119 : : u32 val; 120 : : 121 : 0 : rational_best_approximation(rate, parent_rate, 122 : 0 : GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0), 123 : : &m, &n); 124 : : 125 : 0 : if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) { 126 : 0 : m--; 127 : 0 : n--; 128 : : } 129 : : 130 : 0 : if (fd->lock) 131 : 0 : spin_lock_irqsave(fd->lock, flags); 132 : : else 133 : : __acquire(fd->lock); 134 : : 135 : : val = clk_fd_readl(fd); 136 : 0 : val &= ~(fd->mmask | fd->nmask); 137 : 0 : val |= (m << fd->mshift) | (n << fd->nshift); 138 : : clk_fd_writel(fd, val); 139 : : 140 : 0 : if (fd->lock) 141 : : spin_unlock_irqrestore(fd->lock, flags); 142 : : else 143 : : __release(fd->lock); 144 : : 145 : 0 : return 0; 146 : : } 147 : : 148 : : const struct clk_ops clk_fractional_divider_ops = { 149 : : .recalc_rate = clk_fd_recalc_rate, 150 : : .round_rate = clk_fd_round_rate, 151 : : .set_rate = clk_fd_set_rate, 152 : : }; 153 : : EXPORT_SYMBOL_GPL(clk_fractional_divider_ops); 154 : : 155 : 0 : struct clk_hw *clk_hw_register_fractional_divider(struct device *dev, 156 : : const char *name, const char *parent_name, unsigned long flags, 157 : : void __iomem *reg, u8 mshift, u8 mwidth, u8 nshift, u8 nwidth, 158 : : u8 clk_divider_flags, spinlock_t *lock) 159 : : { 160 : : struct clk_fractional_divider *fd; 161 : : struct clk_init_data init; 162 : : struct clk_hw *hw; 163 : : int ret; 164 : : 165 : 0 : fd = kzalloc(sizeof(*fd), GFP_KERNEL); 166 : 0 : if (!fd) 167 : : return ERR_PTR(-ENOMEM); 168 : : 169 : 0 : init.name = name; 170 : 0 : init.ops = &clk_fractional_divider_ops; 171 : 0 : init.flags = flags; 172 : 0 : init.parent_names = parent_name ? &parent_name : NULL; 173 : 0 : init.num_parents = parent_name ? 1 : 0; 174 : : 175 : 0 : fd->reg = reg; 176 : 0 : fd->mshift = mshift; 177 : 0 : fd->mwidth = mwidth; 178 : 0 : fd->mmask = GENMASK(mwidth - 1, 0) << mshift; 179 : 0 : fd->nshift = nshift; 180 : 0 : fd->nwidth = nwidth; 181 : 0 : fd->nmask = GENMASK(nwidth - 1, 0) << nshift; 182 : 0 : fd->flags = clk_divider_flags; 183 : 0 : fd->lock = lock; 184 : 0 : fd->hw.init = &init; 185 : : 186 : 0 : hw = &fd->hw; 187 : 0 : ret = clk_hw_register(dev, hw); 188 : 0 : if (ret) { 189 : 0 : kfree(fd); 190 : : hw = ERR_PTR(ret); 191 : : } 192 : : 193 : 0 : return hw; 194 : : } 195 : : EXPORT_SYMBOL_GPL(clk_hw_register_fractional_divider); 196 : : 197 : 0 : struct clk *clk_register_fractional_divider(struct device *dev, 198 : : const char *name, const char *parent_name, unsigned long flags, 199 : : void __iomem *reg, u8 mshift, u8 mwidth, u8 nshift, u8 nwidth, 200 : : u8 clk_divider_flags, spinlock_t *lock) 201 : : { 202 : : struct clk_hw *hw; 203 : : 204 : 0 : hw = clk_hw_register_fractional_divider(dev, name, parent_name, flags, 205 : : reg, mshift, mwidth, nshift, nwidth, clk_divider_flags, 206 : : lock); 207 : 0 : if (IS_ERR(hw)) 208 : : return ERR_CAST(hw); 209 : 0 : return hw->clk; 210 : : } 211 : : EXPORT_SYMBOL_GPL(clk_register_fractional_divider); 212 : : 213 : 0 : void clk_hw_unregister_fractional_divider(struct clk_hw *hw) 214 : : { 215 : : struct clk_fractional_divider *fd; 216 : : 217 : : fd = to_clk_fd(hw); 218 : : 219 : 0 : clk_hw_unregister(hw); 220 : 0 : kfree(fd); 221 : 0 : }