Merge git://git.denx.de/u-boot-spi
diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c
index c501aee..0e93b62 100644
--- a/drivers/spi/designware_spi.c
+++ b/drivers/spi/designware_spi.c
@@ -10,6 +10,7 @@
  * SPDX-License-Identifier:	GPL-2.0
  */
 
+#include <asm-generic/gpio.h>
 #include <common.h>
 #include <clk.h>
 #include <dm.h>
@@ -18,6 +19,7 @@
 #include <spi.h>
 #include <fdtdec.h>
 #include <linux/compat.h>
+#include <linux/iopoll.h>
 #include <asm/io.h>
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -97,6 +99,8 @@
 	struct clk clk;
 	unsigned long bus_clk_rate;
 
+	struct gpio_desc cs_gpio;	/* External chip-select gpio */
+
 	int bits_per_word;
 	u8 cs;			/* chip select pin */
 	u8 tmode;		/* TR/TO/RO/EEPROM */
@@ -110,24 +114,40 @@
 	void *rx_end;
 };
 
-static inline u32 dw_readl(struct dw_spi_priv *priv, u32 offset)
+static inline u32 dw_read(struct dw_spi_priv *priv, u32 offset)
 {
 	return __raw_readl(priv->regs + offset);
 }
 
-static inline void dw_writel(struct dw_spi_priv *priv, u32 offset, u32 val)
+static inline void dw_write(struct dw_spi_priv *priv, u32 offset, u32 val)
 {
 	__raw_writel(val, priv->regs + offset);
 }
 
-static inline u16 dw_readw(struct dw_spi_priv *priv, u32 offset)
+static int request_gpio_cs(struct udevice *bus)
 {
-	return __raw_readw(priv->regs + offset);
-}
+#if defined(CONFIG_DM_GPIO) && !defined(CONFIG_SPL_BUILD)
+	struct dw_spi_priv *priv = dev_get_priv(bus);
+	int ret;
 
