diff options
Diffstat (limited to 'target/linux/s3c24xx/patches-2.6.30/060-spi-gpio-non-blocking.patch')
-rw-r--r-- | target/linux/s3c24xx/patches-2.6.30/060-spi-gpio-non-blocking.patch | 432 |
1 files changed, 432 insertions, 0 deletions
diff --git a/target/linux/s3c24xx/patches-2.6.30/060-spi-gpio-non-blocking.patch b/target/linux/s3c24xx/patches-2.6.30/060-spi-gpio-non-blocking.patch new file mode 100644 index 000000000..ec61f03e0 --- /dev/null +++ b/target/linux/s3c24xx/patches-2.6.30/060-spi-gpio-non-blocking.patch @@ -0,0 +1,432 @@ +Index: linux-2.6.30-rc6/arch/arm/mach-s3c2410/include/mach/spi-gpio.h +=================================================================== +--- linux-2.6.30-rc6.orig/arch/arm/mach-s3c2410/include/mach/spi-gpio.h 2009-05-16 06:12:57.000000000 +0200 ++++ linux-2.6.30-rc6/arch/arm/mach-s3c2410/include/mach/spi-gpio.h 2009-05-18 19:08:34.000000000 +0200 +@@ -21,7 +21,8 @@ + int num_chipselect; + int bus_num; + +- void (*chip_select)(struct s3c2410_spigpio_info *spi, int cs); ++ int non_blocking_transfer; ++ void (*chip_select)(struct s3c2410_spigpio_info *spi, int csid, int cs); + }; + + +Index: linux-2.6.30-rc6/drivers/spi/spi_bitbang.c +=================================================================== +--- linux-2.6.30-rc6.orig/drivers/spi/spi_bitbang.c 2009-05-16 06:12:57.000000000 +0200 ++++ linux-2.6.30-rc6/drivers/spi/spi_bitbang.c 2009-05-18 19:08:34.000000000 +0200 +@@ -264,6 +264,123 @@ + * Drivers can provide word-at-a-time i/o primitives, or provide + * transfer-at-a-time ones to leverage dma or fifo hardware. + */ ++ ++/* Synchronous non blocking transfer */ ++int ++spi_bitbang_transfer_sync(struct spi_device *spi, struct spi_message *m) ++{ ++ struct spi_bitbang *bitbang = spi_master_get_devdata(spi->master); ++ struct spi_transfer *t; ++ unsigned long flags; ++ int cs_change = 1; ++ int status; ++ int nsecs; ++ int (*setup_transfer)(struct spi_device *, struct spi_transfer *); ++ ++ /* FIXME this is made-up ... the correct value is known to ++ * word-at-a-time bitbang code, and presumably chipselect() ++ * should enforce these requirements too? ++ */ ++ nsecs = 100; ++ cs_change = 1; ++ status = 0; ++ setup_transfer = NULL; ++ ++ local_irq_save(flags); ++ list_for_each_entry (t, &m->transfers, transfer_list) { ++ /* override or restore speed and wordsize */ ++ if (t->speed_hz || t->bits_per_word) { ++ setup_transfer = bitbang->setup_transfer; ++ if (!setup_transfer) { ++ status = -ENOPROTOOPT; ++ break; ++ } ++ } ++ if (setup_transfer) { ++ status = setup_transfer(spi, t); ++ if (status < 0) ++ break; ++ } ++ ++ /* set up default clock polarity, and activate chip; ++ * this implicitly updates clock and spi modes as ++ * previously recorded for this device via setup(). ++ * (and also deselects any other chip that might be ++ * selected ...) ++ */ ++ ++ if (cs_change) { ++ bitbang->chipselect(spi, BITBANG_CS_ACTIVE); ++ ndelay(nsecs); ++ } ++ ++ cs_change = t->cs_change; ++ if (!t->tx_buf && !t->rx_buf && t->len) { ++ status = -EINVAL; ++ break; ++ } ++ ++ /* transfer data. the lower level code handles any ++ * new dma mappings it needs. our caller always gave ++ * us dma-safe buffers. ++ */ ++ if (t->len) { ++ /* REVISIT dma API still needs a designated ++ * DMA_ADDR_INVALID; ~0 might be better. ++ */ ++ if (!m->is_dma_mapped) ++ t->rx_dma = t->tx_dma = 0; ++ status = bitbang->txrx_bufs(spi, t); ++ } ++ ++ if (status > 0) ++ m->actual_length += status; ++ if (status != t->len) { ++ /* always report some kind of error */ ++ if (status >= 0) ++ status = -EREMOTEIO; ++ break; ++ } ++ status = 0; ++ /* protocol tweaks before next transfer */ ++ if (t->delay_usecs) ++ udelay(t->delay_usecs); ++ if (!cs_change) ++ continue; ++ if (t->transfer_list.next == &m->transfers) ++ break; ++ /* sometimes a short mid-message deselect of the chip ++ * may be needed to terminate a mode or command ++ */ ++ ndelay(nsecs); ++ bitbang->chipselect(spi, BITBANG_CS_INACTIVE); ++ ndelay(nsecs); ++ } ++ ++ m->status = status; ++ if (m->complete) ++ m->complete(m->context); ++ ++ /* restore speed and wordsize */ ++ if (setup_transfer) ++ setup_transfer(spi, NULL); ++ ++ /* normally deactivate chipselect ... unless no error and ++ * cs_change has hinted that the next message will probably ++ * be for this chip too. ++ */ ++ if (!(status == 0 && cs_change)) { ++ ndelay(nsecs); ++ bitbang->chipselect(spi, BITBANG_CS_INACTIVE); ++ ndelay(nsecs); ++ } ++ ++ local_irq_restore(flags); ++ ++ return status; ++} ++EXPORT_SYMBOL_GPL(spi_bitbang_transfer_sync); ++ + static void bitbang_work(struct work_struct *work) + { + struct spi_bitbang *bitbang = +@@ -274,120 +391,13 @@ + bitbang->busy = 1; + while (!list_empty(&bitbang->queue)) { + struct spi_message *m; +- struct spi_device *spi; +- unsigned nsecs; +- struct spi_transfer *t = NULL; +- unsigned tmp; +- unsigned cs_change; +- int status; +- int (*setup_transfer)(struct spi_device *, +- struct spi_transfer *); + + m = container_of(bitbang->queue.next, struct spi_message, + queue); + list_del_init(&m->queue); +- spin_unlock_irqrestore(&bitbang->lock, flags); +- +- /* FIXME this is made-up ... the correct value is known to +- * word-at-a-time bitbang code, and presumably chipselect() +- * should enforce these requirements too? +- */ +- nsecs = 100; +- +- spi = m->spi; +- tmp = 0; +- cs_change = 1; +- status = 0; +- setup_transfer = NULL; +- +- list_for_each_entry (t, &m->transfers, transfer_list) { +- +- /* override or restore speed and wordsize */ +- if (t->speed_hz || t->bits_per_word) { +- setup_transfer = bitbang->setup_transfer; +- if (!setup_transfer) { +- status = -ENOPROTOOPT; +- break; +- } +- } +- if (setup_transfer) { +- status = setup_transfer(spi, t); +- if (status < 0) +- break; +- } +- +- /* set up default clock polarity, and activate chip; +- * this implicitly updates clock and spi modes as +- * previously recorded for this device via setup(). +- * (and also deselects any other chip that might be +- * selected ...) +- */ +- if (cs_change) { +- bitbang->chipselect(spi, BITBANG_CS_ACTIVE); +- ndelay(nsecs); +- } +- cs_change = t->cs_change; +- if (!t->tx_buf && !t->rx_buf && t->len) { +- status = -EINVAL; +- break; +- } +- +- /* transfer data. the lower level code handles any +- * new dma mappings it needs. our caller always gave +- * us dma-safe buffers. +- */ +- if (t->len) { +- /* REVISIT dma API still needs a designated +- * DMA_ADDR_INVALID; ~0 might be better. +- */ +- if (!m->is_dma_mapped) +- t->rx_dma = t->tx_dma = 0; +- status = bitbang->txrx_bufs(spi, t); +- } +- if (status > 0) +- m->actual_length += status; +- if (status != t->len) { +- /* always report some kind of error */ +- if (status >= 0) +- status = -EREMOTEIO; +- break; +- } +- status = 0; +- +- /* protocol tweaks before next transfer */ +- if (t->delay_usecs) +- udelay(t->delay_usecs); +- +- if (!cs_change) +- continue; +- if (t->transfer_list.next == &m->transfers) +- break; +- +- /* sometimes a short mid-message deselect of the chip +- * may be needed to terminate a mode or command +- */ +- ndelay(nsecs); +- bitbang->chipselect(spi, BITBANG_CS_INACTIVE); +- ndelay(nsecs); +- } +- +- m->status = status; +- m->complete(m->context); +- +- /* restore speed and wordsize */ +- if (setup_transfer) +- setup_transfer(spi, NULL); +- +- /* normally deactivate chipselect ... unless no error and +- * cs_change has hinted that the next message will probably +- * be for this chip too. +- */ +- if (!(status == 0 && cs_change)) { +- ndelay(nsecs); +- bitbang->chipselect(spi, BITBANG_CS_INACTIVE); +- ndelay(nsecs); +- } + ++ spin_unlock_irqrestore(&bitbang->lock, flags); ++ spi_bitbang_transfer_sync(m->spi, m); + spin_lock_irqsave(&bitbang->lock, flags); + } + bitbang->busy = 0; +@@ -459,6 +469,9 @@ + + if (!bitbang->master->transfer) + bitbang->master->transfer = spi_bitbang_transfer; ++ if (!bitbang->master->transfer_sync && bitbang->non_blocking_transfer) ++ bitbang->master->transfer_sync = spi_bitbang_transfer_sync; ++ + if (!bitbang->txrx_bufs) { + bitbang->use_dma = 0; + bitbang->txrx_bufs = spi_bitbang_bufs; +Index: linux-2.6.30-rc6/drivers/spi/spi_s3c24xx_gpio.c +=================================================================== +--- linux-2.6.30-rc6.orig/drivers/spi/spi_s3c24xx_gpio.c 2009-05-16 06:12:57.000000000 +0200 ++++ linux-2.6.30-rc6/drivers/spi/spi_s3c24xx_gpio.c 2009-05-18 19:08:34.000000000 +0200 +@@ -91,7 +91,7 @@ + struct s3c2410_spigpio *sg = spidev_to_sg(dev); + + if (sg->info && sg->info->chip_select) +- (sg->info->chip_select)(sg->info, value); ++ (sg->info->chip_select)(sg->info, dev->chip_select, value); + } + + static int s3c2410_spigpio_probe(struct platform_device *dev) +@@ -112,14 +112,17 @@ + + platform_set_drvdata(dev, sp); + +- /* copy in the plkatform data */ ++ /* copy in the platform data */ + info = sp->info = dev->dev.platform_data; + ++ master->num_chipselect = info->num_chipselect; ++ + /* setup spi bitbang adaptor */ + sp->bitbang.master = spi_master_get(master); + sp->bitbang.master->bus_num = info->bus_num; + sp->bitbang.master->num_chipselect = info->num_chipselect; + sp->bitbang.chipselect = s3c2410_spigpio_chipselect; ++ sp->bitbang.non_blocking_transfer = info->non_blocking_transfer; + + sp->bitbang.txrx_word[SPI_MODE_0] = s3c2410_spigpio_txrx_mode0; + sp->bitbang.txrx_word[SPI_MODE_1] = s3c2410_spigpio_txrx_mode1; +Index: linux-2.6.30-rc6/include/linux/mmc/core.h +=================================================================== +--- linux-2.6.30-rc6.orig/include/linux/mmc/core.h 2009-05-16 06:12:57.000000000 +0200 ++++ linux-2.6.30-rc6/include/linux/mmc/core.h 2009-05-18 19:08:34.000000000 +0200 +@@ -129,6 +129,8 @@ + struct mmc_host; + struct mmc_card; + ++extern void mmc_flush_scheduled_work(void); ++ + extern void mmc_wait_for_req(struct mmc_host *, struct mmc_request *); + extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int); + extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *, +Index: linux-2.6.30-rc6/include/linux/mmc/sdio_ids.h +=================================================================== +--- linux-2.6.30-rc6.orig/include/linux/mmc/sdio_ids.h 2009-05-16 06:12:57.000000000 +0200 ++++ linux-2.6.30-rc6/include/linux/mmc/sdio_ids.h 2009-05-18 19:08:34.000000000 +0200 +@@ -25,5 +25,9 @@ + + #define SDIO_VENDOR_ID_MARVELL 0x02df + #define SDIO_DEVICE_ID_MARVELL_LIBERTAS 0x9103 ++#define SDIO_DEVICE_ID_MARVELL_88W8688 0x9104 ++#define SDIO_VENDOR_ID_ATHEROS 0x0271 ++#define SDIO_DEVICE_ID_ATHEROS_AR6001 0x0100 ++#define SDIO_DEVICE_ID_ATHEROS_AR6002 0x0200 + + #endif +Index: linux-2.6.30-rc6/include/linux/spi/spi_bitbang.h +=================================================================== +--- linux-2.6.30-rc6.orig/include/linux/spi/spi_bitbang.h 2009-05-16 06:12:57.000000000 +0200 ++++ linux-2.6.30-rc6/include/linux/spi/spi_bitbang.h 2009-05-18 19:08:34.000000000 +0200 +@@ -31,6 +31,9 @@ + u8 use_dma; + u8 flags; /* extra spi->mode support */ + ++ /* Support for synchronous non blocking transfers */ ++ int non_blocking_transfer; ++ + struct spi_master *master; + + /* setup_transfer() changes clock and/or wordsize to match settings +@@ -62,6 +65,8 @@ + extern int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m); + extern int spi_bitbang_setup_transfer(struct spi_device *spi, + struct spi_transfer *t); ++extern int spi_bitbang_transfer_sync(struct spi_device *spi, ++ struct spi_message *m); + + /* start or stop queue processing */ + extern int spi_bitbang_start(struct spi_bitbang *spi); +Index: linux-2.6.30-rc6/include/linux/spi/spi.h +=================================================================== +--- linux-2.6.30-rc6.orig/include/linux/spi/spi.h 2009-05-16 06:12:57.000000000 +0200 ++++ linux-2.6.30-rc6/include/linux/spi/spi.h 2009-05-18 19:08:34.000000000 +0200 +@@ -204,7 +204,6 @@ + * SPI slaves, and are numbered from zero to num_chipselects. + * each slave has a chipselect signal, but it's common that not + * every chipselect is connected to a slave. +- * @dma_alignment: SPI controller constraint on DMA buffers alignment. + * @setup: updates the device mode and clocking records used by a + * device's SPI controller; protocol code may call this. This + * must fail if an unrecognized or unsupported mode is requested. +@@ -240,17 +239,7 @@ + */ + u16 num_chipselect; + +- /* some SPI controllers pose alignment requirements on DMAable +- * buffers; let protocol drivers know about these requirements. +- */ +- u16 dma_alignment; +- +- /* Setup mode and clock, etc (spi driver may call many times). +- * +- * IMPORTANT: this may be called when transfers to another +- * device are active. DO NOT UPDATE SHARED REGISTERS in ways +- * which could break those transfers. +- */ ++ /* setup mode and clock, etc (spi driver may call many times) */ + int (*setup)(struct spi_device *spi); + + /* bidirectional bulk transfers +@@ -275,6 +264,13 @@ + int (*transfer)(struct spi_device *spi, + struct spi_message *mesg); + ++ /* ++ * Synchronous non blocking transfer function. Should guarantee ++ * data availability when it returns ++ */ ++ int (*transfer_sync)(struct spi_device *spi, ++ struct spi_message *mesg); ++ + /* called on release() to free memory provided by spi_master */ + void (*cleanup)(struct spi_device *spi); + }; +@@ -584,6 +580,29 @@ + return spi->master->transfer(spi, message); + } + ++/** ++ * spi_non_blocking_transfer - Synchronous, non blocking transfer ++ * @spi: device with which data will be exchanged ++ * @message: describes the data transfers with optional completion handlers ++ * Context: any (irqs may be blocked, etc) ++ * ++ * Data is guaranteed to be written or read when this function returns. ++ * ++ * Note : This may not be supported by all spi masters. ++ */ ++ ++static inline int ++spi_non_blocking_transfer(struct spi_device *spi, struct spi_message *message) ++{ ++ if (unlikely(!spi->master->transfer_sync)) { ++ dev_err(&spi->master->dev, ++ "non-blocking transfers not supported\n"); ++ return -EIO; ++ } ++ ++ return spi->master->transfer_sync(spi, message); ++} ++ + /*---------------------------------------------------------------------------*/ + + /* All these synchronous SPI transfer routines are utilities layered |