Skip to content

Commit b4e2ade

Browse files
Stephan Olbrichbroonie
authored andcommitted
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>
1 parent f29ab18 commit b4e2ade

File tree

1 file changed

+41
-16
lines changed

1 file changed

+41
-16
lines changed

drivers/spi/spi-bcm2835aux.c

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -218,9 +218,9 @@ static irqreturn_t bcm2835aux_spi_interrupt(int irq, void *dev_id)
218218
BCM2835_AUX_SPI_CNTL1_IDLE);
219219
}
220220

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 */
222222
if (!bs->rx_len) {
223-
bcm2835aux_spi_reset_hw(bs);
223+
bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1]);
224224
complete(&master->xfer_completion);
225225
}
226226

@@ -313,9 +313,6 @@ static int bcm2835aux_spi_transfer_one_poll(struct spi_master *master,
313313
}
314314
}
315315

316-
/* Transfer complete - reset SPI HW */
317-
bcm2835aux_spi_reset_hw(bs);
318-
319316
/* and return without waiting for completion */
320317
return 0;
321318
}
@@ -336,10 +333,6 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master,
336333
* resulting (potentially) in more interrupts when transferring
337334
* more than 12 bytes
338335
*/
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;
343336

344337
/* set clock */
345338
spi_hz = tfr->speed_hz;
@@ -354,17 +347,13 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master,
354347
} else { /* the slowest we can go */
355348
speed = BCM2835_AUX_SPI_CNTL0_SPEED_MAX;
356349
}
350+
/* mask out old speed from previous spi_transfer */
351+
bs->cntl[0] &= ~(BCM2835_AUX_SPI_CNTL0_SPEED);
352+
/* set the new speed */
357353
bs->cntl[0] |= speed << BCM2835_AUX_SPI_CNTL0_SPEED_SHIFT;
358354

359355
spi_used_hz = clk_hz / (2 * (speed + 1));
360356

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-
368357
/* set transmit buffers and length */
369358
bs->tx_buf = tfr->tx_buf;
370359
bs->rx_buf = tfr->rx_buf;
@@ -388,6 +377,40 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master,
388377
return bcm2835aux_spi_transfer_one_irq(master, spi, tfr);
389378
}
390379

380+
static 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+
404+
static 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+
391414
static void bcm2835aux_spi_handle_err(struct spi_master *master,
392415
struct spi_message *msg)
393416
{
@@ -416,6 +439,8 @@ static int bcm2835aux_spi_probe(struct platform_device *pdev)
416439
master->num_chipselect = -1;
417440
master->transfer_one = bcm2835aux_spi_transfer_one;
418441
master->handle_err = bcm2835aux_spi_handle_err;
442+
master->prepare_message = bcm2835aux_spi_prepare_message;
443+
master->unprepare_message = bcm2835aux_spi_unprepare_message;
419444
master->dev.of_node = pdev->dev.of_node;
420445

421446
bs = spi_master_get_devdata(master);

0 commit comments

Comments
 (0)