From 4302a59629f7a0bd70fd1605d2b558597517372a Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Fri, 31 Jan 2014 13:44:59 +0100 Subject: spi: fsl: Fix problem with multi message transfers When used via spidev with more than one messages to tranfer via SPI_IOC_MESSAGE the current implementation would return with -EINVAL, since bits_per_word and speed_hz are set in all transfer structs. And in the 2nd loop status will stay at -EINVAL as its not overwritten again via fsl_spi_setup_transfer(). This patch changes this behavious by first checking if one of the messages uses different settings. If this is the case the function will return with -EINVAL. If not, the messages are transferred correctly. Signed-off-by: Stefan Roese Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-spi.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'drivers/spi/spi-fsl-spi.c') diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index 119f7af9453..4dcb2929c01 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -362,18 +362,28 @@ static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t, static void fsl_spi_do_one_msg(struct spi_message *m) { struct spi_device *spi = m->spi; - struct spi_transfer *t; + struct spi_transfer *t, *first; unsigned int cs_change; const int nsecs = 50; int status; - cs_change = 1; - status = 0; + /* Don't allow changes if CS is active */ + first = list_first_entry(&m->transfers, struct spi_transfer, + transfer_list); list_for_each_entry(t, &m->transfers, transfer_list) { - if (t->bits_per_word || t->speed_hz) { - /* Don't allow changes if CS is active */ + if ((first->bits_per_word != t->bits_per_word) || + (first->speed_hz != t->speed_hz)) { status = -EINVAL; + dev_err(&spi->dev, + "bits_per_word/speed_hz should be same for the same SPI transfer\n"); + return; + } + } + cs_change = 1; + status = -EINVAL; + list_for_each_entry(t, &m->transfers, transfer_list) { + if (t->bits_per_word || t->speed_hz) { if (cs_change) status = fsl_spi_setup_transfer(spi, t); if (status < 0) -- cgit v1.2.3-70-g09d2 From f734394d861fe71eafa28d6c28199d9847c5a319 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 13 Feb 2014 19:05:38 +0800 Subject: spi: fsl-spi: Convert to let spi core validate xfer->bits_per_word Set bits_per_word_mask so spi core will reject transfers that attempt to use an unsupported bits_per_word value. fsl_spi_grlib_probe() may update mpc8xxx_spi->max_bits_per_word setting. So set master->bits_per_word_mask after fsl_spi_grlib_probe(). Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-spi.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers/spi/spi-fsl-spi.c') diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index 4dcb2929c01..f35488ed62a 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -239,12 +239,6 @@ static int fsl_spi_setup_transfer(struct spi_device *spi, if (!bits_per_word) bits_per_word = spi->bits_per_word; - /* Make sure its a bit width we support [4..16, 32] */ - if ((bits_per_word < 4) - || ((bits_per_word > 16) && (bits_per_word != 32)) - || (bits_per_word > mpc8xxx_spi->max_bits_per_word)) - return -EINVAL; - if (!hz) hz = spi->max_speed_hz; @@ -651,6 +645,10 @@ static struct spi_master * fsl_spi_probe(struct device *dev, if (mpc8xxx_spi->type == TYPE_GRLIB) fsl_spi_grlib_probe(dev); + master->bits_per_word_mask = + (SPI_BPW_RANGE_MASK(4, 16) | SPI_BPW_MASK(32)) & + SPI_BPW_RANGE_MASK(1, mpc8xxx_spi->max_bits_per_word); + if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) mpc8xxx_spi->set_shifts = fsl_spi_qe_cpu_set_shifts; -- cgit v1.2.3-70-g09d2