Skip to content

Commit

Permalink
Merge branch 'spi/next' of git://git.secretlab.ca/git/linux-2.6
Browse files Browse the repository at this point in the history
* 'spi/next' of git://git.secretlab.ca/git/linux-2.6:
  spi/amba-pl022: work in polling or interrupt mode if pl022_dma_probe fails
  spi/spi_s3c24xx: Use spi_bitbang_stop instead of spi_unregister_master in s3c24xx_spi_remove
  spi/spi_nuc900: Use spi_bitbang_stop instead of spi_unregister_master in nuc900_spi_remove
  spi/spi_tegra: use spi_unregister_master() instead of spi_master_put()
  spi/spi_sh: use spi_unregister_master instead of spi_master_put in remove path
  spi: Use void pointers for data in simple SPI I/O operations
  spi/pl022: use cpu_relax in the busy loop
  spi/pl022: mark driver non-experimental
  spi/pl022: timeout on polled transfer v2
  spi/dw_spi: improve the interrupt mode with the batch ops
  spi/dw_spi: change poll mode transfer from byte ops to batch ops
  spi/dw_spi: remove the un-necessary flush()
  spi/dw_spi: unify the low level read/write routines
  • Loading branch information
Linus Torvalds committed May 26, 2011
2 parents 829ae27 + 43c6401 commit 20e0ec1
Show file tree
Hide file tree
Showing 10 changed files with 100 additions and 163 deletions.
4 changes: 2 additions & 2 deletions drivers/spi/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -271,8 +271,8 @@ config SPI_ORION
This enables using the SPI master controller on the Orion chips.

config SPI_PL022
tristate "ARM AMBA PL022 SSP controller (EXPERIMENTAL)"
depends on ARM_AMBA && EXPERIMENTAL
tristate "ARM AMBA PL022 SSP controller"
depends on ARM_AMBA
default y if MACH_U300
default y if ARCH_REALVIEW
default y if INTEGRATOR_IMPD1
Expand Down
35 changes: 22 additions & 13 deletions drivers/spi/amba-pl022.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,6 @@
* GNU General Public License for more details.
*/

/*
* TODO:
* - add timeout on polled transfers
*/

#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
Expand Down Expand Up @@ -287,6 +282,8 @@

#define CLEAR_ALL_INTERRUPTS 0x3

#define SPI_POLLING_TIMEOUT 1000


/*
* The type of reading going on on this chip
Expand Down Expand Up @@ -1063,21 +1060,21 @@ static int __init pl022_dma_probe(struct pl022 *pl022)
pl022->master_info->dma_filter,
pl022->master_info->dma_rx_param);
if (!pl022->dma_rx_channel) {
dev_err(&pl022->adev->dev, "no RX DMA channel!\n");
dev_dbg(&pl022->adev->dev, "no RX DMA channel!\n");
goto err_no_rxchan;
}

pl022->dma_tx_channel = dma_request_channel(mask,
pl022->master_info->dma_filter,
pl022->master_info->dma_tx_param);
if (!pl022->dma_tx_channel) {
dev_err(&pl022->adev->dev, "no TX DMA channel!\n");
dev_dbg(&pl022->adev->dev, "no TX DMA channel!\n");
goto err_no_txchan;
}

pl022->dummypage = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!pl022->dummypage) {
dev_err(&pl022->adev->dev, "no DMA dummypage!\n");
dev_dbg(&pl022->adev->dev, "no DMA dummypage!\n");
goto err_no_dummypage;
}

Expand All @@ -1093,6 +1090,8 @@ static int __init pl022_dma_probe(struct pl022 *pl022)
dma_release_channel(pl022->dma_rx_channel);
pl022->dma_rx_channel = NULL;
err_no_rxchan:
dev_err(&pl022->adev->dev,
"Failed to work in dma mode, work without dma!\n");
return -ENODEV;
}

Expand Down Expand Up @@ -1378,6 +1377,7 @@ static void do_polling_transfer(struct pl022 *pl022)
struct spi_transfer *transfer = NULL;
struct spi_transfer *previous = NULL;
struct chip_data *chip;
unsigned long time, timeout;

chip = pl022->cur_chip;
message = pl022->cur_msg;
Expand Down Expand Up @@ -1415,9 +1415,19 @@ static void do_polling_transfer(struct pl022 *pl022)
SSP_CR1(pl022->virtbase));

dev_dbg(&pl022->adev->dev, "polling transfer ongoing ...\n");
/* FIXME: insert a timeout so we don't hang here indefinitely */
while (pl022->tx < pl022->tx_end || pl022->rx < pl022->rx_end)

timeout = jiffies + msecs_to_jiffies(SPI_POLLING_TIMEOUT);
while (pl022->tx < pl022->tx_end || pl022->rx < pl022->rx_end) {
time = jiffies;
readwriter(pl022);
if (time_after(time, timeout)) {
dev_warn(&pl022->adev->dev,
"%s: timeout!\n", __func__);
message->state = STATE_ERROR;
goto out;
}
cpu_relax();
}

/* Update total byte transferred */
message->actual_length += pl022->cur_transfer->len;
Expand All @@ -1426,7 +1436,7 @@ static void do_polling_transfer(struct pl022 *pl022)
/* Move to next transfer */
message->state = next_transfer(pl022);
}

out:
/* Handle end of message */
if (message->state == STATE_DONE)
message->status = 0;
Expand Down Expand Up @@ -2107,7 +2117,7 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id)
if (platform_info->enable_dma) {
status = pl022_dma_probe(pl022);
if (status != 0)
goto err_no_dma;
platform_info->enable_dma = 0;
}

/* Initialize and start queue */
Expand Down Expand Up @@ -2143,7 +2153,6 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id)
err_init_queue:
destroy_queue(pl022);
pl022_dma_remove(pl022);
err_no_dma:
free_irq(adev->irq[0], pl022);
err_no_irq:
clk_put(pl022->clk);
Expand Down
Loading

0 comments on commit 20e0ec1

Please sign in to comment.