2007-11-02 02:38:46

by Bryan Wu

[permalink] [raw]
Subject: [PATCH 0/4] Blackfin SPI driver updates and fixing

According to David and Andrew's advices, update the Blackfin SPI series patches
in -mm tree.


2007-11-02 02:39:00

by Bryan Wu

[permalink] [raw]
Subject: [PATCH 2/4] Blackfin SPI driver: use void __iomem * for regs_base

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

diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
index fc0c374..a6f6d5f 100644
--- a/drivers/spi/spi_bfin5xx.c
+++ b/drivers/spi/spi_bfin5xx.c
@@ -78,7 +78,7 @@ struct driver_data {
struct spi_master *master;

/* Regs base of SPI controller */
- u32 regs_base;
+ void __iomem *regs_base;

/* BFIN hookup */
struct bfin5xx_spi_master *master_info;
@@ -1301,9 +1301,8 @@ static int __init bfin5xx_spi_probe(struct platform_device *pdev)
goto out_error_get_res;
}

- drv_data->regs_base = (u32) ioremap(res->start,
- (res->end - res->start + 1));
- if (!drv_data->regs_base) {
+ drv_data->regs_base = ioremap(res->start, (res->end - res->start + 1));
+ if (drv_data->regs_base == NULL) {
dev_err(dev, "Cannot map IO\n");
status = -ENXIO;
goto out_error_ioremap;
@@ -1342,7 +1341,7 @@ static int __init bfin5xx_spi_probe(struct platform_device *pdev)
goto out_error;
}

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

2007-11-02 02:39:21

by Bryan Wu

[permalink] [raw]
Subject: [PATCH 1/4] Blackfin SPI driver: use cpu_relax() to replace continue in while busywait

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

diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
index 83c866d..fc0c374 100644
--- a/drivers/spi/spi_bfin5xx.c
+++ b/drivers/spi/spi_bfin5xx.c
@@ -186,7 +186,7 @@ static int flush(struct driver_data *drv_data)

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

write_STAT(drv_data, BIT_STAT_CLR);

@@ -262,7 +262,7 @@ static void null_writer(struct driver_data *drv_data)
while (drv_data->tx < drv_data->tx_end) {
write_TDBR(drv_data, 0);
while ((read_STAT(drv_data) & BIT_STAT_TXS))
- continue;
+ cpu_relax();
drv_data->tx += n_bytes;
}
}
@@ -274,7 +274,7 @@ static void null_reader(struct driver_data *drv_data)

while (drv_data->rx < drv_data->rx_end) {
while (!(read_STAT(drv_data) & BIT_STAT_RXS))
- continue;
+ cpu_relax();
dummy_read(drv_data);
drv_data->rx += n_bytes;
}
@@ -287,12 +287,12 @@ static void u8_writer(struct driver_data *drv_data)

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

while (drv_data->tx < drv_data->tx_end) {
write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
while (read_STAT(drv_data) & BIT_STAT_TXS)
- continue;
+ cpu_relax();
++drv_data->tx;
}
}
@@ -303,14 +303,14 @@ static void u8_cs_chg_writer(struct driver_data *drv_data)

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

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

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

cs_deactive(drv_data, chip);

@@ -325,7 +325,7 @@ static void u8_reader(struct driver_data *drv_data)

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

/* clear TDBR buffer before read(else it will be shifted out) */
write_TDBR(drv_data, 0xFFFF);
@@ -334,13 +334,13 @@ static void u8_reader(struct driver_data *drv_data)

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

while (!(read_STAT(drv_data) & BIT_STAT_RXS))
- continue;
+ cpu_relax();
*(u8 *) (drv_data->rx) = read_SHAW(drv_data);
++drv_data->rx;
}
@@ -351,7 +351,7 @@ static void u8_cs_chg_reader(struct driver_data *drv_data)

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

/* clear TDBR buffer before read(else it will be shifted out) */
write_TDBR(drv_data, 0xFFFF);
@@ -363,7 +363,7 @@ static void u8_cs_chg_reader(struct driver_data *drv_data)
cs_deactive(drv_data, chip);

while (!(read_STAT(drv_data) & BIT_STAT_RXS))
- continue;
+ cpu_relax();
cs_active(drv_data, chip);
*(u8 *) (drv_data->rx) = read_RDBR(drv_data);
++drv_data->rx;
@@ -371,7 +371,7 @@ static void u8_cs_chg_reader(struct driver_data *drv_data)
cs_deactive(drv_data, chip);

