2007-10-30 09:18:23

by Bryan Wu

[permalink] [raw]
Subject: [PATCH 00/14] Blackfin on-chip SPI controller driver updates and bug-fixing

- BF54x supported
- multi-port supported
- bunch of bug fixing


2007-10-30 09:18:38

by Bryan Wu

[permalink] [raw]
Subject: [PATCH 01/14] Blackfin SPI driver: Initial supporting BF54x in SPI driver

- support BF54x SPI0
- clean up some code
- will support multiports in the future

Signed-off-by: Bryan Wu <[email protected]>
---
drivers/spi/spi_bfin5xx.c | 129 +++++++++++------------
include/asm-blackfin/mach-bf548/defBF54x_base.h | 17 +++
2 files changed, 80 insertions(+), 66 deletions(-)

diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
index 2ef11bb..621a3eb 100644
--- a/drivers/spi/spi_bfin5xx.c
+++ b/drivers/spi/spi_bfin5xx.c
@@ -1,17 +1,20 @@
/*
- * File: drivers/spi/bfin5xx_spi.c
- * Based on: N/A
- * Author: Luke Yang (Analog Devices Inc.)
+ * File: drivers/spi/bfin5xx_spi.c
+ * Maintainer:
+ * Bryan Wu <[email protected]>
+ * Original Author:
+ * Luke Yang (Analog Devices Inc.)
*
- * Created: March. 10th 2006
- * Description: SPI controller driver for Blackfin 5xx
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ * Created: March. 10th 2006
+ * Description: SPI controller driver for Blackfin BF5xx
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
*
* Modified:
* March 10, 2006 bfin5xx_spi.c Created. (Luke Yang)
* August 7, 2006 added full duplex mode (Axel Weiss & Luke Yang)
+ * July 17, 2007 add support for BF54x SPI0 controller (Bryan Wu)
*
- * Copyright 2004-2006 Analog Devices Inc.
+ * Copyright 2004-2007 Analog Devices Inc.
*
* This program is free software ; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -31,27 +34,27 @@

#include <linux/init.h>
#include <linux/module.h>
+#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/io.h>
#include <linux/ioport.h>
+#include <linux/irq.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/spi/spi.h>
#include <linux/workqueue.h>
-#include <linux/delay.h>

-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/delay.h>
#include <asm/dma.h>
-
+#include <asm/portmux.h>
#include <asm/bfin5xx_spi.h>

-MODULE_AUTHOR("Luke Yang");
-MODULE_DESCRIPTION("Blackfin 5xx SPI Contoller");
+MODULE_AUTHOR("Bryan Wu, Luke Yang");
+MODULE_DESCRIPTION("Blackfin BF5xx SPI Contoller Driver");
MODULE_LICENSE("GPL");

+#define DRV_NAME "bfin-spi-master"
#define IS_DMA_ALIGNED(x) (((u32)(x)&0x07)==0)

#define DEFINE_SPI_REG(reg, off) \
@@ -124,6 +127,7 @@ struct chip_data {
u16 flag;

u8 chip_select_num;
+ u8 chip_select_requested;
u8 n_bytes;
u8 width; /* 0 or 1 */
u8 enable_dma;
@@ -188,53 +192,37 @@ static void restore_state(struct driver_data *drv_data)
bfin_spi_disable(drv_data);
dev_dbg(&drv_data->pdev->dev, "restoring spi ctl state\n");

-#if defined(CONFIG_BF534) || defined(CONFIG_BF536) || defined(CONFIG_BF537)
- dev_dbg(&drv_data->pdev->dev,
- "chip select number is %d\n", chip->chip_select_num);
-
- switch (chip->chip_select_num) {
- case 1:
- bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3c00);
- SSYNC();
- break;
-
- case 2:
- case 3:
- bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PJSE_SPI);
- SSYNC();
- bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3800);
- SSYNC();
- break;
-
- case 4:
- bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PFS4E_SPI);
- SSYNC();
- bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3840);
- SSYNC();
- break;
+ if (!chip->chip_select_requested) {

- case 5:
- bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PFS5E_SPI);
- SSYNC();
- bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3820);
- SSYNC();
- break;
+ dev_dbg(&drv_data->pdev->dev,
+ "chip select number is %d\n", chip->chip_select_num);

- case 6:
- bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PFS6E_SPI);
- SSYNC();
- bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3810);
- SSYNC();
- break;
+ switch (chip->chip_select_num) {
+ case 1:
+ peripheral_request(P_SPI0_SSEL1, DRV_NAME);
+ break;
+ case 2:
+ peripheral_request(P_SPI0_SSEL2, DRV_NAME);
+ break;
+ case 3:
+ peripheral_request(P_SPI0_SSEL3, DRV_NAME);
+ break;
+ case 4:
+ peripheral_request(P_SPI0_SSEL4, DRV_NAME);
+ break;
+ case 5:
+ peripheral_request(P_SPI0_SSEL5, DRV_NAME);
+ break;
+ case 6:
+ peripheral_request(P_SPI0_SSEL6, DRV_NAME);
+ break;
+ case 7:
+ peripheral_request(P_SPI0_SSEL7, DRV_NAME);
+ break;
+ }

- case 7:
- bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PJCE_SPI);
- SSYNC();
- bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3800);
- SSYNC();
- break;
+ chip->chip_select_requested = 1;
}
-#endif

/* Load the registers */
write_CTRL(chip->ctl_reg);
@@ -277,7 +265,7 @@ static void null_reader(struct driver_data *drv_data)

static void u8_writer(struct driver_data *drv_data)
{
- dev_dbg(&drv_data->pdev->dev,
+ 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));
@@ -316,7 +304,7 @@ static void u8_cs_chg_writer(struct driver_data *drv_data)

static void u8_reader(struct driver_data *drv_data)
{
- dev_dbg(&drv_data->pdev->dev,
+ dev_dbg(&drv_data->pdev->dev,
"cr-8 is 0x%x\n", read_STAT());

/* clear TDBR buffer before read(else it will be shifted out) */
@@ -403,7 +391,7 @@ static void u8_cs_chg_duplex(struct driver_data *drv_data)

static void u16_writer(struct driver_data *drv_data)
{
- dev_dbg(&drv_data->pdev->dev,
+ dev_dbg(&drv_data->pdev->dev,
"cr16 is 0x%x\n", read_STAT());

while (drv_data->tx < drv_data->tx_end) {
@@ -816,7 +804,7 @@ static void pump_transfers(unsigned long data)
/* 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 = (read_CTRL() & (~BIT_CTL_TIMOD));
cr |= CFG_SPI_WRITE | (width << 8) |
(CFG_SPI_ENABLE << 14);
dev_dbg(&drv_data->pdev->dev,
@@ -834,7 +822,7 @@ static void pump_transfers(unsigned long data)
cr = (read_CTRL() & (~BIT_CTL_TIMOD));
cr |= CFG_SPI_WRITE | (width << 8) |
(CFG_SPI_ENABLE << 14);
- dev_dbg(&drv_data->pdev->dev,
+ dev_dbg(&drv_data->pdev->dev,
"IO write: cr is 0x%x\n", cr);

write_CTRL(cr);
@@ -849,7 +837,7 @@ static void pump_transfers(unsigned long data)
cr = (read_CTRL() & (~BIT_CTL_TIMOD));
cr |= CFG_SPI_READ | (width << 8) |
(CFG_SPI_ENABLE << 14);
- dev_dbg(&drv_data->pdev->dev,
+ dev_dbg(&drv_data->pdev->dev,
"IO read: cr is 0x%x\n", cr);

write_CTRL(cr);
@@ -861,7 +849,7 @@ static void pump_transfers(unsigned long data)
}

if (!tranf_success) {
- dev_dbg(&drv_data->pdev->dev,
+ dev_dbg(&drv_data->pdev->dev,
"IO write error!\n");
message->state = ERROR_STATE;
} else {
@@ -916,8 +904,8 @@ static void pump_messages(struct work_struct *work)
"got a message to pump, state is set to: baud %d, flag 0x%x, ctl 0x%x\n",
drv_data->cur_chip->baud, drv_data->cur_chip->flag,
drv_data->cur_chip->ctl_reg);
-
- dev_dbg(&drv_data->pdev->dev,
+
+ dev_dbg(&drv_data->pdev->dev,
"the first transfer len is %d\n",
drv_data->cur_transfer->len);

@@ -1193,6 +1181,15 @@ static int __init bfin5xx_spi_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "can not alloc spi_master\n");
return -ENOMEM;
}
+
+ if (peripheral_request(P_SPI0_SCK, DRV_NAME) ||
+ peripheral_request(P_SPI0_MISO, DRV_NAME) ||
+ peripheral_request(P_SPI0_MOSI, DRV_NAME) ) {
+
+ dev_err(&pdev->dev, ": Requesting Peripherals failed\n");
+ goto out_error_queue_alloc;
+ }
+
drv_data = spi_master_get_devdata(master);
drv_data->master = master;
drv_data->master_info = platform_info;
diff --git a/include/asm-blackfin/mach-bf548/defBF54x_base.h b/include/asm-blackfin/mach-bf548/defBF54x_base.h
index da979cb..319a485 100644
--- a/include/asm-blackfin/mach-bf548/defBF54x_base.h
+++ b/include/asm-blackfin/mach-bf548/defBF54x_base.h
@@ -1644,8 +1644,25 @@
#define RESTART 0x20 /* Work Unit Transitions */
#define DI_SEL 0x40 /* Data Interrupt Timing Select */
#define DI_EN 0x80 /* Data Interrupt Enable */
+
#define NDSIZE 0xf00 /* Flex Descriptor Size */
+#define NDSIZE_0 0x0000 /* Next Descriptor Size = 0 (Stop/Autobuffer) */
+#define NDSIZE_1 0x0100 /* Next Descriptor Size = 1 */
+#define NDSIZE_2 0x0200 /* Next Descriptor Size = 2 */
+#define NDSIZE_3 0x0300 /* Next Descriptor Size = 3 */
+#define NDSIZE_4 0x0400 /* Next Descriptor Size = 4 */
+#define NDSIZE_5 0x0500 /* Next Descriptor Size = 5 */
+#define NDSIZE_6 0x0600 /* Next Descriptor Size = 6 */
+#define NDSIZE_7 0x0700 /* Next Descriptor Size = 7 */
+#define NDSIZE_8 0x0800 /* Next Descriptor Size = 8 */
+#define NDSIZE_9 0x0900 /* Next Descriptor Size = 9 */
+
#define DMAFLOW 0xf000 /* Next Operation */
+#define DMAFLOW_STOP 0x0000 /* Stop Mode */
+#define DMAFLOW_AUTO 0x1000 /* Autobuffer Mode */
+#define DMAFLOW_ARRAY 0x4000 /* Descriptor Array Mode */
+#define DMAFLOW_SMALL 0x6000 /* Small Model Descriptor List Mode */
+#define DMAFLOW_LARGE 0x7000 /* Large Model Descriptor List Mode */

/* Bit masks for DMAx_IRQ_STATUS, MDMA_Sx_IRQ_STATUS, MDMA_Dx_IRQ_STATUS */

--
1.5.3.4

2007-10-30 09:18:52

by Bryan Wu

[permalink] [raw]
Subject: [PATCH 03/14] Blackfin SPI driver: add error handing

- add error handling in SPI bus driver with selecting clients
- use proper defines to access Blackfin MMRs
- remove useless SSYNCs

Signed-off-by: Michael Hennerich <[email protected]>
Signed-off-by: Bryan Wu <[email protected]>
---
drivers/spi/spi_bfin5xx.c | 107 +++++++++++++++++++--------------------------
1 files changed, 45 insertions(+), 62 deletions(-)

diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
index eeaa65d..49f4eac 100644
--- a/drivers/spi/spi_bfin5xx.c
+++ b/drivers/spi/spi_bfin5xx.c
@@ -59,10 +59,9 @@ MODULE_LICENSE("GPL");

#define DEFINE_SPI_REG(reg, off) \
static inline u16 read_##reg(void) \
- { return *(volatile unsigned short*)(SPI0_REGBASE + off); } \
+ { return bfin_read16(SPI0_REGBASE + off); } \
static inline void write_##reg(u16 v) \
- {*(volatile unsigned short*)(SPI0_REGBASE + off) = v;\
- SSYNC();}
+ {bfin_write16(SPI0_REGBASE + off, v); }

DEFINE_SPI_REG(CTRL, 0x00)
DEFINE_SPI_REG(FLAG, 0x04)
@@ -145,7 +144,6 @@ static void bfin_spi_enable(struct driver_data *drv_data)

cr = read_CTRL();
write_CTRL(cr | BIT_CTL_ENABLE);
- SSYNC();
}

static void bfin_spi_disable(struct driver_data *drv_data)
@@ -154,7 +152,6 @@ static void bfin_spi_disable(struct driver_data *drv_data)

cr = read_CTRL();
write_CTRL(cr & (~BIT_CTL_ENABLE));
- SSYNC();
}

/* Caculate the SPI_BAUD register value based on input HZ */
@@ -182,52 +179,44 @@ static int flush(struct driver_data *drv_data)
return limit;
}

+#define MAX_SPI0_SSEL 7
+
/* stop controller and re-config current chip*/
-static void restore_state(struct driver_data *drv_data)
+static int restore_state(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;
+ int ret = 0;
+ u16 ssel[MAX_SPI0_SSEL] = {P_SPI0_SSEL1, P_SPI0_SSEL2, P_SPI0_SSEL3,
+ P_SPI0_SSEL4, P_SPI0_SSEL5,
+ P_SPI0_SSEL6, P_SPI0_SSEL7,};

/* Clear status and disable clock */
write_STAT(BIT_STAT_CLR);
bfin_spi_disable(drv_data);
dev_dbg(&drv_data->pdev->dev, "restoring spi ctl state\n");

+ /* Load the registers */
+ write_CTRL(chip->ctl_reg);
+ write_BAUD(chip->baud);
+ write_FLAG(chip->flag);
+
if (!chip->chip_select_requested) {
+ int i = chip->chip_select_num;

- dev_dbg(&drv_data->pdev->dev,
- "chip select number is %d\n", chip->chip_select_num);
-
- switch (chip->chip_select_num) {
- case 1:
- peripheral_request(P_SPI0_SSEL1, DRV_NAME);
- break;
- case 2:
- peripheral_request(P_SPI0_SSEL2, DRV_NAME);
- break;
- case 3:
- peripheral_request(P_SPI0_SSEL3, DRV_NAME);
- break;
- case 4:
- peripheral_request(P_SPI0_SSEL4, DRV_NAME);
- break;
- case 5:
- peripheral_request(P_SPI0_SSEL5, DRV_NAME);
- break;
- case 6:
- peripheral_request(P_SPI0_SSEL6, DRV_NAME);
- break;
- case 7:
- peripheral_request(P_SPI0_SSEL7, DRV_NAME);
- break;
- }
+ dev_dbg(&drv_data->pdev->dev, "chip select number is %d\n", i);
+
+ if ((i > 0) && (i <= MAX_SPI0_SSEL))
+ ret = peripheral_request(ssel[i-1], DRV_NAME);

chip->chip_select_requested = 1;
}

- /* Load the registers */
- write_CTRL(chip->ctl_reg);
- write_BAUD(chip->baud);
- write_FLAG(chip->flag);
+ if (ret)
+ dev_dbg(&drv_data->pdev->dev,
+ ": request chip select number %d failed\n",
+ chip->chip_select_num);
+
+ return ret;
}

/* used to kick off transfer in rx mode */
@@ -285,7 +274,6 @@ static void u8_cs_chg_writer(struct driver_data *drv_data)

while (drv_data->tx < drv_data->tx_end) {
write_FLAG(chip->flag);
- SSYNC();

write_TDBR(*(u8 *) (drv_data->tx));
while (read_STAT() & BIT_STAT_TXS)
@@ -293,13 +281,13 @@ static void u8_cs_chg_writer(struct driver_data *drv_data)
while (!(read_STAT() & BIT_STAT_SPIF))
continue;
write_FLAG(0xFF00 | chip->flag);
- SSYNC();
+
if (chip->cs_chg_udelay)
udelay(chip->cs_chg_udelay);
++drv_data->tx;
}
write_FLAG(0xFF00);
- SSYNC();
+
}

static void u8_reader(struct driver_data *drv_data)
@@ -331,7 +319,6 @@ static void u8_cs_chg_reader(struct driver_data *drv_data)

while (drv_data->rx < drv_data->rx_end) {
write_FLAG(chip->flag);
- SSYNC();

read_RDBR(); /* kick off */
while (!(read_STAT() & BIT_STAT_RXS))
@@ -340,13 +327,13 @@ static void u8_cs_chg_reader(struct driver_data *drv_data)
continue;
*(u8 *) (drv_data->rx) = read_SHAW();
write_FLAG(0xFF00 | chip->flag);
- SSYNC();
+
if (chip->cs_chg_udelay)
udelay(chip->cs_chg_udelay);
++drv_data->rx;
}
write_FLAG(0xFF00);
- SSYNC();
+
}

