aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUwe Kleine-König <uwe@kleine-koenig.org>2016-12-08 11:37:08 -0500
committerMark Brown <broonie@kernel.org>2016-12-08 12:54:51 -0500
commit7243e0b20729d372e97763617a7a9c89f29b33e1 (patch)
treeb75e2be1faaecc337cca9496f30517b9e7d8b8ce
parentdf34d04a6f09ba41037e58c3df6d6fbed0ffcde9 (diff)
spi: mvebu: fix baudrate calculation for armada variant
The calculation of SPR and SPPR doesn't round correctly at several places which might result in baud rates that are too big. For example with tclk_hz = 250000001 and target rate 25000000 it determined a divider of 10 which is wrong. Instead of fixing all the corner cases replace the calculation by an algorithm without a loop which should even be quicker to execute apart from being correct. Fixes: df59fa7f4bca ("spi: orion: support armada extended baud rates") Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--drivers/spi/spi-orion.c83
1 files changed, 54 insertions, 29 deletions
diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c
index ded37025b445..6b001c4a5640 100644
--- a/drivers/spi/spi-orion.c
+++ b/drivers/spi/spi-orion.c
@@ -138,37 +138,62 @@ static int orion_spi_baudrate_set(struct spi_device *spi, unsigned int speed)
138 tclk_hz = clk_get_rate(orion_spi->clk); 138 tclk_hz = clk_get_rate(orion_spi->clk);
139 139
140 if (devdata->typ == ARMADA_SPI) { 140 if (devdata->typ == ARMADA_SPI) {
141 unsigned int clk, spr, sppr, sppr2, err; 141 /*
142 unsigned int best_spr, best_sppr, best_err; 142 * Given the core_clk (tclk_hz) and the target rate (speed) we
143 143 * determine the best values for SPR (in [0 .. 15]) and SPPR (in
144 best_err = speed; 144 * [0..7]) such that
145 best_spr = 0; 145 *
146 best_sppr = 0; 146 * core_clk / (SPR * 2 ** SPPR)
147 147 *
148 /* Iterate over the valid range looking for best fit */ 148 * is as big as possible but not bigger than speed.
149 for (sppr = 0; sppr < 8; sppr++) { 149 */
150 sppr2 = 0x1 << sppr;
151
152 spr = tclk_hz / sppr2;
153 spr = DIV_ROUND_UP(spr, speed);
154 if ((spr == 0) || (spr > 15))
155 continue;
156
157 clk = tclk_hz / (spr * sppr2);
158 err = speed - clk;
159
160 if (err < best_err) {
161 best_spr = spr;
162 best_sppr = sppr;
163 best_err = err;
164 }
165 }
166 150
167 if ((best_sppr == 0) && (best_spr == 0)) 151 /* best integer divider: */
168 return -EINVAL; 152 unsigned divider = DIV_ROUND_UP(tclk_hz, speed);
153 unsigned spr, sppr;
154
155 if (divider < 16) {
156 /* This is the easy case, divider is less than 16 */
157 spr = divider;
158 sppr = 0;
159
160 } else {
161 unsigned two_pow_sppr;
162 /*
163 * Find the highest bit set in divider. This and the
164 * three next bits define SPR (apart from rounding).
165 * SPPR is then the number of zero bits that must be
166 * appended:
167 */
168 sppr = fls(divider) - 4;
169
170 /*
171 * As SPR only has 4 bits, we have to round divider up
172 * to the next multiple of 2 ** sppr.
173 */
174 two_pow_sppr = 1 << sppr;
175 divider = (divider + two_pow_sppr - 1) & -two_pow_sppr;
176
177 /*
178 * recalculate sppr as rounding up divider might have
179 * increased it enough to change the position of the
180 * highest set bit. In this case the bit that now
181 * doesn't make it into SPR is 0, so there is no need to
182 * round again.
183 */
184 sppr = fls(divider) - 4;
185 spr = divider >> sppr;
186
187 /*
188 * Now do range checking. SPR is constructed to have a
189 * width of 4 bits, so this is fine for sure. So we
190 * still need to check for sppr to fit into 3 bits:
191 */
192 if (sppr > 7)
193 return -EINVAL;
194 }
169 195
170 prescale = ((best_sppr & 0x6) << 5) | 196 prescale = ((sppr & 0x6) << 5) | ((sppr & 0x1) << 4) | spr;
171 ((best_sppr & 0x1) << 4) | best_spr;
172 } else { 197 } else {
173 /* 198 /*
174 * the supported rates are: 4,6,8...30 199 * the supported rates are: 4,6,8...30