mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-11-04 06:54:27 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			419 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			419 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
--- 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
 |