static void u8_duplex(struct driver_data *drv_data)
@@ -370,7 +357,7 @@ static void u8_cs_chg_duplex(struct driver_data *drv_data)

while (drv_data->rx < drv_data->rx_end) {
write_FLAG(chip->flag);
- SSYNC();
+

write_TDBR(*(u8 *) (drv_data->tx));
while (!(read_STAT() & BIT_STAT_SPIF))
@@ -379,14 +366,14 @@ static void u8_cs_chg_duplex(struct driver_data *drv_data)
continue;
*(u8 *) (drv_data->rx) = read_RDBR();
write_FLAG(0xFF00 | chip->flag);
- SSYNC();
+
if (chip->cs_chg_udelay)
udelay(chip->cs_chg_udelay);
++drv_data->rx;
++drv_data->tx;
}
write_FLAG(0xFF00);
- SSYNC();
+
}

static void u16_writer(struct driver_data *drv_data)
@@ -412,7 +399,6 @@ static void u16_cs_chg_writer(struct driver_data *drv_data)

while (drv_data->tx < drv_data->tx_end) {
write_FLAG(chip->flag);
- SSYNC();

write_TDBR(*(u16 *) (drv_data->tx));
while ((read_STAT() & BIT_STAT_TXS))
@@ -420,13 +406,12 @@ static void u16_cs_chg_writer(struct driver_data *drv_data)
while (!(read_STAT() & BIT_STAT_SPIF))
continue;
write_FLAG(0xFF00 | chip->flag);
- SSYNC();
+
if (chip->cs_chg_udelay)
udelay(chip->cs_chg_udelay);
drv_data->tx += 2;
}
write_FLAG(0xFF00);
- SSYNC();
}

static void u16_reader(struct driver_data *drv_data)
@@ -454,7 +439,6 @@ static void u16_cs_chg_reader(struct driver_data *drv_data)

while (drv_data->rx < drv_data->rx_end) {
write_FLAG(chip->flag);
- SSYNC();

read_RDBR(); /* kick off */
while (!(read_STAT() & BIT_STAT_RXS))
@@ -463,13 +447,12 @@ static void u16_cs_chg_reader(struct driver_data *drv_data)
continue;
*(u16 *) (drv_data->rx) = read_SHAW();
write_FLAG(0xFF00 | chip->flag);
- SSYNC();
+
if (chip->cs_chg_udelay)
udelay(chip->cs_chg_udelay);
drv_data->rx += 2;
}
write_FLAG(0xFF00);
- SSYNC();
}

static void u16_duplex(struct driver_data *drv_data)
@@ -493,7 +476,6 @@ static void u16_cs_chg_duplex(struct driver_data *drv_data)

while (drv_data->tx < drv_data->tx_end) {
write_FLAG(chip->flag);
- SSYNC();

write_TDBR(*(u16 *) (drv_data->tx));
while (!(read_STAT() & BIT_STAT_SPIF))
@@ -502,14 +484,13 @@ static void u16_cs_chg_duplex(struct driver_data *drv_data)
continue;
*(u16 *) (drv_data->rx) = read_RDBR();
write_FLAG(0xFF00 | chip->flag);
- SSYNC();
+
if (chip->cs_chg_udelay)
udelay(chip->cs_chg_udelay);
drv_data->rx += 2;
drv_data->tx += 2;
}
write_FLAG(0xFF00);
- SSYNC();
}

/* test if ther is more transfer to be done */
@@ -811,7 +792,6 @@ static void pump_transfers(unsigned long data)
"IO duplex: cr is 0x%x\n", cr);

write_CTRL(cr);
- SSYNC();

drv_data->duplex(drv_data);

@@ -826,7 +806,6 @@ static void pump_transfers(unsigned long data)
"IO write: cr is 0x%x\n", cr);

write_CTRL(cr);
- SSYNC();

drv_data->write(drv_data);

@@ -841,7 +820,6 @@ static void pump_transfers(unsigned long data)
"IO read: cr is 0x%x\n", cr);

write_CTRL(cr);
- SSYNC();

drv_data->read(drv_data);
if (drv_data->rx != drv_data->rx_end)
@@ -890,6 +868,14 @@ static void pump_messages(struct work_struct *work)
/* Extract head of queue */
drv_data->cur_msg = list_entry(drv_data->queue.next,
struct spi_message, queue);
+
+ /* Setup the SSP using the per chip configuration */
+ drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi);
+ if (restore_state(drv_data)) {
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+ return;
+ };
+
list_del_init(&drv_data->cur_msg->queue);

/* Initial message state */
@@ -897,13 +883,10 @@ static void pump_messages(struct work_struct *work)
drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next,
struct spi_transfer, transfer_list);

- /* Setup the SSP using the per chip configuration */
- drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi);
- restore_state(drv_data);
dev_dbg(&drv_data->pdev->dev,
"got a message to pump, state is set to: baud %d, flag 0x%x, ctl 0x%x\n",
- drv_data->cur_chip->baud, drv_data->cur_chip->flag,
- drv_data->cur_chip->ctl_reg);
+ drv_data->cur_chip->baud, drv_data->cur_chip->flag,
+ drv_data->cur_chip->ctl_reg);

dev_dbg(&drv_data->pdev->dev,
"the first transfer len is %d\n",
--
1.5.3.4

2007-10-30 09:19:15

by Bryan Wu

[permalink] [raw]
Subject: [PATCH 02/14] Blackfin SPI driver: use new GPIO API and add error handling

From: Michael Hennerich <[email protected]>

Signed-off-by: Michael Hennerich <[email protected]>
Signed-off-by: Bryan Wu <[email protected]>
---
drivers/spi/spi_bfin5xx.c | 29 +++++++++++++++++++++++------
include/asm-blackfin/mach-bf533/portmux.h | 2 +-
2 files changed, 24 insertions(+), 7 deletions(-)

diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
index 621a3eb..eeaa65d 100644
--- a/drivers/spi/spi_bfin5xx.c
+++ b/drivers/spi/spi_bfin5xx.c
@@ -1165,6 +1165,22 @@ static inline int destroy_queue(struct driver_data *drv_data)
return 0;
}

+static int setup_pin_mux(int action)
+{
+
+ u16 pin_req[] = {P_SPI0_SCK, P_SPI0_MISO, P_SPI0_MOSI, 0};
+
+ if (action) {
+ if (peripheral_request_list(pin_req, DRV_NAME)) {
+ return -EFAULT;
+ }
+ } else {
+ peripheral_free_list(pin_req);
+ }
+
+ return 0;
+}
+
static int __init bfin5xx_spi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -1182,12 +1198,9 @@ static int __init bfin5xx_spi_probe(struct platform_device *pdev)
return -ENOMEM;
}

- if (peripheral_request(P_SPI0_SCK, DRV_NAME) ||
- peripheral_request(P_SPI0_MISO, DRV_NAME) ||
- peripheral_request(P_SPI0_MOSI, DRV_NAME) ) {
-
+ if (setup_pin_mux(1)) {
dev_err(&pdev->dev, ": Requesting Peripherals failed\n");
- goto out_error_queue_alloc;
+ goto out_error;
}

drv_data = spi_master_get_devdata(master);
@@ -1223,9 +1236,11 @@ static int __init bfin5xx_spi_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "controller probe successfully\n");
return status;

- out_error_queue_alloc:
+out_error_queue_alloc:
destroy_queue(drv_data);
+out_error:
spi_master_put(master);
+
return status;
}

@@ -1255,6 +1270,8 @@ static int __devexit bfin5xx_spi_remove(struct platform_device *pdev)
/* Disconnect from the SPI framework */
spi_unregister_master(drv_data->master);

+ setup_pin_mux(0);
+
/* Prevent double remove */
platform_set_drvdata(pdev, NULL);

diff --git a/include/asm-blackfin/mach-bf533/portmux.h b/include/asm-blackfin/mach-bf533/portmux.h
index b88d7a0..137f488 100644
--- a/include/asm-blackfin/mach-bf533/portmux.h
+++ b/include/asm-blackfin/mach-bf533/portmux.h
@@ -42,7 +42,7 @@
#define P_SPORT0_DRPRI (P_DONTCARE)

#define P_SPI0_MOSI (P_DONTCARE)
-#define P_SPI0_MIS0 (P_DONTCARE)
+#define P_SPI0_MISO (P_DONTCARE)
#define P_SPI0_SCK (P_DONTCARE)
#define P_SPI0_SSEL7 (P_DEFINED | P_IDENT(GPIO_PF7))
#define P_SPI0_SSEL6 (P_DEFINED | P_IDENT(GPIO_PF6))
--
1.5.3.4

2007-10-30 09:19:31

by Bryan Wu

[permalink] [raw]
Subject: [PATCH 04/14] Blackfin SPI driver: Blackfin SPI driver does not respect the per-transfer cs_change field

Add cs_active/cs_deactive functions and try to catch the cs_change flag.

Signed-off-by: Bryan Wu <[email protected]>
---
drivers/spi/spi_bfin5xx.c | 76 ++++++++++++++++++++++++++++++++-------------
1 files changed, 54 insertions(+), 22 deletions(-)

diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
index 49f4eac..1a55aa7 100644
--- a/drivers/spi/spi_bfin5xx.c
+++ b/drivers/spi/spi_bfin5xx.c
@@ -115,6 +115,7 @@ struct driver_data {
size_t rx_map_len;
size_t tx_map_len;
u8 n_bytes;
+ int cs_change;
void (*write) (struct driver_data *);
void (*read) (struct driver_data *);
void (*duplex) (struct driver_data *);
@@ -179,6 +180,26 @@ static int flush(struct driver_data *drv_data)
return limit;
}

+/* Chip select operation functions for cs_change flag */
+static void cs_active(struct chip_data *chip)
+{
+ u16 flag = read_FLAG();
+
+ flag |= chip->flag;
+ flag &= ~(chip->flag << 8);
+
+ write_FLAG(flag);
+}
+
+static void cs_deactive(struct chip_data *chip)
+{
+ u16 flag = read_FLAG();
+
+ flag |= (chip->flag << 8);
+
+ write_FLAG(flag);
+}
+
#define MAX_SPI0_SSEL 7

/* stop controller and re-config current chip*/
@@ -198,7 +219,7 @@ static int restore_state(struct driver_data *drv_data)
/* Load the registers */
write_CTRL(chip->ctl_reg);
write_BAUD(chip->baud);
- write_FLAG(chip->flag);
+ cs_active(chip);

if (!chip->chip_select_requested) {
int i = chip->chip_select_num;
@@ -273,20 +294,20 @@ static void u8_cs_chg_writer(struct driver_data *drv_data)
struct chip_data *chip = drv_data->cur_chip;

while (drv_data->tx < drv_data->tx_end) {
- write_FLAG(chip->flag);
+ cs_active(chip);

write_TDBR(*(u8 *) (drv_data->tx));
while (read_STAT() & BIT_STAT_TXS)
continue;
while (!(read_STAT() & BIT_STAT_SPIF))
continue;
- write_FLAG(0xFF00 | chip->flag);
+ cs_deactive(chip);

if (chip->cs_chg_udelay)
udelay(chip->cs_chg_udelay);
++drv_data->tx;
}
- write_FLAG(0xFF00);
+ cs_deactive(chip);

}

@@ -318,7 +339,7 @@ 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) {
- write_FLAG(chip->flag);
+ cs_active(chip);

read_RDBR(); /* kick off */
while (!(read_STAT() & BIT_STAT_RXS))
@@ -326,13 +347,13 @@ static void u8_cs_chg_reader(struct driver_data *drv_data)
while (!(read_STAT() & BIT_STAT_SPIF))
continue;
*(u8 *) (drv_data->rx) = read_SHAW();
- write_FLAG(0xFF00 | chip->flag);
+ cs_deactive(chip);

if (chip->cs_chg_udelay)
udelay(chip->cs_chg_udelay);
++drv_data->rx;
}
- write_FLAG(0xFF00);
+ cs_deactive(chip);

}

@@ -356,7 +377,7 @@ static void u8_cs_chg_duplex(struct driver_data *drv_data)
struct chip_data *chip = drv_data->cur_chip;

while (drv_data->rx < drv_data->rx_end) {
- write_FLAG(chip->flag);
+ cs_active(chip);


write_TDBR(*(u8 *) (drv_data->tx));
@@ -365,15 +386,14 @@ static void u8_cs_chg_duplex(struct driver_data *drv_data)
while (!(read_STAT() & BIT_STAT_RXS))
continue;
*(u8 *) (drv_data->rx) = read_RDBR();
- write_FLAG(0xFF00 | chip->flag);
+ cs_deactive(chip);

if (chip->cs_chg_udelay)
udelay(chip->cs_chg_udelay);
++drv_data->rx;
++drv_data->tx;
}
- write_FLAG(0xFF00);
-
+ cs_deactive(chip);
}

static void u16_writer(struct driver_data *drv_data)
@@ -398,20 +418,20 @@ static void u16_cs_chg_writer(struct driver_data *drv_data)
struct chip_data *chip = drv_data->cur_chip;

while (drv_data->tx < drv_data->tx_end) {
- write_FLAG(chip->flag);
+ cs_active(chip);

write_TDBR(*(u16 *) (drv_data->tx));
while ((read_STAT() & BIT_STAT_TXS))
continue;
while (!(read_STAT() & BIT_STAT_SPIF))
continue;
- write_FLAG(0xFF00 | chip->flag);
+ cs_deactive(chip);

if (chip->cs_chg_udelay)
udelay(chip->cs_chg_udelay);
drv_data->tx += 2;
}
- write_FLAG(0xFF00);
+ cs_deactive(chip);
}

static void u16_reader(struct driver_data *drv_data)
@@ -438,7 +458,7 @@ 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) {
- write_FLAG(chip->flag);
+ cs_active(chip);

read_RDBR(); /* kick off */
while (!(read_STAT() & BIT_STAT_RXS))
@@ -446,13 +466,13 @@ static void u16_cs_chg_reader(struct driver_data *drv_data)
while (!(read_STAT() & BIT_STAT_SPIF))
continue;
*(u16 *) (drv_data->rx) = read_SHAW();
- write_FLAG(0xFF00 | chip->flag);
+ cs_deactive(chip);

if (chip->cs_chg_udelay)
udelay(chip->cs_chg_udelay);
drv_data->rx += 2;
}
- write_FLAG(0xFF00);
+ cs_deactive(chip);
}

static void u16_duplex(struct driver_data *drv_data)
@@ -475,7 +495,7 @@ static void u16_cs_chg_duplex(struct driver_data *drv_data)
struct chip_data *chip = drv_data->cur_chip;

while (drv_data->tx < drv_data->tx_end) {
- write_FLAG(chip->flag);
+ cs_active(chip);

write_TDBR(*(u16 *) (drv_data->tx));
while (!(read_STAT() & BIT_STAT_SPIF))
@@ -483,14 +503,14 @@ static void u16_cs_chg_duplex(struct driver_data *drv_data)
while (!(read_STAT() & BIT_STAT_RXS))
continue;
*(u16 *) (drv_data->rx) = read_RDBR();
- write_FLAG(0xFF00 | chip->flag);
+ cs_deactive(chip);

if (chip->cs_chg_udelay)
udelay(chip->cs_chg_udelay);
drv_data->rx += 2;
drv_data->tx += 2;
}
- write_FLAG(0xFF00);
+ cs_deactive(chip);
}

/* test if ther is more transfer to be done */
@@ -515,6 +535,7 @@ static void *next_transfer(struct driver_data *drv_data)
*/
static void giveback(struct driver_data *drv_data)
{
+ struct chip_data *chip = drv_data->cur_chip;
struct spi_transfer *last_transfer;
unsigned long flags;
struct spi_message *msg;
@@ -534,10 +555,13 @@ static void giveback(struct driver_data *drv_data)

/* disable chip select signal. And not stop spi in autobuffer mode */
if (drv_data->tx_dma != 0xFFFF) {
- write_FLAG(0xFF00);
+ cs_deactive(chip);
bfin_spi_disable(drv_data);
}

+ if (!drv_data->cs_change)
+ cs_deactive(chip);
+
if (msg->complete)
msg->complete(msg->context);
}
@@ -546,6 +570,7 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id)
{
struct driver_data *drv_data = (struct driver_data *)dev_id;
struct spi_message *msg = drv_data->cur_msg;
+ struct chip_data *chip = drv_data->cur_chip;

dev_dbg(&drv_data->pdev->dev, "in dma_irq_handler\n");
clear_dma_irqstat(CH_SPI);
@@ -573,6 +598,9 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id)

