Blackfin: bfin_spi: support gpios as chip selects

Rather than only support the pins dedicated as chip selects, utilize the
gpio framework to support any gpio pin.

Signed-off-by: Mike Frysinger <vapier@gentoo.org>
diff --git a/drivers/spi/bfin_spi.c b/drivers/spi/bfin_spi.c
index 4e008a7..e0ad029 100644
--- a/drivers/spi/bfin_spi.c
+++ b/drivers/spi/bfin_spi.c
@@ -13,6 +13,7 @@
 #include <spi.h>
 
 #include <asm/blackfin.h>
+#include <asm/gpio.h>
 #include <asm/portmux.h>
 #include <asm/mach-common/bits/spi.h>
 
@@ -34,48 +35,68 @@
 
 #define to_bfin_spi_slave(s) container_of(s, struct bfin_spi_slave, slave)
 
-__attribute__((weak))
+#define MAX_CTRL_CS 7
+
+#define gpio_cs(cs) ((cs) - MAX_CTRL_CS)
+#ifdef CONFIG_BFIN_SPI_GPIO_CS
+# define is_gpio_cs(cs) ((cs) > MAX_CTRL_CS)
+#else
+# define is_gpio_cs(cs) 0
+#endif
+
 int spi_cs_is_valid(unsigned int bus, unsigned int cs)
 {
-#if defined(__ADSPBF538__) || defined(__ADSPBF539__)
-	/* The SPI1/SPI2 buses are weird ... only 1 CS */
-	if (bus > 0 && cs != 1)
-		return 0;
-#endif
-	return (cs >= 1 && cs <= 7);
+	if (is_gpio_cs(cs))
+		return gpio_is_valid(gpio_cs(cs));
+	else
+		return (cs >= 1 && cs <= MAX_CTRL_CS);
 }
 
-__attribute__((weak))
 void spi_cs_activate(struct spi_slave *slave)
 {
 	struct bfin_spi_slave *bss = to_bfin_spi_slave(slave);
-	write_SPI_FLG(bss,
-		(read_SPI_FLG(bss) &
-		~((!bss->flg << 8) << slave->cs)) |
-		(1 << slave->cs));
+
+	if (is_gpio_cs(slave->cs)) {
+		unsigned int cs = gpio_cs(slave->cs);
+		gpio_set_value(cs, bss->flg);
+		debug("%s: SPI_CS_GPIO:%x\n", __func__, gpio_get_value(cs));
+	} else {
+		write_SPI_FLG(bss,
+			(read_SPI_FLG(bss) &
+			~((!bss->flg << 8) << slave->cs)) |
+			(1 << slave->cs));
+		debug("%s: SPI_FLG:%x\n", __func__, read_SPI_FLG(bss));
+	}
+
 	SSYNC();
-	debug("%s: SPI_FLG:%x\n", __func__, read_SPI_FLG(bss));
 }
 
-__attribute__((weak))
 void spi_cs_deactivate(struct spi_slave *slave)
 {
 	struct bfin_spi_slave *bss = to_bfin_spi_slave(slave);
-	u16 flg;
 
-	/* make sure we force the cs to deassert rather than let the
-	 * pin float back up.  otherwise, exact timings may not be
-	 * met some of the time leading to random behavior (ugh).
-	 */
-	flg = read_SPI_FLG(bss) | ((!bss->flg << 8) << slave->cs);
-	write_SPI_FLG(bss, flg);
-	SSYNC();
-	debug("%s: SPI_FLG:%x\n", __func__, read_SPI_FLG(bss));
+	if (is_gpio_cs(slave->cs)) {
+		unsigned int cs = gpio_cs(slave->cs);
+		gpio_set_value(cs, !bss->flg);
+		debug("%s: SPI_CS_GPIO:%x\n", __func__, gpio_get_value(cs));
+	} else {
+		u16 flg;
 
-	flg &= ~(1 << slave->cs);
-	write_SPI_FLG(bss, flg);
+		/* make sure we force the cs to deassert rather than let the
+		 * pin float back up.  otherwise, exact timings may not be
+		 * met some of the time leading to random behavior (ugh).
+		 */
+		flg = read_SPI_FLG(bss) | ((!bss->flg << 8) << slave->cs);
+		write_SPI_FLG(bss, flg);
+		SSYNC();
+		debug("%s: SPI_FLG:%x\n", __func__, read_SPI_FLG(bss));
+
+		flg &= ~(1 << slave->cs);
+		write_SPI_FLG(bss, flg);
+		debug("%s: SPI_FLG:%x\n", __func__, read_SPI_FLG(bss));
+	}
+
 	SSYNC();
-	debug("%s: SPI_FLG:%x\n", __func__, read_SPI_FLG(bss));
 }
 
 void spi_init()
@@ -188,7 +209,13 @@
 
 	debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
 
-	pins[slave->bus][0] = cs_pins[slave->bus][slave->cs - 1];
+	if (is_gpio_cs(slave->cs)) {
+		unsigned int cs = gpio_cs(slave->cs);
+		gpio_request(cs, "bfin-spi");
+		gpio_direction_output(cs, !bss->flg);
+		pins[slave->bus][0] = P_DONTCARE;
+	} else
+		pins[slave->bus][0] = cs_pins[slave->bus][slave->cs - 1];
 	peripheral_request_list(pins[slave->bus], "bfin-spi");
 
 	write_SPI_CTL(bss, bss->ctl);
@@ -205,6 +232,8 @@
 	debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
 
 	peripheral_free_list(pins[slave->bus]);
+	if (is_gpio_cs(slave->cs))
+		gpio_free(gpio_cs(slave->cs));
 
 	write_SPI_CTL(bss, 0);
 	SSYNC();