* [PATCH 01/14] spi: rspi: Remove unused mesg parameter from {send,receive}_pio()
2014-01-24 8:43 [PATCH 0/14] spi: rspi: Add support for RZ/A1H, DT, and Quad/Dual on QSPI Geert Uytterhoeven
@ 2014-01-24 8:43 ` Geert Uytterhoeven
[not found] ` <1390553044-11860-2-git-send-email-geert-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org>
2014-01-24 8:43 ` [PATCH 02/14] spi: rspi: Use core message handling Geert Uytterhoeven
` (11 subsequent siblings)
12 siblings, 1 reply; 31+ messages in thread
From: Geert Uytterhoeven @ 2014-01-24 8:43 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-spi, linux-sh, linux-kernel, Geert Uytterhoeven
From: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
Signed-off-by: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
---
drivers/spi/spi-rspi.c | 27 ++++++++++-----------------
1 file changed, 10 insertions(+), 17 deletions(-)
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c
index 28987d9fcfe5..ccd5cf201d04 100644
--- a/drivers/spi/spi-rspi.c
+++ b/drivers/spi/spi-rspi.c
@@ -228,11 +228,8 @@ static u16 rspi_read16(const struct rspi_data *rspi, u16 offset)
struct spi_ops {
int (*set_config_register)(const struct rspi_data *rspi,
int access_size);
- int (*send_pio)(struct rspi_data *rspi, struct spi_message *mesg,
- struct spi_transfer *t);
- int (*receive_pio)(struct rspi_data *rspi, struct spi_message *mesg,
- struct spi_transfer *t);
-
+ int (*send_pio)(struct rspi_data *rspi, struct spi_transfer *t);
+ int (*receive_pio)(struct rspi_data *rspi, struct spi_transfer *t);
};
/*
@@ -358,8 +355,7 @@ static void rspi_negate_ssl(const struct rspi_data *rspi)
rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_SPE, RSPI_SPCR);
}
-static int rspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg,
- struct spi_transfer *t)
+static int rspi_send_pio(struct rspi_data *rspi, struct spi_transfer *t)
{
int remain = t->len;
const u8 *data = t->tx_buf;
@@ -384,8 +380,7 @@ static int rspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg,
return 0;
}
-static int qspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg,
- struct spi_transfer *t)
+static int qspi_send_pio(struct rspi_data *rspi, struct spi_transfer *t)
{
int remain = t->len;
const u8 *data = t->tx_buf;
@@ -418,7 +413,7 @@ static int qspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg,
return 0;
}
-#define send_pio(spi, mesg, t) spi->ops->send_pio(spi, mesg, t)
+#define send_pio(spi, t) spi->ops->send_pio(spi, t)
static void rspi_dma_complete(void *arg)
{
@@ -551,8 +546,7 @@ static void rspi_receive_init(const struct rspi_data *rspi)
RSPI_SPSR);
}
-static int rspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg,
- struct spi_transfer *t)
+static int rspi_receive_pio(struct rspi_data *rspi, struct spi_transfer *t)
{
int remain = t->len;
u8 *data;
@@ -598,8 +592,7 @@ static void qspi_receive_init(const struct rspi_data *rspi)
rspi_write8(rspi, 0x00, QSPI_SPBFCR);
}
-static int qspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg,
- struct spi_transfer *t)
+static int qspi_receive_pio(struct rspi_data *rspi, struct spi_transfer *t)
{
int remain = t->len;
u8 *data;
@@ -630,7 +623,7 @@ static int qspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg,
return 0;
}
-#define receive_pio(spi, mesg, t) spi->ops->receive_pio(spi, mesg, t)
+#define receive_pio(spi, t) spi->ops->receive_pio(spi, t)
static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t)
{
@@ -771,7 +764,7 @@ static void rspi_work(struct work_struct *work)
if (rspi_is_dma(rspi, t))
ret = rspi_send_dma(rspi, t);
else
- ret = send_pio(rspi, mesg, t);
+ ret = send_pio(rspi, t);
if (ret < 0)
goto error;
}
@@ -779,7 +772,7 @@ static void rspi_work(struct work_struct *work)
if (rspi_is_dma(rspi, t))
ret = rspi_receive_dma(rspi, t);
else
- ret = receive_pio(rspi, mesg, t);
+ ret = receive_pio(rspi, t);
if (ret < 0)
goto error;
}
--
1.7.9.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH 02/14] spi: rspi: Use core message handling
2014-01-24 8:43 [PATCH 0/14] spi: rspi: Add support for RZ/A1H, DT, and Quad/Dual on QSPI Geert Uytterhoeven
2014-01-24 8:43 ` [PATCH 01/14] spi: rspi: Remove unused mesg parameter from {send,receive}_pio() Geert Uytterhoeven
@ 2014-01-24 8:43 ` Geert Uytterhoeven
2014-01-27 20:02 ` Mark Brown
2014-01-24 8:43 ` [PATCH 03/14] spi: rspi: Abstract 8/16-bit Data Register access Geert Uytterhoeven
` (10 subsequent siblings)
12 siblings, 1 reply; 31+ messages in thread
From: Geert Uytterhoeven @ 2014-01-24 8:43 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-spi, linux-sh, linux-kernel, Geert Uytterhoeven
From: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
Let the generic SPI core handle SPI messages, calling into our
rspi_transfer_one() method.
rspi_assert_ssl() and rspi_negate_ssl() are absorbed into
rspi_prepare_message() and rspi_unprepare_message(), as they actually
enable/disable the whole SPI function, instead of just (de)asserting the
chip select line.
Signed-off-by: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
---
drivers/spi/spi-rspi.c | 111 +++++++++++++++---------------------------------
1 file changed, 34 insertions(+), 77 deletions(-)
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c
index ccd5cf201d04..0e4d169c90d7 100644
--- a/drivers/spi/spi-rspi.c
+++ b/drivers/spi/spi-rspi.c
@@ -25,8 +25,6 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/errno.h>
-#include <linux/list.h>
-#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/io.h>
@@ -181,10 +179,7 @@ struct rspi_data {
void __iomem *addr;
u32 max_speed_hz;
struct spi_master *master;
- struct list_head queue;
- struct work_struct ws;
wait_queue_head_t wait;
- spinlock_t lock;
struct clk *clk;
u8 spsr;
u16 spcmd;
@@ -345,16 +340,6 @@ static int rspi_wait_for_interrupt(struct rspi_data *rspi, u8 wait_mask,
return 0;
}
-static void rspi_assert_ssl(const struct rspi_data *rspi)
-{
- rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_SPE, RSPI_SPCR);
-}
-
-static void rspi_negate_ssl(const struct rspi_data *rspi)
-{
- rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_SPE, RSPI_SPCR);
-}
-
static int rspi_send_pio(struct rspi_data *rspi, struct spi_transfer *t)
{
int remain = t->len;
@@ -739,56 +724,27 @@ static int rspi_is_dma(const struct rspi_data *rspi, struct spi_transfer *t)
return 0;
}
-static void rspi_work(struct work_struct *work)
+static int rspi_transfer_one(struct spi_master *master, struct spi_device *spi,
+ struct spi_transfer *xfer)
{
- struct rspi_data *rspi = container_of(work, struct rspi_data, ws);
- struct spi_message *mesg;
- struct spi_transfer *t;
- unsigned long flags;
- int ret;
-
- while (1) {
- spin_lock_irqsave(&rspi->lock, flags);
- if (list_empty(&rspi->queue)) {
- spin_unlock_irqrestore(&rspi->lock, flags);
- break;
- }
- mesg = list_entry(rspi->queue.next, struct spi_message, queue);
- list_del_init(&mesg->queue);
- spin_unlock_irqrestore(&rspi->lock, flags);
-
- rspi_assert_ssl(rspi);
-
- list_for_each_entry(t, &mesg->transfers, transfer_list) {
- if (t->tx_buf) {
- if (rspi_is_dma(rspi, t))
- ret = rspi_send_dma(rspi, t);
- else
- ret = send_pio(rspi, t);
- if (ret < 0)
- goto error;
- }
- if (t->rx_buf) {
- if (rspi_is_dma(rspi, t))
- ret = rspi_receive_dma(rspi, t);
- else
- ret = receive_pio(rspi, t);
- if (ret < 0)
- goto error;
- }
- mesg->actual_length += t->len;
- }
- rspi_negate_ssl(rspi);
+ struct rspi_data *rspi = spi_master_get_devdata(master);
+ int ret = 0;
- mesg->status = 0;
- mesg->complete(mesg->context);
+ if (xfer->tx_buf) {
+ if (rspi_is_dma(rspi, xfer))
+ ret = rspi_send_dma(rspi, xfer);
+ else
+ ret = send_pio(rspi, xfer);
+ if (ret < 0)
+ return ret;
}
-
- return;
-
-error:
- mesg->status = ret;
- mesg->complete(mesg->context);
+ if (xfer->rx_buf) {
+ if (rspi_is_dma(rspi, xfer))
+ ret = rspi_receive_dma(rspi, xfer);
+ else
+ ret = receive_pio(rspi, xfer);
+ }
+ return ret;
}
static int rspi_setup(struct spi_device *spi)
@@ -808,24 +764,26 @@ static int rspi_setup(struct spi_device *spi)
return 0;
}
-static int rspi_transfer(struct spi_device *spi, struct spi_message *mesg)
+static void rspi_cleanup(struct spi_device *spi)
{
- struct rspi_data *rspi = spi_master_get_devdata(spi->master);
- unsigned long flags;
-
- mesg->actual_length = 0;
- mesg->status = -EINPROGRESS;
+}
- spin_lock_irqsave(&rspi->lock, flags);
- list_add_tail(&mesg->queue, &rspi->queue);
- schedule_work(&rspi->ws);
- spin_unlock_irqrestore(&rspi->lock, flags);
+static int rspi_prepare_message(struct spi_master *master,
+ struct spi_message *message)
+{
+ struct rspi_data *rspi = spi_master_get_devdata(master);
+ rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_SPE, RSPI_SPCR);
return 0;
}
-static void rspi_cleanup(struct spi_device *spi)
+static int rspi_unprepare_message(struct spi_master *master,
+ struct spi_message *message)
{
+ struct rspi_data *rspi = spi_master_get_devdata(master);
+
+ rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_SPE, RSPI_SPCR);
+ return 0;
}
static irqreturn_t rspi_irq(int irq, void *_sr)
@@ -972,9 +930,6 @@ static int rspi_probe(struct platform_device *pdev)
}
clk_enable(rspi->clk);
- INIT_LIST_HEAD(&rspi->queue);
- spin_lock_init(&rspi->lock);
- INIT_WORK(&rspi->ws, rspi_work);
init_waitqueue_head(&rspi->wait);
if (rspi_pd && rspi_pd->num_chipselect)
@@ -984,8 +939,10 @@ static int rspi_probe(struct platform_device *pdev)
master->bus_num = pdev->id;
master->setup = rspi_setup;
- master->transfer = rspi_transfer;
+ master->transfer_one = rspi_transfer_one;
master->cleanup = rspi_cleanup;
+ master->prepare_message = rspi_prepare_message;
+ master->unprepare_message = rspi_unprepare_message;
master->mode_bits = SPI_CPHA | SPI_CPOL;
ret = devm_request_irq(&pdev->dev, irq, rspi_irq, 0,
--
1.7.9.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* Re: [PATCH 02/14] spi: rspi: Use core message handling
2014-01-24 8:43 ` [PATCH 02/14] spi: rspi: Use core message handling Geert Uytterhoeven
@ 2014-01-27 20:02 ` Mark Brown
0 siblings, 0 replies; 31+ messages in thread
From: Mark Brown @ 2014-01-27 20:02 UTC (permalink / raw)
To: Geert Uytterhoeven; +Cc: linux-spi, linux-sh, linux-kernel, Geert Uytterhoeven
[-- Attachment #1: Type: text/plain, Size: 249 bytes --]
On Fri, Jan 24, 2014 at 09:43:52AM +0100, Geert Uytterhoeven wrote:
> From: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
>
> Let the generic SPI core handle SPI messages, calling into our
> rspi_transfer_one() method.
Applied, thanks.
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH 03/14] spi: rspi: Abstract 8/16-bit Data Register access
2014-01-24 8:43 [PATCH 0/14] spi: rspi: Add support for RZ/A1H, DT, and Quad/Dual on QSPI Geert Uytterhoeven
2014-01-24 8:43 ` [PATCH 01/14] spi: rspi: Remove unused mesg parameter from {send,receive}_pio() Geert Uytterhoeven
2014-01-24 8:43 ` [PATCH 02/14] spi: rspi: Use core message handling Geert Uytterhoeven
@ 2014-01-24 8:43 ` Geert Uytterhoeven
2014-01-27 20:02 ` Mark Brown
2014-01-24 8:43 ` [PATCH 04/14] spi: rspi: Add rspi_data_{out,in,out_in}() helpers Geert Uytterhoeven
` (9 subsequent siblings)
12 siblings, 1 reply; 31+ messages in thread
From: Geert Uytterhoeven @ 2014-01-24 8:43 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-spi, linux-sh, linux-kernel, Geert Uytterhoeven
From: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
Add rspi_{write,read}_data(), to abstract 8-bit (QSPI, and RSPI on RZ/A1H)
versus 16-bit (RSPI) Data Register access.
Signed-off-by: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
---
drivers/spi/spi-rspi.c | 56 ++++++++++++++++++++++++++++++------------------
1 file changed, 35 insertions(+), 21 deletions(-)
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c
index 0e4d169c90d7..a0bb3c28ae91 100644
--- a/drivers/spi/spi-rspi.c
+++ b/drivers/spi/spi-rspi.c
@@ -192,6 +192,7 @@ struct rspi_data {
unsigned dma_width_16bit:1;
unsigned dma_callbacked:1;
+ unsigned byte_access:1;
};
static void rspi_write8(const struct rspi_data *rspi, u8 data, u16 offset)
@@ -219,10 +220,25 @@ static u16 rspi_read16(const struct rspi_data *rspi, u16 offset)
return ioread16(rspi->addr + offset);
}
+static void rspi_write_data(const struct rspi_data *rspi, u16 data)
+{
+ if (rspi->byte_access)
+ rspi_write8(rspi, data, RSPI_SPDR);
+ else /* 16 bit */
+ rspi_write16(rspi, data, RSPI_SPDR);
+}
+
+static u16 rspi_read_data(const struct rspi_data *rspi)
+{
+ if (rspi->byte_access)
+ return rspi_read8(rspi, RSPI_SPDR);
+ else /* 16 bit */
+ return rspi_read16(rspi, RSPI_SPDR);
+}
+
/* optional functions */
struct spi_ops {
- int (*set_config_register)(const struct rspi_data *rspi,
- int access_size);
+ int (*set_config_register)(struct rspi_data *rspi, int access_size);
int (*send_pio)(struct rspi_data *rspi, struct spi_transfer *t);
int (*receive_pio)(struct rspi_data *rspi, struct spi_transfer *t);
};
@@ -230,8 +246,7 @@ struct spi_ops {
/*
* functions for RSPI
*/
-static int rspi_set_config_register(const struct rspi_data *rspi,
- int access_size)
+static int rspi_set_config_register(struct rspi_data *rspi, int access_size)
{
int spbr;
@@ -242,8 +257,9 @@ static int rspi_set_config_register(const struct rspi_data *rspi,
spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz) - 1;
rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR);
- /* Sets number of frames to be used: 1 frame */
- rspi_write8(rspi, 0x00, RSPI_SPDCR);
+ /* Disable dummy transmission, set 16-bit word access, 1 frame */
+ rspi_write8(rspi, 0, RSPI_SPDCR);
+ rspi->byte_access = 0;
/* Sets RSPCK, SSL, next-access delay value */
rspi_write8(rspi, 0x00, RSPI_SPCKD);
@@ -266,8 +282,7 @@ static int rspi_set_config_register(const struct rspi_data *rspi,
/*
* functions for QSPI
*/
-static int qspi_set_config_register(const struct rspi_data *rspi,
- int access_size)
+static int qspi_set_config_register(struct rspi_data *rspi, int access_size)
{
u16 spcmd;
int spbr;
@@ -279,8 +294,9 @@ static int qspi_set_config_register(const struct rspi_data *rspi,
spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz);
rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR);
- /* Sets number of frames to be used: 1 frame */
- rspi_write8(rspi, 0x00, RSPI_SPDCR);
+ /* Disable dummy transmission, set byte access */
+ rspi_write8(rspi, 0, RSPI_SPDCR);
+ rspi->byte_access = 1;
/* Sets RSPCK, SSL, next-access delay value */
rspi_write8(rspi, 0x00, RSPI_SPCKD);
@@ -354,7 +370,7 @@ static int rspi_send_pio(struct rspi_data *rspi, struct spi_transfer *t)
return -ETIMEDOUT;
}
- rspi_write16(rspi, *data, RSPI_SPDR);
+ rspi_write_data(rspi, *data);
data++;
remain--;
}
@@ -380,14 +396,14 @@ static int qspi_send_pio(struct rspi_data *rspi, struct spi_transfer *t)
"%s: tx empty timeout\n", __func__);
return -ETIMEDOUT;
}
- rspi_write8(rspi, *data++, RSPI_SPDR);
+ rspi_write_data(rspi, *data++);
if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) {
dev_err(&rspi->master->dev,
"%s: receive timeout\n", __func__);
return -ETIMEDOUT;
}
- rspi_read8(rspi, RSPI_SPDR);
+ rspi_read_data(rspi);
remain--;
}
@@ -525,7 +541,7 @@ static void rspi_receive_init(const struct rspi_data *rspi)
spsr = rspi_read8(rspi, RSPI_SPSR);
if (spsr & SPSR_SPRF)
- rspi_read16(rspi, RSPI_SPDR); /* dummy read */
+ rspi_read_data(rspi); /* dummy read */
if (spsr & SPSR_OVRF)
rspi_write8(rspi, rspi_read8(rspi, RSPI_SPSR) & ~SPSR_OVRF,
RSPI_SPSR);
@@ -549,15 +565,14 @@ static int rspi_receive_pio(struct rspi_data *rspi, struct spi_transfer *t)
return -ETIMEDOUT;
}
/* dummy write for generate clock */
- rspi_write16(rspi, DUMMY_DATA, RSPI_SPDR);
+ rspi_write_data(rspi, DUMMY_DATA);
if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) {
dev_err(&rspi->master->dev,
"%s: receive timeout\n", __func__);
return -ETIMEDOUT;
}
- /* SPDR allows 16 or 32-bit access only */
- *data = (u8)rspi_read16(rspi, RSPI_SPDR);
+ *data = rspi_read_data(rspi);
data++;
remain--;
@@ -572,7 +587,7 @@ static void qspi_receive_init(const struct rspi_data *rspi)
spsr = rspi_read8(rspi, RSPI_SPSR);
if (spsr & SPSR_SPRF)
- rspi_read8(rspi, RSPI_SPDR); /* dummy read */
+ rspi_read_data(rspi); /* dummy read */
rspi_write8(rspi, SPBFCR_TXRST | SPBFCR_RXRST, QSPI_SPBFCR);
rspi_write8(rspi, 0x00, QSPI_SPBFCR);
}
@@ -593,15 +608,14 @@ static int qspi_receive_pio(struct rspi_data *rspi, struct spi_transfer *t)
return -ETIMEDOUT;
}
/* dummy write for generate clock */
- rspi_write8(rspi, DUMMY_DATA, RSPI_SPDR);
+ rspi_write_data(rspi, DUMMY_DATA);
if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) {
dev_err(&rspi->master->dev,
"%s: receive timeout\n", __func__);
return -ETIMEDOUT;
}
- /* SPDR allows 8, 16 or 32-bit access */
- *data++ = rspi_read8(rspi, RSPI_SPDR);
+ *data++ = rspi_read_data(rspi);
remain--;
}
--
1.7.9.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* Re: [PATCH 03/14] spi: rspi: Abstract 8/16-bit Data Register access
2014-01-24 8:43 ` [PATCH 03/14] spi: rspi: Abstract 8/16-bit Data Register access Geert Uytterhoeven
@ 2014-01-27 20:02 ` Mark Brown
0 siblings, 0 replies; 31+ messages in thread
From: Mark Brown @ 2014-01-27 20:02 UTC (permalink / raw)
To: Geert Uytterhoeven; +Cc: linux-spi, linux-sh, linux-kernel, Geert Uytterhoeven
[-- Attachment #1: Type: text/plain, Size: 276 bytes --]
On Fri, Jan 24, 2014 at 09:43:53AM +0100, Geert Uytterhoeven wrote:
> From: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
>
> Add rspi_{write,read}_data(), to abstract 8-bit (QSPI, and RSPI on RZ/A1H)
> versus 16-bit (RSPI) Data Register access.
Applied, thanks.
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH 04/14] spi: rspi: Add rspi_data_{out,in,out_in}() helpers
2014-01-24 8:43 [PATCH 0/14] spi: rspi: Add support for RZ/A1H, DT, and Quad/Dual on QSPI Geert Uytterhoeven
` (2 preceding siblings ...)
2014-01-24 8:43 ` [PATCH 03/14] spi: rspi: Abstract 8/16-bit Data Register access Geert Uytterhoeven
@ 2014-01-24 8:43 ` Geert Uytterhoeven
2014-01-27 20:03 ` Mark Brown
2014-01-24 8:43 ` [PATCH 05/14] spi: rspi: Abstract transfer_one() for RSPI and QSPI Geert Uytterhoeven
` (8 subsequent siblings)
12 siblings, 1 reply; 31+ messages in thread
From: Geert Uytterhoeven @ 2014-01-24 8:43 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-spi, linux-sh, linux-kernel, Geert Uytterhoeven
From: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
Add helpers rspi_data_{out,in,out_in}() to write, read, or write and
read data to/from the Data Register, taking care of waiting until data
or space is available in the buffers.
Signed-off-by: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
---
drivers/spi/spi-rspi.c | 117 +++++++++++++++++++++++-------------------------
1 file changed, 56 insertions(+), 61 deletions(-)
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c
index a0bb3c28ae91..4b27513e7204 100644
--- a/drivers/spi/spi-rspi.c
+++ b/drivers/spi/spi-rspi.c
@@ -356,22 +356,51 @@ static int rspi_wait_for_interrupt(struct rspi_data *rspi, u8 wait_mask,
return 0;
}
+static int rspi_data_out(struct rspi_data *rspi, u8 data)
+{
+ if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
+ dev_err(&rspi->master->dev, "transmit timeout\n");
+ return -ETIMEDOUT;
+ }
+ rspi_write_data(rspi, data);
+ return 0;
+}
+
+static int rspi_data_in(struct rspi_data *rspi)
+{
+ u8 data;
+
+ if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) {
+ dev_err(&rspi->master->dev, "receive timeout\n");
+ return -ETIMEDOUT;
+ }
+ data = rspi_read_data(rspi);
+ return data;
+}
+
+static int rspi_data_out_in(struct rspi_data *rspi, u8 data)
+{
+ int ret;
+
+ ret = rspi_data_out(rspi, data);
+ if (ret < 0)
+ return ret;
+
+ return rspi_data_in(rspi);
+}
+
static int rspi_send_pio(struct rspi_data *rspi, struct spi_transfer *t)
{
- int remain = t->len;
+ int remain = t->len, ret;
const u8 *data = t->tx_buf;
+
while (remain > 0) {
rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_TXMD,
RSPI_SPCR);
- if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
- dev_err(&rspi->master->dev,
- "%s: tx empty timeout\n", __func__);
- return -ETIMEDOUT;
- }
-
- rspi_write_data(rspi, *data);
- data++;
+ ret = rspi_data_out(rspi, *data++);
+ if (ret < 0)
+ return ret;
remain--;
}
@@ -383,28 +412,17 @@ static int rspi_send_pio(struct rspi_data *rspi, struct spi_transfer *t)
static int qspi_send_pio(struct rspi_data *rspi, struct spi_transfer *t)
{
- int remain = t->len;
+ int remain = t->len, ret;
const u8 *data = t->tx_buf;
rspi_write8(rspi, SPBFCR_TXRST, QSPI_SPBFCR);
rspi_write8(rspi, 0x00, QSPI_SPBFCR);
while (remain > 0) {
-
- if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
- dev_err(&rspi->master->dev,
- "%s: tx empty timeout\n", __func__);
- return -ETIMEDOUT;
- }
- rspi_write_data(rspi, *data++);
-
- if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) {
- dev_err(&rspi->master->dev,
- "%s: receive timeout\n", __func__);
- return -ETIMEDOUT;
- }
- rspi_read_data(rspi);
-
+ /* dummy read */
+ ret = rspi_data_out_in(rspi, *data++);
+ if (ret < 0)
+ return ret;
remain--;
}
@@ -549,32 +567,20 @@ static void rspi_receive_init(const struct rspi_data *rspi)
static int rspi_receive_pio(struct rspi_data *rspi, struct spi_transfer *t)
{
- int remain = t->len;
- u8 *data;
+ int remain = t->len, ret;
+ u8 *data = t->rx_buf;
rspi_receive_init(rspi);
- data = t->rx_buf;
while (remain > 0) {
rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_TXMD,
RSPI_SPCR);
- if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
- dev_err(&rspi->master->dev,
- "%s: tx empty timeout\n", __func__);
- return -ETIMEDOUT;
- }
- /* dummy write for generate clock */
- rspi_write_data(rspi, DUMMY_DATA);
-
- if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) {
- dev_err(&rspi->master->dev,
- "%s: receive timeout\n", __func__);
- return -ETIMEDOUT;
- }
- *data = rspi_read_data(rspi);
-
- data++;
+ /* dummy write data for generate clock */
+ ret = rspi_data_out_in(rspi, DUMMY_DATA);
+ if (ret < 0)
+ return ret;
+ *data++ = ret;
remain--;
}
@@ -594,28 +600,17 @@ static void qspi_receive_init(const struct rspi_data *rspi)
static int qspi_receive_pio(struct rspi_data *rspi, struct spi_transfer *t)
{
- int remain = t->len;
- u8 *data;
+ int remain = t->len, ret;
+ u8 *data = t->rx_buf;
qspi_receive_init(rspi);
- data = t->rx_buf;
while (remain > 0) {
-
- if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
- dev_err(&rspi->master->dev,
- "%s: tx empty timeout\n", __func__);
- return -ETIMEDOUT;
- }
/* dummy write for generate clock */
- rspi_write_data(rspi, DUMMY_DATA);
-
- if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) {
- dev_err(&rspi->master->dev,
- "%s: receive timeout\n", __func__);
- return -ETIMEDOUT;
- }
- *data++ = rspi_read_data(rspi);
+ ret = rspi_data_out_in(rspi, DUMMY_DATA);
+ if (ret < 0)
+ return ret;
+ *data++ = ret;
remain--;
}
--
1.7.9.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* Re: [PATCH 04/14] spi: rspi: Add rspi_data_{out,in,out_in}() helpers
2014-01-24 8:43 ` [PATCH 04/14] spi: rspi: Add rspi_data_{out,in,out_in}() helpers Geert Uytterhoeven
@ 2014-01-27 20:03 ` Mark Brown
0 siblings, 0 replies; 31+ messages in thread
From: Mark Brown @ 2014-01-27 20:03 UTC (permalink / raw)
To: Geert Uytterhoeven; +Cc: linux-spi, linux-sh, linux-kernel, Geert Uytterhoeven
[-- Attachment #1: Type: text/plain, Size: 339 bytes --]
On Fri, Jan 24, 2014 at 09:43:54AM +0100, Geert Uytterhoeven wrote:
> From: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
>
> Add helpers rspi_data_{out,in,out_in}() to write, read, or write and
> read data to/from the Data Register, taking care of waiting until data
> or space is available in the buffers.
Applied, thanks.
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH 05/14] spi: rspi: Abstract transfer_one() for RSPI and QSPI
2014-01-24 8:43 [PATCH 0/14] spi: rspi: Add support for RZ/A1H, DT, and Quad/Dual on QSPI Geert Uytterhoeven
` (3 preceding siblings ...)
2014-01-24 8:43 ` [PATCH 04/14] spi: rspi: Add rspi_data_{out,in,out_in}() helpers Geert Uytterhoeven
@ 2014-01-24 8:43 ` Geert Uytterhoeven
2014-01-27 20:03 ` Mark Brown
2014-01-24 8:43 ` [PATCH 06/14] spi: rspi: Merge rspi_send_pio() and rspi_receive_pio() Geert Uytterhoeven
` (7 subsequent siblings)
12 siblings, 1 reply; 31+ messages in thread
From: Geert Uytterhoeven @ 2014-01-24 8:43 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-spi, linux-sh, linux-kernel, Geert Uytterhoeven
From: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
Split off qspi_transfer_one() (which doesn't support DMA yet) from
rspi_transfer_one().
Replace the abstraction of send_pio()/receive_pio() by the abstracrion of
transfer_one().
Signed-off-by: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
---
drivers/spi/spi-rspi.c | 36 +++++++++++++++++++++++-------------
1 file changed, 23 insertions(+), 13 deletions(-)
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c
index 4b27513e7204..d837c5029308 100644
--- a/drivers/spi/spi-rspi.c
+++ b/drivers/spi/spi-rspi.c
@@ -239,8 +239,8 @@ static u16 rspi_read_data(const struct rspi_data *rspi)
/* optional functions */
struct spi_ops {
int (*set_config_register)(struct rspi_data *rspi, int access_size);
- int (*send_pio)(struct rspi_data *rspi, struct spi_transfer *t);
- int (*receive_pio)(struct rspi_data *rspi, struct spi_transfer *t);
+ int (*transfer_one)(struct spi_master *master, struct spi_device *spi,
+ struct spi_transfer *xfer);
};
/*
@@ -432,8 +432,6 @@ static int qspi_send_pio(struct rspi_data *rspi, struct spi_transfer *t)
return 0;
}
-#define send_pio(spi, t) spi->ops->send_pio(spi, t)
-
static void rspi_dma_complete(void *arg)
{
struct rspi_data *rspi = arg;
@@ -617,8 +615,6 @@ static int qspi_receive_pio(struct rspi_data *rspi, struct spi_transfer *t)
return 0;
}
-#define receive_pio(spi, t) spi->ops->receive_pio(spi, t)
-
static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t)
{
struct scatterlist sg, sg_dummy;
@@ -743,7 +739,7 @@ static int rspi_transfer_one(struct spi_master *master, struct spi_device *spi,
if (rspi_is_dma(rspi, xfer))
ret = rspi_send_dma(rspi, xfer);
else
- ret = send_pio(rspi, xfer);
+ ret = rspi_send_pio(rspi, xfer);
if (ret < 0)
return ret;
}
@@ -751,8 +747,24 @@ static int rspi_transfer_one(struct spi_master *master, struct spi_device *spi,
if (rspi_is_dma(rspi, xfer))
ret = rspi_receive_dma(rspi, xfer);
else
- ret = receive_pio(rspi, xfer);
+ ret = rspi_receive_pio(rspi, xfer);
+ }
+ return ret;
+}
+
+static int qspi_transfer_one(struct spi_master *master, struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct rspi_data *rspi = spi_master_get_devdata(master);
+ int ret = 0;
+
+ if (xfer->tx_buf) {
+ ret = qspi_send_pio(rspi, xfer);
+ if (ret < 0)
+ return ret;
}
+ if (xfer->rx_buf)
+ ret = qspi_receive_pio(rspi, xfer);
return ret;
}
@@ -948,7 +960,7 @@ static int rspi_probe(struct platform_device *pdev)
master->bus_num = pdev->id;
master->setup = rspi_setup;
- master->transfer_one = rspi_transfer_one;
+ master->transfer_one = ops->transfer_one;
master->cleanup = rspi_cleanup;
master->prepare_message = rspi_prepare_message;
master->unprepare_message = rspi_unprepare_message;
@@ -990,14 +1002,12 @@ error1:
static struct spi_ops rspi_ops = {
.set_config_register = rspi_set_config_register,
- .send_pio = rspi_send_pio,
- .receive_pio = rspi_receive_pio,
+ .transfer_one = rspi_transfer_one,
};
static struct spi_ops qspi_ops = {
.set_config_register = qspi_set_config_register,
- .send_pio = qspi_send_pio,
- .receive_pio = qspi_receive_pio,
+ .transfer_one = qspi_transfer_one,
};
static struct platform_device_id spi_driver_ids[] = {
--
1.7.9.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* Re: [PATCH 05/14] spi: rspi: Abstract transfer_one() for RSPI and QSPI
2014-01-24 8:43 ` [PATCH 05/14] spi: rspi: Abstract transfer_one() for RSPI and QSPI Geert Uytterhoeven
@ 2014-01-27 20:03 ` Mark Brown
0 siblings, 0 replies; 31+ messages in thread
From: Mark Brown @ 2014-01-27 20:03 UTC (permalink / raw)
To: Geert Uytterhoeven; +Cc: linux-spi, linux-sh, linux-kernel, Geert Uytterhoeven
[-- Attachment #1: Type: text/plain, Size: 342 bytes --]
On Fri, Jan 24, 2014 at 09:43:55AM +0100, Geert Uytterhoeven wrote:
> From: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
>
> Split off qspi_transfer_one() (which doesn't support DMA yet) from
> rspi_transfer_one().
> Replace the abstraction of send_pio()/receive_pio() by the abstracrion of
> transfer_one().
Applied, thanks.
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH 06/14] spi: rspi: Merge rspi_send_pio() and rspi_receive_pio()
2014-01-24 8:43 [PATCH 0/14] spi: rspi: Add support for RZ/A1H, DT, and Quad/Dual on QSPI Geert Uytterhoeven
` (4 preceding siblings ...)
2014-01-24 8:43 ` [PATCH 05/14] spi: rspi: Abstract transfer_one() for RSPI and QSPI Geert Uytterhoeven
@ 2014-01-24 8:43 ` Geert Uytterhoeven
[not found] ` <1390553044-11860-7-git-send-email-geert-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org>
2014-01-24 8:43 ` [PATCH 07/14] spi: rspi: Merge qspi_send_pio() and qspi_receive_pio() Geert Uytterhoeven
` (6 subsequent siblings)
12 siblings, 1 reply; 31+ messages in thread
From: Geert Uytterhoeven @ 2014-01-24 8:43 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-spi, linux-sh, linux-kernel, Geert Uytterhoeven
From: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
rspi_send_pio() and rspi_receive_pio() are very similar:
- the former only sends data, using TX Only Mode,
- the latter sends and receives full duplex data to/from the hardware,
but uses dummy transmit data.
Merge them into rspi_transfer_out_in(), now supporting full duplex if
needed.
Signed-off-by: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
---
drivers/spi/spi-rspi.c | 101 ++++++++++++++++++++++--------------------------
1 file changed, 46 insertions(+), 55 deletions(-)
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c
index d837c5029308..cc90136d02c8 100644
--- a/drivers/spi/spi-rspi.c
+++ b/drivers/spi/spi-rspi.c
@@ -389,27 +389,6 @@ static int rspi_data_out_in(struct rspi_data *rspi, u8 data)
return rspi_data_in(rspi);
}
-static int rspi_send_pio(struct rspi_data *rspi, struct spi_transfer *t)
-{
- int remain = t->len, ret;
- const u8 *data = t->tx_buf;
-
- while (remain > 0) {
- rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_TXMD,
- RSPI_SPCR);
-
- ret = rspi_data_out(rspi, *data++);
- if (ret < 0)
- return ret;
- remain--;
- }
-
- /* Waiting for the last transmission */
- rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
-
- return 0;
-}
-
static int qspi_send_pio(struct rspi_data *rspi, struct spi_transfer *t)
{
int remain = t->len, ret;
@@ -563,28 +542,6 @@ static void rspi_receive_init(const struct rspi_data *rspi)
RSPI_SPSR);
}
-static int rspi_receive_pio(struct rspi_data *rspi, struct spi_transfer *t)
-{
- int remain = t->len, ret;
- u8 *data = t->rx_buf;
-
- rspi_receive_init(rspi);
-
- while (remain > 0) {
- rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_TXMD,
- RSPI_SPCR);
-
- /* dummy write data for generate clock */
- ret = rspi_data_out_in(rspi, DUMMY_DATA);
- if (ret < 0)
- return ret;
- *data++ = ret;
- remain--;
- }
-
- return 0;
-}
-
static void qspi_receive_init(const struct rspi_data *rspi)
{
u8 spsr;
@@ -729,27 +686,61 @@ static int rspi_is_dma(const struct rspi_data *rspi, struct spi_transfer *t)
return 0;
}
+static int rspi_transfer_out_in(struct rspi_data *rspi,
+ struct spi_transfer *xfer)
+{
+ int remain = xfer->len, ret;
+ const u8 *tx_buf = xfer->tx_buf;
+ u8 *rx_buf = xfer->rx_buf;
+ u8 spcr, data;
+
+ rspi_receive_init(rspi);
+
+ spcr = rspi_read8(rspi, RSPI_SPCR);
+ if (rx_buf)
+ spcr &= ~SPCR_TXMD;
+ else
+ spcr |= SPCR_TXMD;
+ rspi_write8(rspi, spcr, RSPI_SPCR);
+
+ while (remain > 0) {
+ data = tx_buf ? *tx_buf++ : DUMMY_DATA;
+ ret = rspi_data_out(rspi, data);
+ if (ret < 0)
+ return ret;
+ if (rx_buf) {
+ ret = rspi_data_in(rspi);
+ if (ret < 0)
+ return ret;
+ *rx_buf++ = ret;
+ }
+ remain--;
+ }
+
+ /* Wait for the last transmission */
+ rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
+
+ return 0;
+}
+
static int rspi_transfer_one(struct spi_master *master, struct spi_device *spi,
struct spi_transfer *xfer)
{
struct rspi_data *rspi = spi_master_get_devdata(master);
- int ret = 0;
+ int ret;
+
+ if (!rspi_is_dma(rspi, xfer))
+ return rspi_transfer_out_in(rspi, xfer);
if (xfer->tx_buf) {
- if (rspi_is_dma(rspi, xfer))
- ret = rspi_send_dma(rspi, xfer);
- else
- ret = rspi_send_pio(rspi, xfer);
+ ret = rspi_send_dma(rspi, xfer);
if (ret < 0)
return ret;
}
- if (xfer->rx_buf) {
- if (rspi_is_dma(rspi, xfer))
- ret = rspi_receive_dma(rspi, xfer);
- else
- ret = rspi_receive_pio(rspi, xfer);
- }
- return ret;
+ if (xfer->rx_buf)
+ return rspi_receive_dma(rspi, xfer);
+
+ return 0;
}
static int qspi_transfer_one(struct spi_master *master, struct spi_device *spi,
--
1.7.9.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH 07/14] spi: rspi: Merge qspi_send_pio() and qspi_receive_pio()
2014-01-24 8:43 [PATCH 0/14] spi: rspi: Add support for RZ/A1H, DT, and Quad/Dual on QSPI Geert Uytterhoeven
` (5 preceding siblings ...)
2014-01-24 8:43 ` [PATCH 06/14] spi: rspi: Merge rspi_send_pio() and rspi_receive_pio() Geert Uytterhoeven
@ 2014-01-24 8:43 ` Geert Uytterhoeven
2014-01-27 20:04 ` Mark Brown
[not found] ` <1390553044-11860-1-git-send-email-geert-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org>
` (5 subsequent siblings)
12 siblings, 1 reply; 31+ messages in thread
From: Geert Uytterhoeven @ 2014-01-24 8:43 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-spi, linux-sh, linux-kernel, Geert Uytterhoeven
From: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
qspi_send_pio() and qspi_receive_pio() are very similar: they both send
and receive full duplex data to/from the hardware, but ignore the data
stream in the unused direction.
Merge them into qspi_transfer_out_in(), now supporting real full duplex.
Signed-off-by: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
---
drivers/spi/spi-rspi.c | 79 +++++++++++++++++-------------------------------
1 file changed, 28 insertions(+), 51 deletions(-)
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c
index cc90136d02c8..5d39cd3eba62 100644
--- a/drivers/spi/spi-rspi.c
+++ b/drivers/spi/spi-rspi.c
@@ -389,28 +389,6 @@ static int rspi_data_out_in(struct rspi_data *rspi, u8 data)
return rspi_data_in(rspi);
}
-static int qspi_send_pio(struct rspi_data *rspi, struct spi_transfer *t)
-{
- int remain = t->len, ret;
- const u8 *data = t->tx_buf;
-
- rspi_write8(rspi, SPBFCR_TXRST, QSPI_SPBFCR);
- rspi_write8(rspi, 0x00, QSPI_SPBFCR);
-
- while (remain > 0) {
- /* dummy read */
- ret = rspi_data_out_in(rspi, *data++);
- if (ret < 0)
- return ret;
- remain--;
- }
-
- /* Waiting for the last transmission */
- rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
-
- return 0;
-}
-
static void rspi_dma_complete(void *arg)
{
struct rspi_data *rspi = arg;
@@ -550,26 +528,7 @@ static void qspi_receive_init(const struct rspi_data *rspi)
if (spsr & SPSR_SPRF)
rspi_read_data(rspi); /* dummy read */
rspi_write8(rspi, SPBFCR_TXRST | SPBFCR_RXRST, QSPI_SPBFCR);
- rspi_write8(rspi, 0x00, QSPI_SPBFCR);
-}
-
-static int qspi_receive_pio(struct rspi_data *rspi, struct spi_transfer *t)
-{
- int remain = t->len, ret;
- u8 *data = t->rx_buf;
-
- qspi_receive_init(rspi);
-
- while (remain > 0) {
- /* dummy write for generate clock */
- ret = rspi_data_out_in(rspi, DUMMY_DATA);
- if (ret < 0)
- return ret;
- *data++ = ret;
- remain--;
- }
-
- return 0;
+ rspi_write8(rspi, 0, QSPI_SPBFCR);
}
static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t)
@@ -743,20 +702,38 @@ static int rspi_transfer_one(struct spi_master *master, struct spi_device *spi,
return 0;
}
-static int qspi_transfer_one(struct spi_master *master, struct spi_device *spi,
- struct spi_transfer *xfer)
+static int qspi_transfer_out_in(struct rspi_data *rspi,
+ struct spi_transfer *xfer)
{
- struct rspi_data *rspi = spi_master_get_devdata(master);
- int ret = 0;
+ int remain = xfer->len, ret;
+ const u8 *tx_buf = xfer->tx_buf;
+ u8 *rx_buf = xfer->rx_buf;
+ u8 data;
- if (xfer->tx_buf) {
- ret = qspi_send_pio(rspi, xfer);
+ qspi_receive_init(rspi);
+
+ while (remain > 0) {
+ data = tx_buf ? *tx_buf++ : DUMMY_DATA;
+ ret = rspi_data_out_in(rspi, data);
if (ret < 0)
return ret;
+ if (rx_buf)
+ *rx_buf++ = ret;
+ remain--;
}
- if (xfer->rx_buf)
- ret = qspi_receive_pio(rspi, xfer);
- return ret;
+
+ /* Wait for the last transmission */
+ rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
+
+ return 0;
+}
+
+static int qspi_transfer_one(struct spi_master *master, struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct rspi_data *rspi = spi_master_get_devdata(master);
+
+ return qspi_transfer_out_in(rspi, xfer);
}
static int rspi_setup(struct spi_device *spi)
--
1.7.9.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* Re: [PATCH 07/14] spi: rspi: Merge qspi_send_pio() and qspi_receive_pio()
2014-01-24 8:43 ` [PATCH 07/14] spi: rspi: Merge qspi_send_pio() and qspi_receive_pio() Geert Uytterhoeven
@ 2014-01-27 20:04 ` Mark Brown
0 siblings, 0 replies; 31+ messages in thread
From: Mark Brown @ 2014-01-27 20:04 UTC (permalink / raw)
To: Geert Uytterhoeven; +Cc: linux-spi, linux-sh, linux-kernel, Geert Uytterhoeven
[-- Attachment #1: Type: text/plain, Size: 412 bytes --]
On Fri, Jan 24, 2014 at 09:43:57AM +0100, Geert Uytterhoeven wrote:
> From: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
>
> qspi_send_pio() and qspi_receive_pio() are very similar: they both send
> and receive full duplex data to/from the hardware, but ignore the data
> stream in the unused direction.
> Merge them into qspi_transfer_out_in(), now supporting real full duplex.
Applied, thanks.
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread
[parent not found: <1390553044-11860-1-git-send-email-geert-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org>]
* [PATCH v3 08/14] spi: rspi: Add support for more than one interrupt
[not found] ` <1390553044-11860-1-git-send-email-geert-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org>
@ 2014-01-24 8:43 ` Geert Uytterhoeven
2014-01-27 20:05 ` Mark Brown
2014-01-24 8:44 ` [PATCH v2 11/14] spi: rspi: Convert to clk_prepare_enable/disable_unprepare Geert Uytterhoeven
1 sibling, 1 reply; 31+ messages in thread
From: Geert Uytterhoeven @ 2014-01-24 8:43 UTC (permalink / raw)
To: Mark Brown
Cc: linux-spi-u79uwXL29TY76Z2rM5mHXA, linux-sh-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Geert Uytterhoeven
From: Geert Uytterhoeven <geert+renesas-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org>
Add support for multiple interrupts, based on the SDK reference code.
This is needed for RZ/A1H, which supports 3 interrupts.
When using multiple interrupts, they must be called "rx" (SPRI) and "tx"
(SPTI). The error interrupt (SPEI) is not used, as it matters for slave
mode only.
When using a single interrupt, it may be called "mux". If it cannot be
found, the first interrupt in the device's resources will be used.
Signed-off-by: Geert Uytterhoeven <geert+renesas-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org>
---
v2:
- s/irq[]/irqs[]/
- s/numirq/num_irqs/
- Use unsigned int for loop counters that cannot be negative
- Merge the platform_get_irq() and devm_request_irq() loops
- Do not update copyright header in further untouched rspi.h
v3:
- Do not request the unused error interrupt
- Add suffixes ":mux", ":rx" and ":tx" to the registered interrupt names
- Use named interrupts
drivers/spi/spi-rspi.c | 106 +++++++++++++++++++++++++++++++++++++++---------
1 file changed, 87 insertions(+), 19 deletions(-)
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c
index 5d39cd3eba62..d2ade5e09f58 100644
--- a/drivers/spi/spi-rspi.c
+++ b/drivers/spi/spi-rspi.c
@@ -1,7 +1,7 @@
/*
* SH RSPI driver
*
- * Copyright (C) 2012 Renesas Solutions Corp.
+ * Copyright (C) 2012, 2013 Renesas Solutions Corp.
*
* Based on spi-sh.c:
* Copyright (C) 2011 Renesas Solutions Corp.
@@ -183,12 +183,12 @@ struct rspi_data {
struct clk *clk;
u8 spsr;
u16 spcmd;
+ int rx_irq, tx_irq;
const struct spi_ops *ops;
/* for dmaengine */
struct dma_chan *chan_tx;
struct dma_chan *chan_rx;
- int irq;
unsigned dma_width_16bit:1;
unsigned dma_callbacked:1;
@@ -440,7 +440,7 @@ static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t)
struct scatterlist sg;
const void *buf = NULL;
struct dma_async_tx_descriptor *desc;
- unsigned len;
+ unsigned int len;
int ret = 0;
if (rspi->dma_width_16bit) {
@@ -478,7 +478,7 @@ static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t)
* DMAC needs SPTIE, but if SPTIE is set, this IRQ routine will be
* called. So, this driver disables the IRQ while DMA transfer.
*/
- disable_irq(rspi->irq);
+ disable_irq(rspi->tx_irq);
rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_TXMD, RSPI_SPCR);
rspi_enable_irq(rspi, SPCR_SPTIE);
@@ -497,7 +497,7 @@ static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t)
ret = -ETIMEDOUT;
rspi_disable_irq(rspi, SPCR_SPTIE);
- enable_irq(rspi->irq);
+ enable_irq(rspi->tx_irq);
end:
rspi_dma_unmap_sg(&sg, rspi->chan_tx, DMA_TO_DEVICE);
@@ -536,7 +536,7 @@ static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t)
struct scatterlist sg, sg_dummy;
void *dummy = NULL, *rx_buf = NULL;
struct dma_async_tx_descriptor *desc, *desc_dummy;
- unsigned len;
+ unsigned int len;
int ret = 0;
if (rspi->dma_width_16bit) {
@@ -594,7 +594,9 @@ static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t)
* DMAC needs SPTIE, but if SPTIE is set, this IRQ routine will be
* called. So, this driver disables the IRQ while DMA transfer.
*/
- disable_irq(rspi->irq);
+ disable_irq(rspi->tx_irq);
+ if (rspi->rx_irq != rspi->tx_irq)
+ disable_irq(rspi->rx_irq);
rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_TXMD, RSPI_SPCR);
rspi_enable_irq(rspi, SPCR_SPTIE | SPCR_SPRIE);
@@ -617,7 +619,9 @@ static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t)
ret = -ETIMEDOUT;
rspi_disable_irq(rspi, SPCR_SPTIE | SPCR_SPRIE);
- enable_irq(rspi->irq);
+ enable_irq(rspi->tx_irq);
+ if (rspi->rx_irq != rspi->tx_irq)
+ enable_irq(rspi->rx_irq);
end:
rspi_dma_unmap_sg(&sg, rspi->chan_rx, DMA_FROM_DEVICE);
@@ -775,7 +779,7 @@ static int rspi_unprepare_message(struct spi_master *master,
return 0;
}
-static irqreturn_t rspi_irq(int irq, void *_sr)
+static irqreturn_t rspi_irq_mux(int irq, void *_sr)
{
struct rspi_data *rspi = _sr;
u8 spsr;
@@ -797,6 +801,36 @@ static irqreturn_t rspi_irq(int irq, void *_sr)
return ret;
}
+static irqreturn_t rspi_irq_rx(int irq, void *_sr)
+{
+ struct rspi_data *rspi = _sr;
+ u8 spsr;
+
+ rspi->spsr = spsr = rspi_read8(rspi, RSPI_SPSR);
+ if (spsr & SPSR_SPRF) {
+ rspi_disable_irq(rspi, SPCR_SPRIE);
+ wake_up(&rspi->wait);
+ return IRQ_HANDLED;
+ }
+
+ return 0;
+}
+
+static irqreturn_t rspi_irq_tx(int irq, void *_sr)
+{
+ struct rspi_data *rspi = _sr;
+ u8 spsr;
+
+ rspi->spsr = spsr = rspi_read8(rspi, RSPI_SPSR);
+ if (spsr & SPSR_SPTEF) {
+ rspi_disable_irq(rspi, SPCR_SPTIE);
+ wake_up(&rspi->wait);
+ return IRQ_HANDLED;
+ }
+
+ return 0;
+}
+
static int rspi_request_dma(struct rspi_data *rspi,
struct platform_device *pdev)
{
@@ -868,12 +902,25 @@ static int rspi_remove(struct platform_device *pdev)
return 0;
}
+static int rspi_request_irq(struct device *dev, unsigned int irq,
+ irq_handler_t handler, const char *suffix,
+ void *dev_id)
+{
+ const char *base = dev_name(dev);
+ size_t len = strlen(base) + strlen(suffix) + 2;
+ char *name = devm_kzalloc(dev, len, GFP_KERNEL);
+ if (!name)
+ return -ENOMEM;
+ snprintf(name, len, "%s:%s", base, suffix);
+ return devm_request_irq(dev, irq, handler, 0, name, dev_id);
+}
+
static int rspi_probe(struct platform_device *pdev)
{
struct resource *res;
struct spi_master *master;
struct rspi_data *rspi;
- int ret, irq;
+ int ret;
char clk_name[16];
const struct rspi_plat_data *rspi_pd = dev_get_platdata(&pdev->dev);
const struct spi_ops *ops;
@@ -886,12 +933,6 @@ static int rspi_probe(struct platform_device *pdev)
return -ENODEV;
}
- irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "platform_get_irq error\n");
- return -ENODEV;
- }
-
master = spi_alloc_master(&pdev->dev, sizeof(struct rspi_data));
if (master == NULL) {
dev_err(&pdev->dev, "spi_alloc_master error.\n");
@@ -934,14 +975,41 @@ static int rspi_probe(struct platform_device *pdev)
master->unprepare_message = rspi_unprepare_message;
master->mode_bits = SPI_CPHA | SPI_CPOL;
- ret = devm_request_irq(&pdev->dev, irq, rspi_irq, 0,
- dev_name(&pdev->dev), rspi);
+ ret = platform_get_irq_byname(pdev, "rx");
+ if (ret < 0) {
+ ret = platform_get_irq_byname(pdev, "mux");
+ if (ret < 0)
+ ret = platform_get_irq(pdev, 0);
+ if (ret >= 0)
+ rspi->rx_irq = rspi->tx_irq = ret;
+ } else {
+ rspi->rx_irq = ret;
+ ret = platform_get_irq_byname(pdev, "tx");
+ if (ret >= 0)
+ rspi->tx_irq = ret;
+ }
+ if (ret < 0) {
+ dev_err(&pdev->dev, "platform_get_irq error\n");
+ goto error2;
+ }
+
+ if (rspi->rx_irq == rspi->tx_irq) {
+ /* Single multiplexed interrupt */
+ ret = rspi_request_irq(&pdev->dev, rspi->rx_irq, rspi_irq_mux,
+ "mux", rspi);
+ } else {
+ /* Multi-interrupt mode, only SPRI and SPTI are used */
+ ret = rspi_request_irq(&pdev->dev, rspi->rx_irq, rspi_irq_rx,
+ "rx", rspi);
+ if (!ret)
+ ret = rspi_request_irq(&pdev->dev, rspi->tx_irq,
+ rspi_irq_tx, "tx", rspi);
+ }
if (ret < 0) {
dev_err(&pdev->dev, "request_irq error\n");
goto error2;
}
- rspi->irq = irq;
ret = rspi_request_dma(rspi, pdev);
if (ret < 0) {
dev_err(&pdev->dev, "rspi_request_dma failed.\n");
--
1.7.9.5
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 31+ messages in thread
* Re: [PATCH v3 08/14] spi: rspi: Add support for more than one interrupt
2014-01-24 8:43 ` [PATCH v3 08/14] spi: rspi: Add support for more than one interrupt Geert Uytterhoeven
@ 2014-01-27 20:05 ` Mark Brown
0 siblings, 0 replies; 31+ messages in thread
From: Mark Brown @ 2014-01-27 20:05 UTC (permalink / raw)
To: Geert Uytterhoeven; +Cc: linux-spi, linux-sh, linux-kernel, Geert Uytterhoeven
[-- Attachment #1: Type: text/plain, Size: 284 bytes --]
On Fri, Jan 24, 2014 at 09:43:58AM +0100, Geert Uytterhoeven wrote:
> From: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
>
> Add support for multiple interrupts, based on the SDK reference code.
> This is needed for RZ/A1H, which supports 3 interrupts.
Applied, thanks.
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 11/14] spi: rspi: Convert to clk_prepare_enable/disable_unprepare
[not found] ` <1390553044-11860-1-git-send-email-geert-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org>
2014-01-24 8:43 ` [PATCH v3 08/14] spi: rspi: Add support for more than one interrupt Geert Uytterhoeven
@ 2014-01-24 8:44 ` Geert Uytterhoeven
2014-01-27 20:08 ` Mark Brown
1 sibling, 1 reply; 31+ messages in thread
From: Geert Uytterhoeven @ 2014-01-24 8:44 UTC (permalink / raw)
To: Mark Brown
Cc: linux-spi-u79uwXL29TY76Z2rM5mHXA, linux-sh-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Geert Uytterhoeven
From: Geert Uytterhoeven <geert+renesas-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org>
Get the driver ready for the migration to the common clock framework by
calling clk_prepare_enable() and clk_disable_unprepare().
Signed-off-by: Geert Uytterhoeven <geert+renesas-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org>
---
v2:
- No changes
drivers/spi/spi-rspi.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c
index 28db8770aaf3..a648b40c271b 100644
--- a/drivers/spi/spi-rspi.c
+++ b/drivers/spi/spi-rspi.c
@@ -980,7 +980,7 @@ static int rspi_remove(struct platform_device *pdev)
struct rspi_data *rspi = platform_get_drvdata(pdev);
rspi_release_dma(rspi);
- clk_disable(rspi->clk);
+ clk_disable_unprepare(rspi->clk);
return 0;
}
@@ -1041,7 +1041,12 @@ static int rspi_probe(struct platform_device *pdev)
ret = PTR_ERR(rspi->clk);
goto error1;
}
- clk_enable(rspi->clk);
+
+ ret = clk_prepare_enable(rspi->clk);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "unable to prepare/enable clock\n");
+ goto error1;
+ }
init_waitqueue_head(&rspi->wait);
@@ -1112,7 +1117,7 @@ static int rspi_probe(struct platform_device *pdev)
error3:
rspi_release_dma(rspi);
error2:
- clk_disable(rspi->clk);
+ clk_disable_unprepare(rspi->clk);
error1:
spi_master_put(master);
--
1.7.9.5
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 31+ messages in thread
* Re: [PATCH v2 11/14] spi: rspi: Convert to clk_prepare_enable/disable_unprepare
2014-01-24 8:44 ` [PATCH v2 11/14] spi: rspi: Convert to clk_prepare_enable/disable_unprepare Geert Uytterhoeven
@ 2014-01-27 20:08 ` Mark Brown
0 siblings, 0 replies; 31+ messages in thread
From: Mark Brown @ 2014-01-27 20:08 UTC (permalink / raw)
To: Geert Uytterhoeven; +Cc: linux-spi, linux-sh, linux-kernel, Geert Uytterhoeven
[-- Attachment #1: Type: text/plain, Size: 288 bytes --]
On Fri, Jan 24, 2014 at 09:44:01AM +0100, Geert Uytterhoeven wrote:
> From: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
>
> Get the driver ready for the migration to the common clock framework by
> calling clk_prepare_enable() and clk_disable_unprepare().
Applied, thanks.
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH 09/14] spi: rspi: Add support for RSPI on RZ/A1H
2014-01-24 8:43 [PATCH 0/14] spi: rspi: Add support for RZ/A1H, DT, and Quad/Dual on QSPI Geert Uytterhoeven
` (7 preceding siblings ...)
[not found] ` <1390553044-11860-1-git-send-email-geert-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org>
@ 2014-01-24 8:43 ` Geert Uytterhoeven
2014-01-27 20:07 ` Mark Brown
2014-01-24 8:44 ` [PATCH v3 10/14] spi: rspi: Add support for loopback mode Geert Uytterhoeven
` (3 subsequent siblings)
12 siblings, 1 reply; 31+ messages in thread
From: Geert Uytterhoeven @ 2014-01-24 8:43 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-spi, linux-sh, linux-kernel, Geert Uytterhoeven
From: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
Add support for the RSPI variant in the RZ/A1H (r7s72100) SoC.
Main differences with RSPI on SH are:
- Lack of TX only mode, hence we always have to use full duplex
transfers,
- The Data Register must be accessed used 8-bit operations.
RSPI on RZ is matched using the new "rspi-rz" platform device name.
Signed-off-by: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
---
drivers/spi/spi-rspi.c | 101 +++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 92 insertions(+), 9 deletions(-)
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c
index d2ade5e09f58..0c7556978d2e 100644
--- a/drivers/spi/spi-rspi.c
+++ b/drivers/spi/spi-rspi.c
@@ -47,7 +47,7 @@
#define RSPI_SPCKD 0x0c /* Clock Delay Register */
#define RSPI_SSLND 0x0d /* Slave Select Negation Delay Register */
#define RSPI_SPND 0x0e /* Next-Access Delay Register */
-#define RSPI_SPCR2 0x0f /* Control Register 2 */
+#define RSPI_SPCR2 0x0f /* Control Register 2 (SH only) */
#define RSPI_SPCMD0 0x10 /* Command Register 0 */
#define RSPI_SPCMD1 0x12 /* Command Register 1 */
#define RSPI_SPCMD2 0x14 /* Command Register 2 */
@@ -56,10 +56,12 @@
#define RSPI_SPCMD5 0x1a /* Command Register 5 */
#define RSPI_SPCMD6 0x1c /* Command Register 6 */
#define RSPI_SPCMD7 0x1e /* Command Register 7 */
+
+/* RSPI on RZ only */
#define RSPI_SPBFCR 0x20 /* Buffer Control Register */
#define RSPI_SPBFDR 0x22 /* Buffer Data Count Setting Register */
-/*qspi only */
+/* QSPI only */
#define QSPI_SPBFCR 0x18 /* Buffer Control Register */
#define QSPI_SPBDCR 0x1a /* Buffer Data Count Register */
#define QSPI_SPBMUL0 0x1c /* Transfer Data Length Multiplier Setting Register 0 */
@@ -102,7 +104,7 @@
#define SPSR_PERF 0x08 /* Parity Error Flag */
#define SPSR_MODF 0x04 /* Mode Fault Error Flag */
#define SPSR_IDLNF 0x02 /* RSPI Idle Flag */
-#define SPSR_OVRF 0x01 /* Overrun Error Flag */
+#define SPSR_OVRF 0x01 /* Overrun Error Flag (RSPI only) */
/* SPSCR - Sequence Control Register */
#define SPSCR_SPSLN_MASK 0x07 /* Sequence Length Specification */
@@ -119,13 +121,13 @@
#define SPDCR_SPLWORD SPDCR_SPLW1
#define SPDCR_SPLBYTE SPDCR_SPLW0
#define SPDCR_SPLW 0x20 /* Access Width Specification (SH) */
-#define SPDCR_SPRDTD 0x10 /* Receive Transmit Data Select */
+#define SPDCR_SPRDTD 0x10 /* Receive Transmit Data Select (SH) */
#define SPDCR_SLSEL1 0x08
#define SPDCR_SLSEL0 0x04
-#define SPDCR_SLSEL_MASK 0x0c /* SSL1 Output Select */
+#define SPDCR_SLSEL_MASK 0x0c /* SSL1 Output Select (SH) */
#define SPDCR_SPFC1 0x02
#define SPDCR_SPFC0 0x01
-#define SPDCR_SPFC_MASK 0x03 /* Frame Count Setting (1-4) */
+#define SPDCR_SPFC_MASK 0x03 /* Frame Count Setting (1-4) (SH) */
/* SPCKD - Clock Delay Register */
#define SPCKD_SCKDL_MASK 0x07 /* Clock Delay Setting (1-8) */
@@ -168,8 +170,8 @@
#define SPCMD_CPHA 0x0001 /* Clock Phase Setting */
/* SPBFCR - Buffer Control Register */
-#define SPBFCR_TXRST 0x80 /* Transmit Buffer Data Reset (qspi only) */
-#define SPBFCR_RXRST 0x40 /* Receive Buffer Data Reset (qspi only) */
+#define SPBFCR_TXRST 0x80 /* Transmit Buffer Data Reset */
+#define SPBFCR_RXRST 0x40 /* Receive Buffer Data Reset */
#define SPBFCR_TXTRG_MASK 0x30 /* Transmit Buffer Data Triggering Number */
#define SPBFCR_RXTRG_MASK 0x07 /* Receive Buffer Data Triggering Number */
@@ -244,7 +246,7 @@ struct spi_ops {
};
/*
- * functions for RSPI
+ * functions for RSPI on legacy SH
*/
static int rspi_set_config_register(struct rspi_data *rspi, int access_size)
{
@@ -280,6 +282,39 @@ static int rspi_set_config_register(struct rspi_data *rspi, int access_size)
}
/*
+ * functions for RSPI on RZ
+ */
+static int rspi_rz_set_config_register(struct rspi_data *rspi, int access_size)
+{
+ int spbr;
+
+ /* Sets output mode */
+ rspi_write8(rspi, 0x00, RSPI_SPPCR);
+
+ /* Sets transfer bit rate */
+ spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz) - 1;
+ rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR);
+
+ /* Disable dummy transmission, set byte access */
+ rspi_write8(rspi, SPDCR_SPLBYTE, RSPI_SPDCR);
+ rspi->byte_access = 1;
+
+ /* Sets RSPCK, SSL, next-access delay value */
+ rspi_write8(rspi, 0x00, RSPI_SPCKD);
+ rspi_write8(rspi, 0x00, RSPI_SSLND);
+ rspi_write8(rspi, 0x00, RSPI_SPND);
+
+ /* Sets SPCMD */
+ rspi->spcmd |= SPCMD_SPB_8_TO_16(access_size);
+ rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0);
+
+ /* Sets RSPI mode */
+ rspi_write8(rspi, SPCR_MSTR, RSPI_SPCR);
+
+ return 0;
+}
+
+/*
* functions for QSPI
*/
static int qspi_set_config_register(struct rspi_data *rspi, int access_size)
@@ -520,6 +555,13 @@ static void rspi_receive_init(const struct rspi_data *rspi)
RSPI_SPSR);
}
+static void rspi_rz_receive_init(const struct rspi_data *rspi)
+{
+ rspi_receive_init(rspi);
+ rspi_write8(rspi, SPBFCR_TXRST | SPBFCR_RXRST, RSPI_SPBFCR);
+ rspi_write8(rspi, 0, RSPI_SPBFCR);
+}
+
static void qspi_receive_init(const struct rspi_data *rspi)
{
u8 spsr;
@@ -706,6 +748,41 @@ static int rspi_transfer_one(struct spi_master *master, struct spi_device *spi,
return 0;
}
+static int rspi_rz_transfer_out_in(struct rspi_data *rspi,
+ struct spi_transfer *xfer)
+{
+ int remain = xfer->len, ret;
+ const u8 *tx_buf = xfer->tx_buf;
+ u8 *rx_buf = xfer->rx_buf;
+ u8 data;
+
+ rspi_rz_receive_init(rspi);
+
+ while (remain > 0) {
+ data = tx_buf ? *tx_buf++ : DUMMY_DATA;
+ ret = rspi_data_out_in(rspi, data);
+ if (ret < 0)
+ return ret;
+ if (rx_buf)
+ *rx_buf++ = ret;
+ remain--;
+ }
+
+ /* Wait for the last transmission */
+ rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
+
+ return 0;
+}
+
+static int rspi_rz_transfer_one(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct rspi_data *rspi = spi_master_get_devdata(master);
+
+ return rspi_rz_transfer_out_in(rspi, xfer);
+}
+
static int qspi_transfer_out_in(struct rspi_data *rspi,
struct spi_transfer *xfer)
{
@@ -1041,6 +1118,11 @@ static struct spi_ops rspi_ops = {
.transfer_one = rspi_transfer_one,
};
+static struct spi_ops rspi_rz_ops = {
+ .set_config_register = rspi_rz_set_config_register,
+ .transfer_one = rspi_rz_transfer_one,
+};
+
static struct spi_ops qspi_ops = {
.set_config_register = qspi_set_config_register,
.transfer_one = qspi_transfer_one,
@@ -1048,6 +1130,7 @@ static struct spi_ops qspi_ops = {
static struct platform_device_id spi_driver_ids[] = {
{ "rspi", (kernel_ulong_t)&rspi_ops },
+ { "rspi-rz", (kernel_ulong_t)&rspi_rz_ops },
{ "qspi", (kernel_ulong_t)&qspi_ops },
{},
};
--
1.7.9.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* Re: [PATCH 09/14] spi: rspi: Add support for RSPI on RZ/A1H
2014-01-24 8:43 ` [PATCH 09/14] spi: rspi: Add support for RSPI on RZ/A1H Geert Uytterhoeven
@ 2014-01-27 20:07 ` Mark Brown
0 siblings, 0 replies; 31+ messages in thread
From: Mark Brown @ 2014-01-27 20:07 UTC (permalink / raw)
To: Geert Uytterhoeven; +Cc: linux-spi, linux-sh, linux-kernel, Geert Uytterhoeven
[-- Attachment #1: Type: text/plain, Size: 605 bytes --]
On Fri, Jan 24, 2014 at 09:43:59AM +0100, Geert Uytterhoeven wrote:
> From: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
>
> Add support for the RSPI variant in the RZ/A1H (r7s72100) SoC.
>
> Main differences with RSPI on SH are:
> - Lack of TX only mode, hence we always have to use full duplex
> transfers,
> - The Data Register must be accessed used 8-bit operations.
Applied, thanks. Ideally (and hopefully soon since I have a use for it
myself) we'll have a feature in the core which automatically provides
dummy data for full duplex mode but that's not a blocker here.
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v3 10/14] spi: rspi: Add support for loopback mode
2014-01-24 8:43 [PATCH 0/14] spi: rspi: Add support for RZ/A1H, DT, and Quad/Dual on QSPI Geert Uytterhoeven
` (8 preceding siblings ...)
2014-01-24 8:43 ` [PATCH 09/14] spi: rspi: Add support for RSPI on RZ/A1H Geert Uytterhoeven
@ 2014-01-24 8:44 ` Geert Uytterhoeven
[not found] ` <1390553044-11860-11-git-send-email-geert-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org>
2014-01-24 8:44 ` [PATCH v2 12/14] spi: rspi: Use NULL as the clock ID Geert Uytterhoeven
` (2 subsequent siblings)
12 siblings, 1 reply; 31+ messages in thread
From: Geert Uytterhoeven @ 2014-01-24 8:44 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-spi, linux-sh, linux-kernel, Geert Uytterhoeven
From: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
Add support for specifying loopback mode.
Signed-off-by: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
---
v3:
- This became a lot simpler after merging the send_pio() and
receive_pio() methods
drivers/spi/spi-rspi.c | 22 ++++++++++++++--------
1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c
index 0c7556978d2e..28db8770aaf3 100644
--- a/drivers/spi/spi-rspi.c
+++ b/drivers/spi/spi-rspi.c
@@ -183,8 +183,9 @@ struct rspi_data {
struct spi_master *master;
wait_queue_head_t wait;
struct clk *clk;
- u8 spsr;
u16 spcmd;
+ u8 spsr;
+ u8 sppcr;
int rx_irq, tx_irq;
const struct spi_ops *ops;
@@ -252,8 +253,8 @@ static int rspi_set_config_register(struct rspi_data *rspi, int access_size)
{
int spbr;
- /* Sets output mode(CMOS) and MOSI signal(from previous transfer) */
- rspi_write8(rspi, 0x00, RSPI_SPPCR);
+ /* Sets output mode, MOSI signal, and (optionally) loopback */
+ rspi_write8(rspi, rspi->sppcr, RSPI_SPPCR);
/* Sets transfer bit rate */
spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz) - 1;
@@ -288,8 +289,8 @@ static int rspi_rz_set_config_register(struct rspi_data *rspi, int access_size)
{
int spbr;
- /* Sets output mode */
- rspi_write8(rspi, 0x00, RSPI_SPPCR);
+ /* Sets output mode, MOSI signal, and (optionally) loopback */
+ rspi_write8(rspi, rspi->sppcr, RSPI_SPPCR);
/* Sets transfer bit rate */
spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz) - 1;
@@ -322,8 +323,8 @@ static int qspi_set_config_register(struct rspi_data *rspi, int access_size)
u16 spcmd;
int spbr;
- /* Sets output mode(CMOS) and MOSI signal(from previous transfer) */
- rspi_write8(rspi, 0x00, RSPI_SPPCR);
+ /* Sets output mode, MOSI signal, and (optionally) loopback */
+ rspi_write8(rspi, rspi->sppcr, RSPI_SPPCR);
/* Sets transfer bit rate */
spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz);
@@ -829,6 +830,11 @@ static int rspi_setup(struct spi_device *spi)
if (spi->mode & SPI_CPHA)
rspi->spcmd |= SPCMD_CPHA;
+ /* CMOS output mode and MOSI signal from previous transfer */
+ rspi->sppcr = 0;
+ if (spi->mode & SPI_LOOP)
+ rspi->sppcr |= SPPCR_SPLP;
+
set_config_register(rspi, 8);
return 0;
@@ -1050,7 +1056,7 @@ static int rspi_probe(struct platform_device *pdev)
master->cleanup = rspi_cleanup;
master->prepare_message = rspi_prepare_message;
master->unprepare_message = rspi_unprepare_message;
- master->mode_bits = SPI_CPHA | SPI_CPOL;
+ master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP;
ret = platform_get_irq_byname(pdev, "rx");
if (ret < 0) {
--
1.7.9.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v2 12/14] spi: rspi: Use NULL as the clock ID
2014-01-24 8:43 [PATCH 0/14] spi: rspi: Add support for RZ/A1H, DT, and Quad/Dual on QSPI Geert Uytterhoeven
` (9 preceding siblings ...)
2014-01-24 8:44 ` [PATCH v3 10/14] spi: rspi: Add support for loopback mode Geert Uytterhoeven
@ 2014-01-24 8:44 ` Geert Uytterhoeven
2014-01-27 20:08 ` Mark Brown
2014-01-24 8:44 ` [PATCH v4 13/14] spi: rspi: Add DT support Geert Uytterhoeven
2014-01-24 8:44 ` [PATCH 14/14] spi: rspi: Add support for Quad and Dual SPI Transfers on QSPI Geert Uytterhoeven
12 siblings, 1 reply; 31+ messages in thread
From: Geert Uytterhoeven @ 2014-01-24 8:44 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-spi, linux-sh, linux-kernel, Geert Uytterhoeven
From: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
There's only one RSPI/QSPI clock, so we can use NULL as the clock ID
Signed-off-by: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
---
v2:
- No changes
drivers/spi/spi-rspi.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c
index a648b40c271b..d79a7ed9b92e 100644
--- a/drivers/spi/spi-rspi.c
+++ b/drivers/spi/spi-rspi.c
@@ -1004,7 +1004,6 @@ static int rspi_probe(struct platform_device *pdev)
struct spi_master *master;
struct rspi_data *rspi;
int ret;
- char clk_name[16];
const struct rspi_plat_data *rspi_pd = dev_get_platdata(&pdev->dev);
const struct spi_ops *ops;
const struct platform_device_id *id_entry = pdev->id_entry;
@@ -1034,8 +1033,7 @@ static int rspi_probe(struct platform_device *pdev)
goto error1;
}
- snprintf(clk_name, sizeof(clk_name), "%s%d", id_entry->name, pdev->id);
- rspi->clk = devm_clk_get(&pdev->dev, clk_name);
+ rspi->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(rspi->clk)) {
dev_err(&pdev->dev, "cannot get clock\n");
ret = PTR_ERR(rspi->clk);
--
1.7.9.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* Re: [PATCH v2 12/14] spi: rspi: Use NULL as the clock ID
2014-01-24 8:44 ` [PATCH v2 12/14] spi: rspi: Use NULL as the clock ID Geert Uytterhoeven
@ 2014-01-27 20:08 ` Mark Brown
0 siblings, 0 replies; 31+ messages in thread
From: Mark Brown @ 2014-01-27 20:08 UTC (permalink / raw)
To: Geert Uytterhoeven; +Cc: linux-spi, linux-sh, linux-kernel, Geert Uytterhoeven
[-- Attachment #1: Type: text/plain, Size: 224 bytes --]
On Fri, Jan 24, 2014 at 09:44:02AM +0100, Geert Uytterhoeven wrote:
> From: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
>
> There's only one RSPI/QSPI clock, so we can use NULL as the clock ID
Applied, thanks.
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v4 13/14] spi: rspi: Add DT support
2014-01-24 8:43 [PATCH 0/14] spi: rspi: Add support for RZ/A1H, DT, and Quad/Dual on QSPI Geert Uytterhoeven
` (10 preceding siblings ...)
2014-01-24 8:44 ` [PATCH v2 12/14] spi: rspi: Use NULL as the clock ID Geert Uytterhoeven
@ 2014-01-24 8:44 ` Geert Uytterhoeven
2014-01-24 9:33 ` Mark Rutland
2014-01-27 20:11 ` Mark Brown
2014-01-24 8:44 ` [PATCH 14/14] spi: rspi: Add support for Quad and Dual SPI Transfers on QSPI Geert Uytterhoeven
12 siblings, 2 replies; 31+ messages in thread
From: Geert Uytterhoeven @ 2014-01-24 8:44 UTC (permalink / raw)
To: Mark Brown
Cc: linux-spi, linux-sh, linux-kernel, Geert Uytterhoeven, devicetree
From: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
Signed-off-by: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
Cc: devicetree@vger.kernel.org
---
v2:
- Clarify RSPI/QSPI
- Add interrupt-parent
- s/should/must/ for #address-cells and #size-cells
v3:
- Add renesas,rspi-sh
- Drop -rcar suffix for QSPI
- Clarify num-cs
- Implement DT support in driver
- Changed one-line summary from "Documentation: dt: Add Renesas RSPI/QSPI
bindings" to "spi: rspi: Add DT support"
v4:
- Clarify SoCtype and interrupts
- Add clock property
- Add QSPI example
- Add interrupt-names
- Add link to Renesas pinctrl
- Rename "renesas,rspi-sh" to "renesas,rspi", to match platform device
naming
- spi-rspi.c:
- Remove Soc-specific matching from spi-rspi.c given the fallback is
mandatory
- Things became a lot simpler due to the replacement of platform_data
fields by the "rspi-rz" platform device binding.
---
Documentation/devicetree/bindings/spi/spi-rspi.txt | 58 +++++++++++
drivers/spi/spi-rspi.c | 106 ++++++++++++++------
2 files changed, 135 insertions(+), 29 deletions(-)
create mode 100644 Documentation/devicetree/bindings/spi/spi-rspi.txt
diff --git a/Documentation/devicetree/bindings/spi/spi-rspi.txt b/Documentation/devicetree/bindings/spi/spi-rspi.txt
new file mode 100644
index 000000000000..ed84299a9c61
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spi-rspi.txt
@@ -0,0 +1,58 @@
+Device tree configuration for Renesas RSPI/QSPI driver
+
+Required properties:
+- compatible : For Renesas Serial Peripheral Interface on legacy SH:
+ "renesas,rspi-<soctype>", "renesas,rspi" as fallback.
+ For Renesas Serial Peripheral Interface on RZ/A1H:
+ "renesas,rspi-<soctype>", "renesas,rspi-rz" as fallback.
+ For Quad Serial Peripheral Interface on R-Car Gen2:
+ "renesas,qspi-<soctype>", "renesas,qspi" as fallback.
+ Examples of valid soctypes are "sh7757" (SH),
+ "r7s72100" (RZ/A1H), "r8a7790" (R-Car H2), and
+ "r8a7791" (R-Car M2).
+- reg : Address start and address range size of the device
+- interrupts : 1 interrupt for RSPI cores using a single multiplexed
+ interrupt,
+ 3 interrupts (SPEI, SPRI, SPTI) for RSPI cores using
+ separate interrupts.
+- interrupt-names : Array of strings associated with the interrupt numbers:
+ "error" for SPEI, "rx" for SPRI, and "tx" for SPTI.
+ For RSPI cores using a single multiplexed interrupt, the
+ name "mux" is optional.
+- interrupt-parent : The phandle for the interrupt controller that
+ services interrupts for this device.
+- num-cs : Number of chip selects. Some RSPI cores have more than 1.
+- #address-cells : Must be <1>
+- #size-cells : Must be <0>
+
+Optional properties:
+- clocks: : Must contain a reference to the functional clock.
+
+Pinctrl properties might be needed, too. See
+Documentation/devicetree/bindings/pinctrl/renesas,*.
+
+Examples:
+
+ spi0: spi@e800c800 {
+ compatible = "renesas,rspi-r7s72100", "renesas,rspi-rz";
+ reg = <0xe800c800 0x24>;
+ interrupts = <0 238 IRQ_TYPE_LEVEL_HIGH>,
+ <0 239 IRQ_TYPE_LEVEL_HIGH>,
+ <0 240 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "error", "rx", "tx";
+ interrupt-parent = <&gic>;
+ num-cs = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ spi: spi@e6b10000 {
+ compatible = "renesas,qspi-r8a7791", "renesas,qspi";
+ reg = <0 0xe6b10000 0 0x2c>;
+ interrupt-parent = <&gic>;
+ interrupts = <0 184 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp9_clks R8A7791_CLK_QSPI_MOD>;
+ num-cs = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c
index d79a7ed9b92e..e56fcb5f7f99 100644
--- a/drivers/spi/spi-rspi.c
+++ b/drivers/spi/spi-rspi.c
@@ -31,6 +31,7 @@
#include <linux/clk.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
+#include <linux/of_device.h>
#include <linux/sh_dma.h>
#include <linux/spi/spi.h>
#include <linux/spi/rspi.h>
@@ -985,6 +986,56 @@ static int rspi_remove(struct platform_device *pdev)
return 0;
}
+static const struct spi_ops rspi_ops = {
+ .set_config_register = rspi_set_config_register,
+ .transfer_one = rspi_transfer_one,
+};
+
+static const struct spi_ops rspi_rz_ops = {
+ .set_config_register = rspi_rz_set_config_register,
+ .transfer_one = rspi_rz_transfer_one,
+};
+
+static const struct spi_ops qspi_ops = {
+ .set_config_register = qspi_set_config_register,
+ .transfer_one = qspi_transfer_one,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id rspi_of_match[] = {
+ /* RSPI on legacy SH */
+ { .compatible = "renesas,rspi", .data = &rspi_ops },
+ /* RSPI on RZ/A1H */
+ { .compatible = "renesas,rspi-rz", .data = &rspi_rz_ops },
+ /* QSPI on R-Car Gen2 */
+ { .compatible = "renesas,qspi", .data = &qspi_ops },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, rspi_of_match);
+
+static int rspi_parse_dt(struct device *dev, struct spi_master *master)
+{
+ u32 num_cs;
+ int error;
+
+ /* Parse DT properties */
+ error = of_property_read_u32(dev->of_node, "num-cs", &num_cs);
+ if (error) {
+ dev_err(dev, "of_property_read_u32 num-cs failed %d\n", error);
+ return error;
+ }
+
+ master->num_chipselect = num_cs;
+ return 0;
+}
+#else
+static inline int rspi_parse_dt(struct device *dev, struct spi_master *master)
+{
+ return -EINVAL;
+}
+#endif /* CONFIG_OF */
+
static int rspi_request_irq(struct device *dev, unsigned int irq,
irq_handler_t handler, const char *suffix,
void *dev_id)
@@ -1004,16 +1055,9 @@ static int rspi_probe(struct platform_device *pdev)
struct spi_master *master;
struct rspi_data *rspi;
int ret;
- const struct rspi_plat_data *rspi_pd = dev_get_platdata(&pdev->dev);
+ const struct of_device_id *of_id;
+ const struct rspi_plat_data *rspi_pd;
const struct spi_ops *ops;
- const struct platform_device_id *id_entry = pdev->id_entry;
-
- ops = (struct spi_ops *)id_entry->driver_data;
- /* ops parameter check */
- if (!ops->set_config_register) {
- dev_err(&pdev->dev, "there is no set_config_register\n");
- return -ENODEV;
- }
master = spi_alloc_master(&pdev->dev, sizeof(struct rspi_data));
if (master == NULL) {
@@ -1021,6 +1065,28 @@ static int rspi_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ of_id = of_match_device(rspi_of_match, &pdev->dev);
+ if (of_id) {
+ ops = of_id->data;
+ ret = rspi_parse_dt(&pdev->dev, master);
+ if (ret)
+ goto error1;
+ } else {
+ ops = (struct spi_ops *)pdev->id_entry->driver_data;
+ rspi_pd = dev_get_platdata(&pdev->dev);
+ if (rspi_pd && rspi_pd->num_chipselect)
+ master->num_chipselect = rspi_pd->num_chipselect;
+ else
+ master->num_chipselect = 2; /* default */
+ };
+
+ /* ops parameter check */
+ if (!ops->set_config_register) {
+ dev_err(&pdev->dev, "there is no set_config_register\n");
+ ret = -ENODEV;
+ goto error1;
+ }
+
rspi = spi_master_get_devdata(master);
platform_set_drvdata(pdev, rspi);
rspi->ops = ops;
@@ -1048,11 +1114,6 @@ static int rspi_probe(struct platform_device *pdev)
init_waitqueue_head(&rspi->wait);
- if (rspi_pd && rspi_pd->num_chipselect)
- master->num_chipselect = rspi_pd->num_chipselect;
- else
- master->num_chipselect = 2; /* default */
-
master->bus_num = pdev->id;
master->setup = rspi_setup;
master->transfer_one = ops->transfer_one;
@@ -1060,6 +1121,7 @@ static int rspi_probe(struct platform_device *pdev)
master->prepare_message = rspi_prepare_message;
master->unprepare_message = rspi_unprepare_message;
master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP;
+ master->dev.of_node = pdev->dev.of_node;
ret = platform_get_irq_byname(pdev, "rx");
if (ret < 0) {
@@ -1122,21 +1184,6 @@ error1:
return ret;
}
-static struct spi_ops rspi_ops = {
- .set_config_register = rspi_set_config_register,
- .transfer_one = rspi_transfer_one,
-};
-
-static struct spi_ops rspi_rz_ops = {
- .set_config_register = rspi_rz_set_config_register,
- .transfer_one = rspi_rz_transfer_one,
-};
-
-static struct spi_ops qspi_ops = {
- .set_config_register = qspi_set_config_register,
- .transfer_one = qspi_transfer_one,
-};
-
static struct platform_device_id spi_driver_ids[] = {
{ "rspi", (kernel_ulong_t)&rspi_ops },
{ "rspi-rz", (kernel_ulong_t)&rspi_rz_ops },
@@ -1153,6 +1200,7 @@ static struct platform_driver rspi_driver = {
.driver = {
.name = "renesas_spi",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(rspi_of_match),
},
};
module_platform_driver(rspi_driver);
--
1.7.9.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* Re: [PATCH v4 13/14] spi: rspi: Add DT support
2014-01-24 8:44 ` [PATCH v4 13/14] spi: rspi: Add DT support Geert Uytterhoeven
@ 2014-01-24 9:33 ` Mark Rutland
[not found] ` <20140124093349.GK15586-NuALmloUBlrZROr8t4l/smS4ubULX0JqMm0uRHvK7Nw@public.gmane.org>
2014-01-27 20:11 ` Mark Brown
1 sibling, 1 reply; 31+ messages in thread
From: Mark Rutland @ 2014-01-24 9:33 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Mark Brown, linux-spi@vger.kernel.org, linux-sh@vger.kernel.org,
linux-kernel@vger.kernel.org, Geert Uytterhoeven,
devicetree@vger.kernel.org
On Fri, Jan 24, 2014 at 08:44:03AM +0000, Geert Uytterhoeven wrote:
> From: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
>
> Signed-off-by: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
> Cc: devicetree@vger.kernel.org
> ---
> v2:
> - Clarify RSPI/QSPI
> - Add interrupt-parent
> - s/should/must/ for #address-cells and #size-cells
> v3:
> - Add renesas,rspi-sh
> - Drop -rcar suffix for QSPI
> - Clarify num-cs
> - Implement DT support in driver
> - Changed one-line summary from "Documentation: dt: Add Renesas RSPI/QSPI
> bindings" to "spi: rspi: Add DT support"
> v4:
> - Clarify SoCtype and interrupts
> - Add clock property
> - Add QSPI example
> - Add interrupt-names
> - Add link to Renesas pinctrl
> - Rename "renesas,rspi-sh" to "renesas,rspi", to match platform device
> naming
> - spi-rspi.c:
> - Remove Soc-specific matching from spi-rspi.c given the fallback is
> mandatory
> - Things became a lot simpler due to the replacement of platform_data
> fields by the "rspi-rz" platform device binding.
> ---
> Documentation/devicetree/bindings/spi/spi-rspi.txt | 58 +++++++++++
> drivers/spi/spi-rspi.c | 106 ++++++++++++++------
> 2 files changed, 135 insertions(+), 29 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/spi/spi-rspi.txt
>
> diff --git a/Documentation/devicetree/bindings/spi/spi-rspi.txt b/Documentation/devicetree/bindings/spi/spi-rspi.txt
> new file mode 100644
> index 000000000000..ed84299a9c61
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/spi/spi-rspi.txt
> @@ -0,0 +1,58 @@
> +Device tree configuration for Renesas RSPI/QSPI driver
> +
> +Required properties:
> +- compatible : For Renesas Serial Peripheral Interface on legacy SH:
> + "renesas,rspi-<soctype>", "renesas,rspi" as fallback.
> + For Renesas Serial Peripheral Interface on RZ/A1H:
> + "renesas,rspi-<soctype>", "renesas,rspi-rz" as fallback.
> + For Quad Serial Peripheral Interface on R-Car Gen2:
> + "renesas,qspi-<soctype>", "renesas,qspi" as fallback.
> + Examples of valid soctypes are "sh7757" (SH),
> + "r7s72100" (RZ/A1H), "r8a7790" (R-Car H2), and
> + "r8a7791" (R-Car M2).
> +- reg : Address start and address range size of the device
> +- interrupts : 1 interrupt for RSPI cores using a single multiplexed
> + interrupt,
> + 3 interrupts (SPEI, SPRI, SPTI) for RSPI cores using
> + separate interrupts.
> +- interrupt-names : Array of strings associated with the interrupt numbers:
> + "error" for SPEI, "rx" for SPRI, and "tx" for SPTI.
> + For RSPI cores using a single multiplexed interrupt, the
> + name "mux" is optional.
Rather than defining the set of interrupts twice, it would be nice to
have interrupts defined in terms of interrupt-names:
- interrupts: a list of interrupt-specifiers, one for each entry in
interrupt-names. If interrupt-names is not present, an interrupt
specifier for a single muxed interrupt.
- interrupt-names: A list of interrupt names. Should contain (if
present):
* "error" for SPEI
* "rx" for SPRI
* "tx" to SPTI
* "mux" for a single muxed interrupt
Thanks,
Mark.
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v4 13/14] spi: rspi: Add DT support
2014-01-24 8:44 ` [PATCH v4 13/14] spi: rspi: Add DT support Geert Uytterhoeven
2014-01-24 9:33 ` Mark Rutland
@ 2014-01-27 20:11 ` Mark Brown
1 sibling, 0 replies; 31+ messages in thread
From: Mark Brown @ 2014-01-27 20:11 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: linux-spi, linux-sh, linux-kernel, Geert Uytterhoeven, devicetree
[-- Attachment #1: Type: text/plain, Size: 300 bytes --]
On Fri, Jan 24, 2014 at 09:44:03AM +0100, Geert Uytterhoeven wrote:
> From: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
>
> Signed-off-by: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
> Cc: devicetree@vger.kernel.org
This looks good modulo Mark's comment on the binding document.
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH 14/14] spi: rspi: Add support for Quad and Dual SPI Transfers on QSPI
2014-01-24 8:43 [PATCH 0/14] spi: rspi: Add support for RZ/A1H, DT, and Quad/Dual on QSPI Geert Uytterhoeven
` (11 preceding siblings ...)
2014-01-24 8:44 ` [PATCH v4 13/14] spi: rspi: Add DT support Geert Uytterhoeven
@ 2014-01-24 8:44 ` Geert Uytterhoeven
2014-01-27 20:27 ` Mark Brown
12 siblings, 1 reply; 31+ messages in thread
From: Geert Uytterhoeven @ 2014-01-24 8:44 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-spi, linux-sh, linux-kernel, Geert Uytterhoeven
From: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
Add support for Quad and Dual SPI Transfers on the Renesas Quad Serial
Peripheral Interface, as found in R-Car Gen2 SoCs like R-Car H2 (r8a7790)
and R-Car M2 (r8a7791):
- Add unidirectional transfer methods for Quad/Dual SPI Transfers.
- Program the sequencer to handle SPI messages with multiple transfer
modes when Quad or Dual transfers are enabled for an SPI slave.
Up to 4 transfer modes per SPI message are supported by the hardware.
- Advertise the availability of Quad and Dual SPI modes on QSPI.
Signed-off-by: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
---
drivers/spi/spi-rspi.c | 162 +++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 148 insertions(+), 14 deletions(-)
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c
index e56fcb5f7f99..34ad4bca8a41 100644
--- a/drivers/spi/spi-rspi.c
+++ b/drivers/spi/spi-rspi.c
@@ -2,6 +2,7 @@
* SH RSPI driver
*
* Copyright (C) 2012, 2013 Renesas Solutions Corp.
+ * Copyright (C) 2014 Glider bvba
*
* Based on spi-sh.c:
* Copyright (C) 2011 Renesas Solutions Corp.
@@ -57,6 +58,10 @@
#define RSPI_SPCMD5 0x1a /* Command Register 5 */
#define RSPI_SPCMD6 0x1c /* Command Register 6 */
#define RSPI_SPCMD7 0x1e /* Command Register 7 */
+#define RSPI_SPCMD(i) (RSPI_SPCMD0 + (i) * 2)
+#define RSPI_NUM_SPCMD 8
+#define RSPI_RZ_NUM_SPCMD 4
+#define QSPI_NUM_SPCMD 4
/* RSPI on RZ only */
#define RSPI_SPBFCR 0x20 /* Buffer Control Register */
@@ -69,6 +74,7 @@
#define QSPI_SPBMUL1 0x20 /* Transfer Data Length Multiplier Setting Register 1 */
#define QSPI_SPBMUL2 0x24 /* Transfer Data Length Multiplier Setting Register 2 */
#define QSPI_SPBMUL3 0x28 /* Transfer Data Length Multiplier Setting Register 3 */
+#define QSPI_SPBMUL(i) (QSPI_SPBMUL0 + (i) * 4)
/* SPCR - Control Register */
#define SPCR_SPRIE 0x80 /* Receive Interrupt Enable */
@@ -152,7 +158,7 @@
#define SPCMD_LSBF 0x1000 /* LSB First */
#define SPCMD_SPB_MASK 0x0f00 /* Data Length Setting */
#define SPCMD_SPB_8_TO_16(bit) (((bit - 1) << 8) & SPCMD_SPB_MASK)
-#define SPCMD_SPB_8BIT 0x0000 /* qspi only */
+#define SPCMD_SPB_8BIT 0x0000 /* QSPI only */
#define SPCMD_SPB_16BIT 0x0100
#define SPCMD_SPB_20BIT 0x0000
#define SPCMD_SPB_24BIT 0x0100
@@ -245,6 +251,7 @@ struct spi_ops {
int (*set_config_register)(struct rspi_data *rspi, int access_size);
int (*transfer_one)(struct spi_master *master, struct spi_device *spi,
struct spi_transfer *xfer);
+ u16 mode_bits;
};
/*
@@ -274,8 +281,8 @@ static int rspi_set_config_register(struct rspi_data *rspi, int access_size)
rspi_write8(rspi, 0x00, RSPI_SPCR2);
/* Sets SPCMD */
- rspi_write16(rspi, SPCMD_SPB_8_TO_16(access_size) | rspi->spcmd,
- RSPI_SPCMD0);
+ rspi->spcmd |= SPCMD_SPB_8_TO_16(access_size);
+ rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0);
/* Sets RSPI mode */
rspi_write8(rspi, SPCR_MSTR, RSPI_SPCR);
@@ -321,7 +328,6 @@ static int rspi_rz_set_config_register(struct rspi_data *rspi, int access_size)
*/
static int qspi_set_config_register(struct rspi_data *rspi, int access_size)
{
- u16 spcmd;
int spbr;
/* Sets output mode, MOSI signal, and (optionally) loopback */
@@ -342,13 +348,13 @@ static int qspi_set_config_register(struct rspi_data *rspi, int access_size)
/* Data Length Setting */
if (access_size == 8)
- spcmd = SPCMD_SPB_8BIT;
+ rspi->spcmd |= SPCMD_SPB_8BIT;
else if (access_size == 16)
- spcmd = SPCMD_SPB_16BIT;
+ rspi->spcmd |= SPCMD_SPB_16BIT;
else
- spcmd = SPCMD_SPB_32BIT;
+ rspi->spcmd |= SPCMD_SPB_32BIT;
- spcmd |= SPCMD_SCKDEN | SPCMD_SLNDEN | rspi->spcmd | SPCMD_SPNDEN;
+ rspi->spcmd |= SPCMD_SCKDEN | SPCMD_SLNDEN | SPCMD_SPNDEN;
/* Resets transfer data length */
rspi_write32(rspi, 0, QSPI_SPBMUL0);
@@ -359,9 +365,9 @@ static int qspi_set_config_register(struct rspi_data *rspi, int access_size)
rspi_write8(rspi, 0x00, QSPI_SPBFCR);
/* Sets SPCMD */
- rspi_write16(rspi, spcmd, RSPI_SPCMD0);
+ rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0);
- /* Enables SPI function in a master mode */
+ /* Enables SPI function in master mode */
rspi_write8(rspi, SPCR_SPE | SPCR_MSTR, RSPI_SPCR);
return 0;
@@ -811,12 +817,55 @@ static int qspi_transfer_out_in(struct rspi_data *rspi,
return 0;
}
+static int qspi_transfer_out(struct rspi_data *rspi, struct spi_transfer *xfer)
+{
+ const u8 *buf = xfer->tx_buf;
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < xfer->len; i++) {
+ ret = rspi_data_out(rspi, *buf++);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* Wait for the last transmission */
+ rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
+
+ return 0;
+}
+
+static int qspi_transfer_in(struct rspi_data *rspi, struct spi_transfer *xfer)
+{
+ u8 *buf = xfer->rx_buf;
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < xfer->len; i++) {
+ ret = rspi_data_in(rspi);
+ if (ret < 0)
+ return ret;
+ *buf++ = ret;
+ }
+
+ return 0;
+}
+
static int qspi_transfer_one(struct spi_master *master, struct spi_device *spi,
struct spi_transfer *xfer)
{
struct rspi_data *rspi = spi_master_get_devdata(master);
- return qspi_transfer_out_in(rspi, xfer);
+ if (xfer->tx_buf && xfer->tx_nbits > SPI_NBITS_SINGLE) {
+ /* Quad or Dual SPI Write */
+ return qspi_transfer_out(rspi, xfer);
+ } else if (xfer->rx_buf && xfer->rx_nbits > SPI_NBITS_SINGLE) {
+ /* Quad or Dual SPI Read */
+ return qspi_transfer_in(rspi, xfer);
+ } else {
+ /* Single SPI Transfer */
+ return qspi_transfer_out_in(rspi, xfer);
+ }
}
static int rspi_setup(struct spi_device *spi)
@@ -845,21 +894,101 @@ static void rspi_cleanup(struct spi_device *spi)
{
}
+static u16 qspi_transfer_mode(const struct spi_transfer *xfer)
+{
+ if (xfer->tx_buf)
+ switch (xfer->tx_nbits) {
+ case SPI_NBITS_QUAD:
+ return SPCMD_SPIMOD_QUAD;
+ case SPI_NBITS_DUAL:
+ return SPCMD_SPIMOD_DUAL;
+ default:
+ return 0;
+ }
+ if (xfer->rx_buf)
+ switch (xfer->rx_nbits) {
+ case SPI_NBITS_QUAD:
+ return SPCMD_SPIMOD_QUAD | SPCMD_SPRW;
+ case SPI_NBITS_DUAL:
+ return SPCMD_SPIMOD_DUAL | SPCMD_SPRW;
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int qspi_setup_sequencer(struct rspi_data *rspi,
+ const struct spi_message *msg)
+{
+ const struct spi_transfer *xfer;
+ unsigned int i = 0, len = 0;
+ u16 current_mode = 0xffff, mode;
+
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ mode = qspi_transfer_mode(xfer);
+ if (mode == current_mode) {
+ len += xfer->len;
+ continue;
+ }
+
+ /* Transfer mode change */
+ if (i) {
+ /* Set transfer data length of previous transfer */
+ rspi_write32(rspi, len, QSPI_SPBMUL(i - 1));
+ }
+
+ if (i >= QSPI_NUM_SPCMD) {
+ dev_err(&msg->spi->dev,
+ "Too many different transfer modes");
+ return -EINVAL;
+ }
+
+ /* Program transfer mode for this transfer */
+ rspi_write16(rspi, rspi->spcmd | mode, RSPI_SPCMD(i));
+ current_mode = mode;
+ len = xfer->len;
+ i++;
+ }
+ if (i) {
+ /* Set final transfer data length and sequence length */
+ rspi_write32(rspi, len, QSPI_SPBMUL(i - 1));
+ rspi_write8(rspi, i - 1, RSPI_SPSCR);
+ }
+
+ return 0;
+}
+
static int rspi_prepare_message(struct spi_master *master,
- struct spi_message *message)
+ struct spi_message *msg)
{
struct rspi_data *rspi = spi_master_get_devdata(master);
+ int ret;
+ if (msg->spi->mode &
+ (SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD)) {
+ /* Setup sequencer for messages with multiple transfer modes */
+ ret = qspi_setup_sequencer(rspi, msg);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* Enable SPI function in master mode */
rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_SPE, RSPI_SPCR);
return 0;
}
static int rspi_unprepare_message(struct spi_master *master,
- struct spi_message *message)
+ struct spi_message *msg)
{
struct rspi_data *rspi = spi_master_get_devdata(master);
+ /* Disable SPI function */
rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_SPE, RSPI_SPCR);
+
+ /* Reset sequencer for Single SPI Transfers */
+ rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0);
+ rspi_write8(rspi, 0, RSPI_SPSCR);
return 0;
}
@@ -989,16 +1118,21 @@ static int rspi_remove(struct platform_device *pdev)
static const struct spi_ops rspi_ops = {
.set_config_register = rspi_set_config_register,
.transfer_one = rspi_transfer_one,
+ .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP,
};
static const struct spi_ops rspi_rz_ops = {
.set_config_register = rspi_rz_set_config_register,
.transfer_one = rspi_rz_transfer_one,
+ .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP,
};
static const struct spi_ops qspi_ops = {
.set_config_register = qspi_set_config_register,
.transfer_one = qspi_transfer_one,
+ .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP |
+ SPI_TX_DUAL | SPI_TX_QUAD |
+ SPI_RX_DUAL | SPI_RX_QUAD,
};
#ifdef CONFIG_OF
@@ -1120,7 +1254,7 @@ static int rspi_probe(struct platform_device *pdev)
master->cleanup = rspi_cleanup;
master->prepare_message = rspi_prepare_message;
master->unprepare_message = rspi_unprepare_message;
- master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP;
+ master->mode_bits = ops->mode_bits;
master->dev.of_node = pdev->dev.of_node;
ret = platform_get_irq_byname(pdev, "rx");
--
1.7.9.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* Re: [PATCH 14/14] spi: rspi: Add support for Quad and Dual SPI Transfers on QSPI
2014-01-24 8:44 ` [PATCH 14/14] spi: rspi: Add support for Quad and Dual SPI Transfers on QSPI Geert Uytterhoeven
@ 2014-01-27 20:27 ` Mark Brown
0 siblings, 0 replies; 31+ messages in thread
From: Mark Brown @ 2014-01-27 20:27 UTC (permalink / raw)
To: Geert Uytterhoeven; +Cc: linux-spi, linux-sh, linux-kernel, Geert Uytterhoeven
[-- Attachment #1: Type: text/plain, Size: 399 bytes --]
On Fri, Jan 24, 2014 at 09:44:04AM +0100, Geert Uytterhoeven wrote:
> From: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
>
> Add support for Quad and Dual SPI Transfers on the Renesas Quad Serial
> Peripheral Interface, as found in R-Car Gen2 SoCs like R-Car H2 (r8a7790)
> and R-Car M2 (r8a7791):
This looks fine but depends on the DT bindings patch so it'll need to
wait for that.
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread