diff options
author | Mark A. Greer <mgreer@animalcreek.com> | 2014-09-02 15:12:45 -0700 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2014-09-07 23:13:45 +0200 |
commit | 13b4272a8264220ec043a922fd1fa05da72d57ae (patch) | |
tree | 16020e2f0755ed64aa02b74bf9b8b330b4647513 /drivers/nfc/trf7970a.c | |
parent | 1961843ceeca0d3e55744bba7ae8d9e23d04cf6a (diff) | |
download | blackbird-op-linux-13b4272a8264220ec043a922fd1fa05da72d57ae.tar.gz blackbird-op-linux-13b4272a8264220ec043a922fd1fa05da72d57ae.zip |
NFC: trf7970a: Add Target Mode Support
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>
Diffstat (limited to 'drivers/nfc/trf7970a.c')
-rw-r--r-- | drivers/nfc/trf7970a.c | 374 |
1 files changed, 339 insertions, 35 deletions
diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c index 8b109e15687f..b33cc0211f53 100644 --- a/drivers/nfc/trf7970a.c +++ b/drivers/nfc/trf7970a.c @@ -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 @@ -121,7 +121,7 @@ #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 */ @@ -240,6 +240,15 @@ #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 */ @@ -265,12 +274,32 @@ #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) @@ -301,6 +330,16 @@ #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; |