NFC: trf7970a: Add Target Mode Support
authorMark A. Greer <mgreer@animalcreek.com>
Tue, 2 Sep 2014 22:12:45 +0000 (15:12 -0700)
committerSamuel Ortiz <sameo@linux.intel.com>
Sun, 7 Sep 2014 21:13:45 +0000 (23:13 +0200)
Add target mode support to the trf7970a
NFC driver.  This effectively enables full
Peer-to-Peer support.

To handle changing framing between sending
a response frame and receiving the subsequent
request frame, most of the framing changes
take effect in the interrupt handler and not
in trf7970a_tg_config_framing().

Signed-off-by: Mark A. Greer <mgreer@animalcreek.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
drivers/nfc/trf7970a.c

index 8b109e15687f6217cdb009f6aa56b96063741c8d..b33cc0211f5362aa8b0d02a09daa6058abf1c319 100644 (file)
@@ -62,7 +62,7 @@
  * way to abort a command that's already been sent to the tag is so turn
  * off power to the tag.  If we do that, though, we'd have to go through
  * the entire anticollision procedure again but the digital layer doesn't
- * support that.  So, if an abort is received before trf7970a_in_send_cmd()
+ * support that.  So, if an abort is received before trf7970a_send_cmd()
  * has sent the command to the tag, it simply returns -ECANCELED.  If the
  * command has already been sent to the tag, then the driver continues
  * normally and recieves the response data (or error) but just before
 #define TRF7970A_SUPPORTED_PROTOCOLS \
                (NFC_PROTO_MIFARE_MASK | NFC_PROTO_ISO14443_MASK |      \
                 NFC_PROTO_ISO14443_B_MASK | NFC_PROTO_FELICA_MASK | \
-                NFC_PROTO_ISO15693_MASK)
+                NFC_PROTO_ISO15693_MASK | NFC_PROTO_NFC_DEP_MASK)
 
 #define TRF7970A_AUTOSUSPEND_DELAY             30000 /* 30 seconds */
 
 #define TRF7970A_ISO_CTRL_14443B_848           0x0f
 #define TRF7970A_ISO_CTRL_FELICA_212           0x1a
 #define TRF7970A_ISO_CTRL_FELICA_424           0x1b
+#define TRF7970A_ISO_CTRL_NFC_NFCA_106         0x01
+#define TRF7970A_ISO_CTRL_NFC_NFCF_212         0x02
+#define TRF7970A_ISO_CTRL_NFC_NFCF_424         0x03
+#define TRF7970A_ISO_CTRL_NFC_CE_14443A                0x00
+#define TRF7970A_ISO_CTRL_NFC_CE_14443B                0x01
+#define TRF7970A_ISO_CTRL_NFC_CE               BIT(2)
+#define TRF7970A_ISO_CTRL_NFC_ACTIVE           BIT(3)
+#define TRF7970A_ISO_CTRL_NFC_INITIATOR                BIT(4)
+#define TRF7970A_ISO_CTRL_NFC_NFC_CE_MODE      BIT(5)
 #define TRF7970A_ISO_CTRL_RFID                 BIT(5)
 #define TRF7970A_ISO_CTRL_DIR_MODE             BIT(6)
 #define TRF7970A_ISO_CTRL_RX_CRC_N             BIT(7)  /* true == No CRC */
 #define TRF7970A_MODULATOR_EN_OOK              BIT(6)
 #define TRF7970A_MODULATOR_27MHZ               BIT(7)
 