msg->actual_length += drv_data->len_in_bytes;

+ if (drv_data->cs_change)
+ cs_deactive(chip);
+
/* Move to next transfer */
msg->state = next_transfer(drv_data);

@@ -659,6 +687,7 @@ static void pump_transfers(unsigned long data)
drv_data->rx_dma = transfer->rx_dma;
drv_data->tx_dma = transfer->tx_dma;
drv_data->len_in_bytes = transfer->len;
+ drv_data->cs_change = transfer->cs_change;

width = chip->width;
if (width == CFG_SPI_WORDSIZE16) {
@@ -683,7 +712,7 @@ static void pump_transfers(unsigned long data)
} else {
write_BAUD(chip->baud);
}
- write_FLAG(chip->flag);
+ cs_active(chip);

dev_dbg(&drv_data->pdev->dev,
"now pumping a transfer: width is %d, len is %d\n",
@@ -834,6 +863,9 @@ 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

2007-10-30 09:19:48

by Bryan Wu

[permalink] [raw]
Subject: [PATCH 05/14] Blackfin SPI driver: prevent people from setting bits in ctl_reg

From: Mike Frysinger <[email protected]>

Prevent people from setting bits in ctl_reg that the SPI
framework already handles, hopefully we can one day drop
ctl_reg completely

Signed-off-by: Mike Frysinger <[email protected]>
Signed-off-by: Bryan Wu <[email protected]>
---
drivers/spi/spi_bfin5xx.c | 10 ++++++++++
1 files changed, 10 insertions(+), 0 deletions(-)

diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
index 1a55aa7..e4d64a0 100644
--- a/drivers/spi/spi_bfin5xx.c
+++ b/drivers/spi/spi_bfin5xx.c
@@ -996,6 +996,16 @@ static int setup(struct spi_device *spi)

/* chip_info isn't always needed */
if (chip_info) {
+ /* Make sure people stop trying to set fields via ctl_reg when they
+ * should actually be using common SPI framework. Currently we let
+ * through: WOM EMISO PSSE GM SZ TIMOD. Not sure if a user actually
+ * needs/uses any of these, but let's assume (for now) they do.
+ */
+ if (chip_info->ctl_reg & (SPE | MSTR | CPOL | CPHA | LSBF | SIZE)) {
+ dev_err(&spi->dev, "do not set bits in ctl_reg that the SPI framework provides\n");
+ return -EINVAL;
+ }
+
chip->enable_dma = chip_info->enable_dma != 0
&& drv_data->master_info->enable_dma;
chip->ctl_reg = chip_info->ctl_reg;
--
1.5.3.4

2007-10-30 09:20:14

by Bryan Wu

[permalink] [raw]
Subject: [PATCH 07/14] Blackfin SPI driver: Add SPI master controller platform device 1

From: Sonic Zhang <[email protected]>

Signed-off-by: Sonic Zhang <[email protected]>
Signed-off-by: Bryan Wu <[email protected]>
---
drivers/spi/spi_bfin5xx.c | 52 ++++++++++++++++++++++++++------------------
1 files changed, 31 insertions(+), 21 deletions(-)

diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
index 3f3630c..3bd8359 100644
--- a/drivers/spi/spi_bfin5xx.c
+++ b/drivers/spi/spi_bfin5xx.c
@@ -209,17 +209,26 @@ static void cs_deactive(struct chip_data *chip)
write_FLAG(flag);
}

-#define MAX_SPI0_SSEL 7
+#define MAX_SPI_SSEL 7

/* stop controller and re-config current chip*/
static int restore_state(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;
int ret = 0;
- u16 ssel[MAX_SPI0_SSEL] = {P_SPI0_SSEL1, P_SPI0_SSEL2, P_SPI0_SSEL3,
- P_SPI0_SSEL4, P_SPI0_SSEL5,
- P_SPI0_SSEL6, P_SPI0_SSEL7,};
-
+ u16 ssel[3][MAX_SPI_SSEL] = {
+ {P_SPI0_SSEL1, P_SPI0_SSEL2, P_SPI0_SSEL3,
+ P_SPI0_SSEL4, P_SPI0_SSEL5,
+ P_SPI0_SSEL6, P_SPI0_SSEL7},
+
+ {P_SPI1_SSEL1, P_SPI1_SSEL2, P_SPI1_SSEL3,
+ P_SPI1_SSEL4, P_SPI1_SSEL5,
+ P_SPI1_SSEL6, P_SPI1_SSEL7},
+
+ {P_SPI2_SSEL1, P_SPI2_SSEL2, P_SPI2_SSEL3,
+ P_SPI2_SSEL4, P_SPI2_SSEL5,
+ P_SPI2_SSEL6, P_SPI2_SSEL7},
+ };
/* Clear status and disable clock */
write_STAT(BIT_STAT_CLR);
bfin_spi_disable(drv_data);
@@ -234,9 +243,9 @@ static int restore_state(struct driver_data *drv_data)
int i = chip->chip_select_num;

dev_dbg(&drv_data->pdev->dev, "chip select number is %d\n", i);
-
- if ((i > 0) && (i <= MAX_SPI0_SSEL))
- ret = peripheral_request(ssel[i-1], DRV_NAME);
+ if ((i > 0) && (i <= MAX_SPI_SSEL))
+ ret = peripheral_request(
+ ssel[drv_data->master->bus_num][i-1], DRV_NAME);

chip->chip_select_requested = 1;
}
@@ -329,7 +338,6 @@ 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;
@@ -640,7 +648,6 @@ static void pump_transfers(unsigned long data)
message = drv_data->cur_msg;
transfer = drv_data->cur_transfer;
chip = drv_data->cur_chip;
-
/*
* if msg is error or done, report it back using complete() callback
*/
@@ -1202,17 +1209,20 @@ static inline int destroy_queue(struct driver_data *drv_data)
return 0;
}

-static int setup_pin_mux(int action)
+static int setup_pin_mux(int action, int bus_num)
{

- u16 pin_req[] = {P_SPI0_SCK, P_SPI0_MISO, P_SPI0_MOSI, 0};
+ u16 pin_req[3][4] = {
+ {P_SPI0_SCK, P_SPI0_MISO, P_SPI0_MOSI, 0},
+ {P_SPI1_SCK, P_SPI1_MISO, P_SPI1_MOSI, 0},
+ {P_SPI2_SCK, P_SPI2_MISO, P_SPI2_MOSI, 0},
+ };

if (action) {
- if (peripheral_request_list(pin_req, DRV_NAME)) {
+ if (peripheral_request_list(pin_req[bus_num], DRV_NAME))
return -EFAULT;
- }
} else {
- peripheral_free_list(pin_req);
+ peripheral_free_list(pin_req[bus_num]);
}

return 0;
@@ -1236,11 +1246,6 @@ static int __init bfin5xx_spi_probe(struct platform_device *pdev)
return -ENOMEM;
}

- if (setup_pin_mux(1)) {
- dev_err(&pdev->dev, ": Requesting Peripherals failed\n");
- goto out_error;
- }
-
drv_data = spi_master_get_devdata(master);
drv_data->master = master;
drv_data->master_info = platform_info;
@@ -1295,6 +1300,11 @@ static int __init bfin5xx_spi_probe(struct platform_device *pdev)
goto out_error_queue_alloc;
}

+ if (setup_pin_mux(1, master->bus_num)) {
+ dev_err(&pdev->dev, ": Requesting Peripherals failed\n");
+ goto out_error;
+ }
+
dev_info(dev, "%s, Version %s, regs_base @ 0x%08x\n",
DRV_DESC, DRV_VERSION, spi_regs_base);
return status;
@@ -1337,7 +1347,7 @@ static int __devexit bfin5xx_spi_remove(struct platform_device *pdev)
/* Disconnect from the SPI framework */
spi_unregister_master(drv_data->master);

- setup_pin_mux(0);
+ setup_pin_mux(0, drv_data->master->bus_num);

/* Prevent double remove */
platform_set_drvdata(pdev, NULL);
--
1.5.3.4

2007-10-30 09:20:39

by Bryan Wu

[permalink] [raw]
Subject: [PATCH 06/14] Blackfin SPI driver: update spi driver to support multi-ports

update spi driver to support multi-ports by add platform_resource,
tested on STAMP537+SPI_MMC, other boards need more testing

Signed-off-by: Bryan Wu <[email protected]>
---
drivers/spi/spi_bfin5xx.c | 124 ++++++++++++++++++++++++++++++---------------
1 files changed, 83 insertions(+), 41 deletions(-)

diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
index e4d64a0..3f3630c 100644
--- a/drivers/spi/spi_bfin5xx.c
+++ b/drivers/spi/spi_bfin5xx.c
@@ -13,6 +13,8 @@
* March 10, 2006 bfin5xx_spi.c Created. (Luke Yang)
* August 7, 2006 added full duplex mode (Axel Weiss & Luke Yang)
* July 17, 2007 add support for BF54x SPI0 controller (Bryan Wu)
+ * July 30, 2007 add platfrom_resource interface to support multi-port
+ * SPI controller (Bryan Wu)
*
* Copyright 2004-2007 Analog Devices Inc.
*
@@ -50,18 +52,25 @@
#include <asm/portmux.h>
#include <asm/bfin5xx_spi.h>

-MODULE_AUTHOR("Bryan Wu, Luke Yang");
-MODULE_DESCRIPTION("Blackfin BF5xx SPI Contoller Driver");
+#define DRV_NAME "bfin-spi"
+#define DRV_AUTHOR "Bryan Wu, Luke Yang"
+#define DRV_DESC "Blackfin BF5xx on-chip SPI Contoller Driver"
+#define DRV_VERSION "1.0"
+
+MODULE_AUTHOR(DRV_AUTHOR);
+MODULE_DESCRIPTION(DRV_DESC);
MODULE_LICENSE("GPL");

-#define DRV_NAME "bfin-spi-master"
#define IS_DMA_ALIGNED(x) (((u32)(x)&0x07)==0)

+static u32 spi_dma_ch;
+static u32 spi_regs_base;
+
#define DEFINE_SPI_REG(reg, off) \
static inline u16 read_##reg(void) \
- { return bfin_read16(SPI0_REGBASE + off); } \
+ { return bfin_read16(spi_regs_base + off); } \
static inline void write_##reg(u16 v) \
- {bfin_write16(SPI0_REGBASE + off, v); }
+ {bfin_write16(spi_regs_base + off, v); }

DEFINE_SPI_REG(CTRL, 0x00)
DEFINE_SPI_REG(FLAG, 0x04)
@@ -573,10 +582,10 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id)
struct chip_data *chip = drv_data->cur_chip;

dev_dbg(&drv_data->pdev->dev, "in dma_irq_handler\n");
- clear_dma_irqstat(CH_SPI);
+ clear_dma_irqstat(spi_dma_ch);

/* Wait for DMA to complete */
- while (get_dma_curr_irqstat(CH_SPI) & DMA_RUN)
+ while (get_dma_curr_irqstat(spi_dma_ch) & DMA_RUN)
continue;

/*
@@ -586,12 +595,12 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id)
* register until it goes low for 2 successive reads
*/
if (drv_data->tx != NULL) {
- while ((bfin_read_SPI_STAT() & TXS) ||
- (bfin_read_SPI_STAT() & TXS))
+ while ((read_STAT() & TXS) ||
+ (read_STAT() & TXS))
continue;
}

- while (!(bfin_read_SPI_STAT() & SPIF))
+ while (!(read_STAT() & SPIF))
continue;

bfin_spi_disable(drv_data);
@@ -610,8 +619,8 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id)
/* free the irq handler before next transfer */
dev_dbg(&drv_data->pdev->dev,
"disable dma channel irq%d\n",
- CH_SPI);
- dma_disable_irq(CH_SPI);
+ spi_dma_ch);
+ dma_disable_irq(spi_dma_ch);

return IRQ_HANDLED;
}
@@ -726,19 +735,19 @@ 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(CH_SPI);
- clear_dma_irqstat(CH_SPI);
+ 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");
if (width == CFG_SPI_WORDSIZE16) {
- set_dma_x_count(CH_SPI, drv_data->len);
- set_dma_x_modify(CH_SPI, 2);
+ set_dma_x_count(spi_dma_ch, drv_data->len);
+ set_dma_x_modify(spi_dma_ch, 2);
dma_width = WDSIZE_16;
} else {
- set_dma_x_count(CH_SPI, drv_data->len);
- set_dma_x_modify(CH_SPI, 1);
+ set_dma_x_count(spi_dma_ch, drv_data->len);
+ set_dma_x_modify(spi_dma_ch, 1);
dma_width = WDSIZE_8;
}

@@ -753,9 +762,10 @@ static void pump_transfers(unsigned long data)
/* no irq in autobuffer mode */
dma_config =
(DMAFLOW_AUTO | RESTART | dma_width | DI_EN);
- set_dma_config(CH_SPI, dma_config);
- set_dma_start_addr(CH_SPI, (unsigned long)drv_data->tx);
- enable_dma(CH_SPI);
+ set_dma_config(spi_dma_ch, dma_config);
+ 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));

@@ -776,14 +786,15 @@ static void pump_transfers(unsigned long data)
/* clear tx reg soformer data is not shifted out */
write_TDBR(0xFF);

- set_dma_x_count(CH_SPI, drv_data->len);
+ set_dma_x_count(spi_dma_ch, drv_data->len);

/* start dma */
- dma_enable_irq(CH_SPI);
+ dma_enable_irq(spi_dma_ch);
dma_config = (WNR | RESTART | dma_width | DI_EN);
- set_dma_config(CH_SPI, dma_config);
- set_dma_start_addr(CH_SPI, (unsigned long)drv_data->rx);
- enable_dma(CH_SPI);
+ set_dma_config(spi_dma_ch, dma_config);
+ set_dma_start_addr(spi_dma_ch,
+ (unsigned long)drv_data->rx);
+ enable_dma(spi_dma_ch);

cr |=
CFG_SPI_DMAREAD | (width << 8) | (CFG_SPI_ENABLE <<
@@ -794,11 +805,12 @@ static void pump_transfers(unsigned long data)
dev_dbg(&drv_data->pdev->dev, "doing DMA out.\n");

/* start dma */
- dma_enable_irq(CH_SPI);
+ dma_enable_irq(spi_dma_ch);
dma_config = (RESTART | dma_width | DI_EN);
- set_dma_config(CH_SPI, dma_config);
- set_dma_start_addr(CH_SPI, (unsigned long)drv_data->tx);
- enable_dma(CH_SPI);
+ set_dma_config(spi_dma_ch, dma_config);
+ 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));
@@ -1030,17 +1042,17 @@ static int setup(struct spi_device *spi)
*/
if (chip->enable_dma && !dma_requested) {
/* register dma irq handler */
- if (request_dma(CH_SPI, "BF53x_SPI_DMA") < 0) {
+ if (request_dma(spi_dma_ch, "BF53x_SPI_DMA") < 0) {
dev_dbg(&spi->dev,
"Unable to request BlackFin SPI DMA channel\n");
return -ENODEV;
}
- if (set_dma_callback(CH_SPI, (void *)dma_irq_handler, drv_data)
- < 0) {
+ if (set_dma_callback(spi_dma_ch, (void *)dma_irq_handler,
+ drv_data) < 0) {
dev_dbg(&spi->dev, "Unable to set dma callback\n");
return -EPERM;
}
- dma_disable_irq(CH_SPI);
+ dma_disable_irq(spi_dma_ch);
dma_requested = 1;
}

@@ -1212,6 +1224,7 @@ static int __init bfin5xx_spi_probe(struct platform_device *pdev)
struct bfin5xx_spi_master *platform_info;
struct spi_master *master;
struct driver_data *drv_data = 0;
+ struct resource *res;
int status = 0;

platform_info = dev->platform_data;
@@ -1239,15 +1252,38 @@ static int __init bfin5xx_spi_probe(struct platform_device *pdev)
master->setup = setup;
master->transfer = transfer;

+ /* Find and map our resources */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(dev, "Cannot get IORESOURCE_MEM\n");
+ status = -ENOENT;
+ goto out_error_get_res;
+ }
+
+ spi_regs_base = (u32) ioremap(res->start, (res->end - res->start)+1);
+ if (!spi_regs_base) {
+ dev_err(dev, "Cannot map IO\n");
+ status = -ENXIO;
+ goto out_error_ioremap;
+ }
+
+ spi_dma_ch = platform_get_irq(pdev, 0);
+ if (spi_dma_ch < 0) {
+ dev_err(dev, "No DMA channel specified\n");
+ status = -ENOENT;
+ goto out_error_no_dma_ch;
+ }
+
/* Initial and start queue */
status = init_queue(drv_data);
if (status != 0) {
- dev_err(&pdev->dev, "problem initializing queue\n");
+ dev_err(dev, "problem initializing queue\n");
goto out_error_queue_alloc;
}
+
status = start_queue(drv_data);
if (status != 0) {
- dev_err(&pdev->dev, "problem starting queue\n");
+ dev_err(dev, "problem starting queue\n");
goto out_error_queue_alloc;
}

@@ -1255,14 +1291,20 @@ static int __init bfin5xx_spi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, drv_data);
status = spi_register_master(master);
if (status != 0) {
- dev_err(&pdev->dev, "problem registering spi master\n");
+ dev_err(dev, "problem registering spi master\n");
goto out_error_queue_alloc;
}
- dev_dbg(&pdev->dev, "controller probe successfully\n");
+
+ dev_info(dev, "%s, Version %s, regs_base @ 0x%08x\n",
+ DRV_DESC, DRV_VERSION, spi_regs_base);
return status;