-static inline void dw_writew(struct dw_spi_priv *priv, u32 offset, u16 val)
-{
-	__raw_writew(val, priv->regs + offset);
+	/* External chip select gpio line is optional */
+	ret = gpio_request_by_name(bus, "cs-gpio", 0, &priv->cs_gpio, 0);
+	if (ret == -ENOENT)
+		return 0;
+
+	if (ret < 0) {
+		printf("Error: %d: Can't get %s gpio!\n", ret, bus->name);
+		return ret;
+	}
+
+	if (dm_gpio_is_valid(&priv->cs_gpio)) {
+		dm_gpio_set_dir_flags(&priv->cs_gpio,
+				      GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+	}
+
+	debug("%s: used external gpio for CS management\n", __func__);
+#endif
+	return 0;
 }
 
 static int dw_spi_ofdata_to_platdata(struct udevice *bus)
@@ -144,19 +164,19 @@
 	debug("%s: regs=%p max-frequency=%d\n", __func__, plat->regs,
 	      plat->frequency);
 
-	return 0;
+	return request_gpio_cs(bus);
 }
 
 static inline void spi_enable_chip(struct dw_spi_priv *priv, int enable)
 {
-	dw_writel(priv, DW_SPI_SSIENR, (enable ? 1 : 0));
+	dw_write(priv, DW_SPI_SSIENR, (enable ? 1 : 0));
 }
 
 /* Restart the controller, disable all interrupts, clean rx fifo */
 static void spi_hw_init(struct dw_spi_priv *priv)
 {
 	spi_enable_chip(priv, 0);
-	dw_writel(priv, DW_SPI_IMR, 0xff);
+	dw_write(priv, DW_SPI_IMR, 0xff);
 	spi_enable_chip(priv, 1);
 
 	/*
@@ -167,13 +187,13 @@
 		u32 fifo;
 
 		for (fifo = 1; fifo < 256; fifo++) {
-			dw_writew(priv, DW_SPI_TXFLTR, fifo);
-			if (fifo != dw_readw(priv, DW_SPI_TXFLTR))
+			dw_write(priv, DW_SPI_TXFLTR, fifo);
+			if (fifo != dw_read(priv, DW_SPI_TXFLTR))
 				break;
 		}
 
 		priv->fifo_len = (fifo == 1) ? 0 : fifo;
-		dw_writew(priv, DW_SPI_TXFLTR, 0);
+		dw_write(priv, DW_SPI_TXFLTR, 0);
 	}
 	debug("%s: fifo_len=%d\n", __func__, priv->fifo_len);
 }
@@ -242,7 +262,7 @@
 	u32 tx_left, tx_room, rxtx_gap;
 
 	tx_left = (priv->tx_end - priv->tx) / (priv->bits_per_word >> 3);
-	tx_room = priv->fifo_len - dw_readw(priv, DW_SPI_TXFLR);
+	tx_room = priv->fifo_len - dw_read(priv, DW_SPI_TXFLR);
 
 	/*
 	 * Another concern is about the tx/rx mismatch, we
@@ -263,7 +283,7 @@
 {
 	u32 rx_left = (priv->rx_end - priv->rx) / (priv->bits_per_word >> 3);
 
-	return min_t(u32, rx_left, dw_readw(priv, DW_SPI_RXFLR));
+	return min_t(u32, rx_left, dw_read(priv, DW_SPI_RXFLR));
 }
 
 static void dw_writer(struct dw_spi_priv *priv)
@@ -279,34 +299,22 @@
 			else
 				txw = *(u16 *)(priv->tx);
 		}
-		dw_writew(priv, DW_SPI_DR, txw);
+		dw_write(priv, DW_SPI_DR, txw);
 		debug("%s: tx=0x%02x\n", __func__, txw);
 		priv->tx += priv->bits_per_word >> 3;
 	}
 }
 
-static int dw_reader(struct dw_spi_priv *priv)
+static void dw_reader(struct dw_spi_priv *priv)
 {
-	unsigned start = get_timer(0);
-	u32 max;
+	u32 max = rx_max(priv);
 	u16 rxw;
 
-	/* Wait for rx data to be ready */
-	while (rx_max(priv) == 0) {
-		if (get_timer(start) > RX_TIMEOUT)
-			return -ETIMEDOUT;
-	}
-
-	max = rx_max(priv);
-
 	while (max--) {
-		rxw = dw_readw(priv, DW_SPI_DR);
+		rxw = dw_read(priv, DW_SPI_DR);
 		debug("%s: rx=0x%02x\n", __func__, rxw);
 
-		/*
-		 * Care about rx only if the transfer's original "rx" is
-		 * not null
-		 */
+		/* Care about rx if the transfer's original "rx" is not null */
 		if (priv->rx_end - priv->len) {
 			if (priv->bits_per_word == 8)
 				*(u8 *)(priv->rx) = rxw;
@@ -315,24 +323,30 @@
 		}
 		priv->rx += priv->bits_per_word >> 3;
 	}
-
-	return 0;
 }
 
 static int poll_transfer(struct dw_spi_priv *priv)
 {
-	int ret;
-
 	do {
 		dw_writer(priv);
-		ret = dw_reader(priv);
-		if (ret < 0)
-			return ret;
+		dw_reader(priv);
 	} while (priv->rx_end > priv->rx);
 
 	return 0;
 }
 
+static void external_cs_manage(struct udevice *dev, bool on)
+{
+#if defined(CONFIG_DM_GPIO) && !defined(CONFIG_SPL_BUILD)
+	struct dw_spi_priv *priv = dev_get_priv(dev->parent);
+
+	if (!dm_gpio_is_valid(&priv->cs_gpio))
+		return;
+
+	dm_gpio_set_value(&priv->cs_gpio, on ? 1 : 0);
+#endif
+}
+
 static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen,
 		       const void *dout, void *din, unsigned long flags)
 {
@@ -342,6 +356,7 @@
 	u8 *rx = din;
 	int ret = 0;
 	u32 cr0 = 0;
+	u32 val;
 	u32 cs;
 
 	/* spi core configured to do 8 bit transfers */
@@ -350,6 +365,10 @@
 		return -1;
 	}
 
