.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) 2014 Intel Corporation |
---|
3 | | - * |
---|
4 | | - * This program is free software; you can redistribute it and/or modify |
---|
5 | | - * it under the terms of the GNU General Public License version 2 as |
---|
6 | | - * published by the Free Software Foundation. |
---|
7 | 4 | * |
---|
8 | 5 | * Adjustable fractional divider clock implementation. |
---|
9 | 6 | * Output rate = (m / n) * parent_rate. |
---|
.. | .. |
---|
11 | 8 | */ |
---|
12 | 9 | |
---|
13 | 10 | #include <linux/clk-provider.h> |
---|
| 11 | +#include <linux/io.h> |
---|
14 | 12 | #include <linux/module.h> |
---|
15 | 13 | #include <linux/device.h> |
---|
16 | 14 | #include <linux/slab.h> |
---|
17 | 15 | #include <linux/rational.h> |
---|
| 16 | + |
---|
| 17 | +static inline u32 clk_fd_readl(struct clk_fractional_divider *fd) |
---|
| 18 | +{ |
---|
| 19 | + if (fd->flags & CLK_FRAC_DIVIDER_BIG_ENDIAN) |
---|
| 20 | + return ioread32be(fd->reg); |
---|
| 21 | + |
---|
| 22 | + return readl(fd->reg); |
---|
| 23 | +} |
---|
| 24 | + |
---|
| 25 | +static inline void clk_fd_writel(struct clk_fractional_divider *fd, u32 val) |
---|
| 26 | +{ |
---|
| 27 | + if (fd->flags & CLK_FRAC_DIVIDER_BIG_ENDIAN) |
---|
| 28 | + iowrite32be(val, fd->reg); |
---|
| 29 | + else |
---|
| 30 | + writel(val, fd->reg); |
---|
| 31 | +} |
---|
18 | 32 | |
---|
19 | 33 | static unsigned long clk_fd_recalc_rate(struct clk_hw *hw, |
---|
20 | 34 | unsigned long parent_rate) |
---|
.. | .. |
---|
30 | 44 | else |
---|
31 | 45 | __acquire(fd->lock); |
---|
32 | 46 | |
---|
33 | | - val = clk_readl(fd->reg); |
---|
| 47 | + val = clk_fd_readl(fd); |
---|
34 | 48 | |
---|
35 | 49 | if (fd->lock) |
---|
36 | 50 | spin_unlock_irqrestore(fd->lock, flags); |
---|
.. | .. |
---|
39 | 53 | |
---|
40 | 54 | m = (val & fd->mmask) >> fd->mshift; |
---|
41 | 55 | n = (val & fd->nmask) >> fd->nshift; |
---|
| 56 | + |
---|
| 57 | + if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) { |
---|
| 58 | + m++; |
---|
| 59 | + n++; |
---|
| 60 | + } |
---|
42 | 61 | |
---|
43 | 62 | if (!n || !m) |
---|
44 | 63 | return parent_rate; |
---|
.. | .. |
---|
77 | 96 | unsigned long m, n; |
---|
78 | 97 | u64 ret; |
---|
79 | 98 | |
---|
80 | | - if (!rate) |
---|
| 99 | + if (!rate && rate >= *parent_rate) |
---|
81 | 100 | return *parent_rate; |
---|
82 | 101 | |
---|
83 | | - if (fd->approximation) { |
---|
| 102 | + if (fd->approximation) |
---|
84 | 103 | fd->approximation(hw, rate, parent_rate, &m, &n); |
---|
85 | | - } else { |
---|
86 | | - if (rate >= *parent_rate) |
---|
87 | | - return *parent_rate; |
---|
| 104 | + else |
---|
88 | 105 | clk_fd_general_approximation(hw, rate, parent_rate, &m, &n); |
---|
89 | | - } |
---|
90 | 106 | |
---|
91 | 107 | ret = (u64)*parent_rate * m; |
---|
92 | 108 | do_div(ret, n); |
---|
.. | .. |
---|
106 | 122 | GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0), |
---|
107 | 123 | &m, &n); |
---|
108 | 124 | |
---|
| 125 | + if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) { |
---|
| 126 | + m--; |
---|
| 127 | + n--; |
---|
| 128 | + } |
---|
109 | 129 | /* |
---|
110 | 130 | * When compensation the fractional divider, |
---|
111 | 131 | * the [1:0] bits of the numerator register are omitted, |
---|
.. | .. |
---|
138 | 158 | else |
---|
139 | 159 | __acquire(fd->lock); |
---|
140 | 160 | |
---|
141 | | - val = clk_readl(fd->reg); |
---|
| 161 | + val = clk_fd_readl(fd); |
---|
142 | 162 | val &= ~(fd->mmask | fd->nmask); |
---|
143 | 163 | val |= (m << fd->mshift) | (n << fd->nshift); |
---|
144 | | - clk_writel(val, fd->reg); |
---|
| 164 | + clk_fd_writel(fd, val); |
---|
145 | 165 | |
---|
146 | 166 | if (fd->lock) |
---|
147 | 167 | spin_unlock_irqrestore(fd->lock, flags); |
---|
.. | .. |
---|
164 | 184 | u8 clk_divider_flags, spinlock_t *lock) |
---|
165 | 185 | { |
---|
166 | 186 | struct clk_fractional_divider *fd; |
---|
167 | | - struct clk_init_data init = {}; |
---|
| 187 | + struct clk_init_data init; |
---|
168 | 188 | struct clk_hw *hw; |
---|
169 | 189 | int ret; |
---|
170 | 190 | |
---|
.. | .. |
---|
174 | 194 | |
---|
175 | 195 | init.name = name; |
---|
176 | 196 | init.ops = &clk_fractional_divider_ops; |
---|
177 | | - init.flags = flags | CLK_IS_BASIC; |
---|
| 197 | + init.flags = flags; |
---|
178 | 198 | init.parent_names = parent_name ? &parent_name : NULL; |
---|
179 | 199 | init.num_parents = parent_name ? 1 : 0; |
---|
180 | 200 | |
---|