out_error_queue_alloc:
destroy_queue(drv_data);
+out_error_no_dma_ch:
+ iounmap((void *) spi_regs_base);
+out_error_ioremap:
+out_error_get_res:
out_error:
spi_master_put(master);

@@ -1288,8 +1330,8 @@ static int __devexit bfin5xx_spi_remove(struct platform_device *pdev)

/* Release DMA */
if (drv_data->master_info->enable_dma) {
- if (dma_channel_active(CH_SPI))
- free_dma(CH_SPI);
+ if (dma_channel_active(spi_dma_ch))
+ free_dma(spi_dma_ch);
}

/* Disconnect from the SPI framework */
@@ -1344,7 +1386,7 @@ static int bfin5xx_spi_resume(struct platform_device *pdev)
MODULE_ALIAS("bfin-spi-master"); /* for platform bus hotplug */
static struct platform_driver bfin5xx_spi_driver = {
.driver = {
- .name = "bfin-spi-master",
+ .name = DRV_NAME,
.owner = THIS_MODULE,
},
.suspend = bfin5xx_spi_suspend,
--
1.5.3.4

2007-10-30 09:20:56

by Bryan Wu

[permalink] [raw]
Subject: [PATCH 08/14] Blackfin SPI driver: Move GPIO config to setup and cleanup

From: Sonic Zhang <[email protected]>

Signed-off-by: Sonic Zhang <[email protected]>
Signed-off-by: Bryan Wu <[email protected]>
---
drivers/spi/spi_bfin5xx.c | 52 +++++++++++++++++++++++---------------------
1 files changed, 27 insertions(+), 25 deletions(-)

diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
index 3bd8359..7f95797 100644
--- a/drivers/spi/spi_bfin5xx.c
+++ b/drivers/spi/spi_bfin5xx.c
@@ -136,7 +136,6 @@ struct chip_data {
u16 flag;

u8 chip_select_num;
- u8 chip_select_requested;
u8 n_bytes;
u8 width; /* 0 or 1 */
u8 enable_dma;
@@ -216,19 +215,7 @@ static int restore_state(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;
int ret = 0;
- u16 ssel[3][MAX_SPI_SSEL] = {
- {P_SPI0_SSEL1, P_SPI0_SSEL2, P_SPI0_SSEL3,
- P_SPI0_SSEL4, P_SPI0_SSEL5,
- P_SPI0_SSEL6, P_SPI0_SSEL7},
-
- {P_SPI1_SSEL1, P_SPI1_SSEL2, P_SPI1_SSEL3,
- P_SPI1_SSEL4, P_SPI1_SSEL5,
- P_SPI1_SSEL6, P_SPI1_SSEL7},
-
- {P_SPI2_SSEL1, P_SPI2_SSEL2, P_SPI2_SSEL3,
- P_SPI2_SSEL4, P_SPI2_SSEL5,
- P_SPI2_SSEL6, P_SPI2_SSEL7},
- };
+
/* Clear status and disable clock */
write_STAT(BIT_STAT_CLR);
bfin_spi_disable(drv_data);
@@ -239,17 +226,6 @@ static int restore_state(struct driver_data *drv_data)
write_BAUD(chip->baud);
cs_active(chip);

- if (!chip->chip_select_requested) {
- int i = chip->chip_select_num;
-
- dev_dbg(&drv_data->pdev->dev, "chip select number is %d\n", i);
- if ((i > 0) && (i <= MAX_SPI_SSEL))
- ret = peripheral_request(
- ssel[drv_data->master->bus_num][i-1], DRV_NAME);
-
- chip->chip_select_requested = 1;
- }
-
if (ret)
dev_dbg(&drv_data->pdev->dev,
": request chip select number %d failed\n",
@@ -981,6 +957,22 @@ static int transfer(struct spi_device *spi, struct spi_message *msg)
return 0;
}

+#define MAX_SPI_SSEL 7
+
+static u16 ssel[3][MAX_SPI_SSEL] = {
+ {P_SPI0_SSEL1, P_SPI0_SSEL2, P_SPI0_SSEL3,
+ P_SPI0_SSEL4, P_SPI0_SSEL5,
+ P_SPI0_SSEL6, P_SPI0_SSEL7},
+
+ {P_SPI1_SSEL1, P_SPI1_SSEL2, P_SPI1_SSEL3,
+ P_SPI1_SSEL4, P_SPI1_SSEL5,
+ P_SPI1_SSEL6, P_SPI1_SSEL7},
+
+ {P_SPI2_SSEL1, P_SPI2_SSEL2, P_SPI2_SSEL3,
+ P_SPI2_SSEL4, P_SPI2_SSEL5,
+ P_SPI2_SSEL6, P_SPI2_SSEL7},
+};
+
/* first setup for new devices */
static int setup(struct spi_device *spi)
{
@@ -1109,6 +1101,12 @@ static int setup(struct spi_device *spi)

spi_set_ctldata(spi, chip);

+ dev_dbg(&spi->dev, "chip select number is %d\n", chip->chip_select_num);
+ if ((chip->chip_select_num > 0)
+ && (chip->chip_select_num <= spi->master->num_chipselect))
+ peripheral_request(ssel[spi->master->bus_num]
+ [chip->chip_select_num-1], DRV_NAME);
+
return 0;
}

@@ -1120,6 +1118,10 @@ static void cleanup(struct spi_device *spi)
{
struct chip_data *chip = spi_get_ctldata(spi);

+ if ((chip->chip_select_num > 0)
+ && (chip->chip_select_num <= spi->master->num_chipselect))
+ peripheral_free(ssel[spi->master->bus_num][chip->chip_select_num-1]);
+
kfree(chip);
}

--
1.5.3.4

2007-10-30 09:21:17

by Bryan Wu

[permalink] [raw]
Subject: [PATCH 09/14] Blackfin SPI driver: Fix SPI driver to work with SPI flash ST25P16 on bf548

From: Sonic Zhang <[email protected]>

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 <[email protected]>
Signed-off-by: Bryan Wu <[email protected]>
---
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

2007-10-30 09:21:36

by Bryan Wu

[permalink] [raw]
Subject: [PATCH 10/14] Blackfin SPI driver: Clean up useless wait in bfin SPI driver

From: Sonic Zhang <[email protected]>

Signed-off-by: Sonic Zhang <[email protected]>
Signed-off-by: Bryan Wu <[email protected]>
---
drivers/spi/spi_bfin5xx.c | 84 ++++++++++++++++++++++++++++-----------------
1 files changed, 52 insertions(+), 32 deletions(-)

diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
index e1fd197..d69719b 100644
--- a/drivers/spi/spi_bfin5xx.c
+++ b/drivers/spi/spi_bfin5xx.c
@@ -276,22 +276,26 @@ static void u8_writer(struct driver_data *drv_data)
dev_dbg(&drv_data->pdev->dev,
"cr8-s is 0x%x\n", read_STAT());

+ /* poll for SPI completion before start */
+ while (!(read_STAT() & BIT_STAT_SPIF))
+ continue;
+
while (drv_data->tx < drv_data->tx_end) {
write_TDBR(*(u8 *) (drv_data->tx));
while (read_STAT() & BIT_STAT_TXS)
continue;
++drv_data->tx;
}
-
- /* poll for SPI completion before returning */
- while (!(read_STAT() & BIT_STAT_SPIF))
- continue;
}

static void u8_cs_chg_writer(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;

+ /* poll for SPI completion before start */
+ while (!(read_STAT() & BIT_STAT_SPIF))
+ continue;
+
while (drv_data->tx < drv_data->tx_end) {
cs_active(chip);

@@ -304,10 +308,6 @@ static void u8_cs_chg_writer(struct driver_data *drv_data)
udelay(chip->cs_chg_udelay);
++drv_data->tx;
}
-
- /* poll for SPI completion before returning */
- while (!(read_STAT() & BIT_STAT_SPIF))
- continue;
}

static void u8_reader(struct driver_data *drv_data)
@@ -315,6 +315,10 @@ static void u8_reader(struct driver_data *drv_data)
dev_dbg(&drv_data->pdev->dev,
"cr-8 is 0x%x\n", read_STAT());

+ /* poll for SPI completion before start */
+ while (!(read_STAT() & BIT_STAT_SPIF))
+ continue;
+
/* clear TDBR buffer before read(else it will be shifted out) */
write_TDBR(0xFFFF);

@@ -337,6 +341,10 @@ static void u8_cs_chg_reader(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;

+ /* poll for SPI completion before start */
+ while (!(read_STAT() & BIT_STAT_SPIF))
+ continue;
+
/* clear TDBR buffer before read(else it will be shifted out) */
write_TDBR(0xFFFF);

@@ -365,6 +373,10 @@ static void u8_cs_chg_reader(struct driver_data *drv_data)

static void u8_duplex(struct driver_data *drv_data)
{
+ /* poll for SPI completion before start */
+ while (!(read_STAT() & BIT_STAT_SPIF))
+ continue;
+
/* in duplex mode, clk is triggered by writing of TDBR */
while (drv_data->rx < drv_data->rx_end) {
write_TDBR(*(u8 *) (drv_data->tx));
@@ -376,16 +388,16 @@ 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)
{
struct chip_data *chip = drv_data->cur_chip;

+ /* poll for SPI completion before start */
+ while (!(read_STAT() & BIT_STAT_SPIF))
+ continue;
+
while (drv_data->rx < drv_data->rx_end) {
cs_active(chip);

@@ -402,10 +414,6 @@ static void u8_cs_chg_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 u16_writer(struct driver_data *drv_data)
@@ -413,22 +421,26 @@ static void u16_writer(struct driver_data *drv_data)
dev_dbg(&drv_data->pdev->dev,
"cr16 is 0x%x\n", read_STAT());

+ /* poll for SPI completion before start */
+ while (!(read_STAT() & BIT_STAT_SPIF))
+ continue;
+
while (drv_data->tx < drv_data->tx_end) {
write_TDBR(*(u16 *) (drv_data->tx));
while ((read_STAT() & BIT_STAT_TXS))
continue;
drv_data->tx += 2;
}
-
- /* poll for SPI completion before returning */
- while (!(read_STAT() & BIT_STAT_SPIF))
- continue;
}

static void u16_cs_chg_writer(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;

+ /* poll for SPI completion before start */
+ while (!(read_STAT() & BIT_STAT_SPIF))
+ continue;
+
while (drv_data->tx < drv_data->tx_end) {
cs_active(chip);

@@ -441,10 +453,6 @@ static void u16_cs_chg_writer(struct driver_data *drv_data)
udelay(chip->cs_chg_udelay);
drv_data->tx += 2;
}
-
- /* poll for SPI completion before returning */
- while (!(read_STAT() & BIT_STAT_SPIF))
- continue;
}

static void u16_reader(struct driver_data *drv_data)
@@ -452,6 +460,10 @@ static void u16_reader(struct driver_data *drv_data)
dev_dbg(&drv_data->pdev->dev,
"cr-16 is 0x%x\n", read_STAT());

+ /* poll for SPI completion before start */
+ while (!(read_STAT() & BIT_STAT_SPIF))
+ continue;
+
/* clear TDBR buffer before read(else it will be shifted out) */
write_TDBR(0xFFFF);

@@ -474,6 +486,10 @@ static void u16_cs_chg_reader(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;

+ /* poll for SPI completion before start */
+ while (!(read_STAT() & BIT_STAT_SPIF))
+ continue;
+
/* clear TDBR buffer before read(else it will be shifted out) */
write_TDBR(0xFFFF);

@@ -502,6 +518,10 @@ static void u16_cs_chg_reader(struct driver_data *drv_data)

static void u16_duplex(struct driver_data *drv_data)
{
+ /* poll for SPI completion before start */
+ while (!(read_STAT() & BIT_STAT_SPIF))
+ continue;
+
/* in duplex mode, clk is triggered by writing of TDBR */
while (drv_data->tx < drv_data->tx_end) {
write_TDBR(*(u16 *) (drv_data->tx));
@@ -513,16 +533,16 @@ 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)
{
struct chip_data *chip = drv_data->cur_chip;

+ /* poll for SPI completion before start */
+ while (!(read_STAT() & BIT_STAT_SPIF))
+ continue;
+
while (drv_data->tx < drv_data->tx_end) {
cs_active(chip);

@@ -539,10 +559,6 @@ static void u16_cs_chg_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;
}

/* test if ther is more transfer to be done */
@@ -765,6 +781,10 @@ static void pump_transfers(unsigned long data)
dma_width = WDSIZE_8;
}

+ /* poll for SPI completion before start */
+ while (!(read_STAT() & BIT_STAT_SPIF))
+ continue;
+
/* dirty hack for autobuffer DMA mode */
if (drv_data->tx_dma == 0xFFFF) {
dev_dbg(&drv_data->pdev->dev,
--
1.5.3.4

2007-10-30 09:21:51

by Bryan Wu

[permalink] [raw]
Subject: [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

Signed-off-by: Bryan Wu <[email protected]>
---
drivers/spi/spi_bfin5xx.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
index 5924903..41282bf 100644
--- a/drivers/spi/spi_bfin5xx.c
+++ b/drivers/spi/spi_bfin5xx.c
@@ -501,7 +501,7 @@ static void u16_cs_chg_reader(struct driver_data *drv_data)
cs_active(drv_data, chip);
dummy_read(drv_data);

- while (drv_data->rx < drv_data->rx_end) {
+ while (drv_data->rx < drv_data->rx_end - 2) {
cs_deactive(drv_data, chip);

if (chip->cs_chg_udelay)
--
1.5.3.4

2007-10-30 09:22:20

by Bryan Wu

[permalink] [raw]
Subject: [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

Fix bug reported by Cameron Barfield <[email protected]>
https://blackfin.uclinux.org/gf/project/uclinux-dist/forum/?action=ForumBrowse&forum_id=39&_forum_action=ForumMessageBrowse&thread_id=23630&feedback=Message%20replied.

Cc: Cameron Barfield <[email protected]>
Signed-off-by: Bryan Wu <[email protected]>
---
drivers/spi/spi_bfin5xx.c | 24 +++++++++---------------
include/asm-blackfin/bfin5xx_spi.h | 2 +-
2 files changed, 10 insertions(+), 16 deletions(-)

diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
index 41282bf..0b22932 100644
--- a/drivers/spi/spi_bfin5xx.c
+++ b/drivers/spi/spi_bfin5xx.c
@@ -132,7 +132,7 @@ struct chip_data {
u8 enable_dma;
u8 bits_per_word; /* 8 or 16 */
u8 cs_change_per_word;
- u8 cs_chg_udelay;
+ u16 cs_chg_udelay; /* Some devices require > 255usec delay */
void (*write) (struct driver_data *);
void (*read) (struct driver_data *);
void (*duplex) (struct driver_data *);
@@ -211,6 +211,10 @@ static void cs_deactive(struct driver_data *drv_data, struct chip_data *chip)
flag |= (chip->flag << 8);

write_FLAG(drv_data, flag);
+
+ /* Move delay here for consistency */
+ if (chip->cs_chg_udelay)
+ udelay(chip->cs_chg_udelay);
}

#define MAX_SPI_SSEL 7
@@ -307,10 +311,9 @@ static void u8_cs_chg_writer(struct driver_data *drv_data)
write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
while (read_STAT(drv_data) & BIT_STAT_TXS)
continue;
+
cs_deactive(drv_data, chip);

- if (chip->cs_chg_udelay)
- udelay(chip->cs_chg_udelay);
++drv_data->tx;
}
}
@@ -359,9 +362,6 @@ static void u8_cs_chg_reader(struct driver_data *drv_data)
while (drv_data->rx < drv_data->rx_end - 1) {
cs_deactive(drv_data, chip);

- if (chip->cs_chg_udelay)
- udelay(chip->cs_chg_udelay);
-
while (!(read_STAT(drv_data) & BIT_STAT_RXS))
continue;
cs_active(drv_data, chip);
@@ -412,10 +412,9 @@ static void u8_cs_chg_duplex(struct driver_data *drv_data)
while (!(read_STAT(drv_data) & BIT_STAT_RXS))
continue;
*(u8 *) (drv_data->rx) = read_RDBR(drv_data);
+
cs_deactive(drv_data, chip);

- if (chip->cs_chg_udelay)
- udelay(chip->cs_chg_udelay);
++drv_data->rx;
++drv_data->tx;
}
@@ -452,10 +451,9 @@ static void u16_cs_chg_writer(struct driver_data *drv_data)
write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
while ((read_STAT(drv_data) & BIT_STAT_TXS))
continue;
+
cs_deactive(drv_data, chip);

- if (chip->cs_chg_udelay)
- udelay(chip->cs_chg_udelay);
drv_data->tx += 2;
}
}
@@ -504,9 +502,6 @@ static void u16_cs_chg_reader(struct driver_data *drv_data)
while (drv_data->rx < drv_data->rx_end - 2) {
cs_deactive(drv_data, chip);

- if (chip->cs_chg_udelay)
- udelay(chip->cs_chg_udelay);
-
while (!(read_STAT(drv_data) & BIT_STAT_RXS))
continue;
cs_active(drv_data, chip);
@@ -557,10 +552,9 @@ static void u16_cs_chg_duplex(struct driver_data *drv_data)
while (!(read_STAT(drv_data) & BIT_STAT_RXS))
continue;
*(u16 *) (drv_data->rx) = read_RDBR(drv_data);
+
cs_deactive(drv_data, chip);

- if (chip->cs_chg_udelay)
- udelay(chip->cs_chg_udelay);
drv_data->rx += 2;
drv_data->tx += 2;
}
diff --git a/include/asm-blackfin/bfin5xx_spi.h b/include/asm-blackfin/bfin5xx_spi.h
index f617d87..d4485b3 100644
--- a/include/asm-blackfin/bfin5xx_spi.h
+++ b/include/asm-blackfin/bfin5xx_spi.h
@@ -162,7 +162,7 @@ struct bfin5xx_spi_chip {
u8 enable_dma;
u8 bits_per_word;
u8 cs_change_per_word;
- u8 cs_chg_udelay;
+ u16 cs_chg_udelay; /* Some devices require 16-bit delays */
};

#endif /* _SPI_CHANNEL_H_ */
--
1.5.3.4

2007-10-30 09:22:34

by Bryan Wu

[permalink] [raw]
Subject: [PATCH 11/14] Blackfin SPI driver: Move global SPI regs_base and dma_ch to struct driver_data

Test on BF54x SPI Flash with 2 SPI master driver enabled

Signed-off-by: Bryan Wu <[email protected]>
---
drivers/spi/spi_bfin5xx.c | 357 +++++++++++++++++++++++----------------------
1 files changed, 182 insertions(+), 175 deletions(-)

diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
index d69719b..5924903 100644
--- a/drivers/spi/spi_bfin5xx.c
+++ b/drivers/spi/spi_bfin5xx.c
@@ -63,29 +63,12 @@ MODULE_LICENSE("GPL");

#define IS_DMA_ALIGNED(x) (((u32)(x)&0x07)==0)

-static u32 spi_dma_ch;
-static u32 spi_regs_base;
-
-#define DEFINE_SPI_REG(reg, off) \
-static inline u16 read_##reg(void) \
- { return bfin_read16(spi_regs_base + off); } \
-static inline void write_##reg(u16 v) \
- {bfin_write16(spi_regs_base + off, v); }
-
-DEFINE_SPI_REG(CTRL, 0x00)
-DEFINE_SPI_REG(FLAG, 0x04)
-DEFINE_SPI_REG(STAT, 0x08)
-DEFINE_SPI_REG(TDBR, 0x0C)
-DEFINE_SPI_REG(RDBR, 0x10)
-DEFINE_SPI_REG(BAUD, 0x14)
-DEFINE_SPI_REG(SHAW, 0x18)
#define START_STATE ((void*)0)
#define RUNNING_STATE ((void*)1)
#define DONE_STATE ((void*)2)
#define ERROR_STATE ((void*)-1)
#define QUEUE_RUNNING 0
#define QUEUE_STOPPED 1
-int dma_requested;

struct driver_data {
/* Driver model hookup */
@@ -94,6 +77,9 @@ struct driver_data {
/* SPI framework hookup */
struct spi_master *master;

+ /* Regs base of SPI controller */
+ u32 regs_base;
+
/* BFIN hookup */
struct bfin5xx_spi_master *master_info;

@@ -118,9 +104,14 @@ struct driver_data {
void *tx_end;
void *rx;
void *rx_end;
+
+ /* DMA stuffs */
+ int dma_channel;
int dma_mapped;
+ int dma_requested;
dma_addr_t rx_dma;
dma_addr_t tx_dma;
+
size_t rx_map_len;
size_t tx_map_len;
u8 n_bytes;
@@ -147,20 +138,34 @@ struct chip_data {
void (*duplex) (struct driver_data *);
};

+#define DEFINE_SPI_REG(reg, off) \
+static inline u16 read_##reg(struct driver_data *drv_data) \
+ { return bfin_read16(drv_data->regs_base + off); } \
+static inline void write_##reg(struct driver_data *drv_data, u16 v) \
+ { bfin_write16(drv_data->regs_base + off, v); }
+
+DEFINE_SPI_REG(CTRL, 0x00)
+DEFINE_SPI_REG(FLAG, 0x04)
+DEFINE_SPI_REG(STAT, 0x08)
+DEFINE_SPI_REG(TDBR, 0x0C)
+DEFINE_SPI_REG(RDBR, 0x10)
+DEFINE_SPI_REG(BAUD, 0x14)
+DEFINE_SPI_REG(SHAW, 0x18)
+
static void bfin_spi_enable(struct driver_data *drv_data)
{
u16 cr;

- cr = read_CTRL();
- write_CTRL(cr | BIT_CTL_ENABLE);
+ cr = read_CTRL(drv_data);
+ write_CTRL(drv_data, (cr | BIT_CTL_ENABLE));
}

static void bfin_spi_disable(struct driver_data *drv_data)
{
u16 cr;

- cr = read_CTRL();
- write_CTRL(cr & (~BIT_CTL_ENABLE));
+ cr = read_CTRL(drv_data);
+ write_CTRL(drv_data, (cr & (~BIT_CTL_ENABLE)));
}

/* Caculate the SPI_BAUD register value based on input HZ */
@@ -180,32 +185,32 @@ static int flush(struct driver_data *drv_data)
unsigned long limit = loops_per_jiffy << 1;

/* wait for stop and clear stat */
- while (!(read_STAT() & BIT_STAT_SPIF) && limit--)
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF) && limit--)
continue;

- write_STAT(BIT_STAT_CLR);
+ write_STAT(drv_data, BIT_STAT_CLR);

return limit;
}

/* Chip select operation functions for cs_change flag */
-static void cs_active(struct chip_data *chip)
+static void cs_active(struct driver_data *drv_data, struct chip_data *chip)
{
- u16 flag = read_FLAG();
+ u16 flag = read_FLAG(drv_data);

flag |= chip->flag;
flag &= ~(chip->flag << 8);

- write_FLAG(flag);
+ write_FLAG(drv_data, flag);
}

-static void cs_deactive(struct chip_data *chip)
+static void cs_deactive(struct driver_data *drv_data, struct chip_data *chip)
{
- u16 flag = read_FLAG();
+ u16 flag = read_FLAG(drv_data);

flag |= (chip->flag << 8);

- write_FLAG(flag);
+ write_FLAG(drv_data, flag);
}

#define MAX_SPI_SSEL 7
@@ -217,16 +222,16 @@ static int restore_state(struct driver_data *drv_data)
int ret = 0;

/* Clear status and disable clock */
- write_STAT(BIT_STAT_CLR);
+ write_STAT(drv_data, BIT_STAT_CLR);
bfin_spi_disable(drv_data);
dev_dbg(&drv_data->pdev->dev, "restoring spi ctl state\n");

/* Load the registers */
- cs_deactive(chip);
- write_BAUD(chip->baud);
+ cs_deactive(drv_data, chip);
+ write_BAUD(drv_data, chip->baud);
chip->ctl_reg &= (~BIT_CTL_TIMOD);
chip->ctl_reg |= (chip->width << 8);
- write_CTRL(chip->ctl_reg);
+ write_CTRL(drv_data, chip->ctl_reg);

bfin_spi_enable(drv_data);

@@ -239,10 +244,10 @@ static int restore_state(struct driver_data *drv_data)
}

/* used to kick off transfer in rx mode */
-static unsigned short dummy_read(void)
+static unsigned short dummy_read(struct driver_data *drv_data)
{
unsigned short tmp;
- tmp = read_RDBR();
+ tmp = read_RDBR(drv_data);
return tmp;
}

@@ -251,8 +256,8 @@ static void null_writer(struct driver_data *drv_data)
u8 n_bytes = drv_data->n_bytes;

while (drv_data->tx < drv_data->tx_end) {
- write_TDBR(0);
- while ((read_STAT() & BIT_STAT_TXS))
+ write_TDBR(drv_data, 0);
+ while ((read_STAT(drv_data) & BIT_STAT_TXS))
continue;
drv_data->tx += n_bytes;
}
@@ -261,12 +266,12 @@ static void null_writer(struct driver_data *drv_data)
static void null_reader(struct driver_data *drv_data)
{
u8 n_bytes = drv_data->n_bytes;
- dummy_read();
+ dummy_read(drv_data);

while (drv_data->rx < drv_data->rx_end) {
- while (!(read_STAT() & BIT_STAT_RXS))
+ while (!(read_STAT(drv_data) & BIT_STAT_RXS))
continue;
- dummy_read();
+ dummy_read(drv_data);
drv_data->rx += n_bytes;
}
}
@@ -274,15 +279,15 @@ static void null_reader(struct driver_data *drv_data)
static void u8_writer(struct driver_data *drv_data)
{
dev_dbg(&drv_data->pdev->dev,
- "cr8-s is 0x%x\n", read_STAT());
+ "cr8-s is 0x%x\n", read_STAT(drv_data));

/* poll for SPI completion before start */
- while (!(read_STAT() & BIT_STAT_SPIF))
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
continue;

while (drv_data->tx < drv_data->tx_end) {
- write_TDBR(*(u8 *) (drv_data->tx));
- while (read_STAT() & BIT_STAT_TXS)
+ write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
+ while (read_STAT(drv_data) & BIT_STAT_TXS)
continue;
++drv_data->tx;
}
@@ -293,16 +298,16 @@ static void u8_cs_chg_writer(struct driver_data *drv_data)
struct chip_data *chip = drv_data->cur_chip;

/* poll for SPI completion before start */
- while (!(read_STAT() & BIT_STAT_SPIF))
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
continue;

while (drv_data->tx < drv_data->tx_end) {
- cs_active(chip);
+ cs_active(drv_data, chip);

- write_TDBR(*(u8 *) (drv_data->tx));
- while (read_STAT() & BIT_STAT_TXS)
+ write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
+ while (read_STAT(drv_data) & BIT_STAT_TXS)
continue;
- cs_deactive(chip);
+ cs_deactive(drv_data, chip);

if (chip->cs_chg_udelay)
udelay(chip->cs_chg_udelay);
@@ -313,27 +318,27 @@ static void u8_cs_chg_writer(struct driver_data *drv_data)
static void u8_reader(struct driver_data *drv_data)
{
dev_dbg(&drv_data->pdev->dev,
- "cr-8 is 0x%x\n", read_STAT());
+ "cr-8 is 0x%x\n", read_STAT(drv_data));

/* poll for SPI completion before start */
- while (!(read_STAT() & BIT_STAT_SPIF))
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
continue;

/* clear TDBR buffer before read(else it will be shifted out) */
- write_TDBR(0xFFFF);
+ write_TDBR(drv_data, 0xFFFF);

- dummy_read();
+ dummy_read(drv_data);

while (drv_data->rx < drv_data->rx_end - 1) {
- while (!(read_STAT() & BIT_STAT_RXS))
+ while (!(read_STAT(drv_data) & BIT_STAT_RXS))
continue;
- *(u8 *) (drv_data->rx) = read_RDBR();
+ *(u8 *) (drv_data->rx) = read_RDBR(drv_data);
++drv_data->rx;
}

- while (!(read_STAT() & BIT_STAT_RXS))
+ while (!(read_STAT(drv_data) & BIT_STAT_RXS))
continue;
- *(u8 *) (drv_data->rx) = read_SHAW();
+ *(u8 *) (drv_data->rx) = read_SHAW(drv_data);
++drv_data->rx;
}

@@ -342,49 +347,49 @@ static void u8_cs_chg_reader(struct driver_data *drv_data)
struct chip_data *chip = drv_data->cur_chip;

/* poll for SPI completion before start */
- while (!(read_STAT() & BIT_STAT_SPIF))
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
continue;

/* clear TDBR buffer before read(else it will be shifted out) */
- write_TDBR(0xFFFF);
+ write_TDBR(drv_data, 0xFFFF);

- cs_active(chip);
- dummy_read();
+ cs_active(drv_data, chip);
+ dummy_read(drv_data);

while (drv_data->rx < drv_data->rx_end - 1) {
- cs_deactive(chip);
+ cs_deactive(drv_data, chip);

if (chip->cs_chg_udelay)
udelay(chip->cs_chg_udelay);

- while (!(read_STAT() & BIT_STAT_RXS))
+ while (!(read_STAT(drv_data) & BIT_STAT_RXS))
continue;
- cs_active(chip);
- *(u8 *) (drv_data->rx) = read_RDBR();
+ cs_active(drv_data, chip);
+ *(u8 *) (drv_data->rx) = read_RDBR(drv_data);
++drv_data->rx;
}
- cs_deactive(chip);
+ cs_deactive(drv_data, chip);

- while (!(read_STAT() & BIT_STAT_RXS))
+ while (!(read_STAT(drv_data) & BIT_STAT_RXS))
continue;
- *(u8 *) (drv_data->rx) = read_SHAW();
+ *(u8 *) (drv_data->rx) = read_SHAW(drv_data);
++drv_data->rx;
}

static void u8_duplex(struct driver_data *drv_data)
{
/* poll for SPI completion before start */
- while (!(read_STAT() & BIT_STAT_SPIF))
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
continue;

/* 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_TXS)
+ write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
+ while (read_STAT(drv_data) & BIT_STAT_TXS)
continue;
- while (!(read_STAT() & BIT_STAT_RXS))
+ while (!(read_STAT(drv_data) & BIT_STAT_RXS))
continue;
- *(u8 *) (drv_data->rx) = read_RDBR();
+ *(u8 *) (drv_data->rx) = read_RDBR(drv_data);
++drv_data->rx;
++drv_data->tx;
}
@@ -395,19 +400,19 @@ static void u8_cs_chg_duplex(struct driver_data *drv_data)
struct chip_data *chip = drv_data->cur_chip;

/* poll for SPI completion before start */
- while (!(read_STAT() & BIT_STAT_SPIF))
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
continue;

while (drv_data->rx < drv_data->rx_end) {
- cs_active(chip);
+ cs_active(drv_data, chip);

- write_TDBR(*(u8 *) (drv_data->tx));
- while (read_STAT() & BIT_STAT_TXS)
+ write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
+ while (read_STAT(drv_data) & BIT_STAT_TXS)
continue;
- while (!(read_STAT() & BIT_STAT_RXS))
+ while (!(read_STAT(drv_data) & BIT_STAT_RXS))
continue;
- *(u8 *) (drv_data->rx) = read_RDBR();
- cs_deactive(chip);
+ *(u8 *) (drv_data->rx) = read_RDBR(drv_data);
+ cs_deactive(drv_data, chip);

if (chip->cs_chg_udelay)
udelay(chip->cs_chg_udelay);
@@ -419,15 +424,15 @@ static void u8_cs_chg_duplex(struct driver_data *drv_data)
static void u16_writer(struct driver_data *drv_data)
{
dev_dbg(&drv_data->pdev->dev,
- "cr16 is 0x%x\n", read_STAT());
+ "cr16 is 0x%x\n", read_STAT(drv_data));

/* poll for SPI completion before start */
- while (!(read_STAT() & BIT_STAT_SPIF))
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
continue;

while (drv_data->tx < drv_data->tx_end) {
- write_TDBR(*(u16 *) (drv_data->tx));
- while ((read_STAT() & BIT_STAT_TXS))
+ write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
+ while ((read_STAT(drv_data) & BIT_STAT_TXS))
continue;
drv_data->tx += 2;
}
@@ -438,16 +443,16 @@ static void u16_cs_chg_writer(struct driver_data *drv_data)
struct chip_data *chip = drv_data->cur_chip;

/* poll for SPI completion before start */
- while (!(read_STAT() & BIT_STAT_SPIF))
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
continue;

while (drv_data->tx < drv_data->tx_end) {
- cs_active(chip);
+ cs_active(drv_data, chip);

- write_TDBR(*(u16 *) (drv_data->tx));
- while ((read_STAT() & BIT_STAT_TXS))
+ write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
+ while ((read_STAT(drv_data) & BIT_STAT_TXS))
continue;
- cs_deactive(chip);
+ cs_deactive(drv_data, chip);

if (chip->cs_chg_udelay)
udelay(chip->cs_chg_udelay);
@@ -458,27 +463,27 @@ static void u16_cs_chg_writer(struct driver_data *drv_data)
static void u16_reader(struct driver_data *drv_data)
{
dev_dbg(&drv_data->pdev->dev,
- "cr-16 is 0x%x\n", read_STAT());
+ "cr-16 is 0x%x\n", read_STAT(drv_data));

/* poll for SPI completion before start */
- while (!(read_STAT() & BIT_STAT_SPIF))
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
continue;

/* clear TDBR buffer before read(else it will be shifted out) */
- write_TDBR(0xFFFF);
+ write_TDBR(drv_data, 0xFFFF);

- dummy_read();
+ dummy_read(drv_data);

while (drv_data->rx < (drv_data->rx_end - 2)) {
- while (!(read_STAT() & BIT_STAT_RXS))
+ while (!(read_STAT(drv_data) & BIT_STAT_RXS))
continue;
- *(u16 *) (drv_data->rx) = read_RDBR();
+ *(u16 *) (drv_data->rx) = read_RDBR(drv_data);
drv_data->rx += 2;
}

- while (!(read_STAT() & BIT_STAT_RXS))
+ while (!(read_STAT(drv_data) & BIT_STAT_RXS))
continue;
- *(u16 *) (drv_data->rx) = read_SHAW();
+ *(u16 *) (drv_data->rx) = read_SHAW(drv_data);
drv_data->rx += 2;
}

@@ -487,49 +492,49 @@ static void u16_cs_chg_reader(struct driver_data *drv_data)
struct chip_data *chip = drv_data->cur_chip;

/* poll for SPI completion before start */
- while (!(read_STAT() & BIT_STAT_SPIF))
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
continue;

/* clear TDBR buffer before read(else it will be shifted out) */
- write_TDBR(0xFFFF);
+ write_TDBR(drv_data, 0xFFFF);

- cs_active(chip);
- dummy_read();
+ cs_active(drv_data, chip);
+ dummy_read(drv_data);

while (drv_data->rx < drv_data->rx_end) {
- cs_deactive(chip);
+ cs_deactive(drv_data, chip);

if (chip->cs_chg_udelay)
udelay(chip->cs_chg_udelay);

- while (!(read_STAT() & BIT_STAT_RXS))
+ while (!(read_STAT(drv_data) & BIT_STAT_RXS))
continue;
- cs_active(chip);
- *(u16 *) (drv_data->rx) = read_RDBR();
+ cs_active(drv_data, chip);
+ *(u16 *) (drv_data->rx) = read_RDBR(drv_data);
drv_data->rx += 2;
}
- cs_deactive(chip);
+ cs_deactive(drv_data, chip);

- while (!(read_STAT() & BIT_STAT_RXS))
+ while (!(read_STAT(drv_data) & BIT_STAT_RXS))
continue;
- *(u16 *) (drv_data->rx) = read_SHAW();
+ *(u16 *) (drv_data->rx) = read_SHAW(drv_data);
drv_data->rx += 2;
}

static void u16_duplex(struct driver_data *drv_data)
{
/* poll for SPI completion before start */
- while (!(read_STAT() & BIT_STAT_SPIF))
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
continue;

/* 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_TXS)
+ write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
+ while (read_STAT(drv_data) & BIT_STAT_TXS)
continue;
- while (!(read_STAT() & BIT_STAT_RXS))
+ while (!(read_STAT(drv_data) & BIT_STAT_RXS))
continue;
- *(u16 *) (drv_data->rx) = read_RDBR();
+ *(u16 *) (drv_data->rx) = read_RDBR(drv_data);
drv_data->rx += 2;
drv_data->tx += 2;
}
@@ -540,19 +545,19 @@ static void u16_cs_chg_duplex(struct driver_data *drv_data)
struct chip_data *chip = drv_data->cur_chip;

/* poll for SPI completion before start */
- while (!(read_STAT() & BIT_STAT_SPIF))
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
continue;

while (drv_data->tx < drv_data->tx_end) {
- cs_active(chip);
+ cs_active(drv_data, chip);

- write_TDBR(*(u16 *) (drv_data->tx));
- while (read_STAT() & BIT_STAT_TXS)
+ write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
+ while (read_STAT(drv_data) & BIT_STAT_TXS)
continue;
- while (!(read_STAT() & BIT_STAT_RXS))
+ while (!(read_STAT(drv_data) & BIT_STAT_RXS))
continue;
- *(u16 *) (drv_data->rx) = read_RDBR();
- cs_deactive(chip);
+ *(u16 *) (drv_data->rx) = read_RDBR(drv_data);
+ cs_deactive(drv_data, chip);

if (chip->cs_chg_udelay)
udelay(chip->cs_chg_udelay);
@@ -603,12 +608,12 @@ static void giveback(struct driver_data *drv_data)

/* disable chip select signal. And not stop spi in autobuffer mode */
if (drv_data->tx_dma != 0xFFFF) {
- cs_deactive(chip);
+ cs_deactive(drv_data, chip);
bfin_spi_disable(drv_data);
}

if (!drv_data->cs_change)
- cs_deactive(chip);
+ cs_deactive(drv_data, chip);

if (msg->complete)
msg->complete(msg->context);
@@ -617,14 +622,14 @@ static void giveback(struct driver_data *drv_data)
static irqreturn_t dma_irq_handler(int irq, void *dev_id)
{
struct driver_data *drv_data = (struct driver_data *)dev_id;
- struct spi_message *msg = drv_data->cur_msg;
struct chip_data *chip = drv_data->cur_chip;
+ struct spi_message *msg = drv_data->cur_msg;

dev_dbg(&drv_data->pdev->dev, "in dma_irq_handler\n");
- clear_dma_irqstat(spi_dma_ch);
+ clear_dma_irqstat(drv_data->dma_channel);

/* Wait for DMA to complete */
- while (get_dma_curr_irqstat(spi_dma_ch) & DMA_RUN)
+ while (get_dma_curr_irqstat(drv_data->dma_channel) & DMA_RUN)
continue;

/*
@@ -634,18 +639,18 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id)
* register until it goes low for 2 successive reads
*/
if (drv_data->tx != NULL) {
- while ((read_STAT() & TXS) ||
- (read_STAT() & TXS))
+ while ((read_STAT(drv_data) & TXS) ||
+ (read_STAT(drv_data) & TXS))
continue;
}

- while (!(read_STAT() & SPIF))
+ while (!(read_STAT(drv_data) & SPIF))
continue;

msg->actual_length += drv_data->len_in_bytes;

if (drv_data->cs_change)
- cs_deactive(chip);
+ cs_deactive(drv_data, chip);

/* Move to next transfer */
msg->state = next_transfer(drv_data);
@@ -656,8 +661,8 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id)
/* free the irq handler before next transfer */
dev_dbg(&drv_data->pdev->dev,
"disable dma channel irq%d\n",
- spi_dma_ch);
- dma_disable_irq(spi_dma_ch);
+ drv_data->dma_channel);
+ dma_disable_irq(drv_data->dma_channel);

return IRQ_HANDLED;
}
@@ -751,9 +756,9 @@ static void pump_transfers(unsigned long data)
message->state = RUNNING_STATE;
dma_config = 0;

- write_STAT(BIT_STAT_CLR);
- cr = (read_CTRL() & (~BIT_CTL_TIMOD));
- cs_active(chip);
+ write_STAT(drv_data, BIT_STAT_CLR);
+ cr = (read_CTRL(drv_data) & (~BIT_CTL_TIMOD));
+ cs_active(drv_data, chip);

dev_dbg(&drv_data->pdev->dev,
"now pumping a transfer: width is %d, len is %d\n",
@@ -766,23 +771,23 @@ static void pump_transfers(unsigned long data)
*/
if (drv_data->cur_chip->enable_dma && drv_data->len > 6) {

- disable_dma(spi_dma_ch);
- clear_dma_irqstat(spi_dma_ch);
+ disable_dma(drv_data->dma_channel);
+ clear_dma_irqstat(drv_data->dma_channel);

/* config dma channel */
dev_dbg(&drv_data->pdev->dev, "doing dma transfer\n");
if (width == CFG_SPI_WORDSIZE16) {
- set_dma_x_count(spi_dma_ch, drv_data->len);
- set_dma_x_modify(spi_dma_ch, 2);
+ set_dma_x_count(drv_data->dma_channel, drv_data->len);
+ set_dma_x_modify(drv_data->dma_channel, 2);
dma_width = WDSIZE_16;
} else {
- set_dma_x_count(spi_dma_ch, drv_data->len);
- set_dma_x_modify(spi_dma_ch, 1);
+ set_dma_x_count(drv_data->dma_channel, drv_data->len);
+ set_dma_x_modify(drv_data->dma_channel, 1);
dma_width = WDSIZE_8;
}

/* poll for SPI completion before start */
- while (!(read_STAT() & BIT_STAT_SPIF))
+ while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
continue;

/* dirty hack for autobuffer DMA mode */
@@ -791,15 +796,15 @@ static void pump_transfers(unsigned long data)
"doing autobuffer DMA out.\n");

/* set SPI transfer mode */
- write_CTRL(cr | CFG_SPI_DMAWRITE);
+ write_CTRL(drv_data, (cr | CFG_SPI_DMAWRITE));

/* no irq in autobuffer mode */
dma_config =
(DMAFLOW_AUTO | RESTART | dma_width | DI_EN);
- set_dma_config(spi_dma_ch, dma_config);
- set_dma_start_addr(spi_dma_ch,
+ set_dma_config(drv_data->dma_channel, dma_config);
+ set_dma_start_addr(drv_data->dma_channel,
(unsigned long)drv_data->tx);
- enable_dma(spi_dma_ch);
+ enable_dma(drv_data->dma_channel);

/* just return here, there can only be one transfer in this mode */
message->status = 0;
@@ -813,34 +818,34 @@ static void pump_transfers(unsigned long data)
dev_dbg(&drv_data->pdev->dev, "doing DMA in.\n");

/* set SPI transfer mode */
- write_CTRL(cr | CFG_SPI_DMAREAD);
+ write_CTRL(drv_data, (cr | CFG_SPI_DMAREAD));

/* clear tx reg soformer data is not shifted out */
- write_TDBR(0xFFFF);
+ write_TDBR(drv_data, 0xFFFF);

- set_dma_x_count(spi_dma_ch, drv_data->len);
+ set_dma_x_count(drv_data->dma_channel, drv_data->len);

/* start dma */
- dma_enable_irq(spi_dma_ch);
+ dma_enable_irq(drv_data->dma_channel);
dma_config = (WNR | RESTART | dma_width | DI_EN);
- set_dma_config(spi_dma_ch, dma_config);
- set_dma_start_addr(spi_dma_ch,
+ set_dma_config(drv_data->dma_channel, dma_config);
+ set_dma_start_addr(drv_data->dma_channel,
(unsigned long)drv_data->rx);
- enable_dma(spi_dma_ch);
+ enable_dma(drv_data->dma_channel);

} 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);
+ write_CTRL(drv_data, (cr | CFG_SPI_DMAWRITE));

/* start dma */
- dma_enable_irq(spi_dma_ch);
+ dma_enable_irq(drv_data->dma_channel);
dma_config = (RESTART | dma_width | DI_EN);
- set_dma_config(spi_dma_ch, dma_config);
- set_dma_start_addr(spi_dma_ch,
+ set_dma_config(drv_data->dma_channel, dma_config);
+ set_dma_start_addr(drv_data->dma_channel,
(unsigned long)drv_data->tx);
- enable_dma(spi_dma_ch);
+ enable_dma(drv_data->dma_channel);
}
} else {
/* IO mode write then read */
@@ -854,7 +859,7 @@ static void pump_transfers(unsigned long data)
"IO duplex: cr is 0x%x\n", cr);

/* set SPI transfer mode */
- write_CTRL(cr | CFG_SPI_WRITE);
+ write_CTRL(drv_data, (cr | CFG_SPI_WRITE));

drv_data->duplex(drv_data);

@@ -866,7 +871,7 @@ static void pump_transfers(unsigned long data)
"IO write: cr is 0x%x\n", cr);

/* set SPI transfer mode */
- write_CTRL(cr | CFG_SPI_WRITE);
+ write_CTRL(drv_data, (cr | CFG_SPI_WRITE));

drv_data->write(drv_data);

@@ -878,7 +883,7 @@ static void pump_transfers(unsigned long data)
"IO read: cr is 0x%x\n", cr);

/* set SPI transfer mode */
- write_CTRL(cr | CFG_SPI_READ);
+ write_CTRL(drv_data, (cr | CFG_SPI_READ));

drv_data->read(drv_data);
if (drv_data->rx != drv_data->rx_end)
@@ -1071,20 +1076,20 @@ static int setup(struct spi_device *spi)
* if any one SPI chip is registered and wants DMA, request the
* DMA channel for it
*/
- if (chip->enable_dma && !dma_requested) {
+ if (chip->enable_dma && !drv_data->dma_requested) {
/* register dma irq handler */
- if (request_dma(spi_dma_ch, "BF53x_SPI_DMA") < 0) {
+ if (request_dma(drv_data->dma_channel, "BF53x_SPI_DMA") < 0) {
dev_dbg(&spi->dev,
"Unable to request BlackFin SPI DMA channel\n");
return -ENODEV;
}
- if (set_dma_callback(spi_dma_ch, (void *)dma_irq_handler,
- drv_data) < 0) {
+ if (set_dma_callback(drv_data->dma_channel,
+ (void *)dma_irq_handler, drv_data) < 0) {
dev_dbg(&spi->dev, "Unable to set dma callback\n");
return -EPERM;
}
- dma_disable_irq(spi_dma_ch);
- dma_requested = 1;
+ dma_disable_irq(drv_data->dma_channel);
+ drv_data->dma_requested = 1;
}

/*
@@ -1299,15 +1304,16 @@ static int __init bfin5xx_spi_probe(struct platform_device *pdev)
goto out_error_get_res;
}

- spi_regs_base = (u32) ioremap(res->start, (res->end - res->start)+1);
- if (!spi_regs_base) {
+ drv_data->regs_base = (u32) ioremap(res->start,
+ (res->end - res->start + 1));
+ if (!drv_data->regs_base) {
dev_err(dev, "Cannot map IO\n");
status = -ENXIO;
goto out_error_ioremap;
}

- spi_dma_ch = platform_get_irq(pdev, 0);
- if (spi_dma_ch < 0) {
+ drv_data->dma_channel = platform_get_irq(pdev, 0);
+ if (drv_data->dma_channel < 0) {
dev_err(dev, "No DMA channel specified\n");
status = -ENOENT;
goto out_error_no_dma_ch;
@@ -1339,14 +1345,15 @@ static int __init bfin5xx_spi_probe(struct platform_device *pdev)
goto out_error;
}

- dev_info(dev, "%s, Version %s, regs_base @ 0x%08x\n",
- DRV_DESC, DRV_VERSION, spi_regs_base);
+ dev_info(dev, "%s, Version %s, regs_base@0x%08x, dma channel@%d\n",
+ DRV_DESC, DRV_VERSION, drv_data->regs_base,
+ drv_data->dma_channel);
return status;

out_error_queue_alloc:
destroy_queue(drv_data);
out_error_no_dma_ch:
- iounmap((void *) spi_regs_base);
+ iounmap((void *) drv_data->regs_base);
out_error_ioremap:
out_error_get_res:
out_error:
@@ -1374,8 +1381,8 @@ static int __devexit bfin5xx_spi_remove(struct platform_device *pdev)

/* Release DMA */
if (drv_data->master_info->enable_dma) {
- if (dma_channel_active(spi_dma_ch))
- free_dma(spi_dma_ch);
+ if (dma_channel_active(drv_data->dma_channel))
+ free_dma(drv_data->dma_channel);
}

/* Disconnect from the SPI framework */
--
1.5.3.4

2007-10-30 09:22:51

by Bryan Wu

[permalink] [raw]
Subject: [PATCH 14/14] Blackfin SPI driver: set correct baud for spi mmc and enable SPI after DMA.

From: Sonic Zhang <[email protected]>

SPI is enabled only after DMA is started.

Signed-off-by: Sonic Zhang <[email protected]>
Signed-off-by: Bryan Wu <[email protected]>
---
drivers/spi/spi_bfin5xx.c | 23 +++++++++++++----------
1 files changed, 13 insertions(+), 10 deletions(-)

diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
index 0b22932..83c866d 100644
--- a/drivers/spi/spi_bfin5xx.c
+++ b/drivers/spi/spi_bfin5xx.c
@@ -231,13 +231,13 @@ static int restore_state(struct driver_data *drv_data)
dev_dbg(&drv_data->pdev->dev, "restoring spi ctl state\n");

/* Load the registers */
- cs_deactive(drv_data, chip);
write_BAUD(drv_data, chip->baud);
chip->ctl_reg &= (~BIT_CTL_TIMOD);
chip->ctl_reg |= (chip->width << 8);
write_CTRL(drv_data, chip->ctl_reg);

bfin_spi_enable(drv_data);
+ cs_active(drv_data, chip);

if (ret)
dev_dbg(&drv_data->pdev->dev,
@@ -767,6 +767,7 @@ static void pump_transfers(unsigned long data)

disable_dma(drv_data->dma_channel);
clear_dma_irqstat(drv_data->dma_channel);
+ bfin_spi_disable(drv_data);

/* config dma channel */
dev_dbg(&drv_data->pdev->dev, "doing dma transfer\n");
@@ -789,9 +790,6 @@ static void pump_transfers(unsigned long data)
dev_dbg(&drv_data->pdev->dev,
"doing autobuffer DMA out.\n");

- /* set SPI transfer mode */
- write_CTRL(drv_data, (cr | CFG_SPI_DMAWRITE));
-
/* no irq in autobuffer mode */
dma_config =
(DMAFLOW_AUTO | RESTART | dma_width | DI_EN);
@@ -800,6 +798,9 @@ static void pump_transfers(unsigned long data)
(unsigned long)drv_data->tx);
enable_dma(drv_data->dma_channel);

+ /* start SPI transfer */
+ write_CTRL(drv_data, (cr | CFG_SPI_DMAWRITE | BIT_CTL_ENABLE));
+
/* just return here, there can only be one transfer in this mode */
message->status = 0;
giveback(drv_data);
@@ -811,9 +812,6 @@ static void pump_transfers(unsigned long data)
/* set transfer mode, and enable SPI */
dev_dbg(&drv_data->pdev->dev, "doing DMA in.\n");

- /* set SPI transfer mode */
- write_CTRL(drv_data, (cr | CFG_SPI_DMAREAD));
-
/* clear tx reg soformer data is not shifted out */
write_TDBR(drv_data, 0xFFFF);

@@ -827,12 +825,12 @@ static void pump_transfers(unsigned long data)
(unsigned long)drv_data->rx);
enable_dma(drv_data->dma_channel);

+ /* start SPI transfer */
+ write_CTRL(drv_data, (cr | CFG_SPI_DMAREAD | BIT_CTL_ENABLE));
+
} else if (drv_data->tx != NULL) {
dev_dbg(&drv_data->pdev->dev, "doing DMA out.\n");

- /* set SPI transfer mode */
- write_CTRL(drv_data, (cr | CFG_SPI_DMAWRITE));
-
/* start dma */
dma_enable_irq(drv_data->dma_channel);
dma_config = (RESTART | dma_width | DI_EN);
@@ -840,6 +838,9 @@ static void pump_transfers(unsigned long data)
set_dma_start_addr(drv_data->dma_channel,
(unsigned long)drv_data->tx);
enable_dma(drv_data->dma_channel);
+
+ /* start SPI transfer */
+ write_CTRL(drv_data, (cr | CFG_SPI_DMAWRITE | BIT_CTL_ENABLE));
}
} else {
/* IO mode write then read */
@@ -1138,6 +1139,8 @@ static int setup(struct spi_device *spi)
peripheral_request(ssel[spi->master->bus_num]
[chip->chip_select_num-1], DRV_NAME);

+ cs_deactive(drv_data, chip);
+
return 0;
}

--
1.5.3.4

2007-10-30 19:08:24

by David Brownell

[permalink] [raw]
Subject: Re: [PATCH 07/14] Blackfin SPI driver: Add SPI master controller platform device 1

On Tuesday 30 October 2007, Bryan Wu wrote:
> From: Sonic Zhang <[email protected]>
>
> Signed-off-by: Sonic Zhang <[email protected]>
> Signed-off-by: Bryan Wu <[email protected]>

The patch comments in this series leave a bit to be desired,
especially patches from Sonic. (Several are like this one:
just a $SUBJECT, no description.) I've improved them in the
versions I'll be sending on ...

It's worth noting that in this case the $SUBJECT doesn't
relate *at all* to what this patch actually does! Namely,
it uses the portmux mechanism to add support for two more
SPI buses ... it doesn't add a platform device.

- Dave

> ---
> drivers/spi/spi_bfin5xx.c | 52 ++++++++++++++++++++++++++------------------
> 1 files changed, 31 insertions(+), 21 deletions(-)
>
> diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
> index 3f3630c..3bd8359 100644
> --- a/drivers/spi/spi_bfin5xx.c
> +++ b/drivers/spi/spi_bfin5xx.c
> @@ -209,17 +209,26 @@ static void cs_deactive(struct chip_data *chip)
> write_FLAG(flag);
> }
>
> -#define MAX_SPI0_SSEL 7
> +#define MAX_SPI_SSEL 7
>
> /* stop controller and re-config current chip*/
> static int restore_state(struct driver_data *drv_data)
> {
> struct chip_data *chip = drv_data->cur_chip;
> int ret = 0;
> - u16 ssel[MAX_SPI0_SSEL] = {P_SPI0_SSEL1, P_SPI0_SSEL2, P_SPI0_SSEL3,
> - P_SPI0_SSEL4, P_SPI0_SSEL5,
> - P_SPI0_SSEL6, P_SPI0_SSEL7,};
> -
> + u16 ssel[3][MAX_SPI_SSEL] = {
> + {P_SPI0_SSEL1, P_SPI0_SSEL2, P_SPI0_SSEL3,
> + P_SPI0_SSEL4, P_SPI0_SSEL5,
> + P_SPI0_SSEL6, P_SPI0_SSEL7},
> +
> + {P_SPI1_SSEL1, P_SPI1_SSEL2, P_SPI1_SSEL3,
> + P_SPI1_SSEL4, P_SPI1_SSEL5,
> + P_SPI1_SSEL6, P_SPI1_SSEL7},
> +
> + {P_SPI2_SSEL1, P_SPI2_SSEL2, P_SPI2_SSEL3,
> + P_SPI2_SSEL4, P_SPI2_SSEL5,
> + P_SPI2_SSEL6, P_SPI2_SSEL7},
> + };
> /* Clear status and disable clock */
> write_STAT(BIT_STAT_CLR);
> bfin_spi_disable(drv_data);
> @@ -234,9 +243,9 @@ static int restore_state(struct driver_data *drv_data)
> int i = chip->chip_select_num;
>
> dev_dbg(&drv_data->pdev->dev, "chip select number is %d\n", i);
> -
> - if ((i > 0) && (i <= MAX_SPI0_SSEL))
> - ret = peripheral_request(ssel[i-1], DRV_NAME);
> + if ((i > 0) && (i <= MAX_SPI_SSEL))
> + ret = peripheral_request(
> + ssel[drv_data->master->bus_num][i-1], DRV_NAME);
>
> chip->chip_select_requested = 1;
> }
> @@ -329,7 +338,6 @@ 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;
> @@ -640,7 +648,6 @@ static void pump_transfers(unsigned long data)
> message = drv_data->cur_msg;
> transfer = drv_data->cur_transfer;
> chip = drv_data->cur_chip;
> -
> /*
> * if msg is error or done, report it back using complete() callback
> */
> @@ -1202,17 +1209,20 @@ static inline int destroy_queue(struct driver_data *drv_data)
> return 0;
> }
>
> -static int setup_pin_mux(int action)
> +static int setup_pin_mux(int action, int bus_num)
> {
>
> - u16 pin_req[] = {P_SPI0_SCK, P_SPI0_MISO, P_SPI0_MOSI, 0};
> + u16 pin_req[3][4] = {
> + {P_SPI0_SCK, P_SPI0_MISO, P_SPI0_MOSI, 0},
> + {P_SPI1_SCK, P_SPI1_MISO, P_SPI1_MOSI, 0},
> + {P_SPI2_SCK, P_SPI2_MISO, P_SPI2_MOSI, 0},
> + };
>
> if (action) {
> - if (peripheral_request_list(pin_req, DRV_NAME)) {
> + if (peripheral_request_list(pin_req[bus_num], DRV_NAME))
> return -EFAULT;
> - }
> } else {
> - peripheral_free_list(pin_req);
> + peripheral_free_list(pin_req[bus_num]);
> }
>
> return 0;
> @@ -1236,11 +1246,6 @@ static int __init bfin5xx_spi_probe(struct platform_device *pdev)
> return -ENOMEM;
> }
>
> - if (setup_pin_mux(1)) {
> - dev_err(&pdev->dev, ": Requesting Peripherals failed\n");
> - goto out_error;
> - }
> -
> drv_data = spi_master_get_devdata(master);
> drv_data->master = master;
> drv_data->master_info = platform_info;
> @@ -1295,6 +1300,11 @@ static int __init bfin5xx_spi_probe(struct platform_device *pdev)
> goto out_error_queue_alloc;
> }
>
> + if (setup_pin_mux(1, master->bus_num)) {
> + dev_err(&pdev->dev, ": Requesting Peripherals failed\n");
> + goto out_error;
> + }
> +
> dev_info(dev, "%s, Version %s, regs_base @ 0x%08x\n",
> DRV_DESC, DRV_VERSION, spi_regs_base);
> return status;
> @@ -1337,7 +1347,7 @@ static int __devexit bfin5xx_spi_remove(struct platform_device *pdev)
> /* Disconnect from the SPI framework */
> spi_unregister_master(drv_data->master);
>
> - setup_pin_mux(0);
> + setup_pin_mux(0, drv_data->master->bus_num);
>
> /* Prevent double remove */
> platform_set_drvdata(pdev, NULL);
> --
> 1.5.3.4
>


2007-10-30 20:24:33

by David Brownell

[permalink] [raw]
Subject: Re: [PATCH 09/14] Blackfin SPI driver: Fix SPI driver to work with SPI flash ST25P16 on bf548

On Tuesday 30 October 2007, Bryan Wu wrote:
> 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.

That's actually not true. If a driver sets spi_transfer.max_speed_hz
to a nonzero value that's different from the previous bit rate (which
may be spi_device.max_speed_hz), it should be updated before that
transfer segment. Example, sometimes data can't be clocked out at
the same rate commands can be clocked in.

Similarly with spi_transfer.bits_per_word ... again, it's very possible
that commands and data have different sizes.

Of course, if those values don't change, there'd be no point in
reconfiguring any aspect of those communications parameters...


I'll be forwarding this patch, since this looks like another case
where the main effect of the patch doesn't match its description
and since this patch series has taken too long already. (Does this
patch even really relate primarily to working with an ST M25P16
flash part??) Though it'd be reasonable to be more hard-nosed
about this and insist on another go-around for thesse patches.
(Making this the fifth one??)

But I *STRONGLY* suggest someone revisit the issue of whether those
two per-transfer options are now being handled correctly. As well
as update procedures so that the patch comments start to have a
direct correspondence to what the patches have changed...

- Dave


> This patch
> move move SPI setting to the begining of a message session. And never
> disables SPI controller until an error occurs.




2007-10-30 20:24:49

by David Brownell

[permalink] [raw]
Subject: Re: [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

On Tuesday 30 October 2007, Bryan Wu wrote:
> @@ -211,6 +211,10 @@ static void cs_deactive(struct driver_data *drv_data, struct chip_data *chip)
> ????????flag |= (chip->flag << 8);
> ?
> ????????write_FLAG(drv_data, flag);
> +
> +???????/* Move delay here for consistency */
> +???????if (chip->cs_chg_udelay)
> +???????????????udelay(chip->cs_chg_udelay);
> ?}
> ?

By the way, if this is something needed very often, that mechanism
should be moved into the SPI framework. It wouldn't be polite if
such LCD drivers could only work on Blackfin boards. :)

2007-10-30 20:25:10

by David Brownell

[permalink] [raw]
Subject: Re: [PATCH 00/14] Blackfin on-chip SPI controller driver updates and bug-fixing

On Tuesday 30 October 2007, Bryan Wu wrote:
> - BF54x supported
> - multi-port supported
> - bunch of bug fixing

OK, I forwarded these with some more checkpatch.pl fixes.

But as I commented elsewhere, please work harder to make sure
that your patch comments actually match the patches!!

And also, pay closer attention to when you may be making
changes that make device drivers work differently over
your spi_master controller driver than anyone elses ...
such platform-specific behaviors are undesirable, and when
they go against specified behavior they are also bugs.

- Dave


2007-10-30 20:29:55

by Mike Frysinger

[permalink] [raw]
Subject: Re: [PATCH 00/14] Blackfin on-chip SPI controller driver updates and bug-fixing

On 10/30/07, David Brownell <[email protected]> wrote:
> And also, pay closer attention to when you may be making
> changes that make device drivers work differently over
> your spi_master controller driver than anyone elses ...
> such platform-specific behaviors are undesirable, and when
> they go against specified behavior they are also bugs.

was there something that caught your eye other than the ugly udelay()
you mentioned in the other thread ?
-mike

2007-10-30 20:42:30

by David Brownell

[permalink] [raw]
Subject: Re: [PATCH 00/14] Blackfin on-chip SPI controller driver updates and bug-fixing

On Tuesday 30 October 2007, Mike Frysinger wrote:
> On 10/30/07, David Brownell <[email protected]> wrote:
> > And also, pay closer attention to when you may be making
> > changes that make device drivers work differently over
> > your spi_master controller driver than anyone elses ...
> > such platform-specific behaviors are undesirable, and when
> > they go against specified behavior they are also bugs.
>
> was there something that caught your eye other than the ugly udelay()
> you mentioned in the other thread ?

That one was a feature that might be more generally necessary,
just to meet chip timing specs. Mostly they're no trouble.
But sometimes there are constraints around chipselect, or at
particular points in a protocol exchange ... as you know, SPI
has no in-band synchronization, so timing delays are about as
good as any standardized infrastructure can get. So if that
particular timing tweak was essential to make that driver work,
it might be something the API should address -- instead of just
a particular controller.

The other point was the handling of the two spi_transfer protocol
tweaking options. The comment went against the interface spec.
Now, maybe that was an issue of weak English skills ... but from
my scanning the patch, I got the impression one intent of that
patch really was to do what the comment said. (Of course it did
a lot of other stuff, which looked less dubious and might have
had a lot more to do with why the patch made that m25p16 chip
behave on that new board.)

- Dave

2007-10-30 21:12:56

by David Brownell

[permalink] [raw]
Subject: Re: [PATCH 00/14] Blackfin on-chip SPI controller driver updates and bug-fixing

On Tuesday 30 October 2007, David Brownell wrote:
> >
> > was there something that caught your eye other than the ugly udelay()
> > you mentioned in the other thread ?
>
> That one was a feature that might be more generally necessary,
> just to meet chip timing specs. ?Mostly they're no trouble.
>

... although I note that the referenced thread suggested maybe
the problem there was a missing pullup on the chipselect line. If
that was really the cause, then I think that feature would best
be left out of the framework. :)


