From: Bryan Wu <bryan.wu@analog.com>
To: dbrownell@users.sourceforge.net, spi-devel-general@lists.sourceforge.net
Cc: linux-kernel@vger.kernel.org,
Sonic Zhang <sonic.zhang@analog.com>,
Bryan Wu <bryan.wu@analog.com>
Subject: [PATCH 09/14] Blackfin SPI driver: Fix SPI driver to work with SPI flash ST25P16 on bf548
Date: Tue, 30 Oct 2007 17:18:00 +0800 [thread overview]
Message-ID: <1193735885-8202-10-git-send-email-bryan.wu@analog.com> (raw)
In-Reply-To: <1193735885-8202-1-git-send-email-bryan.wu@analog.com>
From: Sonic Zhang <sonic.zhang@analog.com>
Current SPI driver enables SPI controller and set the SPI baud register
for each SPI transfer. But, they should never be changed within a SPI
message session, in which seveal SPI transfers are pumped. This patch
move move SPI setting to the begining of a message session. And never
disables SPI controller until an error occurs.
Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
Signed-off-by: Bryan Wu <bryan.wu@analog.com>
---
drivers/spi/spi_bfin5xx.c | 162 ++++++++++++++++++++++++---------------------
1 files changed, 87 insertions(+), 75 deletions(-)
diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
index 7f95797..e1fd197 100644
--- a/drivers/spi/spi_bfin5xx.c
+++ b/drivers/spi/spi_bfin5xx.c
@@ -222,9 +222,13 @@ static int restore_state(struct driver_data *drv_data)
dev_dbg(&drv_data->pdev->dev, "restoring spi ctl state\n");
/* Load the registers */
- write_CTRL(chip->ctl_reg);
+ cs_deactive(chip);
write_BAUD(chip->baud);
- cs_active(chip);
+ chip->ctl_reg &= (~BIT_CTL_TIMOD);
+ chip->ctl_reg |= (chip->width << 8);
+ write_CTRL(chip->ctl_reg);
+
+ bfin_spi_enable(drv_data);
if (ret)
dev_dbg(&drv_data->pdev->dev,
@@ -271,6 +275,7 @@ static void u8_writer(struct driver_data *drv_data)
{
dev_dbg(&drv_data->pdev->dev,
"cr8-s is 0x%x\n", read_STAT());
+
while (drv_data->tx < drv_data->tx_end) {
write_TDBR(*(u8 *) (drv_data->tx));
while (read_STAT() & BIT_STAT_TXS)
@@ -293,16 +298,16 @@ static void u8_cs_chg_writer(struct driver_data *drv_data)
write_TDBR(*(u8 *) (drv_data->tx));
while (read_STAT() & BIT_STAT_TXS)
continue;
- while (!(read_STAT() & BIT_STAT_SPIF))
- continue;
cs_deactive(chip);
if (chip->cs_chg_udelay)
udelay(chip->cs_chg_udelay);
++drv_data->tx;
}
- cs_deactive(chip);
+ /* poll for SPI completion before returning */
+ while (!(read_STAT() & BIT_STAT_SPIF))
+ continue;
}
static void u8_reader(struct driver_data *drv_data)
@@ -314,6 +319,7 @@ static void u8_reader(struct driver_data *drv_data)
write_TDBR(0xFFFF);
dummy_read();
+
while (drv_data->rx < drv_data->rx_end - 1) {
while (!(read_STAT() & BIT_STAT_RXS))
continue;
@@ -331,23 +337,30 @@ static void u8_cs_chg_reader(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;
- while (drv_data->rx < drv_data->rx_end) {
- cs_active(chip);
+ /* clear TDBR buffer before read(else it will be shifted out) */
+ write_TDBR(0xFFFF);
- read_RDBR(); /* kick off */
- while (!(read_STAT() & BIT_STAT_RXS))
- continue;
- while (!(read_STAT() & BIT_STAT_SPIF))
- continue;
- *(u8 *) (drv_data->rx) = read_SHAW();
+ cs_active(chip);
+ dummy_read();
+
+ while (drv_data->rx < drv_data->rx_end - 1) {
cs_deactive(chip);
if (chip->cs_chg_udelay)
udelay(chip->cs_chg_udelay);
+
+ while (!(read_STAT() & BIT_STAT_RXS))
+ continue;
+ cs_active(chip);
+ *(u8 *) (drv_data->rx) = read_RDBR();
++drv_data->rx;
}
cs_deactive(chip);
+ while (!(read_STAT() & BIT_STAT_RXS))
+ continue;
+ *(u8 *) (drv_data->rx) = read_SHAW();
+ ++drv_data->rx;
}
static void u8_duplex(struct driver_data *drv_data)
@@ -355,7 +368,7 @@ static void u8_duplex(struct driver_data *drv_data)
/* in duplex mode, clk is triggered by writing of TDBR */
while (drv_data->rx < drv_data->rx_end) {
write_TDBR(*(u8 *) (drv_data->tx));
- while (!(read_STAT() & BIT_STAT_SPIF))
+ while (read_STAT() & BIT_STAT_TXS)
continue;
while (!(read_STAT() & BIT_STAT_RXS))
continue;
@@ -363,6 +376,10 @@ static void u8_duplex(struct driver_data *drv_data)
++drv_data->rx;
++drv_data->tx;
}
+
+ /* poll for SPI completion before returning */
+ while (!(read_STAT() & BIT_STAT_SPIF))
+ continue;
}
static void u8_cs_chg_duplex(struct driver_data *drv_data)
@@ -372,9 +389,8 @@ static void u8_cs_chg_duplex(struct driver_data *drv_data)
while (drv_data->rx < drv_data->rx_end) {
cs_active(chip);
-
write_TDBR(*(u8 *) (drv_data->tx));
- while (!(read_STAT() & BIT_STAT_SPIF))
+ while (read_STAT() & BIT_STAT_TXS)
continue;
while (!(read_STAT() & BIT_STAT_RXS))
continue;
@@ -386,7 +402,10 @@ static void u8_cs_chg_duplex(struct driver_data *drv_data)
++drv_data->rx;
++drv_data->tx;
}
- cs_deactive(chip);
+
+ /* poll for SPI completion before returning */
+ while (!(read_STAT() & BIT_STAT_SPIF))
+ continue;
}
static void u16_writer(struct driver_data *drv_data)
@@ -416,21 +435,26 @@ static void u16_cs_chg_writer(struct driver_data *drv_data)
write_TDBR(*(u16 *) (drv_data->tx));
while ((read_STAT() & BIT_STAT_TXS))
continue;
- while (!(read_STAT() & BIT_STAT_SPIF))
- continue;
cs_deactive(chip);
if (chip->cs_chg_udelay)
udelay(chip->cs_chg_udelay);
drv_data->tx += 2;
}
- cs_deactive(chip);
+
+ /* poll for SPI completion before returning */
+ while (!(read_STAT() & BIT_STAT_SPIF))
+ continue;
}
static void u16_reader(struct driver_data *drv_data)
{
dev_dbg(&drv_data->pdev->dev,
"cr-16 is 0x%x\n", read_STAT());
+
+ /* clear TDBR buffer before read(else it will be shifted out) */
+ write_TDBR(0xFFFF);
+
dummy_read();
while (drv_data->rx < (drv_data->rx_end - 2)) {
@@ -450,22 +474,30 @@ static void u16_cs_chg_reader(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;
- while (drv_data->rx < drv_data->rx_end) {
- cs_active(chip);
+ /* clear TDBR buffer before read(else it will be shifted out) */
+ write_TDBR(0xFFFF);
- read_RDBR(); /* kick off */
- while (!(read_STAT() & BIT_STAT_RXS))
- continue;
- while (!(read_STAT() & BIT_STAT_SPIF))
- continue;
- *(u16 *) (drv_data->rx) = read_SHAW();
+ cs_active(chip);
+ dummy_read();
+
+ while (drv_data->rx < drv_data->rx_end) {
cs_deactive(chip);
if (chip->cs_chg_udelay)
udelay(chip->cs_chg_udelay);
+
+ while (!(read_STAT() & BIT_STAT_RXS))
+ continue;
+ cs_active(chip);
+ *(u16 *) (drv_data->rx) = read_RDBR();
drv_data->rx += 2;
}
cs_deactive(chip);
+
+ while (!(read_STAT() & BIT_STAT_RXS))
+ continue;
+ *(u16 *) (drv_data->rx) = read_SHAW();
+ drv_data->rx += 2;
}
static void u16_duplex(struct driver_data *drv_data)
@@ -473,7 +505,7 @@ static void u16_duplex(struct driver_data *drv_data)
/* in duplex mode, clk is triggered by writing of TDBR */
while (drv_data->tx < drv_data->tx_end) {
write_TDBR(*(u16 *) (drv_data->tx));
- while (!(read_STAT() & BIT_STAT_SPIF))
+ while (read_STAT() & BIT_STAT_TXS)
continue;
while (!(read_STAT() & BIT_STAT_RXS))
continue;
@@ -481,6 +513,10 @@ static void u16_duplex(struct driver_data *drv_data)
drv_data->rx += 2;
drv_data->tx += 2;
}
+
+ /* poll for SPI completion before returning */
+ while (!(read_STAT() & BIT_STAT_SPIF))
+ continue;
}
static void u16_cs_chg_duplex(struct driver_data *drv_data)
@@ -491,7 +527,7 @@ static void u16_cs_chg_duplex(struct driver_data *drv_data)
cs_active(chip);
write_TDBR(*(u16 *) (drv_data->tx));
- while (!(read_STAT() & BIT_STAT_SPIF))
+ while (read_STAT() & BIT_STAT_TXS)
continue;
while (!(read_STAT() & BIT_STAT_RXS))
continue;
@@ -503,7 +539,10 @@ static void u16_cs_chg_duplex(struct driver_data *drv_data)
drv_data->rx += 2;
drv_data->tx += 2;
}
- cs_deactive(chip);
+
+ /* poll for SPI completion before returning */
+ while (!(read_STAT() & BIT_STAT_SPIF))
+ continue;
}
/* test if ther is more transfer to be done */
@@ -587,8 +626,6 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id)
while (!(read_STAT() & SPIF))
continue;
- bfin_spi_disable(drv_data);
-
msg->actual_length += drv_data->len_in_bytes;
if (drv_data->cs_change)
@@ -698,12 +735,8 @@ static void pump_transfers(unsigned long data)
message->state = RUNNING_STATE;
dma_config = 0;
- /* restore spi status for each spi transfer */
- if (transfer->speed_hz) {
- write_BAUD(hz_to_spi_baud(transfer->speed_hz));
- } else {
- write_BAUD(chip->baud);
- }
+ write_STAT(BIT_STAT_CLR);
+ cr = (read_CTRL() & (~BIT_CTL_TIMOD));
cs_active(chip);
dev_dbg(&drv_data->pdev->dev,
@@ -717,10 +750,8 @@ static void pump_transfers(unsigned long data)
*/
if (drv_data->cur_chip->enable_dma && drv_data->len > 6) {
- write_STAT(BIT_STAT_CLR);
disable_dma(spi_dma_ch);
clear_dma_irqstat(spi_dma_ch);
- bfin_spi_disable(drv_data);
/* config dma channel */
dev_dbg(&drv_data->pdev->dev, "doing dma transfer\n");
@@ -734,14 +765,14 @@ static void pump_transfers(unsigned long data)
dma_width = WDSIZE_8;
}
- /* set transfer width,direction. And enable spi */
- cr = (read_CTRL() & (~BIT_CTL_TIMOD));
-
/* dirty hack for autobuffer DMA mode */
if (drv_data->tx_dma == 0xFFFF) {
dev_dbg(&drv_data->pdev->dev,
"doing autobuffer DMA out.\n");
+ /* set SPI transfer mode */
+ write_CTRL(cr | CFG_SPI_DMAWRITE);
+
/* no irq in autobuffer mode */
dma_config =
(DMAFLOW_AUTO | RESTART | dma_width | DI_EN);
@@ -749,8 +780,6 @@ static void pump_transfers(unsigned long data)
set_dma_start_addr(spi_dma_ch,
(unsigned long)drv_data->tx);
enable_dma(spi_dma_ch);
- write_CTRL(cr | CFG_SPI_DMAWRITE | (width << 8) |
- (CFG_SPI_ENABLE << 14));
/* just return here, there can only be one transfer in this mode */
message->status = 0;
@@ -763,11 +792,11 @@ static void pump_transfers(unsigned long data)
/* set transfer mode, and enable SPI */
dev_dbg(&drv_data->pdev->dev, "doing DMA in.\n");
- /* disable SPI before write to TDBR */
- write_CTRL(cr & ~BIT_CTL_ENABLE);
+ /* set SPI transfer mode */
+ write_CTRL(cr | CFG_SPI_DMAREAD);
/* clear tx reg soformer data is not shifted out */
- write_TDBR(0xFF);
+ write_TDBR(0xFFFF);
set_dma_x_count(spi_dma_ch, drv_data->len);
@@ -779,14 +808,12 @@ static void pump_transfers(unsigned long data)
(unsigned long)drv_data->rx);
enable_dma(spi_dma_ch);
- cr |=
- CFG_SPI_DMAREAD | (width << 8) | (CFG_SPI_ENABLE <<
- 14);
- /* set transfer mode, and enable SPI */
- write_CTRL(cr);
} else if (drv_data->tx != NULL) {
dev_dbg(&drv_data->pdev->dev, "doing DMA out.\n");
+ /* set SPI transfer mode */
+ write_CTRL(cr | CFG_SPI_DMAWRITE);
+
/* start dma */
dma_enable_irq(spi_dma_ch);
dma_config = (RESTART | dma_width | DI_EN);
@@ -794,28 +821,20 @@ static void pump_transfers(unsigned long data)
set_dma_start_addr(spi_dma_ch,
(unsigned long)drv_data->tx);
enable_dma(spi_dma_ch);
-
- write_CTRL(cr | CFG_SPI_DMAWRITE | (width << 8) |
- (CFG_SPI_ENABLE << 14));
-
}
} else {
/* IO mode write then read */
dev_dbg(&drv_data->pdev->dev, "doing IO transfer\n");
- write_STAT(BIT_STAT_CLR);
-
if (drv_data->tx != NULL && drv_data->rx != NULL) {
/* full duplex mode */
BUG_ON((drv_data->tx_end - drv_data->tx) !=
(drv_data->rx_end - drv_data->rx));
- cr = (read_CTRL() & (~BIT_CTL_TIMOD));
- cr |= CFG_SPI_WRITE | (width << 8) |
- (CFG_SPI_ENABLE << 14);
dev_dbg(&drv_data->pdev->dev,
"IO duplex: cr is 0x%x\n", cr);
- write_CTRL(cr);
+ /* set SPI transfer mode */
+ write_CTRL(cr | CFG_SPI_WRITE);
drv_data->duplex(drv_data);
@@ -823,13 +842,11 @@ static void pump_transfers(unsigned long data)
tranf_success = 0;
} else if (drv_data->tx != NULL) {
/* write only half duplex */
- cr = (read_CTRL() & (~BIT_CTL_TIMOD));
- cr |= CFG_SPI_WRITE | (width << 8) |
- (CFG_SPI_ENABLE << 14);
dev_dbg(&drv_data->pdev->dev,
"IO write: cr is 0x%x\n", cr);
- write_CTRL(cr);
+ /* set SPI transfer mode */
+ write_CTRL(cr | CFG_SPI_WRITE);
drv_data->write(drv_data);
@@ -837,13 +854,11 @@ static void pump_transfers(unsigned long data)
tranf_success = 0;
} else if (drv_data->rx != NULL) {
/* read only half duplex */
- cr = (read_CTRL() & (~BIT_CTL_TIMOD));
- cr |= CFG_SPI_READ | (width << 8) |
- (CFG_SPI_ENABLE << 14);
dev_dbg(&drv_data->pdev->dev,
"IO read: cr is 0x%x\n", cr);
- write_CTRL(cr);
+ /* set SPI transfer mode */
+ write_CTRL(cr | CFG_SPI_READ);
drv_data->read(drv_data);
if (drv_data->rx != drv_data->rx_end)
@@ -858,9 +873,6 @@ static void pump_transfers(unsigned long data)
/* Update total byte transfered */
message->actual_length += drv_data->len;
- if (drv_data->cs_change)
- cs_deactive(chip);
-
/* Move to next transfer of this msg */
message->state = next_transfer(drv_data);
}
--
1.5.3.4
next prev parent reply other threads:[~2007-10-30 9:21 UTC|newest]
Thread overview: 34+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-10-30 9:17 [PATCH 00/14] Blackfin on-chip SPI controller driver updates and bug-fixing Bryan Wu
2007-10-30 9:17 ` [PATCH 01/14] Blackfin SPI driver: Initial supporting BF54x in SPI driver Bryan Wu
2007-10-30 9:17 ` [PATCH 02/14] Blackfin SPI driver: use new GPIO API and add error handling Bryan Wu
2007-10-30 9:17 ` [PATCH 03/14] Blackfin SPI driver: add error handing Bryan Wu
2007-10-30 9:17 ` [PATCH 04/14] Blackfin SPI driver: Blackfin SPI driver does not respect the per-transfer cs_change field Bryan Wu
2007-10-30 9:17 ` [PATCH 05/14] Blackfin SPI driver: prevent people from setting bits in ctl_reg Bryan Wu
2007-10-30 9:17 ` [PATCH 06/14] Blackfin SPI driver: update spi driver to support multi-ports Bryan Wu
2007-10-30 9:17 ` [PATCH 07/14] Blackfin SPI driver: Add SPI master controller platform device 1 Bryan Wu
2007-10-30 19:08 ` David Brownell
2007-10-31 4:18 ` Bryan Wu
2007-10-30 9:17 ` [PATCH 08/14] Blackfin SPI driver: Move GPIO config to setup and cleanup Bryan Wu
2007-10-30 9:18 ` Bryan Wu [this message]
2007-10-30 20:05 ` [PATCH 09/14] Blackfin SPI driver: Fix SPI driver to work with SPI flash ST25P16 on bf548 David Brownell
2007-10-31 6:50 ` Bryan Wu
2007-10-31 7:11 ` David Brownell
2007-10-31 7:35 ` Bryan Wu
2007-10-31 8:02 ` David Brownell
2007-10-31 8:52 ` Bryan Wu
2007-10-31 8:33 ` Mike Frysinger
2007-10-31 19:01 ` David Brownell
2007-10-31 19:16 ` Mike Frysinger
2007-10-31 20:14 ` David Brownell
2007-10-30 9:18 ` [PATCH 10/14] Blackfin SPI driver: Clean up useless wait in bfin SPI driver Bryan Wu
2007-10-30 9:18 ` [PATCH 11/14] Blackfin SPI driver: Move global SPI regs_base and dma_ch to struct driver_data Bryan Wu
2007-10-30 9:18 ` [PATCH 12/14] Blackfin SPI driver: Fix bug in u16_cs_chg_reader to read data_len-2 bytes data firstly, then read out the last 2 bytes data Bryan Wu
2007-10-30 9:18 ` [PATCH 13/14] Blackfin SPI driver: Move cs_chg_udelay to cs_deactive to fix bug when some SPI LCD driver needs delay after cs_deactive Bryan Wu
2007-10-30 20:18 ` David Brownell
2007-10-31 6:30 ` Bryan Wu
2007-10-31 19:04 ` Cameron Barfield
2007-10-30 9:18 ` [PATCH 14/14] Blackfin SPI driver: set correct baud for spi mmc and enable SPI after DMA Bryan Wu
2007-10-30 20:24 ` [PATCH 00/14] Blackfin on-chip SPI controller driver updates and bug-fixing David Brownell
2007-10-30 20:29 ` Mike Frysinger
2007-10-30 20:42 ` David Brownell
2007-10-30 20:54 ` David Brownell
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1193735885-8202-10-git-send-email-bryan.wu@analog.com \
--to=bryan.wu@analog.com \
--cc=dbrownell@users.sourceforge.net \
--cc=linux-kernel@vger.kernel.org \
--cc=sonic.zhang@analog.com \
--cc=spi-devel-general@lists.sourceforge.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Powered by JetHome