aboutsummaryrefslogtreecommitdiffstats
path: root/recipes/linux/linux-openmoko-2.6.30.4/060-spi-gpio-non-blocking.patch
diff options
context:
space:
mode:
Diffstat (limited to 'recipes/linux/linux-openmoko-2.6.30.4/060-spi-gpio-non-blocking.patch')
-rw-r--r--recipes/linux/linux-openmoko-2.6.30.4/060-spi-gpio-non-blocking.patch418
1 files changed, 418 insertions, 0 deletions
diff --git a/recipes/linux/linux-openmoko-2.6.30.4/060-spi-gpio-non-blocking.patch b/recipes/linux/linux-openmoko-2.6.30.4/060-spi-gpio-non-blocking.patch
new file mode 100644
index 0000000000..3dcf9c0486
--- /dev/null
+++ b/recipes/linux/linux-openmoko-2.6.30.4/060-spi-gpio-non-blocking.patch
@@ -0,0 +1,418 @@
+--- a/arch/arm/mach-s3c2410/include/mach/spi-gpio.h
++++ b/arch/arm/mach-s3c2410/include/mach/spi-gpio.h
+@@ -21,7 +21,8 @@ struct s3c2410_spigpio_info {
+ 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);
+ };
+
+
+--- a/drivers/spi/spi_bitbang.c
++++ b/drivers/spi/spi_bitbang.c
+@@ -264,6 +264,123 @@ static int spi_bitbang_bufs(struct spi_d
+ * 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 @@ static void bitbang_work(struct work_str
+ 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 @@ int spi_bitbang_start(struct spi_bitbang
+
+ 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;
+--- a/drivers/spi/spi_s3c24xx_gpio.c
++++ b/drivers/spi/spi_s3c24xx_gpio.c
+@@ -91,7 +91,7 @@ static void s3c2410_spigpio_chipselect(s
+ 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 @@ static int s3c2410_spigpio_probe(struct
+
+ 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;
+--- a/include/linux/mmc/core.h
++++ b/include/linux/mmc/core.h
+@@ -129,6 +129,8 @@ struct mmc_request {
+ 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 *,
+--- a/include/linux/mmc/sdio_ids.h
++++ b/include/linux/mmc/sdio_ids.h
+@@ -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
+--- a/include/linux/spi/spi_bitbang.h
++++ b/include/linux/spi/spi_bitbang.h
+@@ -31,6 +31,9 @@ struct spi_bitbang {
+ 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 void spi_bitbang_cleanup(struct s
+ 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);
+--- a/include/linux/spi/spi.h
++++ b/include/linux/spi/spi.h
+@@ -204,7 +204,6 @@ static inline void spi_unregister_driver
+ * 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 @@ struct spi_master {
+ */
+ 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 @@ struct spi_master {
+ 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 @@ spi_async(struct spi_device *spi, struct
+ 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