2007-10-31 04:18:24

by Bryan Wu

[permalink] [raw]
Subject: Re: [PATCH 07/14] Blackfin SPI driver: Add SPI master controller platform device 1


On Tue, 2007-10-30 at 12:08 -0700, David Brownell wrote:
> On Tuesday 30 October 2007, Bryan Wu wrote:
> > From: Sonic Zhang <[email protected]>
> >
> > Signed-off-by: Sonic Zhang <[email protected]>
> > Signed-off-by: Bryan Wu <[email protected]>
>
> The patch comments in this series leave a bit to be desired,
> especially patches from Sonic. (Several are like this one:
> just a $SUBJECT, no description.) I've improved them in the
> versions I'll be sending on ...
>
Sorry, that's my fault.

Sonic's original patch modified this driver file and the Blackfin arch
related files. So I separated the patch to this SPI driver specific code
and Blackfin arch related patch which should be merged in Blackfin git
tree.

But I didn't change the description and subject here.

> It's worth noting that in this case the $SUBJECT doesn't
> relate *at all* to what this patch actually does! Namely,
> it uses the portmux mechanism to add support for two more
> SPI buses ... it doesn't add a platform device.
>

Sorry again, it will not happen again.

-Bryan Wu

2007-10-31 06:30:32

by Bryan Wu

