summaryrefslogtreecommitdiff
path: root/drivers/nfc/trf7970a.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-10-08 21:40:54 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-10-08 21:40:54 -0400
commit35a9ad8af0bb0fa3525e6d0d20e32551d226f38e (patch)
tree15b4b33206818886d9cff371fd2163e073b70568 /drivers/nfc/trf7970a.c
parentd5935b07da53f74726e2a65dd4281d0f2c70e5d4 (diff)
parent64b1f00a0830e1c53874067273a096b228d83d36 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
Pull networking updates from David Miller: "Most notable changes in here: 1) By far the biggest accomplishment, thanks to a large range of contributors, is the addition of multi-send for transmit. This is the result of discussions back in Chicago, and the hard work of several individuals. Now, when the ->ndo_start_xmit() method of a driver sees skb->xmit_more as true, it can choose to defer the doorbell telling the driver to start processing the new TX queue entires. skb->xmit_more means that the generic networking is guaranteed to call the driver immediately with another SKB to send. There is logic added to the qdisc layer to dequeue multiple packets at a time, and the handling mis-predicted offloads in software is now done with no locks held. Finally, pktgen is extended to have a "burst" parameter that can be used to test a multi-send implementation. Several drivers have xmit_more support: i40e, igb, ixgbe, mlx4, virtio_net Adding support is almost trivial, so export more drivers to support this optimization soon. I want to thank, in no particular or implied order, Jesper Dangaard Brouer, Eric Dumazet, Alexander Duyck, Tom Herbert, Jamal Hadi Salim, John Fastabend, Florian Westphal, Daniel Borkmann, David Tat, Hannes Frederic Sowa, and Rusty Russell. 2) PTP and timestamping support in bnx2x, from Michal Kalderon. 3) Allow adjusting the rx_copybreak threshold for a driver via ethtool, and add rx_copybreak support to enic driver. From Govindarajulu Varadarajan. 4) Significant enhancements to the generic PHY layer and the bcm7xxx driver in particular (EEE support, auto power down, etc.) from Florian Fainelli. 5) Allow raw buffers to be used for flow dissection, allowing drivers to determine the optimal "linear pull" size for devices that DMA into pools of pages. The objective is to get exactly the necessary amount of headers into the linear SKB area pre-pulled, but no more. The new interface drivers use is eth_get_headlen(). From WANG Cong, with driver conversions (several had their own by-hand duplicated implementations) by Alexander Duyck and Eric Dumazet. 6) Support checksumming more smoothly and efficiently for encapsulations, and add "foo over UDP" facility. From Tom Herbert. 7) Add Broadcom SF2 switch driver to DSA layer, from Florian Fainelli. 8) eBPF now can load programs via a system call and has an extensive testsuite. Alexei Starovoitov and Daniel Borkmann. 9) Major overhaul of the packet scheduler to use RCU in several major areas such as the classifiers and rate estimators. From John Fastabend. 10) Add driver for Intel FM10000 Ethernet Switch, from Alexander Duyck. 11) Rearrange TCP_SKB_CB() to reduce cache line misses, from Eric Dumazet. 12) Add Datacenter TCP congestion control algorithm support, From Florian Westphal. 13) Reorganize sk_buff so that __copy_skb_header() is significantly faster. From Eric Dumazet" * git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1558 commits) netlabel: directly return netlbl_unlabel_genl_init() net: add netdev_txq_bql_{enqueue, complete}_prefetchw() helpers net: description of dma_cookie cause make xmldocs warning cxgb4: clean up a type issue cxgb4: potential shift wrapping bug i40e: skb->xmit_more support net: fs_enet: Add NAPI TX net: fs_enet: Remove non NAPI RX r8169:add support for RTL8168EP net_sched: copy exts->type in tcf_exts_change() wimax: convert printk to pr_foo() af_unix: remove 0 assignment on static ipv6: Do not warn for informational ICMP messages, regardless of type. Update Intel Ethernet Driver maintainers list bridge: Save frag_max_size between PRE_ROUTING and POST_ROUTING tipc: fix bug in multicast congestion handling net: better IFF_XMIT_DST_RELEASE support net/mlx4_en: remove NETDEV_TX_BUSY 3c59x: fix bad split of cpu_to_le32(pci_map_single()) net: bcmgenet: fix Tx ring priority programming ...
Diffstat (limited to 'drivers/nfc/trf7970a.c')
-rw-r--r--drivers/nfc/trf7970a.c1059
1 files changed, 892 insertions, 167 deletions
diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c
index 3b78b031e617..d2ccd2890647 100644
--- a/drivers/nfc/trf7970a.c
+++ b/drivers/nfc/trf7970a.c
@@ -36,7 +36,13 @@
* The trf7970a is very timing sensitive and the VIN, EN2, and EN
* pins must asserted in that order and with specific delays in between.
* The delays used in the driver were provided by TI and have been
- * confirmed to work with this driver.
+ * confirmed to work with this driver. There is a bug with the current
+ * version of the trf7970a that requires that EN2 remain low no matter
+ * what. If it goes high, it will generate an RF field even when in
+ * passive target mode. TI has indicated that the chip will work okay
+ * when EN2 is left low. The 'en2-rf-quirk' device tree property
+ * indicates that trf7970a currently being used has the erratum and
+ * that EN2 must be kept low.
*
* Timeouts are implemented using the delayed workqueue kernel facility.
* Timeouts are required so things don't hang when there is no response
@@ -56,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
@@ -77,6 +83,13 @@
* been received and there isn't an error). The delay is 20 ms since delays
* of ~16 ms have been observed during testing.
*
+ * When transmitting a frame larger than the FIFO size (127 bytes), the
+ * driver will wait 20 ms for the FIFO to drain past the low-watermark
+ * and generate an interrupt. The low-watermark set to 32 bytes so the
+ * interrupt should fire after 127 - 32 = 95 bytes have been sent. At
+ * the lowest possible bit rate (6.62 kbps for 15693), it will take up
+ * to ~14.35 ms so 20 ms is used for the timeout.
+ *
* Type 2 write and sector select commands respond with a 4-bit ACK or NACK.
* Having only 4 bits in the FIFO won't normally generate an interrupt so
* driver enables the '4_bit_RX' bit of the Special Functions register 1
@@ -99,40 +112,43 @@
* Note under Table 1-1 in section 1.6 of
* http://www.ti.com/lit/ug/scbu011/scbu011.pdf, that wait should be at least
* 10 ms for TI Tag-it HF-I tags; however testing has shown that is not long
- * enough. For this reason, the driver waits 20 ms which seems to work
+ * enough so 20 ms is used. So the timer is set to 40 ms - 20 ms to drain
+ * up to 127 bytes in the FIFO at the lowest bit rate plus another 20 ms to
+ * ensure the wait is long enough before sending the EOF. This seems to work
* reliably.
*/
#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 */
-/* TX data must be prefixed with a FIFO reset cmd, a cmd that depends
- * on what the current framing is, the address of the TX length byte 1
- * register (0x1d), and the 2 byte length of the data to be transmitted.
- * That totals 5 bytes.
- */
-#define TRF7970A_TX_SKB_HEADROOM 5
-
#define TRF7970A_RX_SKB_ALLOC_SIZE 256
-#define TRF7970A_FIFO_SIZE 128
+#define TRF7970A_FIFO_SIZE 127
/* 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 3
-#define TRF7970A_WAIT_TO_ISSUE_ISO15693_EOF 20
+#define TRF7970A_WAIT_FOR_FIFO_DRAIN_TIMEOUT 20
+#define TRF7970A_WAIT_TO_ISSUE_ISO15693_EOF 40
+
+/* Guard times for various RF technologies (in us) */
+#define TRF7970A_GUARD_TIME_NFCA 5000
+#define TRF7970A_GUARD_TIME_NFCB 5000
+#define TRF7970A_GUARD_TIME_NFCF 20000
+#define TRF7970A_GUARD_TIME_15693 1000
/* Quirks */
/* Erratum: When reading IRQ Status register on trf7970a, we must issue a
* read continuous command for IRQ Status and Collision Position registers.
*/
-#define TRF7970A_QUIRK_IRQ_STATUS_READ_ERRATA BIT(0)
+#define TRF7970A_QUIRK_IRQ_STATUS_READ BIT(0)
+#define TRF7970A_QUIRK_EN2_MUST_STAY_LOW BIT(1)
/* Direct commands */
#define TRF7970A_CMD_IDLE 0x00
@@ -149,8 +165,8 @@
#define TRF7970A_CMD_CLOSE_SLOT 0x15
#define TRF7970A_CMD_BLOCK_RX 0x16
#define TRF7970A_CMD_ENABLE_RX 0x17
-#define TRF7970A_CMD_TEST_EXT_RF 0x18
-#define TRF7970A_CMD_TEST_INT_RF 0x19
+#define TRF7970A_CMD_TEST_INT_RF 0x18
+#define TRF7970A_CMD_TEST_EXT_RF 0x19
#define TRF7970A_CMD_RX_GAIN_ADJUST 0x1a
/* Bits determining whether its a direct command or register R/W,
@@ -224,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 */
@@ -249,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)
@@ -265,6 +310,10 @@
TRF7970A_IRQ_STATUS_PARITY_ERROR | \
TRF7970A_IRQ_STATUS_CRC_ERROR)
+#define TRF7970A_RSSI_OSC_STATUS_RSSI_MASK (BIT(2) | BIT(1) | BIT(0))
+#define TRF7970A_RSSI_OSC_STATUS_RSSI_X_MASK (BIT(5) | BIT(4) | BIT(3))
+#define TRF7970A_RSSI_OSC_STATUS_RSSI_OSC_OK BIT(6)
+
#define TRF7970A_SPECIAL_FCN_REG1_COL_7_6 BIT(0)
#define TRF7970A_SPECIAL_FCN_REG1_14_ANTICOLL BIT(1)
#define TRF7970A_SPECIAL_FCN_REG1_4_BIT_RX BIT(2)
@@ -281,6 +330,49 @@
#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 TRF79070A_NFC_TARGET_PROTOCOL_NFCBR_106 BIT(0)
+#define TRF79070A_NFC_TARGET_PROTOCOL_NFCBR_212 BIT(1)
+#define TRF79070A_NFC_TARGET_PROTOCOL_NFCBR_424 (BIT(0) | BIT(1))
+#define TRF79070A_NFC_TARGET_PROTOCOL_PAS_14443B BIT(2)
+#define TRF79070A_NFC_TARGET_PROTOCOL_PAS_106 BIT(3)
+#define TRF79070A_NFC_TARGET_PROTOCOL_FELICA BIT(4)
+#define TRF79070A_NFC_TARGET_PROTOCOL_RF_L BIT(6)
+#define TRF79070A_NFC_TARGET_PROTOCOL_RF_H BIT(7)
+
+#define TRF79070A_NFC_TARGET_PROTOCOL_106A \
+ (TRF79070A_NFC_TARGET_PROTOCOL_RF_H | \
+ TRF79070A_NFC_TARGET_PROTOCOL_RF_L | \
+ TRF79070A_NFC_TARGET_PROTOCOL_PAS_106 | \
+ TRF79070A_NFC_TARGET_PROTOCOL_NFCBR_106)
+
+#define TRF79070A_NFC_TARGET_PROTOCOL_106B \
+ (TRF79070A_NFC_TARGET_PROTOCOL_RF_H | \
+ TRF79070A_NFC_TARGET_PROTOCOL_RF_L | \
+ TRF79070A_NFC_TARGET_PROTOCOL_PAS_14443B | \
+ TRF79070A_NFC_TARGET_PROTOCOL_NFCBR_106)
+
+#define TRF79070A_NFC_TARGET_PROTOCOL_212F \
+ (TRF79070A_NFC_TARGET_PROTOCOL_RF_H | \
+ TRF79070A_NFC_TARGET_PROTOCOL_RF_L | \
+ TRF79070A_NFC_TARGET_PROTOCOL_FELICA | \
+ TRF79070A_NFC_TARGET_PROTOCOL_NFCBR_212)
+
+#define TRF79070A_NFC_TARGET_PROTOCOL_424F \
+ (TRF79070A_NFC_TARGET_PROTOCOL_RF_H | \
+ TRF79070A_NFC_TARGET_PROTOCOL_RF_L | \
+ TRF79070A_NFC_TARGET_PROTOCOL_FELICA | \
+ TRF79070A_NFC_TARGET_PROTOCOL_NFCBR_424)
+
#define TRF7970A_FIFO_STATUS_OVERFLOW BIT(7)
/* NFC (ISO/IEC 14443A) Type 2 Tag commands */
@@ -317,13 +409,16 @@
(ISO15693_REQ_FLAG_SUB_CARRIER | ISO15693_REQ_FLAG_DATA_RATE)
enum trf7970a_state {
- TRF7970A_ST_OFF,
+ TRF7970A_ST_PWR_OFF,
+ TRF7970A_ST_RF_OFF,
TRF7970A_ST_IDLE,
TRF7970A_ST_IDLE_RX_BLOCKED,
TRF7970A_ST_WAIT_FOR_TX_FIFO,
TRF7970A_ST_WAIT_FOR_RX_DATA,
TRF7970A_ST_WAIT_FOR_RX_DATA_CONT,
TRF7970A_ST_WAIT_TO_ISSUE_EOF,
+ TRF7970A_ST_LISTENING,
+ TRF7970A_ST_LISTENING_MD,
TRF7970A_ST_MAX
};
@@ -334,6 +429,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;
@@ -344,8 +440,10 @@ struct trf7970a {
u8 iso_ctrl_tech;
u8 modulator_sys_clk_ctrl;
u8 special_fcn_reg1;
+ unsigned int guard_time;
int technology;
int framing;
+ u8 md_rf_tech;
u8 tx_cmd;
bool issue_eof;
int en2_gpio;
@@ -386,15 +484,28 @@ static int trf7970a_read(struct trf7970a *trf, u8 reg, u8 *val)
return ret;
}
-static int trf7970a_read_cont(struct trf7970a *trf, u8 reg,
- u8 *buf, size_t len)
+static int trf7970a_read_cont(struct trf7970a *trf, u8 reg, u8 *buf, size_t len)
{
u8 addr = reg | TRF7970A_CMD_BIT_RW | TRF7970A_CMD_BIT_CONTINUOUS;
+ struct spi_transfer t[2];
+ struct spi_message m;
int ret;
dev_dbg(trf->dev, "read_cont(0x%x, %zd)\n", addr, len);
- ret = spi_write_then_read(trf->spi, &addr, 1, buf, len);
+ spi_message_init(&m);
+
+ memset(&t, 0, sizeof(t));
+
+ t[0].tx_buf = &addr;
+ t[0].len = sizeof(addr);
+ spi_message_add_tail(&t[0], &m);
+
+ t[1].rx_buf = buf;
+ t[1].len = len;
+ spi_message_add_tail(&t[1], &m);
+
+ ret = spi_sync(trf->spi, &m);
if (ret)
dev_err(trf->dev, "%s - addr: 0x%x, ret: %d\n", __func__, addr,
ret);
@@ -424,7 +535,7 @@ static int trf7970a_read_irqstatus(struct trf7970a *trf, u8 *status)
addr = TRF7970A_IRQ_STATUS | TRF7970A_CMD_BIT_RW;
- if (trf->quirks & TRF7970A_QUIRK_IRQ_STATUS_READ_ERRATA) {
+ if (trf->quirks & TRF7970A_QUIRK_IRQ_STATUS_READ) {
addr |= TRF7970A_CMD_BIT_CONTINUOUS;
ret = spi_write_then_read(trf->spi, &addr, 1, buf, 2);
} else {
@@ -440,10 +551,60 @@ static int trf7970a_read_irqstatus(struct trf7970a *trf, u8 *status)
return ret;
}
-static void trf7970a_send_upstream(struct trf7970a *trf)
+static int trf7970a_read_target_proto(struct trf7970a *trf, u8 *target_proto)
{
- u8 rssi;
+ int ret;
+ u8 buf[2];
+ u8 addr;
+ addr = TRF79070A_NFC_TARGET_PROTOCOL | TRF7970A_CMD_BIT_RW |
+ TRF7970A_CMD_BIT_CONTINUOUS;
+
+ ret = spi_write_then_read(trf->spi, &addr, 1, buf, 2);
+ if (ret)
+ dev_err(trf->dev, "%s - target_proto: Read failed: %d\n",
+ __func__, ret);
+ else
+ *target_proto = buf[0];
+
+ return ret;
+}
+
+static int trf7970a_mode_detect(struct trf7970a *trf, u8 *rf_tech)
+{
+ int ret;
+ u8 target_proto, tech;
+
+ ret = trf7970a_read_target_proto(trf, &target_proto);
+ if (ret)
+ return ret;
+
+ switch (target_proto) {
+ case TRF79070A_NFC_TARGET_PROTOCOL_106A:
+ tech = NFC_DIGITAL_RF_TECH_106A;
+ break;
+ case TRF79070A_NFC_TARGET_PROTOCOL_106B:
+ tech = NFC_DIGITAL_RF_TECH_106B;
+ break;
+ case TRF79070A_NFC_TARGET_PROTOCOL_212F:
+ tech = NFC_DIGITAL_RF_TECH_212F;
+ break;
+ case TRF79070A_NFC_TARGET_PROTOCOL_424F:
+ tech = NFC_DIGITAL_RF_TECH_424F;
+ break;
+ default:
+ dev_dbg(trf->dev, "%s - mode_detect: target_proto: 0x%x\n",
+ __func__, target_proto);
+ return -EIO;
+ }
+
+ *rf_tech = tech;
+
+ return ret;
+}
+
+static void trf7970a_send_upstream(struct trf7970a *trf)
+{
dev_kfree_skb_any(trf->tx_skb);
trf->tx_skb = NULL;
@@ -452,13 +613,6 @@ static void trf7970a_send_upstream(struct trf7970a *trf)
16, 1, trf->rx_skb->data, trf->rx_skb->len,
false);
- /* According to the manual it is "good form" to reset the fifo and
- * read the RSSI levels & oscillator status register here. It doesn't
- * explain why.
- */
- trf7970a_cmd(trf, TRF7970A_CMD_FIFO_RESET);
- trf7970a_read(trf, TRF7970A_RSSI_OSC_STATUS, &rssi);
-
trf->state = TRF7970A_ST_IDLE;
if (trf->aborting) {
@@ -481,6 +635,8 @@ static void trf7970a_send_err_upstream(struct trf7970a *trf, int errno)
{
dev_dbg(trf->dev, "Error - state: %d, errno: %d\n", trf->state, errno);
+ cancel_delayed_work(&trf->timeout_work);
+
kfree_skb(trf->rx_skb);
trf->rx_skb = ERR_PTR(errno);
@@ -488,15 +644,29 @@ static void trf7970a_send_err_upstream(struct trf7970a *trf, int errno)
}
static int trf7970a_transmit(struct trf7970a *trf, struct sk_buff *skb,
- unsigned int len)
+ unsigned int len, u8 *prefix, unsigned int prefix_len)
{
+ struct spi_transfer t[2];
+ struct spi_message m;
unsigned int timeout;
int ret;
print_hex_dump_debug("trf7970a tx data: ", DUMP_PREFIX_NONE,
16, 1, skb->data, len, false);
- ret = spi_write(trf->spi, skb->data, len);
+ spi_message_init(&m);
+
+ memset(&t, 0, sizeof(t));
+
+ t[0].tx_buf = prefix;
+ t[0].len = prefix_len;
+ spi_message_add_tail(&t[0], &m);
+
+ t[1].tx_buf = skb->data;
+ t[1].len = len;
+ spi_message_add_tail(&t[1], &m);
+
+ ret = spi_sync(trf->spi, &m);
if (ret) {
dev_err(trf->dev, "%s - Can't send tx data: %d\n", __func__,
ret);
@@ -514,7 +684,11 @@ static int trf7970a_transmit(struct trf7970a *trf, struct sk_buff *skb,
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;
}
}
@@ -532,6 +706,7 @@ static void trf7970a_fill_fifo(struct trf7970a *trf)
unsigned int len;
int ret;
u8 fifo_bytes;
+ u8 prefix;
ret = trf7970a_read(trf, TRF7970A_FIFO_STATUS, &fifo_bytes);
if (ret) {
@@ -541,18 +716,21 @@ static void trf7970a_fill_fifo(struct trf7970a *trf)
dev_dbg(trf->dev, "Filling FIFO - fifo_bytes: 0x%x\n", fifo_bytes);
- if (fifo_bytes & TRF7970A_FIFO_STATUS_OVERFLOW) {
- dev_err(trf->dev, "%s - fifo overflow: 0x%x\n", __func__,
- fifo_bytes);
- trf7970a_send_err_upstream(trf, -EIO);
- return;
- }
+ fifo_bytes &= ~TRF7970A_FIFO_STATUS_OVERFLOW;
/* Calculate how much more data can be written to the fifo */
len = TRF7970A_FIFO_SIZE - fifo_bytes;
+ if (!len) {
+ schedule_delayed_work(&trf->timeout_work,
+ msecs_to_jiffies(TRF7970A_WAIT_FOR_FIFO_DRAIN_TIMEOUT));
+ return;
+ }
+
len = min(skb->len, len);
- ret = trf7970a_transmit(trf, skb, len);
+ prefix = TRF7970A_CMD_BIT_CONTINUOUS | TRF7970A_FIFO_IO_REGISTER;
+
+ ret = trf7970a_transmit(trf, skb, len, &prefix, sizeof(prefix));
if (ret)
trf7970a_send_err_upstream(trf, ret);
}
@@ -576,16 +754,11 @@ static void trf7970a_drain_fifo(struct trf7970a *trf, u8 status)
dev_dbg(trf->dev, "Draining FIFO - fifo_bytes: 0x%x\n", fifo_bytes);
+ fifo_bytes &= ~TRF7970A_FIFO_STATUS_OVERFLOW;
+
if (!fifo_bytes)
goto no_rx_data;
- if (fifo_bytes & TRF7970A_FIFO_STATUS_OVERFLOW) {
- dev_err(trf->dev, "%s - fifo overflow: 0x%x\n", __func__,
- fifo_bytes);
- trf7970a_send_err_upstream(trf, -EIO);
- return;
- }
-
if (fifo_bytes > skb_tailroom(skb)) {
skb = skb_copy_expand(skb, skb_headroom(skb),
max_t(int, fifo_bytes,
@@ -615,6 +788,21 @@ static void trf7970a_drain_fifo(struct trf7970a *trf, u8 status)
status = TRF7970A_IRQ_STATUS_SRX;
} else {
trf->state = TRF7970A_ST_WAIT_FOR_RX_DATA_CONT;
+
+ ret = trf7970a_read(trf, TRF7970A_FIFO_STATUS, &fifo_bytes);
+ if (ret) {
+ trf7970a_send_err_upstream(trf, ret);
+ return;
+ }
+
+ fifo_bytes &= ~TRF7970A_FIFO_STATUS_OVERFLOW;
+
+ /* If there are bytes in the FIFO, set status to '0' so
+ * the if stmt below doesn't fire and the driver will wait
+ * for the trf7970a to generate another RX interrupt.
+ */
+ if (fifo_bytes)
+ status = 0;
}
no_rx_data:
@@ -634,11 +822,11 @@ static irqreturn_t trf7970a_irq(int irq, void *dev_id)
{
struct trf7970a *trf = dev_id;
int ret;
- u8 status;
+ u8 status, fifo_bytes, iso_ctrl;
mutex_lock(&trf->lock);
- if (trf->state == TRF7970A_ST_OFF) {
+ if (trf->state == TRF7970A_ST_RF_OFF) {
mutex_unlock(&trf->lock);
return IRQ_NONE;
}
@@ -660,12 +848,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;
}
@@ -687,8 +875,68 @@ static irqreturn_t trf7970a_irq(int irq, void *dev_id)
trf->ignore_timeout =
!cancel_delayed_work(&trf->timeout_work);
trf7970a_drain_fifo(trf, status);
- } else if (status == TRF7970A_IRQ_STATUS_TX) {
+ } else if (status & TRF7970A_IRQ_STATUS_FIFO) {
+ ret = trf7970a_read(trf, TRF7970A_FIFO_STATUS,
+ &fifo_bytes);
+
+ fifo_bytes &= ~TRF7970A_FIFO_STATUS_OVERFLOW;
+
+ if (ret)
+ trf7970a_send_err_upstream(trf, ret);
+ else if (!fifo_bytes)
+ trf7970a_cmd(trf, TRF7970A_CMD_FIFO_RESET);
+ } 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) {
+ trf->ignore_timeout = !cancel_delayed_work(
+ &trf->timeout_work);
+ trf->rx_skb = ERR_PTR(0);
+ 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)
+ goto err_unlock_exit;
+
+ 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)
+ goto err_unlock_exit;
+
+ trf->iso_ctrl = iso_ctrl;
+ }
} else {
trf7970a_send_err_upstream(trf, -EIO);
}
@@ -697,11 +945,37 @@ 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;
+ case TRF7970A_ST_LISTENING_MD:
+ if (status & TRF7970A_IRQ_STATUS_SRX) {
+ trf->ignore_timeout =
+ !cancel_delayed_work(&trf->timeout_work);
+
+ ret = trf7970a_mode_detect(trf, &trf->md_rf_tech);
+ if (ret) {
+ trf7970a_send_err_upstream(trf, ret);
+ } else {
+ trf->state = TRF7970A_ST_LISTENING;
+ 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);
}
+err_unlock_exit:
mutex_unlock(&trf->lock);
return IRQ_HANDLED;
}
@@ -742,7 +1016,7 @@ static void trf7970a_timeout_work_handler(struct work_struct *work)
if (trf->ignore_timeout)
trf->ignore_timeout = false;
else if (trf->state == TRF7970A_ST_WAIT_FOR_RX_DATA_CONT)
- trf7970a_send_upstream(trf); /* No more rx data so send up */
+ trf7970a_drain_fifo(trf, TRF7970A_IRQ_STATUS_SRX);
else if (trf->state == TRF7970A_ST_WAIT_TO_ISSUE_EOF)
trf7970a_issue_eof(trf);
else
@@ -765,11 +1039,16 @@ static int trf7970a_init(struct trf7970a *trf)
if (ret)
goto err_out;
- /* Must clear NFC Target Detection Level reg due to erratum */
- ret = trf7970a_write(trf, TRF7970A_NFC_TARGET_LEVEL, 0);
+ usleep_range(1000, 2000);
+
+ trf->chip_status_ctrl &= ~TRF7970A_CHIP_STATUS_RF_ON;
+
+ ret = trf7970a_write(trf, TRF7970A_MODULATOR_SYS_CLK_CTRL, 0);
if (ret)
goto err_out;
+ trf->modulator_sys_clk_ctrl = 0;
+
ret = trf7970a_write(trf, TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS,
TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLH_96 |
TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_32);
@@ -792,6 +1071,10 @@ err_out:
static void trf7970a_switch_rf_off(struct trf7970a *trf)
{
+ if ((trf->state == TRF7970A_ST_PWR_OFF) ||
+ (trf->state == TRF7970A_ST_RF_OFF))
+ return;
+
dev_dbg(trf->dev, "Switching rf off\n");
trf->chip_status_ctrl &= ~TRF7970A_CHIP_STATUS_RF_ON;
@@ -799,24 +1082,41 @@ static void trf7970a_switch_rf_off(struct trf7970a *trf)
trf7970a_write(trf, TRF7970A_CHIP_STATUS_CTRL, trf->chip_status_ctrl);
trf->aborting = false;
- trf->state = TRF7970A_ST_OFF;
+ trf->state = TRF7970A_ST_RF_OFF;
pm_runtime_mark_last_busy(trf->dev);
pm_runtime_put_autosuspend(trf->dev);
}
-static void trf7970a_switch_rf_on(struct trf7970a *trf)
+static int trf7970a_switch_rf_on(struct trf7970a *trf)
{
+ int ret;
+
dev_dbg(trf->dev, "Switching rf on\n");
pm_runtime_get_sync(trf->dev);
+ if (trf->state != TRF7970A_ST_RF_OFF) { /* Power on, RF off */
+ dev_err(trf->dev, "%s - Incorrect state: %d\n", __func__,
+ trf->state);
+ return -EINVAL;
+ }
+
+ ret = trf7970a_init(trf);
+ if (ret) {
+ dev_err(trf->dev, "%s - Can't initialize: %d\n", __func__, ret);
+ return ret;
+ }
+
trf->state = TRF7970A_ST_IDLE;
+
+ return 0;
}
static int trf7970a_switch_rf(struct nfc_digital_dev *ddev, bool on)
{
struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+ int ret = 0;
dev_dbg(trf->dev, "Switching RF - state: %d, on: %d\n", trf->state, on);
@@ -824,8 +1124,9 @@ static int trf7970a_switch_rf(struct nfc_digital_dev *ddev, bool on)
if (on) {
switch (trf->state) {
- case TRF7970A_ST_OFF:
- trf7970a_switch_rf_on(trf);
+ case TRF7970A_ST_PWR_OFF:
+ case TRF7970A_ST_RF_OFF:
+ ret = trf7970a_switch_rf_on(trf);
break;
case TRF7970A_ST_IDLE:
case TRF7970A_ST_IDLE_RX_BLOCKED:
@@ -834,26 +1135,31 @@ static int trf7970a_switch_rf(struct nfc_digital_dev *ddev, bool on)
dev_err(trf->dev, "%s - Invalid request: %d %d\n",
__func__, trf->state, on);
trf7970a_switch_rf_off(trf);
+ ret = -EINVAL;
}
} else {
switch (trf->state) {
- case TRF7970A_ST_OFF:
+ case TRF7970A_ST_PWR_OFF:
+ case TRF7970A_ST_RF_OFF:
break;
default:
dev_err(trf->dev, "%s - Invalid request: %d %d\n",
__func__, trf->state, on);
+ ret = -EINVAL;
/* 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);
}
}
mutex_unlock(&trf->lock);
- return 0;
+ return ret;
}
-static int trf7970a_config_rf_tech(struct trf7970a *trf, int tech)
+static int trf7970a_in_config_rf_tech(struct trf7970a *trf, int tech)
{
int ret = 0;
@@ -863,22 +1169,27 @@ static int trf7970a_config_rf_tech(struct trf7970a *trf, int tech)
case NFC_DIGITAL_RF_TECH_106A:
trf->iso_ctrl_tech = TRF7970A_ISO_CTRL_14443A_106;
trf->modulator_sys_clk_ctrl = TRF7970A_MODULATOR_DEPTH_OOK;
+ trf->guard_time = TRF7970A_GUARD_TIME_NFCA;
break;
case NFC_DIGITAL_RF_TECH_106B:
trf->iso_ctrl_tech = TRF7970A_ISO_CTRL_14443B_106;
trf->modulator_sys_clk_ctrl = TRF7970A_MODULATOR_DEPTH_ASK10;
+ trf->guard_time = TRF7970A_GUARD_TIME_NFCB;
break;
case NFC_DIGITAL_RF_TECH_212F:
trf->iso_ctrl_tech = TRF7970A_ISO_CTRL_FELICA_212;
trf->modulator_sys_clk_ctrl = TRF7970A_MODULATOR_DEPTH_ASK10;
+ trf->guard_time = TRF7970A_GUARD_TIME_NFCF;
break;
case NFC_DIGITAL_RF_TECH_424F:
trf->iso_ctrl_tech = TRF7970A_ISO_CTRL_FELICA_424;
trf->modulator_sys_clk_ctrl = TRF7970A_MODULATOR_DEPTH_ASK10;
+ trf->guard_time = TRF7970A_GUARD_TIME_NFCF;
break;
case NFC_DIGITAL_RF_TECH_ISO15693:
trf->iso_ctrl_tech = TRF7970A_ISO_CTRL_15693_SGL_1OF4_2648;
trf->modulator_sys_clk_ctrl = TRF7970A_MODULATOR_DEPTH_OOK;
+ trf->guard_time = TRF7970A_GUARD_TIME_15693;
break;
default:
dev_dbg(trf->dev, "Unsupported rf technology: %d\n", tech);
@@ -887,12 +1198,54 @@ static int trf7970a_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;
}
-static int trf7970a_config_framing(struct trf7970a *trf, int framing)
+static int trf7970a_is_rf_field(struct trf7970a *trf, bool *is_rf_field)
+{
+ int ret;
+ u8 rssi;
+
+ ret = trf7970a_write(trf, TRF7970A_CHIP_STATUS_CTRL,
+ trf->chip_status_ctrl | TRF7970A_CHIP_STATUS_REC_ON);
+ if (ret)
+ return ret;
+
+ ret = trf7970a_cmd(trf, TRF7970A_CMD_TEST_EXT_RF);
+ if (ret)
+ return ret;
+
+ usleep_range(50, 60);
+
+ ret = trf7970a_read(trf, TRF7970A_RSSI_OSC_STATUS, &rssi);
+ if (ret)
+ return ret;
+
+ ret = trf7970a_write(trf, TRF7970A_CHIP_STATUS_CTRL,
+ trf->chip_status_ctrl);
+ if (ret)
+ return ret;
+
+ if (rssi & TRF7970A_RSSI_OSC_STATUS_RSSI_MASK)
+ *is_rf_field = true;
+ else
+ *is_rf_field = false;
+
+ return 0;
+}
+
+static int trf7970a_in_config_framing(struct trf7970a *trf, int framing)
{
u8 iso_ctrl = trf->iso_ctrl_tech;
+ bool is_rf_field = false;
int ret;
dev_dbg(trf->dev, "framing: %d\n", framing);
@@ -911,6 +1264,8 @@ static int trf7970a_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;
@@ -925,6 +1280,15 @@ static int trf7970a_config_framing(struct trf7970a *trf, int framing)
trf->framing = framing;
+ if (!(trf->chip_status_ctrl & TRF7970A_CHIP_STATUS_RF_ON)) {
+ ret = trf7970a_is_rf_field(trf, &is_rf_field);
+ if (ret)
+ return ret;
+
+ if (is_rf_field)
+ return -EBUSY;
+ }
+
if (iso_ctrl != trf->iso_ctrl) {
ret = trf7970a_write(trf, TRF7970A_ISO_CTRL, iso_ctrl);
if (ret)
@@ -947,7 +1311,7 @@ static int trf7970a_config_framing(struct trf7970a *trf, int framing)
trf->chip_status_ctrl |= TRF7970A_CHIP_STATUS_RF_ON;
- usleep_range(5000, 6000);
+ usleep_range(trf->guard_time, trf->guard_time + 1000);
}
return 0;
@@ -963,21 +1327,28 @@ static int trf7970a_in_configure_hw(struct nfc_digital_dev *ddev, int type,
mutex_lock(&trf->lock);
- if (trf->state == TRF7970A_ST_OFF)
- trf7970a_switch_rf_on(trf);
+ trf->is_initiator = true;
+
+ 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_config_rf_tech(trf, param);
+ ret = trf7970a_in_config_rf_tech(trf, param);
break;
case NFC_DIGITAL_CONFIG_FRAMING:
- ret = trf7970a_config_framing(trf, param);
+ ret = trf7970a_in_config_framing(trf, param);
break;
default:
dev_dbg(trf->dev, "Unknown type: %d\n", type);
ret = -EINVAL;
}
+err_unlock:
mutex_unlock(&trf->lock);
return ret;
}
@@ -1067,14 +1438,15 @@ 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)
{
struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
- char *prefix;
+ u8 prefix[5];
unsigned int len;
int ret;
+ u8 status;
dev_dbg(trf->dev, "New request - state: %d, timeout: %d ms, len: %d\n",
trf->state, timeout, skb->len);
@@ -1099,12 +1471,14 @@ static int trf7970a_in_send_cmd(struct nfc_digital_dev *ddev,
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) {
@@ -1115,9 +1489,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;
@@ -1127,11 +1503,11 @@ static int trf7970a_in_send_cmd(struct nfc_digital_dev *ddev,
trf->ignore_timeout = false;
len = skb->len;
- prefix = skb_push(skb, TRF7970A_TX_SKB_HEADROOM);
/* TX data must be prefixed with a FIFO reset cmd, a cmd that depends
* on what the current framing is, the address of the TX length byte 1
* register (0x1d), and the 2 byte length of the data to be transmitted.
+ * That totals 5 bytes.
*/
prefix[0] = TRF7970A_CMD_BIT_CTRL |
TRF7970A_CMD_BIT_OPCODE(TRF7970A_CMD_FIFO_RESET);
@@ -1150,9 +1526,12 @@ static int trf7970a_in_send_cmd(struct nfc_digital_dev *ddev,
len = min_t(int, skb->len, TRF7970A_FIFO_SIZE);
- usleep_range(1000, 2000);
+ /* Clear possible spurious interrupt */
+ ret = trf7970a_read_irqstatus(trf, &status);
+ if (ret)
+ goto out_err;
- ret = trf7970a_transmit(trf, skb, len);
+ ret = trf7970a_transmit(trf, skb, len, prefix, sizeof(prefix));
if (ret) {
kfree_skb(trf->rx_skb);
trf->rx_skb = NULL;
@@ -1163,46 +1542,272 @@ 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)
+{
+ 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;
+
+ /* 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 ret;
+}
+
+/* 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;
+
+ 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;
+ }
+
+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, bool mode_detect)
{
struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+ int ret;
+
+ 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;
+ }
- return -EINVAL;
+ 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)
+ goto out_err;
+
+ ret = trf7970a_write(trf, TRF7970A_REG_IO_CTRL,
+ TRF7970A_REG_IO_CTRL_VRS(0x1));
+ if (ret)
+ goto out_err;
+
+ ret = trf7970a_write(trf, TRF7970A_NFC_LOW_FIELD_LEVEL,
+ TRF7970A_NFC_LOW_FIELD_LEVEL_RFDET(0x3));
+ if (ret)
+ goto out_err;
+
+ ret = trf7970a_write(trf, TRF7970A_NFC_TARGET_LEVEL,
+ TRF7970A_NFC_TARGET_LEVEL_RFDET(0x7));
+ if (ret)
+ goto out_err;
+
+ 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 = mode_detect ? TRF7970A_ST_LISTENING_MD :
+ TRF7970A_ST_LISTENING;
+
+ schedule_delayed_work(&trf->timeout_work, msecs_to_jiffies(timeout));
+
+out_err:
+ mutex_unlock(&trf->lock);
+ return ret;
}
-static int trf7970a_tg_send_cmd(struct nfc_digital_dev *ddev,
- struct sk_buff *skb, u16 timeout,
+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);
- dev_dbg(trf->dev, "Unsupported interface\n");
+ dev_dbg(trf->dev, "Listen - state: %d, timeout: %d ms\n",
+ trf->state, timeout);
- return -EINVAL;
+ return _trf7970a_tg_listen(ddev, timeout, cb, arg, false);
}
-static int trf7970a_tg_listen(struct nfc_digital_dev *ddev,
+static int trf7970a_tg_listen_md(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 MD - state: %d, timeout: %d ms\n",
+ trf->state, timeout);
- dev_dbg(trf->dev, "Unsupported interface\n");
+ ret = trf7970a_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH,
+ NFC_DIGITAL_RF_TECH_106A);
+ if (ret)
+ return ret;
- return -EINVAL;
+ ret = trf7970a_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING,
+ NFC_DIGITAL_FRAMING_NFCA_NFC_DEP);
+ if (ret)
+ return ret;
+
+ return _trf7970a_tg_listen(ddev, timeout, cb, arg, true);
}
-static int trf7970a_tg_listen_mdaa(struct nfc_digital_dev *ddev,
- struct digital_tg_mdaa_params *mdaa_params,
- u16 timeout, nfc_digital_cmd_complete_t cb, void *arg)
+static int trf7970a_tg_get_rf_tech(struct nfc_digital_dev *ddev, u8 *rf_tech)
{
struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
- dev_dbg(trf->dev, "Unsupported interface\n");
+ dev_dbg(trf->dev, "Get RF Tech - state: %d, rf_tech: %d\n",
+ trf->state, trf->md_rf_tech);
- return -EINVAL;
+ *rf_tech = trf->md_rf_tech;
+
+ return 0;
}
static void trf7970a_abort_cmd(struct nfc_digital_dev *ddev)
@@ -1220,6 +1825,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;
}
@@ -1229,15 +1839,114 @@ 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,
- .tg_listen_mdaa = trf7970a_tg_listen_mdaa,
+ .tg_listen_md = trf7970a_tg_listen_md,
+ .tg_get_rf_tech = trf7970a_tg_get_rf_tech,
.switch_rf = trf7970a_switch_rf,
.abort_cmd = trf7970a_abort_cmd,
};
+static int trf7970a_power_up(struct trf7970a *trf)
+{
+ int ret;
+
+ dev_dbg(trf->dev, "Powering up - state: %d\n", trf->state);
+
+ if (trf->state != TRF7970A_ST_PWR_OFF)
+ return 0;
+
+ ret = regulator_enable(trf->regulator);
+ if (ret) {
+ dev_err(trf->dev, "%s - Can't enable VIN: %d\n", __func__, ret);
+ return ret;
+ }
+
+ usleep_range(5000, 6000);
+
+ if (!(trf->quirks & TRF7970A_QUIRK_EN2_MUST_STAY_LOW)) {
+ gpio_set_value(trf->en2_gpio, 1);
+ usleep_range(1000, 2000);
+ }
+
+ gpio_set_value(trf->en_gpio, 1);
+
+ usleep_range(20000, 21000);
+
+ trf->state = TRF7970A_ST_RF_OFF;
+
+ return 0;
+}
+
+static int trf7970a_power_down(struct trf7970a *trf)
+{
+ int ret;
+
+ dev_dbg(trf->dev, "Powering down - state: %d\n", trf->state);
+
+ if (trf->state == TRF7970A_ST_PWR_OFF)
+ return 0;
+
+ if (trf->state != TRF7970A_ST_RF_OFF) {
+ dev_dbg(trf->dev, "Can't power down - not RF_OFF state (%d)\n",
+ trf->state);
+ return -EBUSY;
+ }
+
+ gpio_set_value(trf->en_gpio, 0);
+ gpio_set_value(trf->en2_gpio, 0);
+
+ ret = regulator_disable(trf->regulator);
+ if (ret)
+ dev_err(trf->dev, "%s - Can't disable VIN: %d\n", __func__,
+ ret);
+
+ trf->state = TRF7970A_ST_PWR_OFF;
+
+ return ret;
+}
+
+static int trf7970a_startup(struct trf7970a *trf)
+{
+ int ret;
+
+ ret = trf7970a_power_up(trf);
+ if (ret)
+ return ret;
+
+ pm_runtime_set_active(trf->dev);
+ pm_runtime_enable(trf->dev);
+ pm_runtime_mark_last_busy(trf->dev);
+
+ return 0;
+}
+
+static void trf7970a_shutdown(struct trf7970a *trf)
+{
+ switch (trf->state) {
+ case TRF7970A_ST_WAIT_FOR_TX_FIFO:
+ 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:
+ case TRF7970A_ST_IDLE_RX_BLOCKED:
+ trf7970a_switch_rf_off(trf);
+ break;
+ default:
+ break;
+ }
+
+ pm_runtime_disable(trf->dev);
+ pm_runtime_set_suspended(trf->dev);
+
+ trf7970a_power_down(trf);
+}
+
static int trf7970a_get_autosuspend_delay(struct device_node *np)
{
int autosuspend_delay, ret;
@@ -1246,15 +1955,18 @@ static int trf7970a_get_autosuspend_delay(struct device_node *np)
if (ret)
autosuspend_delay = TRF7970A_AUTOSUSPEND_DELAY;
- of_node_put(np);
-
return autosuspend_delay;
}
+static int trf7970a_get_vin_voltage_override(struct device_node *np,
+ u32 *vin_uvolts)
+{
+ return of_property_read_u32(np, "vin-voltage-override", vin_uvolts);
+}
+
static int trf7970a_probe(struct spi_device *spi)
{
struct device_node *np = spi->dev.of_node;
- const struct spi_device_id *id = spi_get_device_id(spi);
struct trf7970a *trf;
int uvolts, autosuspend_delay, ret;
@@ -1267,14 +1979,22 @@ static int trf7970a_probe(struct spi_device *spi)
if (!trf)
return -ENOMEM;
- trf->state = TRF7970A_ST_OFF;
+ trf->state = TRF7970A_ST_PWR_OFF;
trf->dev = &spi->dev;
trf->spi = spi;
- trf->quirks = id->driver_data;
spi->mode = SPI_MODE_1;
spi->bits_per_word = 8;
+ ret = spi_setup(spi);
+ if (ret < 0) {
+ dev_err(trf->dev, "Can't set up SPI Communication\n");
+ return ret;
+ }
+
+ if (of_property_read_bool(np, "irq-status-read-quirk"))
+ trf->quirks |= TRF7970A_QUIRK_IRQ_STATUS_READ;
+
/* There are two enable pins - both must be present */
trf->en_gpio = of_get_named_gpio(np, "ti,enable-gpios", 0);
if (!gpio_is_valid(trf->en_gpio)) {
@@ -1283,7 +2003,7 @@ static int trf7970a_probe(struct spi_device *spi)
}
ret = devm_gpio_request_one(trf->dev, trf->en_gpio,
- GPIOF_DIR_OUT | GPIOF_INIT_LOW, "EN");
+ GPIOF_DIR_OUT | GPIOF_INIT_LOW, "trf7970a EN");
if (ret) {
dev_err(trf->dev, "Can't request EN GPIO: %d\n", ret);
return ret;
@@ -1296,12 +2016,15 @@ static int trf7970a_probe(struct spi_device *spi)
}
ret = devm_gpio_request_one(trf->dev, trf->en2_gpio,
- GPIOF_DIR_OUT | GPIOF_INIT_LOW, "EN2");
+ GPIOF_DIR_OUT | GPIOF_INIT_LOW, "trf7970a EN2");
if (ret) {
dev_err(trf->dev, "Can't request EN2 GPIO: %d\n", ret);
return ret;
}
+ if (of_property_read_bool(np, "en2-rf-quirk"))
+ trf->quirks |= TRF7970A_QUIRK_EN2_MUST_STAY_LOW;
+
ret = devm_request_threaded_irq(trf->dev, spi->irq, NULL,
trf7970a_irq, IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"trf7970a", trf);
@@ -1326,15 +2049,17 @@ static int trf7970a_probe(struct spi_device *spi)
goto err_destroy_lock;
}
- uvolts = regulator_get_voltage(trf->regulator);
+ ret = trf7970a_get_vin_voltage_override(np, &uvolts);
+ if (ret)
+ uvolts = regulator_get_voltage(trf->regulator);
if (uvolts > 4000000)
trf->chip_status_ctrl = TRF7970A_CHIP_STATUS_VRS5_3;
trf->ddev = nfc_digital_allocate_device(&trf7970a_nfc_ops,
TRF7970A_SUPPORTED_PROTOCOLS,
- NFC_DIGITAL_DRV_CAPS_IN_CRC, TRF7970A_TX_SKB_HEADROOM,
- 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;
@@ -1349,19 +2074,23 @@ static int trf7970a_probe(struct spi_device *spi)
pm_runtime_set_autosuspend_delay(trf->dev, autosuspend_delay);
pm_runtime_use_autosuspend(trf->dev);
- pm_runtime_enable(trf->dev);
+
+ ret = trf7970a_startup(trf);
+ if (ret)
+ goto err_free_ddev;
ret = nfc_digital_register_device(trf->ddev);
if (ret) {
dev_err(trf->dev, "Can't register NFC digital device: %d\n",
ret);
- goto err_free_ddev;
+ goto err_shutdown;
}
return 0;
+err_shutdown:
+ trf7970a_shutdown(trf);
err_free_ddev:
- pm_runtime_disable(trf->dev);
nfc_digital_free_device(trf->ddev);
err_disable_regulator:
regulator_disable(trf->regulator);
@@ -1376,25 +2105,10 @@ static int trf7970a_remove(struct spi_device *spi)
mutex_lock(&trf->lock);
- switch (trf->state) {
- case TRF7970A_ST_WAIT_FOR_TX_FIFO:
- case TRF7970A_ST_WAIT_FOR_RX_DATA:
- case TRF7970A_ST_WAIT_FOR_RX_DATA_CONT:
- case TRF7970A_ST_WAIT_TO_ISSUE_EOF:
- trf7970a_send_err_upstream(trf, -ECANCELED);
- /* FALLTHROUGH */
- case TRF7970A_ST_IDLE:
- case TRF7970A_ST_IDLE_RX_BLOCKED:
- pm_runtime_put_sync(trf->dev);
- break;
- default:
- break;
- }
+ trf7970a_shutdown(trf);
mutex_unlock(&trf->lock);
- pm_runtime_disable(trf->dev);
-
nfc_digital_unregister_device(trf->ddev);
nfc_digital_free_device(trf->ddev);
@@ -1405,72 +2119,83 @@ static int trf7970a_remove(struct spi_device *spi)
return 0;
}
-#ifdef CONFIG_PM_RUNTIME
-static int trf7970a_pm_runtime_suspend(struct device *dev)
+#ifdef CONFIG_PM_SLEEP
+static int trf7970a_suspend(struct device *dev)
+{
+ struct spi_device *spi = container_of(dev, struct spi_device, dev);
+ struct trf7970a *trf = spi_get_drvdata(spi);
+
+ dev_dbg(dev, "Suspend\n");
+
+ mutex_lock(&trf->lock);
+
+ trf7970a_shutdown(trf);
+
+ mutex_unlock(&trf->lock);
+
+ return 0;
+}
+
+static int trf7970a_resume(struct device *dev)
{
struct spi_device *spi = container_of(dev, struct spi_device, dev);
struct trf7970a *trf = spi_get_drvdata(spi);
int ret;
- dev_dbg(dev, "Runtime suspend\n");
+ dev_dbg(dev, "Resume\n");
- if (trf->state != TRF7970A_ST_OFF) {
- dev_dbg(dev, "Can't suspend - not in OFF state (%d)\n",
- trf->state);
- return -EBUSY;
- }
+ mutex_lock(&trf->lock);
- gpio_set_value(trf->en_gpio, 0);
- gpio_set_value(trf->en2_gpio, 0);
+ ret = trf7970a_startup(trf);
- ret = regulator_disable(trf->regulator);
- if (ret)
- dev_err(dev, "%s - Can't disable VIN: %d\n", __func__, ret);
+ mutex_unlock(&trf->lock);
return ret;
}
+#endif
-static int trf7970a_pm_runtime_resume(struct device *dev)
+#ifdef CONFIG_PM_RUNTIME
+static int trf7970a_pm_runtime_suspend(struct device *dev)
{
struct spi_device *spi = container_of(dev, struct spi_device, dev);
struct trf7970a *trf = spi_get_drvdata(spi);
int ret;
- dev_dbg(dev, "Runtime resume\n");
+ dev_dbg(dev, "Runtime suspend\n");
- ret = regulator_enable(trf->regulator);
- if (ret) {
- dev_err(dev, "%s - Can't enable VIN: %d\n", __func__, ret);
- return ret;
- }
+ mutex_lock(&trf->lock);
- usleep_range(5000, 6000);
+ ret = trf7970a_power_down(trf);
- gpio_set_value(trf->en2_gpio, 1);
- usleep_range(1000, 2000);
- gpio_set_value(trf->en_gpio, 1);
+ mutex_unlock(&trf->lock);
- usleep_range(20000, 21000);
+ return ret;
+}
- ret = trf7970a_init(trf);
- if (ret) {
- dev_err(dev, "%s - Can't initialize: %d\n", __func__, ret);
- return ret;
- }
+static int trf7970a_pm_runtime_resume(struct device *dev)
+{
+ struct spi_device *spi = container_of(dev, struct spi_device, dev);
+ struct trf7970a *trf = spi_get_drvdata(spi);
+ int ret;
- pm_runtime_mark_last_busy(dev);
+ dev_dbg(dev, "Runtime resume\n");
- return 0;
+ ret = trf7970a_power_up(trf);
+ if (!ret)
+ pm_runtime_mark_last_busy(dev);
+
+ return ret;
}
#endif
static const struct dev_pm_ops trf7970a_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(trf7970a_suspend, trf7970a_resume)
SET_RUNTIME_PM_OPS(trf7970a_pm_runtime_suspend,
trf7970a_pm_runtime_resume, NULL)
};
static const struct spi_device_id trf7970a_id_table[] = {
- { "trf7970a", TRF7970A_QUIRK_IRQ_STATUS_READ_ERRATA },
+ { "trf7970a", 0 },
{ }
};
MODULE_DEVICE_TABLE(spi, trf7970a_id_table);