From a2fd4f9fa3b9f051550b36c4dfa74bc32bda24ee Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 10 Jul 2013 14:57:26 +0100 Subject: [PATCH 1/3] spi: Support transfer speed checking in the core Allow drivers to avoid implementing their own checks for simple rates by specifying the limits in the master structure. Signed-off-by: Mark Brown --- drivers/spi/spi.c | 7 +++++++ include/linux/spi/spi.h | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 978dda2c5239..a52f16685d6a 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1387,6 +1387,13 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message) BIT(xfer->bits_per_word - 1))) return -EINVAL; } + + if (xfer->speed_hz && master->min_speed_hz && + xfer->speed_hz < master->min_speed_hz) + return -EINVAL; + if (xfer->speed_hz && master->max_speed_hz && + xfer->speed_hz > master->max_speed_hz) + return -EINVAL; } message->spi = spi; diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 28e440be1c07..cdf668156154 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -233,6 +233,8 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) * suported. If set, the SPI core will reject any transfer with an * unsupported bits_per_word. If not set, this value is simply ignored, * and it's up to the individual driver to perform any validation. + * @min_speed_hz: Lowest supported transfer speed + * @max_speed_hz: Highest supported transfer speed * @flags: other constraints relevant to this driver * @bus_lock_spinlock: spinlock for SPI bus locking * @bus_lock_mutex: mutex for SPI bus locking @@ -312,6 +314,10 @@ struct spi_master { #define SPI_BIT_MASK(bits) (((bits) == 32) ? ~0UL : (BIT(bits) - 1)) #define SPI_BPW_RANGE_MASK(min, max) (SPI_BIT_MASK(max) - SPI_BIT_MASK(min - 1)) + /* limits on transfer speed */ + u32 min_speed_hz; + u32 max_speed_hz; + /* other constraints relevant to this driver */ u16 flags; #define SPI_MASTER_HALF_DUPLEX BIT(0) /* can't do full duplex */ From 24a0013a04e81e95198daab98edf4df02e191568 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 10 Jul 2013 15:05:40 +0100 Subject: [PATCH 2/3] spi: More sanity checks for transfers Check that transfers are non-empty and that there is a completion for them. Signed-off-by: Mark Brown --- drivers/spi/spi.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index a52f16685d6a..c2899161ccac 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1351,6 +1351,11 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message) struct spi_master *master = spi->master; struct spi_transfer *xfer; + if (list_empty(&message->transfers)) + return -EINVAL; + if (!message->complete) + return -EINVAL; + /* Half-duplex links include original MicroWire, and ones with * only one data pin like SPI_3WIRE (switches direction) or where * either MOSI or MISO is missing. They can also be caused by From 56ede94a000bb9635b326db38baf66da6dfc174e Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Wed, 14 Aug 2013 10:25:28 +0200 Subject: [PATCH 3/3] spi: limit default transfer speed to controller's max speed Since the 'spi: Support transfer speed checking in the core' change, the SPI core validates the desired speed of a given transfer against the minimum and maximum speeds supported by the controller. If the speed of a transfer is not specified, the core uses the maximum speed of the actual SPI device. However if the maximum speed of the actual device is greater than the maximum speed of the controller, the core will reject the transfer due to the aforementioned change. Change the code to use the maximum speed of the controller by default if that is below the device's maximum speed. Signed-off-by: Gabor Juhos Signed-off-by: Mark Brown --- drivers/spi/spi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index c2899161ccac..2a20c32c8277 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1382,8 +1382,13 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message) list_for_each_entry(xfer, &message->transfers, transfer_list) { if (!xfer->bits_per_word) xfer->bits_per_word = spi->bits_per_word; - if (!xfer->speed_hz) + if (!xfer->speed_hz) { xfer->speed_hz = spi->max_speed_hz; + if (master->max_speed_hz && + xfer->speed_hz > master->max_speed_hz) + xfer->speed_hz = master->max_speed_hz; + } + if (master->bits_per_word_mask) { /* Only 32 bits fit in the mask */ if (xfer->bits_per_word > 32)