[permalink] [raw]
Subject: Re: [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


On Tue, 2007-10-30 at 13:18 -0700, David Brownell wrote:
> On Tuesday 30 October 2007, Bryan Wu wrote:
> > @@ -211,6 +211,10 @@ static void cs_deactive(struct driver_data *drv_data, struct chip_data *chip)
> > flag |= (chip->flag << 8);
> >
> > write_FLAG(drv_data, flag);
> > +
> > + /* Move delay here for consistency */
> > + if (chip->cs_chg_udelay)
> > + udelay(chip->cs_chg_udelay);
> > }
> >
>
> By the way, if this is something needed very often, that mechanism
> should be moved into the SPI framework. It wouldn't be polite if
> such LCD drivers could only work on Blackfin boards. :)

I am not sure whether this LCD needs cs_chg_udelay on other boards.
It is found by Cameron Barfield. Maybe it is some timing requirement for
specific hardware.

-Bryan Wu

2007-10-31 06:50:47

by Bryan Wu

[permalink] [raw]
Subject: Re: [PATCH 09/14] Blackfin SPI driver: Fix SPI driver to work with SPI flash ST25P16 on bf548


On Tue, 2007-10-30 at 13:05 -0700, David Brownell wrote:
> On Tuesday 30 October 2007, Bryan Wu wrote:
> > 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.
>
> That's actually not true. If a driver sets spi_transfer.max_speed_hz
> to a nonzero value that's different from the previous bit rate (which
> may be spi_device.max_speed_hz), it should be updated before that
> transfer segment. Example, sometimes data can't be clocked out at
> the same rate commands can be clocked in.
>
> Similarly with spi_transfer.bits_per_word ... again, it's very possible
> that commands and data have different sizes.
>
I agree with you here.