+#define TRF7970A_RX_SPECIAL_SETTINGS_NO_LIM    BIT(0)
+#define TRF7970A_RX_SPECIAL_SETTINGS_AGCR      BIT(1)
+#define TRF7970A_RX_SPECIAL_SETTINGS_GD_0DB    (0x0 << 2)
+#define TRF7970A_RX_SPECIAL_SETTINGS_GD_5DB    (0x1 << 2)
+#define TRF7970A_RX_SPECIAL_SETTINGS_GD_10DB   (0x2 << 2)
+#define TRF7970A_RX_SPECIAL_SETTINGS_GD_15DB   (0x3 << 2)
+#define TRF7970A_RX_SPECIAL_SETTINGS_HBT       BIT(4)
+#define TRF7970A_RX_SPECIAL_SETTINGS_M848      BIT(5)
+#define TRF7970A_RX_SPECIAL_SETTINGS_C424      BIT(6)
+#define TRF7970A_RX_SPECIAL_SETTINGS_C212      BIT(7)
+
+#define TRF7970A_REG_IO_CTRL_VRS(v)            ((v) & 0x07)
+#define TRF7970A_REG_IO_CTRL_IO_LOW            BIT(5)
+#define TRF7970A_REG_IO_CTRL_EN_EXT_PA         BIT(6)
+#define TRF7970A_REG_IO_CTRL_AUTO_REG          BIT(7)
+
 /* IRQ Status Register Bits */
 #define TRF7970A_IRQ_STATUS_NORESP             BIT(0) /* ISO15693 only */
+#define TRF7970A_IRQ_STATUS_NFC_COL_ERROR      BIT(0)
 #define TRF7970A_IRQ_STATUS_COL                        BIT(1)
 #define TRF7970A_IRQ_STATUS_FRAMING_EOF_ERROR  BIT(2)
+#define TRF7970A_IRQ_STATUS_NFC_RF             BIT(2)
 #define TRF7970A_IRQ_STATUS_PARITY_ERROR       BIT(3)
+#define TRF7970A_IRQ_STATUS_NFC_SDD            BIT(3)
 #define TRF7970A_IRQ_STATUS_CRC_ERROR          BIT(4)
+#define TRF7970A_IRQ_STATUS_NFC_PROTO_ERROR    BIT(4)
 #define TRF7970A_IRQ_STATUS_FIFO               BIT(5)
 #define TRF7970A_IRQ_STATUS_SRX                        BIT(6)
 #define TRF7970A_IRQ_STATUS_TX                 BIT(7)
 #define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_16      0x2
 #define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_32      0x3
 
+#define TRF7970A_NFC_LOW_FIELD_LEVEL_RFDET(v)  ((v) & 0x07)
+#define TRF7970A_NFC_LOW_FIELD_LEVEL_CLEX_DIS  BIT(7)
+
+#define TRF7970A_NFC_TARGET_LEVEL_RFDET(v)     ((v) & 0x07)
+#define TRF7970A_NFC_TARGET_LEVEL_HI_RF                BIT(3)
+#define TRF7970A_NFC_TARGET_LEVEL_SDD_EN       BIT(3)
+#define TRF7970A_NFC_TARGET_LEVEL_LD_S_4BYTES  (0x0 << 6)
+#define TRF7970A_NFC_TARGET_LEVEL_LD_S_7BYTES  (0x1 << 6)
+#define TRF7970A_NFC_TARGET_LEVEL_LD_S_10BYTES (0x2 << 6)
+
 #define TRF7970A_FIFO_STATUS_OVERFLOW          BIT(7)
 
 /* NFC (ISO/IEC 14443A) Type 2 Tag commands */
@@ -345,6 +384,7 @@ enum trf7970a_state {
        TRF7970A_ST_WAIT_FOR_RX_DATA,
        TRF7970A_ST_WAIT_FOR_RX_DATA_CONT,
        TRF7970A_ST_WAIT_TO_ISSUE_EOF,
+       TRF7970A_ST_LISTENING,
        TRF7970A_ST_MAX
 };
 
