aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/spi/spi_mpc83xx.c
diff options
context:
space:
mode:
authorAnton Vorontsov <avorontsov@ru.mvista.com>2007-08-10 16:01:02 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-08-11 18:47:41 -0400
commita44648b057f5331fe6c0e863dc693ed335490e7a (patch)
tree629f37533b3427598c46f38596a92735a31df441 /drivers/spi/spi_mpc83xx.c
parente24a4d1ee337e3a67a502f3f19cdec3ffc45ad05 (diff)
spi_mpc83xx: fix prescale modulus calculation
Long ago I've noticed (but didn't pay much attention) that spi_mpc83xx using PM calculations that differs from what specs describe. I.e. u8 pm = mpc83xx_spi->spibrg / (spi->max_speed_hz * 4); While specs says: "The SPI baud rate generator clock source (either system clock or system clock divided by 16, depending on DIV16 bit) is divided by 4 * ([PM] + 1), a range from 4 to 64.". Thus " - 1" is missing in the spi_mpc83xx's formula. Why nobody noticed that bug? Probably because sysclk usually less then user expects, e.g. you expect 200 MHz, but real clock is 198 MHz, and integer rounding helps when this formula is used. Suppose it's SPI in QE, SYSCLK at 198 MHz, thus SPIBRG at 99MHz, 25 MHz requested. PM = (99MHz / ( 25 MHz * 4 )), PM == 0, output SPICLK will be 24.75 MHz At lower frequencies this bug is more noticeable, though. And this bug shows itself in all its beauty if SYSCLK is equal or a bit more than you expect (200 MHz SYSCLK, 100 MHz SPIBRG): PM = (100MHz / ( 25 MHz * 4 )), PM == 1, output SPICLK will be 12.625 MHz! Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com> Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/spi/spi_mpc83xx.c')
-rw-r--r--drivers/spi/spi_mpc83xx.c8
1 files changed, 6 insertions, 2 deletions
diff --git a/drivers/spi/spi_mpc83xx.c b/drivers/spi/spi_mpc83xx.c
index fe69e94043e1..2adf856e44c2 100644
--- a/drivers/spi/spi_mpc83xx.c
+++ b/drivers/spi/spi_mpc83xx.c
@@ -148,6 +148,8 @@ static void mpc83xx_spi_chipselect(struct spi_device *spi, int value)
148 if (value == BITBANG_CS_ACTIVE) { 148 if (value == BITBANG_CS_ACTIVE) {
149 u32 regval = mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode); 149 u32 regval = mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode);
150 u32 len = spi->bits_per_word; 150 u32 len = spi->bits_per_word;
151 u8 pm;
152
151 if (len == 32) 153 if (len == 32)
152 len = 0; 154 len = 0;
153 else 155 else
@@ -170,7 +172,7 @@ static void mpc83xx_spi_chipselect(struct spi_device *spi, int value)
170 regval |= SPMODE_LEN(len); 172 regval |= SPMODE_LEN(len);
171 173
172 if ((mpc83xx_spi->spibrg / spi->max_speed_hz) >= 64) { 174 if ((mpc83xx_spi->spibrg / spi->max_speed_hz) >= 64) {
173 u8 pm = mpc83xx_spi->spibrg / (spi->max_speed_hz * 64); 175 pm = mpc83xx_spi->spibrg / (spi->max_speed_hz * 64) - 1;
174 if (pm > 0x0f) { 176 if (pm > 0x0f) {
175 dev_err(&spi->dev, "Requested speed is too " 177 dev_err(&spi->dev, "Requested speed is too "
176 "low: %d Hz. Will use %d Hz instead.\n", 178 "low: %d Hz. Will use %d Hz instead.\n",
@@ -180,7 +182,9 @@ static void mpc83xx_spi_chipselect(struct spi_device *spi, int value)
180 } 182 }
181 regval |= SPMODE_PM(pm) | SPMODE_DIV16; 183 regval |= SPMODE_PM(pm) | SPMODE_DIV16;
182 } else { 184 } else {
183 u8 pm = mpc83xx_spi->spibrg / (spi->max_speed_hz * 4); 185 pm = mpc83xx_spi->spibrg / (spi->max_speed_hz * 4);
186 if (pm)
187 pm--;
184 regval |= SPMODE_PM(pm); 188 regval |= SPMODE_PM(pm);
185 } 189 }
186 190