Change the S3C SPI driver to use poll mode instead of interrupt mode. This reduces the gap between bytes from about 2.25us [1] to 100ns [2]. [1] http://people.openmoko.org/werner/wlan-spi/spi-int.png [2] http://people.openmoko.org/werner/wlan-spi/spi-poll.png Index: korig/drivers/spi/spi_s3c24xx.c =================================================================== --- korig.orig/drivers/spi/spi_s3c24xx.c 2008-09-27 22:45:38.000000000 -0300 +++ korig/drivers/spi/spi_s3c24xx.c 2008-09-27 22:46:45.000000000 -0300 @@ -56,7 +56,7 @@ struct s3c2410_spi_info *pdata; }; -#define SPCON_DEFAULT (S3C2410_SPCON_MSTR | S3C2410_SPCON_SMOD_INT) +#define SPCON_DEFAULT (S3C2410_SPCON_MSTR | S3C2410_SPCON_SMOD_POLL) #define SPPIN_DEFAULT (S3C2410_SPPIN_KEEP) static inline struct s3c24xx_spi *to_hw(struct spi_device *sdev) @@ -183,6 +183,7 @@ static int s3c24xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t) { struct s3c24xx_spi *hw = to_hw(spi); + int i; dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n", t->tx_buf, t->rx_buf, t->len); @@ -194,9 +195,19 @@ hw->len = t->len; hw->count = 0; - /* send the first byte */ - writeb(hw_txbyte(hw, 0), hw->regs + S3C2410_SPTDAT); - wait_for_completion(&hw->done); + for (i = 0; i != t->len; i++) { + u8 spsta; + + writeb(hw_txbyte(hw, i), hw->regs + S3C2410_SPTDAT); + do spsta = readb(hw->regs + S3C2410_SPSTA); + while (!(spsta & S3C2410_SPSTA_READY)); + if (hw->rx) { + u8 b = readb(hw->regs + S3C2410_SPRDAT); + + if (i) + hw->rx[i-1] = b; + } + } /* * Get the last byte. Since we don't have more data we can send in @@ -206,9 +217,9 @@ * going on in the hardware. This is the voodoo ritual that makes it * work while anything else fails. */ - if (hw->rx && hw->count) { + if (hw->rx && i) { udelay(1+10*1000000/spi->max_speed_hz); - hw->rx[hw->count-1] = readb(hw->regs + S3C2410_SPRDAT); + hw->rx[i-1] = readb(hw->regs + S3C2410_SPRDAT); } if (0&&t->rx_buf && t->len > 18) { @@ -219,7 +230,7 @@ printk(" %02x", ((u8 *) t->rx_buf)[i]); printk("\n"); } - return hw->count; + return t->len; } static irqreturn_t s3c24xx_spi_irq(int irq, void *dev) @@ -351,6 +362,7 @@ goto err_no_iomap; } +#if 0 hw->irq = platform_get_irq(pdev, 0); if (hw->irq < 0) { dev_err(&pdev->dev, "No IRQ specified\n"); @@ -363,6 +375,7 @@ dev_err(&pdev->dev, "Cannot claim IRQ\n"); goto err_no_irq; } +#endif hw->clk = clk_get(&pdev->dev, "spi"); if (IS_ERR(hw->clk)) { @@ -416,7 +429,7 @@ clk_put(hw->clk); err_no_clk: - free_irq(hw->irq, hw); + //free_irq(hw->irq, hw); err_no_irq: iounmap(hw->regs); @@ -444,7 +457,7 @@ clk_disable(hw->clk); clk_put(hw->clk); - free_irq(hw->irq, hw); + //free_irq(hw->irq, hw); iounmap(hw->regs); release_resource(hw->ioarea);