while (!(read_STAT(drv_data) & BIT_STAT_RXS))
- continue;
+ cpu_relax();
*(u8 *) (drv_data->rx) = read_SHAW(drv_data);
++drv_data->rx;
}
@@ -380,15 +380,15 @@ static void u8_duplex(struct driver_data *drv_data)
{
/* poll for SPI completion before start */
while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
- continue;
+ cpu_relax();

/* in duplex mode, clk is triggered by writing of TDBR */
while (drv_data->rx < drv_data->rx_end) {
write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
while (read_STAT(drv_data) & BIT_STAT_TXS)
- continue;
+ cpu_relax();
while (!(read_STAT(drv_data) & BIT_STAT_RXS))
- continue;
+ cpu_relax();
*(u8 *) (drv_data->rx) = read_RDBR(drv_data);
++drv_data->rx;
++drv_data->tx;
@@ -401,16 +401,16 @@ static void u8_cs_chg_duplex(struct driver_data *drv_data)

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

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

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

cs_deactive(drv_data, chip);
@@ -427,12 +427,12 @@ static void u16_writer(struct driver_data *drv_data)

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

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

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

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

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

cs_deactive(drv_data, chip);

@@ -465,7 +465,7 @@ static void u16_reader(struct driver_data *drv_data)

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

/* clear TDBR buffer before read(else it will be shifted out) */
write_TDBR(drv_data, 0xFFFF);
@@ -474,13 +474,13 @@ static void u16_reader(struct driver_data *drv_data)

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

while (!(read_STAT(drv_data) & BIT_STAT_RXS))
- continue;
+ cpu_relax();
*(u16 *) (drv_data->rx) = read_SHAW(drv_data);
drv_data->rx += 2;
}
@@ -491,7 +491,7 @@ static void u16_cs_chg_reader(struct driver_data *drv_data)

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

/* clear TDBR buffer before read(else it will be shifted out) */
write_TDBR(drv_data, 0xFFFF);
@@ -503,7 +503,7 @@ static void u16_cs_chg_reader(struct driver_data *drv_data)
cs_deactive(drv_data, chip);

while (!(read_STAT(drv_data) & BIT_STAT_RXS))
- continue;
+ cpu_relax();
cs_active(drv_data, chip);
*(u16 *) (drv_data->rx) = read_RDBR(drv_data);
drv_data->rx += 2;
@@ -511,7 +511,7 @@ static void u16_cs_chg_reader(struct driver_data *drv_data)
cs_deactive(drv_data, chip);

while (!(read_STAT(drv_data) & BIT_STAT_RXS))
- continue;
+ cpu_relax();
*(u16 *) (drv_data->rx) = read_SHAW(drv_data);
drv_data->rx += 2;
}
@@ -520,15 +520,15 @@ static void u16_duplex(struct driver_data *drv_data)
{
/* poll for SPI completion before start */
while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
- continue;
+ cpu_relax();

/* in duplex mode, clk is triggered by writing of TDBR */
while (drv_data->tx < drv_data->tx_end) {
write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
while (read_STAT(drv_data) & BIT_STAT_TXS)
- continue;
+ cpu_relax();
while (!(read_STAT(drv_data) & BIT_STAT_RXS))
- continue;
+ cpu_relax();
*(u16 *) (drv_data->rx) = read_RDBR(drv_data);
drv_data->rx += 2;
drv_data->tx += 2;
@@ -541,16 +541,16 @@ static void u16_cs_chg_duplex(struct driver_data *drv_data)

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

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

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

cs_deactive(drv_data, chip);
@@ -624,7 +624,7 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id)

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

/*
* wait for the last transaction shifted out. HRM states:
@@ -635,11 +635,11 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id)
if (drv_data->tx != NULL) {
while ((read_STAT(drv_data) & TXS) ||
(read_STAT(drv_data) & TXS))
- continue;
+ cpu_relax();
}

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

msg->actual_length += drv_data->len_in_bytes;

@@ -783,7 +783,7 @@ static void pump_transfers(unsigned long data)

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

/* dirty hack for autobuffer DMA mode */
if (drv_data->tx_dma == 0xFFFF) {
--
1.5.3.4

2007-11-02 02:39:37

by Bryan Wu

[permalink] [raw]
Subject: [PATCH 3/4] Blackfin SPI driver: move hard coded pin_req to board file

Remove some sort of bloaty code, try to get these pin_req arrays built at compile-time

- move this static things to the blackfin board file
- add pin_req array to struct bfin5xx_spi_master
- tested on BF537/BF548 with SPI flash

Signed-off-by: Bryan Wu <[email protected]>
---
drivers/spi/spi_bfin5xx.c | 28 +++++++---------------------
include/asm-blackfin/bfin5xx_spi.h | 1 +
2 files changed, 8 insertions(+), 21 deletions(-)

diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
index a6f6d5f..f466fa0 100644
--- a/drivers/spi/spi_bfin5xx.c
+++ b/drivers/spi/spi_bfin5xx.c
@@ -80,6 +80,9 @@ struct driver_data {
/* Regs base of SPI controller */
void __iomem *regs_base;

+ /* Pin request list */
+ u16 *pin_req;
+
/* BFIN hookup */
struct bfin5xx_spi_master *master_info;

@@ -1245,25 +1248,6 @@ static inline int destroy_queue(struct driver_data *drv_data)
return 0;
}

-static int setup_pin_mux(int action, int bus_num)
-{
-
- 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[bus_num], DRV_NAME))
- return -EFAULT;
- } else {
- peripheral_free_list(pin_req[bus_num]);
- }
-
- return 0;
-}
-
static int __init bfin5xx_spi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -1286,6 +1270,7 @@ static int __init bfin5xx_spi_probe(struct platform_device *pdev)
drv_data->master = master;
drv_data->master_info = platform_info;
drv_data->pdev = pdev;
+ drv_data->pin_req = platform_info->pin_req;

