aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephan Olbrich <stephanolbrich@gmx.de>2016-02-14 05:04:28 -0500
committerMark Brown <broonie@kernel.org>2016-02-15 15:45:19 -0500
commitb4e2adef62062cf716d1c81adc12ad6def516f72 (patch)
treec18a2f0cfccffb6f23757cb9552e9d4e9fe60d54
parentf29ab1845f3e2684ba1c6de6c3bd5198e4b1459c (diff)
spi: bcm2835aux: set up spi-mode before asserting cs-gpio
When using reverse polarity for clock (spi-cpol) on a device the clock line gets altered after chip-select has been asserted resulting in an additional clock beat, which confuses hardware. This happens due to the fact, the the hardware was initialized and reset at the begin and end of each transfer which results in default state for all lines except chip-select which is handled by the spi-subsystem as gpio-cs is used. To avoid this situation this patch moves the setup of polarity (spi-cpol and spi-cpha) outside of the chip-select into prepare_message, which is run prior to asserting chip-select. Signed-off-by: Stephan Olbrich <stephanolbrich@gmx.de> Reviewed-by: Martin Sperl <kernel@martin.sperl.org> Tested-by: Martin Sperl <kernel@martin.sperl.org> Reviewed-by: Eric Anholt <eric@anholt.net> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--drivers/spi/spi-bcm2835aux.c57
1 files changed, 41 insertions, 16 deletions
diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c
index e1b2fec1db63..a6e25c6c66ca 100644
--- a/drivers/spi/spi-bcm2835aux.c
+++ b/drivers/spi/spi-bcm2835aux.c
@@ -218,9 +218,9 @@ static irqreturn_t bcm2835aux_spi_interrupt(int irq, void *dev_id)
218 BCM2835_AUX_SPI_CNTL1_IDLE); 218 BCM2835_AUX_SPI_CNTL1_IDLE);
219 } 219 }
220 220
221 /* and if rx_len is 0 then wake up completion and disable spi */ 221 /* and if rx_len is 0 then disable interrupts and wake up completion */
222 if (!bs->rx_len) { 222 if (!bs->rx_len) {
223 bcm2835aux_spi_reset_hw(bs); 223 bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1]);
224 complete(&master->xfer_completion); 224 complete(&master->xfer_completion);
225 } 225 }
226 226
@@ -313,9 +313,6 @@ static int bcm2835aux_spi_transfer_one_poll(struct spi_master *master,
313 } 313 }
314 } 314 }
315 315
316 /* Transfer complete - reset SPI HW */
317 bcm2835aux_spi_reset_hw(bs);
318
319 /* and return without waiting for completion */ 316 /* and return without waiting for completion */
320 return 0; 317 return 0;
321} 318}
@@ -336,10 +333,6 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master,
336 * resulting (potentially) in more interrupts when transferring 333 * resulting (potentially) in more interrupts when transferring
337 * more than 12 bytes 334 * more than 12 bytes
338 */ 335 */
339 bs->cntl[0] = BCM2835_AUX_SPI_CNTL0_ENABLE |
340 BCM2835_AUX_SPI_CNTL0_VAR_WIDTH |
341 BCM2835_AUX_SPI_CNTL0_MSBF_OUT;
342 bs->cntl[1] = BCM2835_AUX_SPI_CNTL1_MSBF_IN;
343 336
344 /* set clock */ 337 /* set clock */
345 spi_hz = tfr->speed_hz; 338 spi_hz = tfr->speed_hz;
@@ -354,17 +347,13 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master,
354 } else { /* the slowest we can go */ 347 } else { /* the slowest we can go */
355 speed = BCM2835_AUX_SPI_CNTL0_SPEED_MAX; 348 speed = BCM2835_AUX_SPI_CNTL0_SPEED_MAX;
356 } 349 }
350 /* mask out old speed from previous spi_transfer */
351 bs->cntl[0] &= ~(BCM2835_AUX_SPI_CNTL0_SPEED);
352 /* set the new speed */
357 bs->cntl[0] |= speed << BCM2835_AUX_SPI_CNTL0_SPEED_SHIFT; 353 bs->cntl[0] |= speed << BCM2835_AUX_SPI_CNTL0_SPEED_SHIFT;
358 354
359 spi_used_hz = clk_hz / (2 * (speed + 1)); 355 spi_used_hz = clk_hz / (2 * (speed + 1));
360 356
361 /* handle all the modes */
362 if (spi->mode & SPI_CPOL)
363 bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPOL;
364 if (spi->mode & SPI_CPHA)
365 bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPHA_OUT |
366 BCM2835_AUX_SPI_CNTL0_CPHA_IN;
367
368 /* set transmit buffers and length */ 357 /* set transmit buffers and length */
369 bs->tx_buf = tfr->tx_buf; 358 bs->tx_buf = tfr->tx_buf;
370 bs->rx_buf = tfr->rx_buf; 359 bs->rx_buf = tfr->rx_buf;
@@ -388,6 +377,40 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master,
388 return bcm2835aux_spi_transfer_one_irq(master, spi, tfr); 377 return bcm2835aux_spi_transfer_one_irq(master, spi, tfr);
389} 378}
390 379
380static int bcm2835aux_spi_prepare_message(struct spi_master *master,
381 struct spi_message *msg)
382{
383 struct spi_device *spi = msg->spi;
384 struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
385
386 bs->cntl[0] = BCM2835_AUX_SPI_CNTL0_ENABLE |
387 BCM2835_AUX_SPI_CNTL0_VAR_WIDTH |
388 BCM2835_AUX_SPI_CNTL0_MSBF_OUT;
389 bs->cntl[1] = BCM2835_AUX_SPI_CNTL1_MSBF_IN;
390
391 /* handle all the modes */
392 if (spi->mode & SPI_CPOL)
393 bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPOL;
394 if (spi->mode & SPI_CPHA)
395 bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPHA_OUT |
396 BCM2835_AUX_SPI_CNTL0_CPHA_IN;
397
398 bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1]);
399 bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL0, bs->cntl[0]);
400
401 return 0;
402}
403
404static int bcm2835aux_spi_unprepare_message(struct spi_master *master,
405 struct spi_message *msg)
406{
407 struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
408
409 bcm2835aux_spi_reset_hw(bs);
410
411 return 0;
412}
413
391static void bcm2835aux_spi_handle_err(struct spi_master *master, 414static void bcm2835aux_spi_handle_err(struct spi_master *master,
392 struct spi_message *msg) 415 struct spi_message *msg)
393{ 416{
@@ -416,6 +439,8 @@ static int bcm2835aux_spi_probe(struct platform_device *pdev)
416 master->num_chipselect = -1; 439 master->num_chipselect = -1;
417 master->transfer_one = bcm2835aux_spi_transfer_one; 440 master->transfer_one = bcm2835aux_spi_transfer_one;
418 master->handle_err = bcm2835aux_spi_handle_err; 441 master->handle_err = bcm2835aux_spi_handle_err;
442 master->prepare_message = bcm2835aux_spi_prepare_message;
443 master->unprepare_message = bcm2835aux_spi_unprepare_message;
419 master->dev.of_node = pdev->dev.of_node; 444 master->dev.of_node = pdev->dev.of_node;
420 445
421 bs = spi_master_get_devdata(master); 446 bs = spi_master_get_devdata(master);