From a2fd4f9fa3b9f051550b36c4dfa74bc32bda24ee Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 10 Jul 2013 14:57:26 +0100 Subject: 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 --- include/linux/spi/spi.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'include/linux/spi/spi.h') diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 28e440be1c0..cdf66815615 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 */ -- cgit v1.2.3-70-g09d2 From 078726ce6d56a767533064e0f2f2100d7cb6fc22 Mon Sep 17 00:00:00 2001 From: Sourav Poddar Date: Thu, 18 Jul 2013 15:31:25 +0530 Subject: driver: spi: Modify core to compute the message length Make spi core calculate the message length while populating the other transfer parameters. Usecase, driver can use it to populate framelength filed in their controller. Signed-off-by: Sourav Poddar Signed-off-by: Mark Brown --- drivers/spi/spi.c | 1 + include/linux/spi/spi.h | 1 + 2 files changed, 2 insertions(+) (limited to 'include/linux/spi/spi.h') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 978dda2c523..7e3446cab72 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1375,6 +1375,7 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message) * it is not set for this transfer. */ list_for_each_entry(xfer, &message->transfers, transfer_list) { + message->frame_length += xfer->len; if (!xfer->bits_per_word) xfer->bits_per_word = spi->bits_per_word; if (!xfer->speed_hz) diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 28e440be1c0..aadd0a885a0 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -578,6 +578,7 @@ struct spi_message { /* completion is reported through a callback */ void (*complete)(void *context); void *context; + unsigned frame_length; unsigned actual_length; int status; -- cgit v1.2.3-70-g09d2 From 49834de234f3cf592c3d242c889ca603db8e7050 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 28 Jul 2013 14:47:02 +0100 Subject: spi: Provide core support for runtime PM during transfers Most SPI drivers that implement runtime PM support use identical code to do so: they acquire a runtime PM lock in prepare_transfer_hardware() and then they release it in unprepare_transfer_hardware(). The variations in this are mostly missing error checking and the choice to use autosuspend. Since these runtime PM calls are normally the only thing in the prepare and unprepare callbacks and the autosuspend API transparently does the right thing on devices with autosuspend disabled factor all of this out into the core with a flag to enable the behaviour. Signed-off-by: Mark Brown Reviewed-by: Stephen Warren Acked-by: Linus Walleij --- drivers/spi/spi.c | 16 ++++++++++++++++ include/linux/spi/spi.h | 5 +++++ 2 files changed, 21 insertions(+) (limited to 'include/linux/spi/spi.h') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 978dda2c523..361cced6806 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -553,6 +553,10 @@ static void spi_pump_messages(struct kthread_work *work) master->unprepare_transfer_hardware(master)) dev_err(&master->dev, "failed to unprepare transfer hardware\n"); + if (master->auto_runtime_pm) { + pm_runtime_mark_last_busy(master->dev.parent); + pm_runtime_put_autosuspend(master->dev.parent); + } return; } @@ -572,11 +576,23 @@ static void spi_pump_messages(struct kthread_work *work) master->busy = true; spin_unlock_irqrestore(&master->queue_lock, flags); + if (!was_busy && master->auto_runtime_pm) { + ret = pm_runtime_get_sync(master->dev.parent); + if (ret < 0) { + dev_err(&master->dev, "Failed to power device: %d\n", + ret); + return; + } + } + if (!was_busy && master->prepare_transfer_hardware) { ret = master->prepare_transfer_hardware(master); if (ret) { dev_err(&master->dev, "failed to prepare transfer hardware\n"); + + if (master->auto_runtime_pm) + pm_runtime_put(master->dev.parent); return; } } diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 28e440be1c0..bf0204c0005 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -254,6 +254,9 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) * @busy: message pump is busy * @running: message pump is running * @rt: whether this queue is set to run as a realtime task + * @auto_runtime_pm: the core should ensure a runtime PM reference is held + * while the hardware is prepared, using the parent + * device for the spidev * @prepare_transfer_hardware: a message will soon arrive from the queue * so the subsystem requests the driver to prepare the transfer hardware * by issuing this call @@ -374,11 +377,13 @@ struct spi_master { bool busy; bool running; bool rt; + bool auto_runtime_pm; int (*prepare_transfer_hardware)(struct spi_master *master); int (*transfer_one_message)(struct spi_master *master, struct spi_message *mesg); int (*unprepare_transfer_hardware)(struct spi_master *master); + /* gpio chip select */ int *cs_gpios; }; -- cgit v1.2.3-70-g09d2 From b6aa23ccaea1548cfb404b41129717f13443bccf Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Thu, 1 Aug 2013 16:08:57 -0600 Subject: spi: fix SPI_BIT_MASK so it always fits into 32-bits On a 64-bit platform, ~0UL fills 64-bits, which causes SPI_BIT_MASK(32) not to fit into 32 bits. This causes a warning when the result is assigned to a 32-bit variable. Use ~0U instead to prevent this. This fixes: drivers/spi/spi-gpio.c: In function 'spi_gpio_probe': drivers/spi/spi-gpio.c:446:2: warning: large integer implicitly truncated to unsigned type [-Woverflow] Reported-by: kbuild test robot Signed-off-by: Stephen Warren Signed-off-by: Mark Brown --- include/linux/spi/spi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux/spi/spi.h') diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 28e440be1c0..c920c2f4dad 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -309,7 +309,7 @@ struct spi_master { /* bitmask of supported bits_per_word for transfers */ u32 bits_per_word_mask; #define SPI_BPW_MASK(bits) BIT((bits) - 1) -#define SPI_BIT_MASK(bits) (((bits) == 32) ? ~0UL : (BIT(bits) - 1)) +#define SPI_BIT_MASK(bits) (((bits) == 32) ? ~0U : (BIT(bits) - 1)) #define SPI_BPW_RANGE_MASK(min, max) (SPI_BIT_MASK(max) - SPI_BIT_MASK(min - 1)) /* other constraints relevant to this driver */ -- cgit v1.2.3-70-g09d2 From f477b7fb13df2b843997559ff34e87d054ba6538 Mon Sep 17 00:00:00 2001 From: wangyuhang Date: Sun, 11 Aug 2013 18:15:17 +0800 Subject: spi: DUAL and QUAD support fix the previous patch some mistake below: 1. DT in slave node, use "spi-tx-nbits = <1/2/4>" in place of using "spi-tx-dual, spi-tx-quad" directly, same to rx. So correct the previous way to get the property in @of_register_spi_devices(). 2. Change the value of transfer bit macro(SPI_NBITS_SINGLE, SPI_NBITS_DUAL SPI_NBITS_QUAD) to 0x01, 0x02 and 0x04 to match the actual wires. 3. Add the following check (1)keep the tx_nbits and rx_nbits in spi_transfer is not beyond the single, dual and quad. (2)keep tx_nbits and rx_nbits are contained by @spi_device->mode example: if @spi_device->mode = DUAL, then tx/rx_nbits can not be set to QUAD(SPI_NBITS_QUAD) (3)if "@spi_device->mode & SPI_3WIRE", then tx/rx_nbits should be in single(SPI_NBITS_SINGLE) Signed-off-by: wangyuhang Signed-off-by: Mark Brown --- drivers/spi/spi.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/spi/spi.h | 22 ++++++++++-- 2 files changed, 116 insertions(+), 2 deletions(-) (limited to 'include/linux/spi/spi.h') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 2a20c32c827..39d38756e98 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -869,6 +869,51 @@ static void of_register_spi_devices(struct spi_master *master) if (of_find_property(nc, "spi-3wire", NULL)) spi->mode |= SPI_3WIRE; + /* Device DUAL/QUAD mode */ + prop = of_get_property(nc, "spi-tx-nbits", &len); + if (!prop || len < sizeof(*prop)) { + dev_err(&master->dev, "%s has no 'spi-tx-nbits' property\n", + nc->full_name); + spi_dev_put(spi); + continue; + } + switch (be32_to_cpup(prop)) { + case SPI_NBITS_SINGLE: + break; + case SPI_NBITS_DUAL: + spi->mode |= SPI_TX_DUAL; + break; + case SPI_NBITS_QUAD: + spi->mode |= SPI_TX_QUAD; + break; + default: + dev_err(&master->dev, "spi-tx-nbits value is not supported\n"); + spi_dev_put(spi); + continue; + } + + prop = of_get_property(nc, "spi-rx-nbits", &len); + if (!prop || len < sizeof(*prop)) { + dev_err(&master->dev, "%s has no 'spi-rx-nbits' property\n", + nc->full_name); + spi_dev_put(spi); + continue; + } + switch (be32_to_cpup(prop)) { + case SPI_NBITS_SINGLE: + break; + case SPI_NBITS_DUAL: + spi->mode |= SPI_RX_DUAL; + break; + case SPI_NBITS_QUAD: + spi->mode |= SPI_RX_QUAD; + break; + default: + dev_err(&master->dev, "spi-rx-nbits value is not supported\n"); + spi_dev_put(spi); + continue; + } + /* Device speed */ prop = of_get_property(nc, "spi-max-frequency", &len); if (!prop || len < sizeof(*prop)) { @@ -1316,6 +1361,19 @@ int spi_setup(struct spi_device *spi) unsigned bad_bits; int status = 0; + /* check mode to prevent that DUAL and QUAD set at the same time + */ + if (((spi->mode & SPI_TX_DUAL) && (spi->mode & SPI_TX_QUAD)) || + ((spi->mode & SPI_RX_DUAL) && (spi->mode & SPI_RX_QUAD))) { + dev_err(&spi->dev, + "setup: can not select dual and quad at the same time\n"); + return -EINVAL; + } + /* if it is SPI_3WIRE mode, DUAL and QUAD should be forbidden + */ + if ((spi->mode & SPI_3WIRE) && (spi->mode & + (SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD))) + return -EINVAL; /* help drivers fail *cleanly* when they need options * that aren't supported with their current master */ @@ -1378,6 +1436,8 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message) /** * Set transfer bits_per_word and max speed as spi device default if * it is not set for this transfer. + * Set transfer tx_nbits and rx_nbits as single transfer default + * (SPI_NBITS_SINGLE) if it is not set for this transfer. */ list_for_each_entry(xfer, &message->transfers, transfer_list) { if (!xfer->bits_per_word) @@ -1403,6 +1463,42 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message) return -EINVAL; if (xfer->speed_hz && master->max_speed_hz && xfer->speed_hz > master->max_speed_hz) + + if (xfer->tx_buf && !xfer->tx_nbits) + xfer->tx_nbits = SPI_NBITS_SINGLE; + if (xfer->rx_buf && !xfer->rx_nbits) + xfer->rx_nbits = SPI_NBITS_SINGLE; + /* check transfer tx/rx_nbits: + * 1. keep the value is not out of single, dual and quad + * 2. keep tx/rx_nbits is contained by mode in spi_device + * 3. if SPI_3WIRE, tx/rx_nbits should be in single + */ + if (xfer->tx_nbits != SPI_NBITS_SINGLE && + xfer->tx_nbits != SPI_NBITS_DUAL && + xfer->tx_nbits != SPI_NBITS_QUAD) + return -EINVAL; + if ((xfer->tx_nbits == SPI_NBITS_DUAL) && + !(spi->mode & (SPI_TX_DUAL | SPI_TX_QUAD))) + return -EINVAL; + if ((xfer->tx_nbits == SPI_NBITS_QUAD) && + !(spi->mode & SPI_TX_QUAD)) + return -EINVAL; + if ((spi->mode & SPI_3WIRE) && + (xfer->tx_nbits != SPI_NBITS_SINGLE)) + return -EINVAL; + /* check transfer rx_nbits */ + if (xfer->rx_nbits != SPI_NBITS_SINGLE && + xfer->rx_nbits != SPI_NBITS_DUAL && + xfer->rx_nbits != SPI_NBITS_QUAD) + return -EINVAL; + if ((xfer->rx_nbits == SPI_NBITS_DUAL) && + !(spi->mode & (SPI_RX_DUAL | SPI_RX_QUAD))) + return -EINVAL; + if ((xfer->rx_nbits == SPI_NBITS_QUAD) && + !(spi->mode & SPI_RX_QUAD)) + return -EINVAL; + if ((spi->mode & SPI_3WIRE) && + (xfer->rx_nbits != SPI_NBITS_SINGLE)) return -EINVAL; } diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index cdf66815615..ccd7840c450 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -74,7 +74,7 @@ struct spi_device { struct spi_master *master; u32 max_speed_hz; u8 chip_select; - u8 mode; + u16 mode; #define SPI_CPHA 0x01 /* clock phase */ #define SPI_CPOL 0x02 /* clock polarity */ #define SPI_MODE_0 (0|0) /* (original MicroWire) */ @@ -87,6 +87,10 @@ struct spi_device { #define SPI_LOOP 0x20 /* loopback mode */ #define SPI_NO_CS 0x40 /* 1 dev/bus, no chipselect */ #define SPI_READY 0x80 /* slave pulls low to pause */ +#define SPI_TX_DUAL 0x100 /* transmit with 2 wires */ +#define SPI_TX_QUAD 0x200 /* transmit with 4 wires */ +#define SPI_RX_DUAL 0x400 /* receive with 2 wires */ +#define SPI_RX_QUAD 0x800 /* receive with 4 wires */ u8 bits_per_word; int irq; void *controller_state; @@ -454,6 +458,10 @@ extern struct spi_master *spi_busnum_to_master(u16 busnum); * @rx_buf: data to be read (dma-safe memory), or NULL * @tx_dma: DMA address of tx_buf, if @spi_message.is_dma_mapped * @rx_dma: DMA address of rx_buf, if @spi_message.is_dma_mapped + * @tx_nbits: number of bits used for writting. If 0 the default + * (SPI_NBITS_SINGLE) is used. + * @rx_nbits: number of bits used for reading. If 0 the default + * (SPI_NBITS_SINGLE) is used. * @len: size of rx and tx buffers (in bytes) * @speed_hz: Select a speed other than the device default for this * transfer. If 0 the default (from @spi_device) is used. @@ -508,6 +516,11 @@ extern struct spi_master *spi_busnum_to_master(u16 busnum); * by the results of previous messages and where the whole transaction * ends when the chipselect goes intactive. * + * When SPI can transfer in 1x,2x or 4x. It can get this tranfer information + * from device through @tx_nbits and @rx_nbits. In Bi-direction, these + * two should both be set. User can set transfer mode with SPI_NBITS_SINGLE(1x) + * SPI_NBITS_DUAL(2x) and SPI_NBITS_QUAD(4x) to support these three transfer. + * * The code that submits an spi_message (and its spi_transfers) * to the lower layers is responsible for managing its memory. * Zero-initialize every field you don't set up explicitly, to @@ -528,6 +541,11 @@ struct spi_transfer { dma_addr_t rx_dma; unsigned cs_change:1; + u8 tx_nbits; + u8 rx_nbits; +#define SPI_NBITS_SINGLE 0x01 /* 1bit transfer */ +#define SPI_NBITS_DUAL 0x02 /* 2bits transfer */ +#define SPI_NBITS_QUAD 0x04 /* 4bits transfer */ u8 bits_per_word; u16 delay_usecs; u32 speed_hz; @@ -875,7 +893,7 @@ struct spi_board_info { /* mode becomes spi_device.mode, and is essential for chips * where the default of SPI_CS_HIGH = 0 is wrong. */ - u8 mode; + u16 mode; /* ... may need additional spi_device chip config data here. * avoid stuff protocol drivers can set; but include stuff -- cgit v1.2.3-70-g09d2