NFC: trf7970a: Handle timeout values of zero

The digital layer can try to send a command with a
timeout value of zero (e.g., digital_tg_send_psl_res().
The zero value is used as a flag to indicate that
the driver should not expect a response.  To handle
this, the driver sets an internal timer because it
should still get an interrupt with the TX bit set
in the IRQ Status Register.  When it gets that
interrupt, it returns a return value of '0'.
If it doesn't get the interrupt before timing out,
it returns ETIMEDOUT as usual.

Signed-off-by: Mark A. Greer <mgreer@animalcreek.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c
index 00fb2ce..8b109e1 100644
--- a/drivers/nfc/trf7970a.c
+++ b/drivers/nfc/trf7970a.c
@@ -132,6 +132,7 @@
 /* TX length is 3 nibbles long ==> 4KB - 1 bytes max */
 #define TRF7970A_TX_MAX				(4096 - 1)
 
+#define TRF7970A_WAIT_FOR_TX_IRQ		20
 #define TRF7970A_WAIT_FOR_RX_DATA_TIMEOUT	20
 #define TRF7970A_WAIT_FOR_FIFO_DRAIN_TIMEOUT	20
 #define TRF7970A_WAIT_TO_ISSUE_ISO15693_EOF	40
@@ -555,7 +556,11 @@
 			timeout = TRF7970A_WAIT_TO_ISSUE_ISO15693_EOF;
 		} else {
 			trf->state = TRF7970A_ST_WAIT_FOR_RX_DATA;
-			timeout = trf->timeout;
+
+			if (!trf->timeout)
+				timeout = TRF7970A_WAIT_FOR_TX_IRQ;
+			else
+				timeout = trf->timeout;
 		}
 	}
 
@@ -754,6 +759,14 @@
 				trf7970a_cmd(trf, TRF7970A_CMD_FIFO_RESET);
 		} else if (status == TRF7970A_IRQ_STATUS_TX) {
 			trf7970a_cmd(trf, TRF7970A_CMD_FIFO_RESET);
+
+			if (!trf->timeout) {
+				trf->ignore_timeout = !cancel_delayed_work(
+						&trf->timeout_work);
+				trf->rx_skb = ERR_PTR(0);
+				trf7970a_send_upstream(trf);
+				break;
+			}
 		} else {
 			trf7970a_send_err_upstream(trf, -EIO);
 		}
@@ -1253,12 +1266,14 @@
 		goto out_err;
 	}
 
-	trf->rx_skb = nfc_alloc_recv_skb(TRF7970A_RX_SKB_ALLOC_SIZE,
-			GFP_KERNEL);
-	if (!trf->rx_skb) {
-		dev_dbg(trf->dev, "Can't alloc rx_skb\n");
-		ret = -ENOMEM;
-		goto out_err;
+	if (timeout) {
+		trf->rx_skb = nfc_alloc_recv_skb(TRF7970A_RX_SKB_ALLOC_SIZE,
+				GFP_KERNEL);
+		if (!trf->rx_skb) {
+			dev_dbg(trf->dev, "Can't alloc rx_skb\n");
+			ret = -ENOMEM;
+			goto out_err;
+		}
 	}
 
 	if (trf->state == TRF7970A_ST_IDLE_RX_BLOCKED) {