master->bus_num = pdev->id;
master->num_chipselect = platform_info->num_chipselect;
@@ -1336,7 +1321,8 @@ static int __init bfin5xx_spi_probe(struct platform_device *pdev)
goto out_error_queue_alloc;
}

- if (setup_pin_mux(1, master->bus_num)) {
+ status = peripheral_request_list(drv_data->pin_req, DRV_NAME);
+ if (status != 0) {
dev_err(&pdev->dev, ": Requesting Peripherals failed\n");
goto out_error;
}
@@ -1384,7 +1370,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, drv_data->master->bus_num);
+ peripheral_free_list(drv_data->pin_req);

/* Prevent double remove */
platform_set_drvdata(pdev, NULL);
diff --git a/include/asm-blackfin/bfin5xx_spi.h b/include/asm-blackfin/bfin5xx_spi.h
index d4485b3..1a0b57f 100644
--- a/include/asm-blackfin/bfin5xx_spi.h
+++ b/include/asm-blackfin/bfin5xx_spi.h
@@ -152,6 +152,7 @@
struct bfin5xx_spi_master {
u16 num_chipselect;
u8 enable_dma;
+ u16 pin_req[4];
};

/* spi_board_info.controller_data for SPI slave devices,
--
1.5.3.4

2007-11-02 02:39:52

by Bryan Wu

[permalink] [raw]
Subject: [PATCH 4/4] Blackfin SPI driver: reconfigure speed_hz and bits_per_word in each spi transfer

- reconfigure SPI baud from speed_hz of each spi transfer
- according to spi_transfer.bits_per_word to reprogram register and setup
correct SPI operation handlers

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

diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
index f466fa0..3e5126e 100644
--- a/drivers/spi/spi_bfin5xx.c
+++ b/drivers/spi/spi_bfin5xx.c
@@ -234,10 +234,8 @@ static int restore_state(struct driver_data *drv_data)
dev_dbg(&drv_data->pdev->dev, "restoring spi ctl state\n");

/* Load the registers */
- 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);
+ write_BAUD(drv_data, chip->baud);

bfin_spi_enable(drv_data);
cs_active(drv_data, chip);
@@ -679,6 +677,7 @@ 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
*/
@@ -736,23 +735,62 @@ static void pump_transfers(unsigned long data)
drv_data->len_in_bytes = transfer->len;
drv_data->cs_change = transfer->cs_change;

