spi_qsd: GPIO configuration changes for SPI chip-select line

The chip-select GPIO's pertaining to each slave remains in suspended
configuration until the first transfer is intiated by the slave.

Change-Id: I3aa8555289be7ce457b91a969cf03909be0965d7
Signed-off-by: Harini Jayaraman <harinij@codeaurora.org>
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 4896556..aaeb790 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -172,11 +172,17 @@
 
 static char const * const spi_rsrcs[] = {
 	"spi_clk",
-	"spi_cs",
 	"spi_miso",
 	"spi_mosi"
 };
 
+static char const * const spi_cs_rsrcs[] = {
+	"spi_cs",
+	"spi_cs1",
+	"spi_cs2",
+	"spi_cs3",
+};
+
 enum msm_spi_mode {
 	SPI_FIFO_MODE  = 0x0,  /* 00 */
 	SPI_BLOCK_MODE = 0x1,  /* 01 */
@@ -184,6 +190,12 @@
 	SPI_MODE_NONE  = 0xFF, /* invalid value */
 };
 
+/* Structure for SPI CS GPIOs */
+struct spi_cs_gpio {
+	int  gpio_num;
+	bool valid;
+};
+
 /* Structures for Data Mover */
 struct spi_dmov_cmd {
 	dmov_box box;      /* data aligned to max(dm_burst_size, block_size)
@@ -330,8 +342,10 @@
 	struct spi_transfer     *cur_rx_transfer;
 	/* Temporary buffer used for WR-WR or WR-RD transfers */
 	u8                      *temp_buf;
-	/* GPIO pin numbers for SPI clk, cs, miso and mosi */
+	/* GPIO pin numbers for SPI clk, miso and mosi */
 	int                      spi_gpios[ARRAY_SIZE(spi_rsrcs)];
+	/* SPI CS GPIOs for each slave */
+	struct spi_cs_gpio       cs_gpios[ARRAY_SIZE(spi_cs_rsrcs)];
 };
 
 /* Forward declaration */
@@ -635,8 +649,8 @@
 		if (dd->spi_gpios[i] >= 0) {
 			result = gpio_request(dd->spi_gpios[i], spi_rsrcs[i]);
 			if (result) {
-				pr_err("%s: gpio_request for pin %d failed\
-					with error%d\n", __func__,
+				dev_err(dd->dev, "%s: gpio_request for pin %d "
+					"failed with error %d\n", __func__,
 					dd->spi_gpios[i], result);
 				goto error;
 			}
@@ -660,6 +674,13 @@
 		if (dd->spi_gpios[i] >= 0)
 			gpio_free(dd->spi_gpios[i]);
 	}
+
+	for (i = 0; i < ARRAY_SIZE(spi_cs_rsrcs); ++i) {
+		if (dd->cs_gpios[i].valid) {
+			gpio_free(dd->cs_gpios[i].gpio_num);
+			dd->cs_gpios[i].valid = 0;
+		}
+	}
 }
 
 static void msm_spi_clock_set(struct msm_spi *dd, int speed)
@@ -1652,7 +1673,24 @@
 static void msm_spi_process_message(struct msm_spi *dd)
 {
 	int xfrs_grped = 0;
+	int cs_num;
+	int rc;
+
 	dd->write_xfr_cnt = dd->read_xfr_cnt = 0;
+	cs_num = dd->cur_msg->spi->chip_select;
+	if ((!(dd->cur_msg->spi->mode & SPI_LOOP)) &&
+		(!(dd->cs_gpios[cs_num].valid)) &&
+		(dd->cs_gpios[cs_num].gpio_num >= 0)) {
+		rc = gpio_request(dd->cs_gpios[cs_num].gpio_num,
+				spi_cs_rsrcs[cs_num]);
+		if (rc) {
+			dev_err(dd->dev, "gpio_request for pin %d failed with "
+				"error %d\n", dd->cs_gpios[cs_num].gpio_num,
+				rc);
+			return;
+		}
+		dd->cs_gpios[cs_num].valid = 1;
+	}
 
 	dd->cur_transfer = list_first_entry(&dd->cur_msg->transfers,
 					    struct spi_transfer,
@@ -1664,7 +1702,7 @@
 				    &dd->cur_msg->transfers,
 				    transfer_list) {
 			if (!dd->cur_transfer->len)
-				return;
+				goto error;
 			if (xfrs_grped) {
 				xfrs_grped--;
 				continue;
@@ -1686,12 +1724,20 @@
 			int ret = msm_spi_map_dma_buffers(dd);
 			if (ret < 0) {
 				dd->cur_msg->status = ret;
-				return;
+				goto error;
 			}
 		}
 		dd->cur_tx_transfer = dd->cur_rx_transfer = dd->cur_transfer;
 		msm_spi_process_transfer(dd);
 	}
+
+	return;
+
+error:
+	if (dd->cs_gpios[cs_num].valid) {
+		gpio_free(dd->cs_gpios[cs_num].gpio_num);
+		dd->cs_gpios[cs_num].valid = 0;
+	}
 }
 
 /* workqueue - pull messages from queue & process */
@@ -2257,9 +2303,17 @@
 		dd->spi_gpios[i] = resource ? resource->start : -1;
 	}
 
+	for (i = 0; i < ARRAY_SIZE(spi_cs_rsrcs); ++i) {
+		resource = platform_get_resource_byname(pdev, IORESOURCE_IO,
+							spi_cs_rsrcs[i]);
+		dd->cs_gpios[i].gpio_num = resource ? resource->start : -1;
+		dd->cs_gpios[i].valid = 0;
+	}
+
 	rc = msm_spi_request_gpios(dd);
 	if (rc)
 		goto err_probe_gpio;
+
 	spin_lock_init(&dd->queue_lock);
 	mutex_init(&dd->core_lock);
 	INIT_LIST_HEAD(&dd->queue);