+	/* Start the transaction if necessary. */
+	if (flags & SPI_XFER_BEGIN)
+		external_cs_manage(dev, false);
+
 	cr0 = (priv->bits_per_word - 1) | (priv->type << SPI_FRF_OFFSET) |
 		(priv->mode << SPI_MODE_OFFSET) |
 		(priv->tmode << SPI_TMOD_OFFSET);
@@ -359,7 +378,11 @@
 	else if (rx)
 		priv->tmode = SPI_TMOD_RO;
 	else
-		priv->tmode = SPI_TMOD_TO;
+		/*
+		 * In transmit only mode (SPI_TMOD_TO) input FIFO never gets
+		 * any data which breaks our logic in poll_transfer() above.
+		 */
+		priv->tmode = SPI_TMOD_TR;
 
 	cr0 &= ~SPI_TMOD_MASK;
 	cr0 |= (priv->tmode << SPI_TMOD_OFFSET);
@@ -377,8 +400,8 @@
 
 	debug("%s: cr0=%08x\n", __func__, cr0);
 	/* Reprogram cr0 only if changed */
-	if (dw_readw(priv, DW_SPI_CTRL0) != cr0)
-		dw_writew(priv, DW_SPI_CTRL0, cr0);
+	if (dw_read(priv, DW_SPI_CTRL0) != cr0)
+		dw_write(priv, DW_SPI_CTRL0, cr0);
 
 	/*
 	 * Configure the desired SS (slave select 0...3) in the controller
@@ -386,7 +409,7 @@
 	 * automatically. So no cs_activate() etc is needed in this driver.
 	 */
 	cs = spi_chip_select(dev);
-	dw_writel(priv, DW_SPI_SER, 1 << cs);
+	dw_write(priv, DW_SPI_SER, 1 << cs);
 
 	/* Enable controller after writing control registers */
 	spi_enable_chip(priv, 1);
@@ -394,6 +417,23 @@
 	/* Start transfer in a polling loop */
 	ret = poll_transfer(priv);
 
+	/*
+	 * Wait for current transmit operation to complete.
+	 * Otherwise if some data still exists in Tx FIFO it can be
+	 * silently flushed, i.e. dropped on disabling of the controller,
+	 * which happens when writing 0 to DW_SPI_SSIENR which happens
+	 * in the beginning of new transfer.
+	 */
+	if (readl_poll_timeout(priv->regs + DW_SPI_SR, val,
+			       !(val & SR_TF_EMPT) || (val & SR_BUSY),
+			       RX_TIMEOUT * 1000)) {
+		ret = -ETIMEDOUT;
+	}
+
+	/* Stop the transaction if necessary */
+	if (flags & SPI_XFER_END)
+		external_cs_manage(dev, true);
+
 	return ret;
 }
 
@@ -412,7 +452,7 @@
 	/* clk_div doesn't support odd number */
 	clk_div = priv->bus_clk_rate / speed;
 	clk_div = (clk_div + 1) & 0xfffe;
-	dw_writel(priv, DW_SPI_BAUDR, clk_div);
+	dw_write(priv, DW_SPI_BAUDR, clk_div);
 
 	/* Enable controller after writing control registers */
 	spi_enable_chip(priv, 1);
diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c
index 053a67b..1ac691a 100644
--- a/drivers/spi/omap3_spi.c
+++ b/drivers/spi/omap3_spi.c
@@ -630,8 +630,10 @@
 		(struct omap2_mcspi_platform_config*)dev_get_driver_data(dev);
 
 	priv->regs = (struct mcspi *)(devfdt_get_addr(dev) + data->regs_offset);
-	priv->pin_dir = fdtdec_get_uint(blob, node, "ti,pindir-d0-out-d1-in",
-					    MCSPI_PINDIR_D0_IN_D1_OUT);
+	if (fdtdec_get_bool(blob, node, "ti,pindir-d0-out-d1-in"))
+		priv->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN;
+	else
+		priv->pin_dir = MCSPI_PINDIR_D0_IN_D1_OUT;
 	priv->wordlen = SPI_DEFAULT_WORDLEN;
 	return 0;
 }