From 91949a2d4a96195ccd37322fafe8d16c68dda86e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Jan 2014 09:43:51 +0100 Subject: spi: rspi: Remove unused mesg parameter from {send,receive}_pio() Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 28987d9fcfe..ccd5cf201d0 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; } -- cgit v1.2.3-70-g09d2 From 79d2349542f38663c3096f389115b1f131d6e564 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Jan 2014 09:43:52 +0100 Subject: spi: rspi: Use core message handling 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 Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 111 +++++++++++++++---------------------------------- 1 file changed, 34 insertions(+), 77 deletions(-) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index ccd5cf201d0..0e4d169c90d 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -25,8 +25,6 @@ #include #include #include -#include -#include #include #include #include @@ -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, -- cgit v1.2.3-70-g09d2 From 74da76865d57161cadf8f324281f23ed3eb5db9c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Jan 2014 09:43:53 +0100 Subject: spi: rspi: Abstract 8/16-bit Data Register access 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 Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 56 +++++++++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 21 deletions(-) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 0e4d169c90d..a0bb3c28ae9 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--; } -- cgit v1.2.3-70-g09d2 From 35301c996046243ca6e41d490dea2823f045614c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Jan 2014 09:43:54 +0100 Subject: spi: rspi: Add rspi_data_{out,in,out_in}() helpers 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 Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 117 +++++++++++++++++++++++-------------------------- 1 file changed, 56 insertions(+), 61 deletions(-) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index a0bb3c28ae9..4b27513e720 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--; } -- cgit v1.2.3-70-g09d2 From eb557f75269e82dd26a79be536eca223ddc3eaf7 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Jan 2014 09:43:55 +0100 Subject: spi: rspi: Abstract transfer_one() for RSPI and QSPI 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 Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 4b27513e720..d837c502930 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[] = { -- cgit v1.2.3-70-g09d2 From 8449fd76deb9ac67a15a6fb8ead7bb4595d019d2 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Jan 2014 09:43:56 +0100 Subject: spi: rspi: Merge rspi_send_pio() and rspi_receive_pio() 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 Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 101 ++++++++++++++++++++++--------------------------- 1 file changed, 46 insertions(+), 55 deletions(-) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index d837c502930..cc90136d02c 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, -- cgit v1.2.3-70-g09d2 From 340a15e6f0d6cd436c55693f7328a1de02fcdb96 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Jan 2014 09:43:57 +0100 Subject: spi: rspi: Merge qspi_send_pio() and qspi_receive_pio() 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 Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 79 ++++++++++++++++++-------------------------------- 1 file changed, 28 insertions(+), 51 deletions(-) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index cc90136d02c..5d39cd3eba6 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) -- cgit v1.2.3-70-g09d2 From 9372220678cd4c62992f7637b2ee36b47fa58d37 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Jan 2014 09:43:58 +0100 Subject: spi: rspi: Add support for more than one interrupt 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 Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 106 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 87 insertions(+), 19 deletions(-) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 5d39cd3eba6..d2ade5e09f5 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"); -- cgit v1.2.3-70-g09d2 From 862d357f84f009fdcba22be8d6a2f82ff80ab740 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Jan 2014 09:43:59 +0100 Subject: spi: rspi: Add support for RSPI on RZ/A1H 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 Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 101 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 92 insertions(+), 9 deletions(-) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index d2ade5e09f5..0c7556978d2 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) { @@ -279,6 +281,39 @@ static int rspi_set_config_register(struct rspi_data *rspi, int access_size) return 0; } +/* + * 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 */ @@ -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 }, {}, }; -- cgit v1.2.3-70-g09d2 From 06a7a3cff042a36fb7e6af71039a17c6d1a6d90f Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Jan 2014 09:44:00 +0100 Subject: spi: rspi: Add support for loopback mode Add support for specifying loopback mode. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 0c7556978d2..28db8770aaf 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) { -- cgit v1.2.3-70-g09d2 From 17fe0d9a28fe742c467f800625459cf7bcb44b3b Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Jan 2014 09:44:01 +0100 Subject: spi: rspi: Convert to clk_prepare_enable/disable_unprepare 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 Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 28db8770aaf..a648b40c271 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); -- cgit v1.2.3-70-g09d2 From 29f397b739ceef90c8b848f6579cbacd088e896e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Jan 2014 09:44:02 +0100 Subject: spi: rspi: Use NULL as the clock ID There's only one RSPI/QSPI clock, so we can use NULL as the clock ID Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index a648b40c271..d79a7ed9b92 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); -- cgit v1.2.3-70-g09d2 From 426ef76dd8a394a0e04d096941cd9acb49539a3e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 28 Jan 2014 10:21:38 +0100 Subject: spi: rspi: Add DT support Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi-rspi.txt | 59 ++++++++++++ drivers/spi/spi-rspi.c | 106 +++++++++++++++------ 2 files changed, 136 insertions(+), 29 deletions(-) create mode 100644 Documentation/devicetree/bindings/spi/spi-rspi.txt (limited to 'drivers/spi/spi-rspi.c') diff --git a/Documentation/devicetree/bindings/spi/spi-rspi.txt b/Documentation/devicetree/bindings/spi/spi-rspi.txt new file mode 100644 index 00000000000..95f9b21d239 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-rspi.txt @@ -0,0 +1,59 @@ +Device tree configuration for Renesas RSPI/QSPI driver + +Required properties: +- compatible : For Renesas Serial Peripheral Interface on legacy SH: + "renesas,rspi-", "renesas,rspi" as fallback. + For Renesas Serial Peripheral Interface on RZ/A1H: + "renesas,rspi-", "renesas,rspi-rz" as fallback. + For Quad Serial Peripheral Interface on R-Car Gen2: + "renesas,qspi-", "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 : 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. +- 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 d79a7ed9b92..e56fcb5f7f9 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -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); -- cgit v1.2.3-70-g09d2 From 880c6d114fd79a6973708744c78c7f55da6aea4c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 30 Jan 2014 09:43:50 +0100 Subject: spi: rspi: Add support for Quad and Dual SPI Transfers on QSPI 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 Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 162 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 148 insertions(+), 14 deletions(-) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index e56fcb5f7f9..34ad4bca8a4 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"); -- cgit v1.2.3-70-g09d2 From 64b67defe4eb4de2d2df8acd5584a9e28fa727d3 Mon Sep 17 00:00:00 2001 From: "Shimoda, Yoshihiro" Date: Mon, 3 Feb 2014 10:43:46 +0900 Subject: spi: rspi: fix build error when CONFIG_OF is not set This patch fixes an issue that the following build error happens when the CONFIG_OF is not set: drivers/spi/spi-rspi.c: In function 'rspi_probe': drivers/spi/spi-rspi.c:1203:26: error: 'rspi_of_match' undeclared (first use in this function) Signed-off-by: Yoshihiro Shimoda Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 34ad4bca8a4..e5cfc3d77b8 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -1164,6 +1164,7 @@ static int rspi_parse_dt(struct device *dev, struct spi_master *master) return 0; } #else +#define rspi_of_match NULL static inline int rspi_parse_dt(struct device *dev, struct spi_master *master) { return -EINVAL; -- cgit v1.2.3-70-g09d2 From 5dd1ad23af689591d70be06ee6efcc57d1ec2d16 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 4 Feb 2014 11:06:24 +0100 Subject: spi: rspi: Only enable interrupts when there's a need to wait rspi_wait_for_interrupt() unconditionally enables interrupts, even when the wait condition is already satisfied. This causes a high interrupt load (2 interrupts/byte for full-duplex Single SPI transfers, 1 interrupt/byte for RSPI with TX Only mode, or QSPI in unidirectional Dual or Quad Transfer mode). Change this to return immediately when the wait condition is satisfied. This dramatically reduces the interrupt load, especially in high-speed Quad Transfer mode, and increases transfer speed, as no interrupts need to be handled when there's space available in the output FIFO, or data available in the input FIFO. Benchmark results for QSPI on r8a7791 while reading 1 MiB from 30 MHz SPI FLASH on the Koelsch development board: Before: Single SPI Dual SPI Quad SPI Interrupts: 2096856 1048592 1048594 Mbps: 0.9 1.6 1.6 After: Single SPI Dual SPI Quad SPI Interrupts: 1048569 21295 8 Mbps: 0.7 10.8 12.9 I don't know why Single SPI slowed down a bit. I've also verified functionality for RSPI-RZ on r7s72100, but don't have benchmark results as there's no SPI FLASH connected to RSPI on the Genmai development board. Unlike RSPI and QSPI, RSPI-RZ has separate interrupts for RX and TX, which shows that Single SPI transfers now generate (mostly) RX interrupts, as expected. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index e5cfc3d77b8..04528888a53 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -391,6 +391,9 @@ static int rspi_wait_for_interrupt(struct rspi_data *rspi, u8 wait_mask, int ret; rspi->spsr = rspi_read8(rspi, RSPI_SPSR); + if (rspi->spsr & wait_mask) + return 0; + rspi_enable_irq(rspi, enable_bit); ret = wait_event_timeout(rspi->wait, rspi->spsr & wait_mask, HZ); if (ret == 0 && !(rspi->spsr & wait_mask)) -- cgit v1.2.3-70-g09d2 From ab98fcba962a57cee9fdb97aff2b25248c93cea5 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Feb 2014 17:29:17 +0100 Subject: spi: rspi: Remove empty rspi_cleanup() If spi_master.cleanup() is not needed, it can be left unimplemented. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 04528888a53..4a1f978c338 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -893,10 +893,6 @@ static int rspi_setup(struct spi_device *spi) return 0; } -static void rspi_cleanup(struct spi_device *spi) -{ -} - static u16 qspi_transfer_mode(const struct spi_transfer *xfer) { if (xfer->tx_buf) @@ -1255,7 +1251,6 @@ static int rspi_probe(struct platform_device *pdev) master->bus_num = pdev->id; master->setup = rspi_setup; master->transfer_one = ops->transfer_one; - master->cleanup = rspi_cleanup; master->prepare_message = rspi_prepare_message; master->unprepare_message = rspi_unprepare_message; master->mode_bits = ops->mode_bits; -- cgit v1.2.3-70-g09d2 From ba824d4971691a7f1f66429e378a08a95fbb5b79 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Feb 2014 17:29:18 +0100 Subject: spi: rspi: Fix loopback mode for Dual/Quad SPI Transfers While normal Dual and Quad SPI Transfers are unidirectional, we must do a bidirectional transfer if loopback mode is enabled, else rx_buf is not filled. With spidev it seemed to work, as spidev uses the same buffer for tranmission and reception. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 4a1f978c338..92bec7e9104 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -859,7 +859,9 @@ static int qspi_transfer_one(struct spi_master *master, struct spi_device *spi, { struct rspi_data *rspi = spi_master_get_devdata(master); - if (xfer->tx_buf && xfer->tx_nbits > SPI_NBITS_SINGLE) { + if (spi->mode & SPI_LOOP) { + return qspi_transfer_out_in(rspi, xfer); + } else 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) { -- cgit v1.2.3-70-g09d2 From 490c97747d5dc77dfb5826e2823b41d8b2ef7ecc Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 11 Mar 2014 10:59:12 +0100 Subject: spi: rspi: Add runtime PM support, using spi core auto_runtime_pm Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 92bec7e9104..1fb0ad21332 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -1111,7 +1112,7 @@ static int rspi_remove(struct platform_device *pdev) struct rspi_data *rspi = platform_get_drvdata(pdev); rspi_release_dma(rspi); - clk_disable_unprepare(rspi->clk); + pm_runtime_disable(&pdev->dev); return 0; } @@ -1242,16 +1243,13 @@ static int rspi_probe(struct platform_device *pdev) goto error1; } - ret = clk_prepare_enable(rspi->clk); - if (ret < 0) { - dev_err(&pdev->dev, "unable to prepare/enable clock\n"); - goto error1; - } + pm_runtime_enable(&pdev->dev); init_waitqueue_head(&rspi->wait); master->bus_num = pdev->id; master->setup = rspi_setup; + master->auto_runtime_pm = true; master->transfer_one = ops->transfer_one; master->prepare_message = rspi_prepare_message; master->unprepare_message = rspi_unprepare_message; @@ -1312,7 +1310,7 @@ static int rspi_probe(struct platform_device *pdev) error3: rspi_release_dma(rspi); error2: - clk_disable_unprepare(rspi->clk); + pm_runtime_disable(&pdev->dev); error1: spi_master_put(master); -- cgit v1.2.3-70-g09d2