@@ -355,6 +395,7 @@ struct trf7970a {
        struct regulator                *regulator;
        struct nfc_digital_dev          *ddev;
        u32                             quirks;
+       bool                            is_initiator;
        bool                            aborting;
        struct sk_buff                  *tx_skb;
        struct sk_buff                  *rx_skb;
@@ -694,7 +735,7 @@ static irqreturn_t trf7970a_irq(int irq, void *dev_id)
 {
        struct trf7970a *trf = dev_id;
        int ret;
-       u8 status, fifo_bytes;
+       u8 status, fifo_bytes, iso_ctrl;
 
        mutex_lock(&trf->lock);
 
@@ -720,12 +761,12 @@ static irqreturn_t trf7970a_irq(int irq, void *dev_id)
        switch (trf->state) {
        case TRF7970A_ST_IDLE:
        case TRF7970A_ST_IDLE_RX_BLOCKED:
-               /* If getting interrupts caused by RF noise, turn off the
-                * receiver to avoid unnecessary interrupts.  It will be
-                * turned back on in trf7970a_in_send_cmd() when the next
-                * command is issued.
+               /* If initiator and getting interrupts caused by RF noise,
+                * turn off the receiver to avoid unnecessary interrupts.
+                * It will be turned back on in trf7970a_send_cmd() when
+                * the next command is issued.
                 */
-               if (status & TRF7970A_IRQ_STATUS_ERROR) {
+               if (trf->is_initiator && (status & TRF7970A_IRQ_STATUS_ERROR)) {
                        trf7970a_cmd(trf, TRF7970A_CMD_BLOCK_RX);
                        trf->state = TRF7970A_ST_IDLE_RX_BLOCKED;
                }
@@ -757,7 +798,10 @@ static irqreturn_t trf7970a_irq(int irq, void *dev_id)
                                trf7970a_send_err_upstream(trf, ret);
                        else if (!fifo_bytes)
                                trf7970a_cmd(trf, TRF7970A_CMD_FIFO_RESET);
-               } else if (status == TRF7970A_IRQ_STATUS_TX) {
+               } else if ((status == TRF7970A_IRQ_STATUS_TX) ||
+                               (!trf->is_initiator &&
+                                (status == (TRF7970A_IRQ_STATUS_TX |
+                                            TRF7970A_IRQ_STATUS_NFC_RF)))) {
                        trf7970a_cmd(trf, TRF7970A_CMD_FIFO_RESET);
 
                        if (!trf->timeout) {
@@ -767,6 +811,45 @@ static irqreturn_t trf7970a_irq(int irq, void *dev_id)
                                trf7970a_send_upstream(trf);
                                break;
                        }
+
+                       if (trf->is_initiator)
+                               break;
+
+                       iso_ctrl = trf->iso_ctrl;
+
+                       switch (trf->framing) {
+                       case NFC_DIGITAL_FRAMING_NFCA_STANDARD:
+                               trf->tx_cmd = TRF7970A_CMD_TRANSMIT_NO_CRC;
+                               iso_ctrl |= TRF7970A_ISO_CTRL_RX_CRC_N;
+                               trf->iso_ctrl = 0xff; /* Force ISO_CTRL write */
+                               break;
+                       case NFC_DIGITAL_FRAMING_NFCA_STANDARD_WITH_CRC_A:
+                               trf->tx_cmd = TRF7970A_CMD_TRANSMIT;
+                               iso_ctrl &= ~TRF7970A_ISO_CTRL_RX_CRC_N;
+                               trf->iso_ctrl = 0xff; /* Force ISO_CTRL write */
+                               break;
+                       case NFC_DIGITAL_FRAMING_NFCA_ANTICOL_COMPLETE:
+                               ret = trf7970a_write(trf,
+                                       TRF7970A_SPECIAL_FCN_REG1,
+                                       TRF7970A_SPECIAL_FCN_REG1_14_ANTICOLL);
+                               if (ret)
+                                       return ret;
+
+                               trf->special_fcn_reg1 =
+                                       TRF7970A_SPECIAL_FCN_REG1_14_ANTICOLL;
+                               break;
+                       default:
+                               break;
+                       }
+
+                       if (iso_ctrl != trf->iso_ctrl) {
+                               ret = trf7970a_write(trf, TRF7970A_ISO_CTRL,
+                                               iso_ctrl);
+                               if (ret)
+                                       return ret;
+
+                               trf->iso_ctrl = iso_ctrl;
+                       }
                } else {
                        trf7970a_send_err_upstream(trf, -EIO);
                }
@@ -775,6 +858,15 @@ static irqreturn_t trf7970a_irq(int irq, void *dev_id)
                if (status != TRF7970A_IRQ_STATUS_TX)
                        trf7970a_send_err_upstream(trf, -EIO);
                break;
+       case TRF7970A_ST_LISTENING:
+               if (status & TRF7970A_IRQ_STATUS_SRX) {
+                       trf->ignore_timeout =
+                               !cancel_delayed_work(&trf->timeout_work);
+                       trf7970a_drain_fifo(trf, status);
+               } else if (!(status & TRF7970A_IRQ_STATUS_NFC_RF)) {
+                       trf7970a_send_err_upstream(trf, -EIO);
+               }
+               break;
        default:
                dev_err(trf->dev, "%s - Driver in invalid state: %d\n",
                                __func__, trf->state);
@@ -853,11 +945,6 @@ static int trf7970a_init(struct trf7970a *trf)
 
        trf->modulator_sys_clk_ctrl = 0;
 
-       /* Must clear NFC Target Detection Level reg due to erratum */
-       ret = trf7970a_write(trf, TRF7970A_NFC_TARGET_LEVEL, 0);
-       if (ret)
-               goto err_out;
-
        ret = trf7970a_write(trf, TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS,
                        TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLH_96 |
                        TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_32);
@@ -958,6 +1045,8 @@ static int trf7970a_switch_rf(struct nfc_digital_dev *ddev, bool on)
                        /* FALLTHROUGH */
                case TRF7970A_ST_IDLE:
                case TRF7970A_ST_IDLE_RX_BLOCKED:
+               case TRF7970A_ST_WAIT_FOR_RX_DATA:
+               case TRF7970A_ST_WAIT_FOR_RX_DATA_CONT:
                        trf7970a_switch_rf_off(trf);
                }
        }
@@ -1005,6 +1094,14 @@ static int trf7970a_in_config_rf_tech(struct trf7970a *trf, int tech)
 
        trf->technology = tech;
 
+       /* If in initiator mode and not changing the RF tech due to a
+        * PSL sequence (indicated by 'trf->iso_ctrl == 0xff' from
+        * trf7970a_init()), clear the NFC Target Detection Level register
+        * due to erratum.
+        */
+       if (trf->iso_ctrl == 0xff)
+               ret = trf7970a_write(trf, TRF7970A_NFC_TARGET_LEVEL, 0);
+
        return ret;
 }
 