Maybe there are some confusion of mixing up the spi_trasnfer.speed_hz
with the spi_device.max_speed_hz.

spi_device.max_speed_hz comes from spi_board_info.max_speed_hz, it is
for the default max speed value.
spi_transfer.speed_hz comes from upper applications for each spi
transfer setting.

Am I right?

I will fix this later.

> Of course, if those values don't change, there'd be no point in
> reconfiguring any aspect of those communications parameters...
>
>
> I'll be forwarding this patch, since this looks like another case
> where the main effect of the patch doesn't match its description
> and since this patch series has taken too long already. (Does this
> patch even really relate primarily to working with an ST M25P16
> flash part??) Though it'd be reasonable to be more hard-nosed
> about this and insist on another go-around for thesse patches.
> (Making this the fifth one??)
>
> But I *STRONGLY* suggest someone revisit the issue of whether those
> two per-transfer options are now being handled correctly. As well
> as update procedures so that the patch comments start to have a
> direct correspondence to what the patches have changed...
>

OK, we will test this on our hardware.
Thanks, Dave
-Bryan Wu

2007-10-31 07:11:44

by David Brownell

[permalink] [raw]
Subject: Re: [PATCH 09/14] Blackfin SPI driver: Fix SPI driver to work with SPI flash ST25P16 on bf548

