| .. | .. |
|---|
| 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 | |
|---|