@@ -1063,6 +1160,8 @@ static int trf7970a_in_config_framing(struct trf7970a *trf, int framing)
        case NFC_DIGITAL_FRAMING_NFCF_T3T:
        case NFC_DIGITAL_FRAMING_ISO15693_INVENTORY:
        case NFC_DIGITAL_FRAMING_ISO15693_T5T:
+       case NFC_DIGITAL_FRAMING_NFCA_NFC_DEP:
+       case NFC_DIGITAL_FRAMING_NFCF_NFC_DEP:
                trf->tx_cmd = TRF7970A_CMD_TRANSMIT;
                iso_ctrl &= ~TRF7970A_ISO_CTRL_RX_CRC_N;
                break;
@@ -1124,6 +1223,8 @@ static int trf7970a_in_configure_hw(struct nfc_digital_dev *ddev, int type,
 
        mutex_lock(&trf->lock);
 
+       trf->is_initiator = true;
+
        if ((trf->state == TRF7970A_ST_PWR_OFF) ||
                        (trf->state == TRF7970A_ST_RF_OFF)) {
                ret = trf7970a_switch_rf_on(trf);
@@ -1233,7 +1334,7 @@ static int trf7970a_per_cmd_config(struct trf7970a *trf, struct sk_buff *skb)
        return 0;
 }
 
-static int trf7970a_in_send_cmd(struct nfc_digital_dev *ddev,
+static int trf7970a_send_cmd(struct nfc_digital_dev *ddev,
                struct sk_buff *skb, u16 timeout,
                nfc_digital_cmd_complete_t cb, void *arg)
 {
@@ -1284,9 +1385,11 @@ static int trf7970a_in_send_cmd(struct nfc_digital_dev *ddev,
                trf->state = TRF7970A_ST_IDLE;
        }
 
-       ret = trf7970a_per_cmd_config(trf, skb);
-       if (ret)
-               goto out_err;
+       if (trf->is_initiator) {
+               ret = trf7970a_per_cmd_config(trf, skb);
+               if (ret)
+                       goto out_err;
+       }
 
        trf->ddev = ddev;
        trf->tx_skb = skb;
@@ -1335,35 +1438,229 @@ out_err:
        return ret;
 }
 
-static int trf7970a_tg_configure_hw(struct nfc_digital_dev *ddev,
-               int type, int param)
+static int trf7970a_tg_config_rf_tech(struct trf7970a *trf, int tech)
 {
-       struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+       int ret = 0;
+
+       dev_dbg(trf->dev, "rf technology: %d\n", tech);
+
+       switch (tech) {
+       case NFC_DIGITAL_RF_TECH_106A:
+               trf->iso_ctrl_tech = TRF7970A_ISO_CTRL_NFC_NFC_CE_MODE |
+                       TRF7970A_ISO_CTRL_NFC_CE |
+                       TRF7970A_ISO_CTRL_NFC_CE_14443A;
+               trf->modulator_sys_clk_ctrl = TRF7970A_MODULATOR_DEPTH_OOK;
+               break;
+       case NFC_DIGITAL_RF_TECH_212F:
+               trf->iso_ctrl_tech = TRF7970A_ISO_CTRL_NFC_NFC_CE_MODE |
+                       TRF7970A_ISO_CTRL_NFC_NFCF_212;
+               trf->modulator_sys_clk_ctrl = TRF7970A_MODULATOR_DEPTH_ASK10;
+               break;
+       case NFC_DIGITAL_RF_TECH_424F:
+               trf->iso_ctrl_tech = TRF7970A_ISO_CTRL_NFC_NFC_CE_MODE |
+                       TRF7970A_ISO_CTRL_NFC_NFCF_424;
+               trf->modulator_sys_clk_ctrl = TRF7970A_MODULATOR_DEPTH_ASK10;
+               break;
+       default:
+               dev_dbg(trf->dev, "Unsupported rf technology: %d\n", tech);
+               return -EINVAL;
+       }
+
+       trf->technology = tech;
 
-       dev_dbg(trf->dev, "Unsupported interface\n");
+       /* Normally we write the ISO_CTRL register in
+        * trf7970a_tg_config_framing() because the framing can change
+        * the value written.  However, when sending a PSL RES,
+        * digital_tg_send_psl_res_complete() doesn't call
+        * trf7970a_tg_config_framing() so we must write the register
+        * here.
+        */
+       if ((trf->framing == NFC_DIGITAL_FRAMING_NFC_DEP_ACTIVATED) &&
+                       (trf->iso_ctrl_tech != trf->iso_ctrl)) {
+               ret = trf7970a_write(trf, TRF7970A_ISO_CTRL,
+                               trf->iso_ctrl_tech);
+
+               trf->iso_ctrl = trf->iso_ctrl_tech;
+       }
 
-       return -EINVAL;
+       return ret;
 }
 
-static int trf7970a_tg_send_cmd(struct nfc_digital_dev *ddev,
-               struct sk_buff *skb, u16 timeout,
-               nfc_digital_cmd_complete_t cb, void *arg)
+/* Since this is a target routine, several of the framing calls are
+ * made between receiving the request and sending the response so they
+ * should take effect until after the response is sent.  This is accomplished
+ * by skipping the ISO_CTRL register write here and doing it in the interrupt
+ * handler.
+ */
+static int trf7970a_tg_config_framing(struct trf7970a *trf, int framing)
+{
+       u8 iso_ctrl = trf->iso_ctrl_tech;
+       int ret;
+
+       dev_dbg(trf->dev, "framing: %d\n", framing);
+
+       switch (framing) {
+       case NFC_DIGITAL_FRAMING_NFCA_NFC_DEP:
+               trf->tx_cmd = TRF7970A_CMD_TRANSMIT_NO_CRC;
+               iso_ctrl |= TRF7970A_ISO_CTRL_RX_CRC_N;
+               break;
+       case NFC_DIGITAL_FRAMING_NFCA_STANDARD:
+       case NFC_DIGITAL_FRAMING_NFCA_STANDARD_WITH_CRC_A:
+       case NFC_DIGITAL_FRAMING_NFCA_ANTICOL_COMPLETE:
+               /* These ones are applied in the interrupt handler */
+               iso_ctrl = trf->iso_ctrl; /* Don't write to ISO_CTRL yet */
+               break;
+       case NFC_DIGITAL_FRAMING_NFCF_NFC_DEP:
+               trf->tx_cmd = TRF7970A_CMD_TRANSMIT;
+               iso_ctrl &= ~TRF7970A_ISO_CTRL_RX_CRC_N;
+               break;
+       case NFC_DIGITAL_FRAMING_NFC_DEP_ACTIVATED:
+               trf->tx_cmd = TRF7970A_CMD_TRANSMIT;
+               iso_ctrl &= ~TRF7970A_ISO_CTRL_RX_CRC_N;
+               break;
+       default:
+               dev_dbg(trf->dev, "Unsupported Framing: %d\n", framing);
+               return -EINVAL;
+       }
+
+       trf->framing = framing;
+
+       if (iso_ctrl != trf->iso_ctrl) {
+               ret = trf7970a_write(trf, TRF7970A_ISO_CTRL, iso_ctrl);
+               if (ret)
+                       return ret;
+
+               trf->iso_ctrl = iso_ctrl;
+
+               ret = trf7970a_write(trf, TRF7970A_MODULATOR_SYS_CLK_CTRL,
+                               trf->modulator_sys_clk_ctrl);
+               if (ret)
+                       return ret;
+       }
+
+       if (!(trf->chip_status_ctrl & TRF7970A_CHIP_STATUS_RF_ON)) {
+               ret = trf7970a_write(trf, TRF7970A_CHIP_STATUS_CTRL,
+                               trf->chip_status_ctrl |
+                                       TRF7970A_CHIP_STATUS_RF_ON);
+               if (ret)
+                       return ret;
+
+               trf->chip_status_ctrl |= TRF7970A_CHIP_STATUS_RF_ON;
+       }
+
+       return 0;
+}
+
+static int trf7970a_tg_configure_hw(struct nfc_digital_dev *ddev, int type,
+               int param)
 {
        struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+       int ret;
+
+       dev_dbg(trf->dev, "Configure hw - type: %d, param: %d\n", type, param);
+
+       mutex_lock(&trf->lock);
+
+       trf->is_initiator = false;
 
-       dev_dbg(trf->dev, "Unsupported interface\n");
+       if ((trf->state == TRF7970A_ST_PWR_OFF) ||
+                       (trf->state == TRF7970A_ST_RF_OFF)) {
+               ret = trf7970a_switch_rf_on(trf);
+               if (ret)
+                       goto err_unlock;
+       }
+
+       switch (type) {
+       case NFC_DIGITAL_CONFIG_RF_TECH:
+               ret = trf7970a_tg_config_rf_tech(trf, param);
+               break;
+       case NFC_DIGITAL_CONFIG_FRAMING:
+               ret = trf7970a_tg_config_framing(trf, param);
+               break;
+       default:
+               dev_dbg(trf->dev, "Unknown type: %d\n", type);
+               ret = -EINVAL;
+       }
 
-       return -EINVAL;
+err_unlock:
+       mutex_unlock(&trf->lock);
+       return ret;
 }
 
-static int trf7970a_tg_listen(struct nfc_digital_dev *ddev,
-               u16 timeout, nfc_digital_cmd_complete_t cb, void *arg)
+static int trf7970a_tg_listen(struct nfc_digital_dev *ddev, u16 timeout,
+               nfc_digital_cmd_complete_t cb, void *arg)
 {
        struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+       int ret;
+
+       dev_dbg(trf->dev, "Listen - state: %d, timeout: %d ms\n",
+                       trf->state, timeout);
+
+       mutex_lock(&trf->lock);
 
-       dev_dbg(trf->dev, "Unsupported interface\n");
+       if ((trf->state != TRF7970A_ST_IDLE) &&
+                       (trf->state != TRF7970A_ST_IDLE_RX_BLOCKED)) {
+               dev_err(trf->dev, "%s - Bogus state: %d\n", __func__,
+                               trf->state);
+               ret = -EIO;
+               goto out_err;
+       }
+
+       if (trf->aborting) {
+               dev_dbg(trf->dev, "Abort process complete\n");
+               trf->aborting = false;
+               ret = -ECANCELED;
+               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;
+       }
+
+       ret = trf7970a_write(trf, TRF7970A_RX_SPECIAL_SETTINGS,
+                       TRF7970A_RX_SPECIAL_SETTINGS_HBT |
+                       TRF7970A_RX_SPECIAL_SETTINGS_M848 |
+                       TRF7970A_RX_SPECIAL_SETTINGS_C424 |
+                       TRF7970A_RX_SPECIAL_SETTINGS_C212);
+       if (ret)
+               return ret;
+
+       ret = trf7970a_write(trf, TRF7970A_REG_IO_CTRL,
+                       TRF7970A_REG_IO_CTRL_VRS(0x1));
+       if (ret)
+               return ret;
 
-       return -EINVAL;
+       ret = trf7970a_write(trf, TRF7970A_NFC_LOW_FIELD_LEVEL,
+                       TRF7970A_NFC_LOW_FIELD_LEVEL_RFDET(0x3));
+       if (ret)
+               return ret;
+
+       ret = trf7970a_write(trf, TRF7970A_NFC_TARGET_LEVEL,
+                       TRF7970A_NFC_TARGET_LEVEL_RFDET(0x7));
+       if (ret)
+               return ret;
+
+       trf->ddev = ddev;
+       trf->cb = cb;
+       trf->cb_arg = arg;
+       trf->timeout = timeout;
+       trf->ignore_timeout = false;
+
+       ret = trf7970a_cmd(trf, TRF7970A_CMD_ENABLE_RX);
+       if (ret)
+               goto out_err;
+
+       trf->state = TRF7970A_ST_LISTENING;
+
+       schedule_delayed_work(&trf->timeout_work, msecs_to_jiffies(timeout));
+
+out_err:
+       mutex_unlock(&trf->lock);
+       return ret;
 }
 
 static void trf7970a_abort_cmd(struct nfc_digital_dev *ddev)
@@ -1381,6 +1678,11 @@ static void trf7970a_abort_cmd(struct nfc_digital_dev *ddev)
        case TRF7970A_ST_WAIT_TO_ISSUE_EOF:
                trf->aborting = true;
                break;
+       case TRF7970A_ST_LISTENING:
+               trf->ignore_timeout = !cancel_delayed_work(&trf->timeout_work);
+               trf7970a_send_err_upstream(trf, -ECANCELED);
+               dev_dbg(trf->dev, "Abort process complete\n");
+               break;
        default:
                break;
        }
@@ -1390,9 +1692,9 @@ static void trf7970a_abort_cmd(struct nfc_digital_dev *ddev)
 
 static struct nfc_digital_ops trf7970a_nfc_ops = {
        .in_configure_hw        = trf7970a_in_configure_hw,
-       .in_send_cmd            = trf7970a_in_send_cmd,
+       .in_send_cmd            = trf7970a_send_cmd,
        .tg_configure_hw        = trf7970a_tg_configure_hw,
-       .tg_send_cmd            = trf7970a_tg_send_cmd,
+       .tg_send_cmd            = trf7970a_send_cmd,
        .tg_listen              = trf7970a_tg_listen,
        .switch_rf              = trf7970a_switch_rf,
        .abort_cmd              = trf7970a_abort_cmd,
@@ -1479,6 +1781,7 @@ static void trf7970a_shutdown(struct trf7970a *trf)
        case TRF7970A_ST_WAIT_FOR_RX_DATA:
        case TRF7970A_ST_WAIT_FOR_RX_DATA_CONT:
        case TRF7970A_ST_WAIT_TO_ISSUE_EOF:
+       case TRF7970A_ST_LISTENING:
                trf7970a_send_err_upstream(trf, -ECANCELED);
                /* FALLTHROUGH */
        case TRF7970A_ST_IDLE:
@@ -1606,7 +1909,8 @@ static int trf7970a_probe(struct spi_device *spi)
 
        trf->ddev = nfc_digital_allocate_device(&trf7970a_nfc_ops,
                        TRF7970A_SUPPORTED_PROTOCOLS,
-                       NFC_DIGITAL_DRV_CAPS_IN_CRC, 0, 0);
+                       NFC_DIGITAL_DRV_CAPS_IN_CRC |
+                               NFC_DIGITAL_DRV_CAPS_TG_CRC, 0, 0);
        if (!trf->ddev) {
                dev_err(trf->dev, "Can't allocate NFC digital device\n");
                ret = -ENOMEM;