diff options
Diffstat (limited to 'drivers/clk/clk-divider.c')
-rw-r--r-- | drivers/clk/clk-divider.c | 25 |
1 files changed, 23 insertions, 2 deletions
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index 6d9674160430..6d55eb2cb959 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c | |||
@@ -150,6 +150,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, | |||
150 | struct clk_divider *divider = to_clk_divider(hw); | 150 | struct clk_divider *divider = to_clk_divider(hw); |
151 | int i, bestdiv = 0; | 151 | int i, bestdiv = 0; |
152 | unsigned long parent_rate, best = 0, now, maxdiv; | 152 | unsigned long parent_rate, best = 0, now, maxdiv; |
153 | unsigned long parent_rate_saved = *best_parent_rate; | ||
153 | 154 | ||
154 | if (!rate) | 155 | if (!rate) |
155 | rate = 1; | 156 | rate = 1; |
@@ -173,6 +174,15 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, | |||
173 | for (i = 1; i <= maxdiv; i++) { | 174 | for (i = 1; i <= maxdiv; i++) { |
174 | if (!_is_valid_div(divider, i)) | 175 | if (!_is_valid_div(divider, i)) |
175 | continue; | 176 | continue; |
177 | if (rate * i == parent_rate_saved) { | ||
178 | /* | ||
179 | * It's the most ideal case if the requested rate can be | ||
180 | * divided from parent clock without needing to change | ||
181 | * parent rate, so return the divider immediately. | ||
182 | */ | ||
183 | *best_parent_rate = parent_rate_saved; | ||
184 | return i; | ||
185 | } | ||
176 | parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), | 186 | parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), |
177 | MULT_ROUND_UP(rate, i)); | 187 | MULT_ROUND_UP(rate, i)); |
178 | now = parent_rate / i; | 188 | now = parent_rate / i; |
@@ -217,8 +227,12 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, | |||
217 | if (divider->lock) | 227 | if (divider->lock) |
218 | spin_lock_irqsave(divider->lock, flags); | 228 | spin_lock_irqsave(divider->lock, flags); |
219 | 229 | ||
220 | val = readl(divider->reg); | 230 | if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { |
221 | val &= ~(div_mask(divider) << divider->shift); | 231 | val = div_mask(divider) << (divider->shift + 16); |
232 | } else { | ||
233 | val = readl(divider->reg); | ||
234 | val &= ~(div_mask(divider) << divider->shift); | ||
235 | } | ||
222 | val |= value << divider->shift; | 236 | val |= value << divider->shift; |
223 | writel(val, divider->reg); | 237 | writel(val, divider->reg); |
224 | 238 | ||
@@ -245,6 +259,13 @@ static struct clk *_register_divider(struct device *dev, const char *name, | |||
245 | struct clk *clk; | 259 | struct clk *clk; |
246 | struct clk_init_data init; | 260 | struct clk_init_data init; |
247 | 261 | ||
262 | if (clk_divider_flags & CLK_DIVIDER_HIWORD_MASK) { | ||
263 | if (width + shift > 16) { | ||
264 | pr_warn("divider value exceeds LOWORD field\n"); | ||
265 | return ERR_PTR(-EINVAL); | ||
266 | } | ||
267 | } | ||
268 | |||
248 | /* allocate the divider */ | 269 | /* allocate the divider */ |
249 | div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL); | 270 | div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL); |
250 | if (!div) { | 271 | if (!div) { |