- width = chip->width;
+ /* Bits per word setup */
+ switch (transfer->bits_per_word) {
+ case 8:
+ drv_data->n_bytes = 1;
+ width = CFG_SPI_WORDSIZE8;
+ drv_data->read = chip->cs_change_per_word ?
+ u8_cs_chg_reader : u8_reader;
+ drv_data->write = chip->cs_change_per_word ?
+ u8_cs_chg_writer : u8_writer;
+ drv_data->duplex = chip->cs_change_per_word ?
+ u8_cs_chg_duplex : u8_duplex;
+ break;
+
+ case 16:
+ drv_data->n_bytes = 2;
+ width = CFG_SPI_WORDSIZE16;
+ drv_data->read = chip->cs_change_per_word ?
+ u16_cs_chg_reader : u16_reader;
+ drv_data->write = chip->cs_change_per_word ?
+ u16_cs_chg_writer : u16_writer;
+ drv_data->duplex = chip->cs_change_per_word ?
+ u16_cs_chg_duplex : u16_duplex;
+ break;
+
+ default:
+ /* No change, the same as default setting */
+ drv_data->n_bytes = chip->n_bytes;
+ width = chip->width;
+ drv_data->write = drv_data->tx ? chip->write : null_writer;
+ drv_data->read = drv_data->rx ? chip->read : null_reader;
+ drv_data->duplex = chip->duplex ? chip->duplex : null_writer;
+ break;
+ }
+ cr = (read_CTRL(drv_data) & (~BIT_CTL_TIMOD));
+ cr |= (width << 8);
+ write_CTRL(drv_data, cr);
+
if (width == CFG_SPI_WORDSIZE16) {
drv_data->len = (transfer->len) >> 1;
} else {
drv_data->len = transfer->len;
}
- drv_data->write = drv_data->tx ? chip->write : null_writer;
- drv_data->read = drv_data->rx ? chip->read : null_reader;
- drv_data->duplex = chip->duplex ? chip->duplex : null_writer;
dev_dbg(&drv_data->pdev->dev,
"transfer: drv_data->write is %p, chip->write is %p, null_wr is %p\n",
- drv_data->write, chip->write, null_writer);
+ drv_data->write, chip->write, null_writer);

/* speed and width has been set on per message */
message->state = RUNNING_STATE;
dma_config = 0;

+ /* Speed setup (surely valid because already checked) */
+ if (transfer->speed_hz)
+ write_BAUD(drv_data, hz_to_spi_baud(transfer->speed_hz));
+ else
+ write_BAUD(drv_data, chip->baud);
+
write_STAT(drv_data, BIT_STAT_CLR);
cr = (read_CTRL(drv_data) & (~BIT_CTL_TIMOD));
cs_active(drv_data, chip);
--
1.5.3.4

2007-11-06 06:03:54

by David Brownell

[permalink] [raw]
Subject: Re: [PATCH 3/4] Blackfin SPI driver: move hard coded pin_req to board file

On Thursday 01 November 2007, Bryan Wu wrote:
> --- a/include/asm-blackfin/bfin5xx_spi.h
> +++ b/include/asm-blackfin/bfin5xx_spi.h
> @@ -152,6 +152,7 @@
> ?struct bfin5xx_spi_master {
> ????????u16 num_chipselect;
> ????????u8 enable_dma;
> +???????u16 pin_req[4];
> ?};
> ?
> ?/* spi_board_info.controller_data for SPI slave devices,

I take it there's a patch some where -- outside of this set
of four -- to initialize that new field so drivers will get
valid pin setup data? (That name doesn't sound like it's
platform data, by the way.)

That's going to need to merge in sync with this patch, else
I'd think the resulting kernel won't run ...

- Dave

2007-11-06 06:46:58

by Bryan Wu

[permalink] [raw]
Subject: Re: [PATCH 3/4] Blackfin SPI driver: move hard coded pin_req to board file

On 11/6/07, David Brownell <[email protected]> wrote:
> On Thursday 01 November 2007, Bryan Wu wrote:
> > --- a/include/asm-blackfin/bfin5xx_spi.h
> > +++ b/include/asm-blackfin/bfin5xx_spi.h
> > @@ -152,6 +152,7 @@
> > struct bfin5xx_spi_master {
> > u16 num_chipselect;
> > u8 enable_dma;
> > +u16 pin_req[4];
> > };
> >
> > /* spi_board_info.controller_data for SPI slave devices,
>
> I take it there's a patch some where -- outside of this set
> of four -- to initialize that new field so drivers will get
> valid pin setup data? (That name doesn't sound like it's
> platform data, by the way.)
>
> That's going to need to merge in sync with this patch, else
> I'd think the resulting kernel won't run ...
>

Yes, I have another patch to add this pin_req field in arch/blackfin
board files.
It is in my blackfin patch queue and will be submitted to upstream later.

Thanks a lot
-Bryan