On Tuesday 30 October 2007, Bryan Wu wrote:
> Maybe there are some confusion of mixing up the spi_trasnfer.speed_hz
> with the spi_device.max_speed_hz.
>
> spi_device.max_speed_hz comes from spi_board_info.max_speed_hz, it is
> for the default max speed value.

It's initialized from board_info, yes. Drivers can override it
using spi_setup().

One would expect they only override _downwards_ but that's not
guaranteed anywhere. A driver might have a way to establish that
this particular board can run faster, for example.


> spi_transfer.speed_hz comes from upper applications for each spi
> transfer setting.

Certainly; all spi_transfer records come from applications!
If that value is zero, that transfer segment uses the limit
from the spi_device ... otherwise, it can differ. Again,
the limits can vary based on devise characteristics; maybe
it can't feed data as fast for some commands.

(ISTR the M25P16 in $SUBJECT has two read commands, one of
which is only usable at clock rates below 33 MHz or so, but
most other commands can work above that speed just fine.)

- Dave

2007-10-31 07:35:26

by Bryan Wu

[permalink] [raw]
Subject: Re: [PATCH 09/14] Blackfin SPI driver: Fix SPI driver to work with SPI flash ST25P16 on bf548


On Wed, 2007-10-31 at 00:11 -0700, David Brownell wrote:
> On Tuesday 30 October 2007, Bryan Wu wrote:
> > Maybe there are some confusion of mixing up the spi_trasnfer.speed_hz
> > with the spi_device.max_speed_hz.
> >
> > spi_device.max_speed_hz comes from spi_board_info.max_speed_hz, it is
> > for the default max speed value.
>
> It's initialized from board_info, yes. Drivers can override it
> using spi_setup().
>
> One would expect they only override _downwards_ but that's not
> guaranteed anywhere. A driver might have a way to establish that
> this particular board can run faster, for example.
>

IMO, the spi_transfer.speed_hz <= spi_board_info.max_speed_hz and if
spi_trasnfer.speed_hz is 0, we should use spi_board_info.max_speed_hz.
>From the meaning of max_speed_hz, the spi_transfer.speed_hz should not
beyond max_speed_hz.

In your explanation, the max_speed_hz is just a default value. the
transfer speed_hz can beyond max_speed_hz. We found the bug in M25P16
should be related this missing checking of the transfer speed_hz.

>
> > spi_transfer.speed_hz comes from upper applications for each spi
> > transfer setting.
>
> Certainly; all spi_transfer records come from applications!
> If that value is zero, that transfer segment uses the limit
> from the spi_device ... otherwise, it can differ. Again,
> the limits can vary based on devise characteristics; maybe
> it can't feed data as fast for some commands.
>
> (ISTR the M25P16 in $SUBJECT has two read commands, one of
> which is only usable at clock rates below 33 MHz or so, but
> most other commands can work above that speed just fine.)
>
OK, We check it on Blackfin board.
-Bryan Wu

2007-10-31 08:02:55

by David Brownell

[permalink] [raw]
Subject: Re: [PATCH 09/14] Blackfin SPI driver: Fix SPI driver to work with SPI flash ST25P16 on bf548

On Wednesday 31 October 2007, Bryan Wu wrote:
> IMO, the spi_transfer.speed_hz <= spi_board_info.max_speed_hz and if
> spi_trasnfer.speed_hz is 0, we should use spi_board_info.max_speed_hz.
> From the meaning of max_speed_hz, the spi_transfer.speed_hz should not
> beyond max_speed_hz.

According to the interface spec that's not how it works; so I'm
not sure what you base your opinion on. It's not defined with
such constraints.

That might be a reasonable policy to adopt in many cases, and
nothing prevents any given protocol driver from choosing to follow
it. But likewise, if the driver chooses _not_ to follow it, it's
wrong for a controller driver to add its own private rules.


> In your explanation, the max_speed_hz is just a default value. the
> transfer speed_hz can beyond max_speed_hz.

Kerneldoc for board info says;

* @max_speed_hz: Initializes spi_device.max_speed_hz; based on limits
* from the chip datasheet and board-specific signal quality issues.

So yes -- initial value, it can be changed. If a driver says

spi->max_speed_hz = X;
spi_setup(spi);

that's how it requests a different clock rate ceiling. It can lower
the rate; it can raise it.


The reason it's called max_speed_hz is that most systems compute the
clock rate by dividing a base clock, and few can achieve that exact
value. The name indicates that it's to be treated as an upper limit,
not a lower limit or exact value. The controller driver should get
as close to that rate as it can, without going over.


> We found the bug in M25P16
> should be related this missing checking of the transfer ?speed_hz.

The m25p80 driver doesn't change that value...

So if there was any issue there, it must have been related to
something else in your controller driver.

- Dave

2007-10-31 08:33:36

by Mike Frysinger

[permalink] [raw]
Subject: Re: [PATCH 09/14] Blackfin SPI driver: Fix SPI driver to work with SPI flash ST25P16 on bf548

On 10/31/07, David Brownell <[email protected]> wrote:
> (ISTR the M25P16 in $SUBJECT has two read commands, one of
> which is only usable at clock rates below 33 MHz or so, but
> most other commands can work above that speed just fine.)

pretty much all SPI flashes have two read commands ("slow" and "fast"
as they're typically called). i dont think any of the linux drivers
though use the "slow" reads with any SPI flashes ... that'd be silly
:)
-mike

2007-10-31 08:53:09

by Bryan Wu

[permalink] [raw]
Subject: Re: [PATCH 09/14] Blackfin SPI driver: Fix SPI driver to work with SPI flash ST25P16 on bf548


On Wed, 2007-10-31 at 01:02 -0700, David Brownell wrote:
> On Wednesday 31 October 2007, Bryan Wu wrote:
> > IMO, the spi_transfer.speed_hz <= spi_board_info.max_speed_hz and if
> > spi_trasnfer.speed_hz is 0, we should use spi_board_info.max_speed_hz.
> > From the meaning of max_speed_hz, the spi_transfer.speed_hz should not
> > beyond max_speed_hz.
>
> According to the interface spec that's not how it works; so I'm
> not sure what you base your opinion on. It's not defined with
> such constraints.
>
My opinion is based on the name of max_speed_hz.
Actually, I know it is for the controller to compute the baud rate from
system bus clock or something similar.

> That might be a reasonable policy to adopt in many cases, and
> nothing prevents any given protocol driver from choosing to follow
> it. But likewise, if the driver chooses _not_ to follow it, it's
> wrong for a controller driver to add its own private rules.
>
> > In your explanation, the max_speed_hz is just a default value. the
> > transfer speed_hz can beyond max_speed_hz.
>
> Kerneldoc for board info says;
>
> * @max_speed_hz: Initializes spi_device.max_speed_hz; based on limits
> * from the chip datasheet and board-specific signal quality issues.
>
> So yes -- initial value, it can be changed. If a driver says
>
> spi->max_speed_hz = X;
> spi_setup(spi);
>
> that's how it requests a different clock rate ceiling. It can lower
> the rate; it can raise it.
>
>
> The reason it's called max_speed_hz is that most systems compute the
> clock rate by dividing a base clock, and few can achieve that exact
> value. The name indicates that it's to be treated as an upper limit,
> not a lower limit or exact value. The controller driver should get
> as close to that rate as it can, without going over.
>

Thanks for this clarification.
max_speed_hz acts as a default clock rate ceiling in the spi_setup(spi)
At the beginning of each real spi transfer, we should check the
spi_transfer.speed_hz like this:

---
/* Speed setup (surely valid because already checked) */
tmp = transfer->speed_hz;
if (tmp == 0)
tmp = chip->max_speed_hz;
spi_set_baud_rate(tmp);
---

-Bryan

2007-10-31 19:05:50

by David Brownell

[permalink] [raw]
Subject: Re: [PATCH 09/14] Blackfin SPI driver: Fix SPI driver to work with SPI flash ST25P16 on bf548

On Wednesday 31 October 2007, Mike Frysinger wrote:
> On 10/31/07, David Brownell <[email protected]> wrote:
> > (ISTR the M25P16 in $SUBJECT has two read commands, one of
> > which is only usable at clock rates below 33 MHz or so, but
> > most other commands can work above that speed just fine.)
>
> pretty much all SPI flashes have two read commands ("slow" and "fast"
> as they're typically called).

Not DataFlash. But many other modern flash chips do, like
most of the ones handled by the m25p80 driver. As noted
there in the comment about how it should switch over to use
the fast read command ...


> i dont think any of the linux drivers though use the "slow"
> reads with any SPI flashes ... that'd be silly :)

Considering the m25p80 driver started on a uClinux platform
that ISTR couldn't achieve the 33+ MHz clock rates for SPI,
it doesn't seem at all odd to me!

And in fact, lots of Linux systems for some reason don't
seem to be able to clock SPI that fast, even if a given
board were laid out to handle 50+ MHz signaling there.

- Dave

2007-10-31 19:11:38

by Cameron Barfield

[permalink] [raw]
Subject: Re: [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

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

It may be hardware specific for our board, but my thought is that any device should be
able to take advantage of the cs_chg_udelay regardless of which write function it uses.

As far as I can see, there is no where else to make a clean change to allow devices that
use the "normal" write function the ability to take advantage of cs_chg_udelay.



Bryan Wu wrote:
> On Tue, 2007-10-30 at 13:18 -0700, David Brownell wrote:
>> On Tuesday 30 October 2007, Bryan Wu wrote:
>>> @@ -211,6 +211,10 @@ static void cs_deactive(struct driver_data *drv_data, struct chip_data *chip)
>>> flag |= (chip->flag << 8);
>>>
>>> write_FLAG(drv_data, flag);
>>> +
>>> + /* Move delay here for consistency */
>>> + if (chip->cs_chg_udelay)
>>> + udelay(chip->cs_chg_udelay);
>>> }
>>>
>> By the way, if this is something needed very often, that mechanism
>> should be moved into the SPI framework. It wouldn't be polite if
>> such LCD drivers could only work on Blackfin boards. :)
>
> I am not sure whether this LCD needs cs_chg_udelay on other boards.
> It is found by Cameron Barfield. Maybe it is some timing requirement for
> specific hardware.
>
> -Bryan Wu
>
>

- --
NOTICE AND DISCLAIMER:

This e-mail message and any attachments may contain confidential information intended
solely for the specified individual(s).
If you are not the intended recipient, you are prohibited from viewing, disseminating,
copying, disclosing, or relying upon this
message or any attachment in any way.

If you received this e-mail in error, you should (1) immediately notify the sender by
forwarding this e-mail to him, her, or it and
(2) delete the original e-mail message and all attachments without reading or saving any
of them in any manner.

CyberData Corporation does not accept liability for any damage caused by any virus
transmitted through this e-mail or its
attachments. CyberData Corporation does not accept liability for any errors or omissions
in the contents of this e-mail
message or any of its attachments.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFHKNGq49ZuPDUolt0RAqq/AJ4pU67Hopp42saSVhxAbSHXK8CPCgCfTjTx
ky1p5ou7vrNBTR4VB3b9zQc=
=3UiY
-----END PGP SIGNATURE-----

2007-10-31 19:16:18

by Mike Frysinger

[permalink] [raw]
Subject: Re: [PATCH 09/14] Blackfin SPI driver: Fix SPI driver to work with SPI flash ST25P16 on bf548

On 10/31/07, David Brownell <[email protected]> wrote:
> On Wednesday 31 October 2007, Mike Frysinger wrote:
> > On 10/31/07, David Brownell <[email protected]> wrote:
> > > (ISTR the M25P16 in $SUBJECT has two read commands, one of
> > > which is only usable at clock rates below 33 MHz or so, but
> > > most other commands can work above that speed just fine.)
> >
> > pretty much all SPI flashes have two read commands ("slow" and "fast"
> > as they're typically called).
>
> Not DataFlash.

doesnt it ? AT45DB642D says 0x0B is fast (up to 66mhz) while 0x03 (up to 33mhz)
-mike

2007-10-31 20:14:27

by David Brownell

[permalink] [raw]
Subject: Re: [PATCH 09/14] Blackfin SPI driver: Fix SPI driver to work with SPI flash ST25P16 on bf548

> > > pretty much all SPI flashes have two read commands ("slow" and "fast"
> > > as they're typically called).
> >
> > Not DataFlash.
>
> doesnt it ? AT45DB642D says 0x0B is fast (up to 66mhz) while 0x03 (up to 33mhz)

And ...041B, ...081B, ...161B, ...321, ...321C, and others don't.
(From a quick scan of datasheets I have locally...)

Those 0x0B and 0x03 commands are "new", and have never been
used by the Linux DataFlash drivers.