Commit b4e2adef authored by Stephan Olbrich's avatar Stephan Olbrich Committed by Mark Brown

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: default avatarStephan Olbrich <stephanolbrich@gmx.de>
Reviewed-by: default avatarMartin Sperl <kernel@martin.sperl.org>
Tested-by: default avatarMartin Sperl <kernel@martin.sperl.org>
Reviewed-by: default avatarEric Anholt <eric@anholt.net>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent f29ab184
......@@ -218,9 +218,9 @@ static irqreturn_t bcm2835aux_spi_interrupt(int irq, void *dev_id)
BCM2835_AUX_SPI_CNTL1_IDLE);
}
/* and if rx_len is 0 then wake up completion and disable spi */
/* and if rx_len is 0 then disable interrupts and wake up completion */
if (!bs->rx_len) {
bcm2835aux_spi_reset_hw(bs);
bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1]);
complete(&master->xfer_completion);
}
......@@ -313,9 +313,6 @@ static int bcm2835aux_spi_transfer_one_poll(struct spi_master *master,
}
}
/* Transfer complete - reset SPI HW */
bcm2835aux_spi_reset_hw(bs);
/* and return without waiting for completion */
return 0;
}
......@@ -336,10 +333,6 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master,
* resulting (potentially) in more interrupts when transferring
* more than 12 bytes
*/
bs->cntl[0] = BCM2835_AUX_SPI_CNTL0_ENABLE |
BCM2835_AUX_SPI_CNTL0_VAR_WIDTH |
BCM2835_AUX_SPI_CNTL0_MSBF_OUT;
bs->cntl[1] = BCM2835_AUX_SPI_CNTL1_MSBF_IN;
/* set clock */
spi_hz = tfr->speed_hz;
......@@ -354,17 +347,13 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master,
} else { /* the slowest we can go */
speed = BCM2835_AUX_SPI_CNTL0_SPEED_MAX;
}
/* mask out old speed from previous spi_transfer */
bs->cntl[0] &= ~(BCM2835_AUX_SPI_CNTL0_SPEED);
/* set the new speed */
bs->cntl[0] |= speed << BCM2835_AUX_SPI_CNTL0_SPEED_SHIFT;
spi_used_hz = clk_hz / (2 * (speed + 1));
/* handle all the modes */
if (spi->mode & SPI_CPOL)
bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPOL;
if (spi->mode & SPI_CPHA)
bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPHA_OUT |
BCM2835_AUX_SPI_CNTL0_CPHA_IN;
/* set transmit buffers and length */
bs->tx_buf = tfr->tx_buf;
bs->rx_buf = tfr->rx_buf;
......@@ -388,6 +377,40 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master,
return bcm2835aux_spi_transfer_one_irq(master, spi, tfr);
}
static int bcm2835aux_spi_prepare_message(struct spi_master *master,
struct spi_message *msg)
{
struct spi_device *spi = msg->spi;
struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
bs->cntl[0] = BCM2835_AUX_SPI_CNTL0_ENABLE |
BCM2835_AUX_SPI_CNTL0_VAR_WIDTH |
BCM2835_AUX_SPI_CNTL0_MSBF_OUT;
bs->cntl[1] = BCM2835_AUX_SPI_CNTL1_MSBF_IN;
/* handle all the modes */
if (spi->mode & SPI_CPOL)
bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPOL;
if (spi->mode & SPI_CPHA)
bs->cntl[0] |= BCM2835_AUX_SPI_CNTL0_CPHA_OUT |
BCM2835_AUX_SPI_CNTL0_CPHA_IN;
bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1]);
bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL0, bs->cntl[0]);
return 0;
}
static int bcm2835aux_spi_unprepare_message(struct spi_master *master,
struct spi_message *msg)
{
struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
bcm2835aux_spi_reset_hw(bs);
return 0;
}
static void bcm2835aux_spi_handle_err(struct spi_master *master,
struct spi_message *msg)
{
......@@ -416,6 +439,8 @@ static int bcm2835aux_spi_probe(struct platform_device *pdev)
master->num_chipselect = -1;
master->transfer_one = bcm2835aux_spi_transfer_one;
master->handle_err = bcm2835aux_spi_handle_err;
master->prepare_message = bcm2835aux_spi_prepare_message;
master->unprepare_message = bcm2835aux_spi_unprepare_message;
master->dev.of_node = pdev->dev.of_node;
bs = spi_master_get_devdata(master);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment