All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] NFC: trf7970a: Add driver with NFC Type 2 and Type V Support
@ 2014-01-31 22:17 ` Mark A. Greer
  0 siblings, 0 replies; 30+ messages in thread
From: Mark A. Greer @ 2014-01-31 22:17 UTC (permalink / raw)
  To: Samuel Ortiz, Lauro Ramos Venancio, Aloisio Almeida Jr
  Cc: Felipe Balbi, Erick Macias, Thierry Escande, linux-wireless,
	linux-nfc, devicetree, Mark A. Greer

This is a driver for the TI TRF7970A RFID/NFC/15693 Transceiver.
The driver was started by Erick Macias and Felipe Balbi but has
been changed significantly by me.  Because of that, Felipe has
allowed me to replace his name by mine in the MODULE_AUTHOR()
line.

The trf7970a has a low-level interface so it requires the NFC
digital layer.

It has been tested on a couple different consumer Type 2 tags
and 3 different types of TI Tag-it HF-I tags.  It seems stable
but the device often reports a CRC or collision error when moving
a tag into the RF field while actively polling.  That means that
an EIO error will be reported and you'll have to retry the poll
in order to communicate with the tag.

The driver is broken into two patches: one for the majority of
the driver which includes 14443 Type 2 (MIFARE Ultralight and
Ultralight C) tags and another for 15693 Type V support.  The
third patch adds DTS documentation.

Mark A. Greer (3):
  NFC: trf7970a: Add driver with ISO/IEC 14443 Type 2 Tag Support
  NFC: trf7970a: Add ISO/IEC 15693 Support
  NFC: trf7970a: Add DTS Documentation

 .../devicetree/bindings/net/nfc/trf7970a.txt       |   37 +
 drivers/nfc/Kconfig                                |   12 +
 drivers/nfc/Makefile                               |    1 +
 drivers/nfc/trf7970a.c                             | 1338 ++++++++++++++++++++
 4 files changed, 1388 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/nfc/trf7970a.txt
 create mode 100644 drivers/nfc/trf7970a.c

-- 
1.8.3.4


^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH 0/3] NFC: trf7970a: Add driver with NFC Type 2 and Type V Support
@ 2014-01-31 22:17 ` Mark A. Greer
  0 siblings, 0 replies; 30+ messages in thread
From: Mark A. Greer @ 2014-01-31 22:17 UTC (permalink / raw)
  To: Samuel Ortiz, Lauro Ramos Venancio, Aloisio Almeida Jr
  Cc: Felipe Balbi, Erick Macias, Thierry Escande,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	linux-nfc-hn68Rpc1hR1g9hUCZPvPmw,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Mark A. Greer

This is a driver for the TI TRF7970A RFID/NFC/15693 Transceiver.
The driver was started by Erick Macias and Felipe Balbi but has
been changed significantly by me.  Because of that, Felipe has
allowed me to replace his name by mine in the MODULE_AUTHOR()
line.

The trf7970a has a low-level interface so it requires the NFC
digital layer.

It has been tested on a couple different consumer Type 2 tags
and 3 different types of TI Tag-it HF-I tags.  It seems stable
but the device often reports a CRC or collision error when moving
a tag into the RF field while actively polling.  That means that
an EIO error will be reported and you'll have to retry the poll
in order to communicate with the tag.

The driver is broken into two patches: one for the majority of
the driver which includes 14443 Type 2 (MIFARE Ultralight and
Ultralight C) tags and another for 15693 Type V support.  The
third patch adds DTS documentation.

Mark A. Greer (3):
  NFC: trf7970a: Add driver with ISO/IEC 14443 Type 2 Tag Support
  NFC: trf7970a: Add ISO/IEC 15693 Support
  NFC: trf7970a: Add DTS Documentation

 .../devicetree/bindings/net/nfc/trf7970a.txt       |   37 +
 drivers/nfc/Kconfig                                |   12 +
 drivers/nfc/Makefile                               |    1 +
 drivers/nfc/trf7970a.c                             | 1338 ++++++++++++++++++++
 4 files changed, 1388 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/nfc/trf7970a.txt
 create mode 100644 drivers/nfc/trf7970a.c

-- 
1.8.3.4

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH 1/3] NFC: trf7970a: Add driver with ISO/IEC 14443 Type 2 Tag Support
@ 2014-01-31 22:17   ` Mark A. Greer
  0 siblings, 0 replies; 30+ messages in thread
From: Mark A. Greer @ 2014-01-31 22:17 UTC (permalink / raw)
  To: Samuel Ortiz, Lauro Ramos Venancio, Aloisio Almeida Jr
  Cc: Felipe Balbi, Erick Macias, Thierry Escande, linux-wireless,
	linux-nfc, devicetree, Mark A. Greer

Add a driver for the Texas Instruments TRF7970a RFID/NFC/15693
transceiver.  The driver currently supports ISO/IEC 14443 Type 2
tags only (MIFARE Ultralight and Ultralight C but not Classic).

CC: Erick Macias <emacias@ti.com>
CC: Felipe Balbi <balbi@ti.com>
Signed-off-by: Mark A. Greer <mgreer@animalcreek.com>
---
 drivers/nfc/Kconfig    |   12 +
 drivers/nfc/Makefile   |    1 +
 drivers/nfc/trf7970a.c | 1191 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1204 insertions(+)
 create mode 100644 drivers/nfc/trf7970a.c

diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig
index fe20e1c..65d4ca1 100644
--- a/drivers/nfc/Kconfig
+++ b/drivers/nfc/Kconfig
@@ -26,6 +26,18 @@ config NFC_WILINK
 	  Say Y here to compile support for Texas Instrument's NFC WiLink driver
 	  into the kernel or say M to compile it as module.
 
+config NFC_TRF7970A
+	tristate "Texas Instruments TRF7970a NFC driver"
+	depends on SPI && NFC_DIGITAL
+	help
+	  This option enables the NFC driver for Texas Instruments' TRF7970a
+	  device. Such device supports 5 different protocols: ISO14443A,
+	  ISO14443B, FeLiCa, ISO15693 and ISO18000-3.
+
+	  Say Y here to compile support for TRF7970a into the kernel or
+	  say M  to compile it as a module. The module will be called
+	  trf7970a.ko.
+
 config NFC_MEI_PHY
 	tristate "MEI bus NFC device support"
 	depends on INTEL_MEI && NFC_HCI
diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile
index 56ab822..ae42a3f 100644
--- a/drivers/nfc/Makefile
+++ b/drivers/nfc/Makefile
@@ -10,5 +10,6 @@ obj-$(CONFIG_NFC_MEI_PHY)	+= mei_phy.o
 obj-$(CONFIG_NFC_SIM)		+= nfcsim.o
 obj-$(CONFIG_NFC_PORT100)	+= port100.o
 obj-$(CONFIG_NFC_MRVL)		+= nfcmrvl/
+obj-$(CONFIG_NFC_TRF7970A)	+= trf7970a.o
 
 ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c
new file mode 100644
index 0000000..7b9cfec
--- /dev/null
+++ b/drivers/nfc/trf7970a.c
@@ -0,0 +1,1191 @@
+/*
+ * TI TRF7970a RFID/NFC Transceiver Driver
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Author: Erick Macias <emacias@ti.com>
+ * Author: Felipe Balbi <balbi@ti.com>
+ * Author: Mark A. Greer <mgreer@animalcreek.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/netdevice.h>
+#include <linux/interrupt.h>
+#include <linux/nfc.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/spi/spi.h>
+
+#include <net/nfc/nfc.h>
+#include <net/nfc/digital.h>
+
+/* There are 3 ways the host can communicate with the trf7970a:
+ * parallel mode, SPI with Slave Select (SS) mode, and SPI without
+ * SS mode.  The driver only supports the two SPI modes.
+ * When the "ti,ss-gpio" device tree property is present, SPI with
+ * SS mode is used; otherwise, SPI without SS mode is used.
+ *
+ * The trf7970a is very timing sensitive and the SS (I/O_4), EN2,
+ * and EN pins must enabled 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.
+ *
+ * Timeouts are implemented using the delayed workqueue kernel facility.
+ * Timeouts are required so things don't hang when there is no response
+ * from the trf7970a (or tag).  Using this mechanism creates a race with
+ * interrupts, however.  That is, an interrupt and a timeout could occur
+ * closely enough together that one is blocked by the mutex while the other
+ * executes.  When the timeout handler executes first and blocks the
+ * interrupt handler, it will eventually set the state to IDLE so the
+ * interrupt handler will check the state and exit with no harm done.
+ * When the interrupt handler executes first and blocks the timeout handler,
+ * the cancel_delayed_work() call will know that it didn't cancel the
+ * work item (i.e., timeout) and will return zero.  That return code is
+ * used by the timer handler to indicate that it should ignore the timeout
+ * once its unblocked.
+ *
+ * When recieving data from a tag and the interrupt status register has
+ * only the SRX bit set, it means that all of the data has been received
+ * (once what's in the fifo has been read).  However, depending on timing
+ * an interrupt status with only the SRX bit set may not be recived.  In
+ * those cases, the timeout mechanism is used to wait 3 ms in case more
+ * data arrives.  After 3 ms, it is assumed that all of the data has been
+ * received and the accumulated rx data is sent upstream.  The
+ * 'TRF7970A_ST_WAIT_FOR_RX_DATA_CONT' state is used for this purpose
+ * (i.e., it indicates that some data has been received but we're not sure
+ * if there is more coming so a timeout in this state means all data has
+ * been received and there isn't an error).  The delay is 3 ms since delays
+ * over 2 ms have been observed during testing.
+ *
+ * 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
+ * to cause an interrupt in that case.  Leaving that bit for a read command
+ * messes up the data returned so it is only enabled when the framing is
+ * 'NFC_DIGITAL_FRAMING_NFCA_T2T' and the command is not a read command.
+ * Unfortunately, that means that the driver has to peek into tx frames
+ * when the framing is 'NFC_DIGITAL_FRAMING_NFCA_T2T'.  This is done by
+ * the trf7970a_per_cmd_config() routine.
+ */
+
+#define TRF7970A_SUPPORTED_PROTOCOLS		NFC_PROTO_MIFARE_MASK
+
+/* 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
+
+/* TX length is 3 nibbles long ==> 4KB - 1 bytes max */
+#define TRF7970A_TX_MAX				(4096 - 1)
+
+#define TRF7970A_WAIT_FOR_RX_DATA_TIMEOUT	3
+#define TRF7970A_WAIT_FOR_FIFO_DRAIN_TIMEOUT	3
+
+/* 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)
+
+/* Direct commands */
+#define TRF7970A_CMD_IDLE			0x00
+#define TRF7970A_CMD_SOFT_INIT			0x03
+#define TRF7970A_CMD_RF_COLLISION		0x04
+#define TRF7970A_CMD_RF_COLLISION_RESPONSE_N	0x05
+#define TRF7970A_CMD_RF_COLLISION_RESPONSE_0	0x06
+#define TRF7970A_CMD_FIFO_RESET			0x0f
+#define TRF7970A_CMD_TRANSMIT_NO_CRC		0x10
+#define TRF7970A_CMD_TRANSMIT			0x11
+#define TRF7970A_CMD_DELAY_TRANSMIT_NO_CRC	0x12
+#define TRF7970A_CMD_DELAY_TRANSMIT		0x13
+#define TRF7970A_CMD_EOF			0x14
+#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_RX_GAIN_ADJUST		0x1a
+
+/* Bits determining whether its a direct command or register R/W,
+ * whether to use a continuous SPI transaction or not, and the actual
+ * direct cmd opcode or regster address.
+ */
+#define TRF7970A_CMD_BIT_CTRL			BIT(7)
+#define TRF7970A_CMD_BIT_RW			BIT(6)
+#define TRF7970A_CMD_BIT_CONTINUOUS		BIT(5)
+#define TRF7970A_CMD_BIT_OPCODE(opcode)		((opcode) & 0x1f)
+
+/* Registers addresses */
+#define TRF7970A_CHIP_STATUS_CTRL		0x00
+#define TRF7970A_ISO_CTRL			0x01
+#define TRF7970A_ISO14443B_TX_OPTIONS		0x02
+#define TRF7970A_ISO14443A_HIGH_BITRATE_OPTIONS	0x03
+#define TRF7970A_TX_TIMER_SETTING_H_BYTE	0x04
+#define TRF7970A_TX_TIMER_SETTING_L_BYTE	0x05
+#define TRF7970A_TX_PULSE_LENGTH_CTRL		0x06
+#define TRF7970A_RX_NO_RESPONSE_WAIT		0x07
+#define TRF7970A_RX_WAIT_TIME			0x08
+#define TRF7970A_MODULATOR_SYS_CLK_CTRL		0x09
+#define TRF7970A_RX_SPECIAL_SETTINGS		0x0a
+#define TRF7970A_REG_IO_CTRL			0x0b
+#define TRF7970A_IRQ_STATUS			0x0c
+#define TRF7970A_COLLISION_IRQ_MASK		0x0d
+#define TRF7970A_COLLISION_POSITION		0x0e
+#define TRF7970A_RSSI_OSC_STATUS		0x0f
+#define TRF7970A_SPECIAL_FCN_REG1		0x10
+#define TRF7970A_SPECIAL_FCN_REG2		0x11
+#define TRF7970A_RAM1				0x12
+#define TRF7970A_RAM2				0x13
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS	0x14
+#define TRF7970A_NFC_LOW_FIELD_LEVEL		0x16
+#define TRF7970A_NFCID1				0x17
+#define TRF7970A_NFC_TARGET_LEVEL		0x18
+#define TRF79070A_NFC_TARGET_PROTOCOL		0x19
+#define TRF7970A_TEST_REGISTER1			0x1a
+#define TRF7970A_TEST_REGISTER2			0x1b
+#define TRF7970A_FIFO_STATUS			0x1c
+#define TRF7970A_TX_LENGTH_BYTE1		0x1d
+#define TRF7970A_TX_LENGTH_BYTE2		0x1e
+#define TRF7970A_FIFO_IO_REGISTER		0x1f
+
+/* Chip Status Control Register Bits */
+#define TRF7970A_CHIP_STATUS_VRS5_3		BIT(0)
+#define TRF7970A_CHIP_STATUS_REC_ON		BIT(1)
+#define TRF7970A_CHIP_STATUS_AGC_ON		BIT(2)
+#define TRF7970A_CHIP_STATUS_PM_ON		BIT(3)
+#define TRF7970A_CHIP_STATUS_RF_PWR		BIT(4)
+#define TRF7970A_CHIP_STATUS_RF_ON		BIT(5)
+#define TRF7970A_CHIP_STATUS_DIRECT		BIT(6)
+#define TRF7970A_CHIP_STATUS_STBY		BIT(7)
+
+/* ISO Control Register Bits */
+#define TRF7970A_ISO_CTRL_15693_SGL_1OF4_662	0x00
+#define TRF7970A_ISO_CTRL_15693_SGL_1OF256_662	0x01
+#define TRF7970A_ISO_CTRL_15693_SGL_1OF4_2648	0x02
+#define TRF7970A_ISO_CTRL_15693_SGL_1OF256_2648	0x03
+#define TRF7970A_ISO_CTRL_15693_DBL_1OF4_667a	0x04
+#define TRF7970A_ISO_CTRL_15693_DBL_1OF256_667	0x05
+#define TRF7970A_ISO_CTRL_15693_DBL_1OF4_2669	0x06
+#define TRF7970A_ISO_CTRL_15693_DBL_1OF256_2669	0x07
+#define TRF7970A_ISO_CTRL_14443A_106		0x08
+#define TRF7970A_ISO_CTRL_14443A_212		0x09
+#define TRF7970A_ISO_CTRL_14443A_424		0x0a
+#define TRF7970A_ISO_CTRL_14443A_848		0x0b
+#define TRF7970A_ISO_CTRL_14443B_106		0x0c
+#define TRF7970A_ISO_CTRL_14443B_212		0x0d
+#define TRF7970A_ISO_CTRL_14443B_424		0x0e
+#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_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_ISO_CTRL_RFID_SPEED_MASK	0x1f
+
+/* Modulator and SYS_CLK Control Register Bits */
+#define TRF7970A_MODULATOR_DEPTH(n)		((n) & 0x7)
+#define TRF7970A_MODULATOR_DEPTH_ASK10		(TRF7970A_MODULATOR_DEPTH(0))
+#define TRF7970A_MODULATOR_DEPTH_OOK		(TRF7970A_MODULATOR_DEPTH(1))
+#define TRF7970A_MODULATOR_DEPTH_ASK7		(TRF7970A_MODULATOR_DEPTH(2))
+#define TRF7970A_MODULATOR_DEPTH_ASK8_5		(TRF7970A_MODULATOR_DEPTH(3))
+#define TRF7970A_MODULATOR_DEPTH_ASK13		(TRF7970A_MODULATOR_DEPTH(4))
+#define TRF7970A_MODULATOR_DEPTH_ASK16		(TRF7970A_MODULATOR_DEPTH(5))
+#define TRF7970A_MODULATOR_DEPTH_ASK22		(TRF7970A_MODULATOR_DEPTH(6))
+#define TRF7970A_MODULATOR_DEPTH_ASK30		(TRF7970A_MODULATOR_DEPTH(7))
+#define TRF7970A_MODULATOR_EN_ANA		BIT(3)
+#define TRF7970A_MODULATOR_CLK(n)		(((n) & 0x3) << 4)
+#define TRF7970A_MODULATOR_CLK_DISABLED		(TRF7970A_MODULATOR_CLK(0))
+#define TRF7970A_MODULATOR_CLK_3_6		(TRF7970A_MODULATOR_CLK(1))
+#define TRF7970A_MODULATOR_CLK_6_13		(TRF7970A_MODULATOR_CLK(2))
+#define TRF7970A_MODULATOR_CLK_13_27		(TRF7970A_MODULATOR_CLK(3))
+#define TRF7970A_MODULATOR_EN_OOK		BIT(6)
+#define TRF7970A_MODULATOR_27MHZ		BIT(7)
+
+/* IRQ Status Register Bits */
+#define TRF7970A_IRQ_STATUS_NORESP		BIT(0) /* ISO15693 only */
+#define TRF7970A_IRQ_STATUS_COL			BIT(1)
+#define TRF7970A_IRQ_STATUS_FRAMING_EOF_ERROR	BIT(2)
+#define TRF7970A_IRQ_STATUS_PARITY_ERROR	BIT(3)
+#define TRF7970A_IRQ_STATUS_CRC_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_IRQ_STATUS_ERROR				\
+		(TRF7970A_IRQ_STATUS_COL |			\
+		 TRF7970A_IRQ_STATUS_FRAMING_EOF_ERROR |	\
+		 TRF7970A_IRQ_STATUS_PARITY_ERROR |		\
+		 TRF7970A_IRQ_STATUS_CRC_ERROR)
+
+#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)
+#define TRF7970A_SPECIAL_FCN_REG1_SP_DIR_MODE		BIT(3)
+#define TRF7970A_SPECIAL_FCN_REG1_NEXT_SLOT_37US	BIT(4)
+#define TRF7970A_SPECIAL_FCN_REG1_PAR43			BIT(5)
+
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLH_124	(0x0 << 2)
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLH_120	(0x1 << 2)
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLH_112	(0x2 << 2)
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLH_96	(0x3 << 2)
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_4	0x0
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_8	0x1
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_16	0x2
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_32	0x3
+
+#define TRF7970A_FIFO_STATUS_OVERFLOW		BIT(7)
+
+/* NFC (ISO/IEC 14443A) Type 2 Tag commands */
+#define NFC_T2T_CMD_READ			0x30
+
+enum trf7970a_state {
+	TRF7970A_ST_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_MAX
+};
+
+struct trf7970a {
+	enum trf7970a_state		state;
+	struct device			*dev;
+	struct spi_device		*spi;
+	struct nfc_digital_dev		*ddev;
+	u32				quirks;
+	bool				initialized;
+	struct sk_buff			*tx_skb;
+	struct sk_buff			*rx_skb;
+	nfc_digital_cmd_complete_t	cb;
+	void				*cb_arg;
+	u8				iso_ctrl;
+	u8				special_fcn_reg1;
+	int				technology;
+	int				framing;
+	u8				tx_cmd;
+	int				ss_gpio;
+	int				en2_gpio;
+	int				en_gpio;
+	struct mutex			lock;
+	unsigned int			timeout;
+	bool				ignore_timeout;
+	struct delayed_work		timeout_work;
+};
+
+
+static int trf7970a_cmd(struct trf7970a *trf, u8 opcode)
+{
+	u8 cmd = TRF7970A_CMD_BIT_CTRL | TRF7970A_CMD_BIT_OPCODE(opcode);
+	int ret;
+
+	dev_dbg(trf->dev, "cmd: 0x%x\n", cmd);
+
+	ret = spi_write(trf->spi, &cmd, 1);
+	if (ret)
+		dev_err(trf->dev, "%s - cmd: 0x%x, ret: %d\n", __func__, cmd,
+				ret);
+	return ret;
+}
+
+static int trf7970a_read(struct trf7970a *trf, u8 reg, u8 *val)
+{
+	u8 addr = TRF7970A_CMD_BIT_RW | reg;
+	int ret;
+
+	ret = spi_write_then_read(trf->spi, &addr, 1, val, 1);
+	if (ret)
+		dev_err(trf->dev, "%s - addr: 0x%x, ret: %d\n", __func__, addr,
+				ret);
+
+	dev_dbg(trf->dev, "read(0x%x): 0x%x\n", addr, *val);
+
+	return ret;
+}
+
+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;
+	int ret;
+
+	dev_dbg(trf->dev, "read_cont(0x%x, %d)\n", addr, len);
+
+	ret = spi_write_then_read(trf->spi, &addr, 1, buf, len);
+	if (ret)
+		dev_err(trf->dev, "%s - addr: 0x%x, ret: %d\n", __func__, addr,
+				ret);
+	return ret;
+}
+
+static int trf7970a_write(struct trf7970a *trf, u8 reg, u8 val)
+{
+	u8 buf[2] = { reg, val };
+	int ret;
+
+	dev_dbg(trf->dev, "write(0x%x): 0x%x\n", reg, val);
+
+	ret = spi_write(trf->spi, buf, 2);
+	if (ret)
+		dev_err(trf->dev, "%s - write: 0x%x 0x%x, ret: %d\n", __func__,
+				buf[0], buf[1], ret);
+
+	return ret;
+}
+
+static int trf7970a_read_irqstatus(struct trf7970a *trf, u8 *status)
+{
+	int ret;
+	u8 buf[2];
+	u8 addr;
+
+	addr = TRF7970A_IRQ_STATUS | TRF7970A_CMD_BIT_RW;
+
+	if (trf->quirks & TRF7970A_QUIRK_IRQ_STATUS_READ_ERRATA) {
+		addr |= TRF7970A_CMD_BIT_CONTINUOUS;
+		ret = spi_write_then_read(trf->spi, &addr, 1, buf, 2);
+	} else {
+		ret = spi_write_then_read(trf->spi, &addr, 1, buf, 1);
+	}
+
+	if (ret)
+		dev_err(trf->dev, "%s - irqstatus: Status read failed: %d\n",
+				__func__, ret);
+	else
+		*status = buf[0];
+
+	return ret;
+}
+
+static void trf7970a_switch_rf_off(struct trf7970a *trf)
+{
+	dev_dbg(trf->dev, "Switching rf off\n");
+
+	gpio_set_value(trf->en_gpio, 0);
+	gpio_set_value(trf->en2_gpio, 0);
+
+	trf->state = TRF7970A_ST_OFF;
+}
+
+static int trf7970a_init(struct trf7970a *trf)
+{
+	int ret;
+
+	dev_dbg(trf->dev, "Initializing device - state: %d\n", trf->state);
+
+	ret = trf7970a_cmd(trf, TRF7970A_CMD_SOFT_INIT);
+	if (ret)
+		goto err_out;
+
+	ret = trf7970a_cmd(trf, TRF7970A_CMD_IDLE);
+	if (ret)
+		goto err_out;
+
+	ret = trf7970a_write(trf, TRF7970A_MODULATOR_SYS_CLK_CTRL,
+			TRF7970A_MODULATOR_DEPTH_OOK);
+	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);
+	if (ret)
+		goto err_out;
+
+	ret = trf7970a_write(trf, TRF7970A_SPECIAL_FCN_REG1, 0);
+	if (ret)
+		goto err_out;
+
+	trf->special_fcn_reg1 = 0;
+
+	ret = trf7970a_write(trf, TRF7970A_CHIP_STATUS_CTRL,
+			TRF7970A_CHIP_STATUS_RF_ON |
+				TRF7970A_CHIP_STATUS_VRS5_3);
+	if (ret)
+		goto err_out;
+
+	trf->state = TRF7970A_ST_IDLE;
+
+	return 0;
+
+err_out:
+	dev_dbg(trf->dev, "Couldn't init device: %d\n", ret);
+
+	trf7970a_switch_rf_off(trf);
+	return ret;
+}
+
+static int trf7970a_switch_rf_on(struct trf7970a *trf)
+{
+	unsigned long delay;
+
+	dev_dbg(trf->dev, "Switching rf on\n");
+
+	gpio_set_value(trf->en2_gpio, 1);
+	usleep_range(1000, 2000);
+	gpio_set_value(trf->en_gpio, 1);
+
+	/* The delay between enabling the trf7970a and issuing the first
+	 * command is significantly longer the very first time after powering
+	 * up.  Make sure the longer delay is only done the first time.
+	 */
+	if (!trf->initialized) {
+		delay = 20000;
+		trf->initialized = true;
+	} else {
+		delay = 5000;
+	}
+
+	usleep_range(delay, delay + 1000);
+
+	return trf7970a_init(trf);
+}
+
+static void _trf7970a_abort_cmd(struct trf7970a *trf)
+{
+	dev_dbg(trf->dev, "Aborting cmd - state: %d\n", trf->state);
+
+	if ((trf->state != TRF7970A_ST_IDLE) &&
+			(trf->state != TRF7970A_ST_IDLE_RX_BLOCKED))
+		trf->ignore_timeout = !cancel_delayed_work(&trf->timeout_work);
+
+	trf7970a_init(trf);
+
+	dev_kfree_skb_any(trf->tx_skb);
+	trf->tx_skb = NULL;
+
+	kfree_skb(trf->rx_skb);
+	trf->rx_skb = NULL;
+
+	trf->state = TRF7970A_ST_IDLE; /* In case trf7970a_init() fails */
+}
+
+static void trf7970a_send_upstream(struct trf7970a *trf)
+{
+	u8 rssi;
+
+	dev_kfree_skb_any(trf->tx_skb);
+	trf->tx_skb = NULL;
+
+	if (trf->rx_skb && !IS_ERR(trf->rx_skb))
+		print_hex_dump_debug("trf7970a rx data: ", DUMP_PREFIX_NONE,
+				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->cb(trf->ddev, trf->cb_arg, trf->rx_skb);
+	trf->rx_skb = NULL;
+
+	trf->state = TRF7970A_ST_IDLE;
+}
+
+static void trf7970a_abort_and_send_err(struct trf7970a *trf, int errno)
+{
+	dev_dbg(trf->dev, "Error - state: %d, errno: %d\n", trf->state, errno);
+
+	_trf7970a_abort_cmd(trf);
+
+	trf->rx_skb = ERR_PTR(errno);
+	trf7970a_send_upstream(trf);
+}
+
+static int trf7970a_transmit(struct trf7970a *trf, struct sk_buff *skb,
+		unsigned int len)
+{
+	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);
+	if (ret) {
+		dev_err(trf->dev, "%s - Can't send tx data: %d\n", __func__,
+				ret);
+		return ret;
+	}
+
+	skb_pull(skb, len);
+
+	if (skb->len > 0) {
+		trf->state = TRF7970A_ST_WAIT_FOR_TX_FIFO;
+		timeout = TRF7970A_WAIT_FOR_FIFO_DRAIN_TIMEOUT;
+	} else {
+		trf->state = TRF7970A_ST_WAIT_FOR_RX_DATA;
+		timeout = trf->timeout;
+	}
+
+	dev_dbg(trf->dev, "Setting timeout for %d ms, state: %d\n", timeout,
+			trf->state);
+
+	schedule_delayed_work(&trf->timeout_work, msecs_to_jiffies(timeout));
+
+	return 0;
+}
+
+static void trf7970a_fill_fifo(struct trf7970a *trf)
+{
+	struct sk_buff *skb = trf->tx_skb;
+	unsigned int len;
+	int ret;
+	u8 fifo_bytes;
+
+	ret = trf7970a_read(trf, TRF7970A_FIFO_STATUS, &fifo_bytes);
+	if (ret) {
+		trf7970a_abort_and_send_err(trf, ret);
+		return;
+	}
+
+	dev_dbg(trf->dev, "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_abort_and_send_err(trf, -EIO);
+		return;
+	}
+
+	/* Calculate how much more data can be written to the fifo */
+	len = TRF7970A_FIFO_SIZE - fifo_bytes;
+	len = min(skb->len, len);
+
+	ret = trf7970a_transmit(trf, skb, len);
+	if (ret)
+		trf7970a_abort_and_send_err(trf, ret);
+}
+
+static void trf7970a_drain_fifo(struct trf7970a *trf, u8 status)
+{
+	struct sk_buff *skb = trf->rx_skb;
+	int ret;
+	u8 fifo_bytes;
+
+	if (status & TRF7970A_IRQ_STATUS_ERROR) {
+		trf7970a_abort_and_send_err(trf, -EIO);
+		return;
+	}
+
+	ret = trf7970a_read(trf, TRF7970A_FIFO_STATUS, &fifo_bytes);
+	if (ret) {
+		trf7970a_abort_and_send_err(trf, ret);
+		return;
+	}
+
+	dev_dbg(trf->dev, "fifo_bytes: 0x%x\n", fifo_bytes);
+
+	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_abort_and_send_err(trf, -EIO);
+		return;
+	}
+
+	if (fifo_bytes > skb_tailroom(skb)) {
+		skb = skb_copy_expand(skb, skb_headroom(skb),
+				max_t(int, fifo_bytes,
+					TRF7970A_RX_SKB_ALLOC_SIZE),
+				GFP_KERNEL);
+		if (!skb) {
+			trf7970a_abort_and_send_err(trf, -ENOMEM);
+			return;
+		}
+
+		kfree_skb(trf->rx_skb);
+		trf->rx_skb = skb;
+	}
+
+	ret = trf7970a_read_cont(trf, TRF7970A_FIFO_IO_REGISTER,
+			skb_put(skb, fifo_bytes), fifo_bytes);
+	if (ret) {
+		trf7970a_abort_and_send_err(trf, ret);
+		return;
+	}
+
+	/* If received Type 2 ACK/NACK, shift right 4 bits and pass up */
+	if ((trf->framing == NFC_DIGITAL_FRAMING_NFCA_T2T) && (skb->len == 1) &&
+			(trf->special_fcn_reg1 ==
+				 TRF7970A_SPECIAL_FCN_REG1_4_BIT_RX)) {
+		skb->data[0] >>= 4;
+		status = TRF7970A_IRQ_STATUS_SRX;
+	} else {
+		trf->state = TRF7970A_ST_WAIT_FOR_RX_DATA_CONT;
+	}
+
+no_rx_data:
+	if (status == TRF7970A_IRQ_STATUS_SRX) { /* Receive complete */
+		trf7970a_send_upstream(trf);
+		return;
+	}
+
+	dev_dbg(trf->dev, "Setting timeout for %d ms\n",
+			TRF7970A_WAIT_FOR_RX_DATA_TIMEOUT);
+
+	schedule_delayed_work(&trf->timeout_work,
+			msecs_to_jiffies(TRF7970A_WAIT_FOR_RX_DATA_TIMEOUT));
+}
+
+static irqreturn_t trf7970a_irq(int irq, void *dev_id)
+{
+	struct trf7970a *trf = dev_id;
+	int ret;
+	u8 status;
+
+	mutex_lock(&trf->lock);
+
+	if (trf->state == TRF7970A_ST_OFF) {
+		mutex_unlock(&trf->lock);
+		return IRQ_NONE;
+	}
+
+	ret = trf7970a_read_irqstatus(trf, &status);
+	if (ret) {
+		mutex_unlock(&trf->lock);
+		return IRQ_NONE;
+	}
+
+	dev_dbg(trf->dev, "IRQ - state: %d, status: 0x%x\n", trf->state,
+			status);
+
+	if (!status) {
+		mutex_unlock(&trf->lock);
+		return IRQ_NONE;
+	}
+
+	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 (status & TRF7970A_IRQ_STATUS_ERROR) {
+			trf7970a_cmd(trf, TRF7970A_CMD_BLOCK_RX);
+			trf->state = TRF7970A_ST_IDLE_RX_BLOCKED;
+		}
+
+		trf7970a_cmd(trf, TRF7970A_CMD_FIFO_RESET);
+		break;
+	case TRF7970A_ST_WAIT_FOR_TX_FIFO:
+		if (status & TRF7970A_IRQ_STATUS_TX) {
+			trf->ignore_timeout =
+				!cancel_delayed_work(&trf->timeout_work);
+			trf7970a_fill_fifo(trf);
+		} else {
+			trf7970a_abort_and_send_err(trf, -EIO);
+		}
+		break;
+	case TRF7970A_ST_WAIT_FOR_RX_DATA:
+	case TRF7970A_ST_WAIT_FOR_RX_DATA_CONT:
+		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_TX)) {
+			trf7970a_abort_and_send_err(trf, -EIO);
+		}
+		break;
+	default:
+		dev_err(trf->dev, "%s - Driver in invalid state: %d\n",
+				__func__, trf->state);
+	}
+
+	mutex_unlock(&trf->lock);
+	return IRQ_HANDLED;
+}
+
+static void trf7970a_timeout_work_handler(struct work_struct *work)
+{
+	struct trf7970a *trf = container_of(work, struct trf7970a,
+			timeout_work.work);
+
+	dev_dbg(trf->dev, "TIMEOUT - state: %d, ignore_timeout: %d\n",
+			trf->state, trf->ignore_timeout);
+
+	mutex_lock(&trf->lock);
+
+	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 */
+	else
+		trf7970a_abort_and_send_err(trf, -ETIMEDOUT);
+
+	mutex_unlock(&trf->lock);
+}
+
+/* ----------------------------------------------------------------- */
+
+static int trf7970a_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 = TRF7970A_ISO_CTRL_14443A_106;
+		break;
+	default:
+		dev_dbg(trf->dev, "Unsupported rf technology: %d\n", tech);
+		return -EINVAL;
+	}
+
+	trf->technology = tech;
+
+	return ret;
+}
+
+static int trf7970a_config_framing(struct trf7970a *trf, int framing)
+{
+	dev_dbg(trf->dev, "framing: %d\n", framing);
+
+	switch (framing) {
+	case NFC_DIGITAL_FRAMING_NFCA_SHORT:
+	case NFC_DIGITAL_FRAMING_NFCA_STANDARD:
+		trf->tx_cmd = TRF7970A_CMD_TRANSMIT_NO_CRC;
+		trf->iso_ctrl |= TRF7970A_ISO_CTRL_RX_CRC_N;
+		break;
+	case NFC_DIGITAL_FRAMING_NFCA_STANDARD_WITH_CRC_A:
+		trf->tx_cmd = TRF7970A_CMD_TRANSMIT;
+		trf->iso_ctrl &= ~TRF7970A_ISO_CTRL_RX_CRC_N;
+		break;
+	case NFC_DIGITAL_FRAMING_NFCA_T2T:
+		trf->tx_cmd = TRF7970A_CMD_TRANSMIT;
+		trf->iso_ctrl |= TRF7970A_ISO_CTRL_RX_CRC_N;
+		break;
+	default:
+		dev_dbg(trf->dev, "Unsupported Framing: %d\n", framing);
+		return -EINVAL;
+	}
+
+	trf->framing = framing;
+
+	return trf7970a_write(trf, TRF7970A_ISO_CTRL, trf->iso_ctrl);
+}
+
+static int trf7970a_in_configure_hw(struct nfc_digital_dev *ddev, int type,
+		int param)
+{
+	struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+	int ret = 0;
+
+	dev_dbg(trf->dev, "Configure hw - type: %d, param: %d\n", type, param);
+
+	mutex_lock(&trf->lock);
+
+	if (trf->state == TRF7970A_ST_OFF) {
+		ret = trf7970a_switch_rf_on(trf);
+		if (ret)
+			goto err_out;
+	}
+
+	switch (type) {
+	case NFC_DIGITAL_CONFIG_RF_TECH:
+		ret = trf7970a_config_rf_tech(trf, param);
+		break;
+	case NFC_DIGITAL_CONFIG_FRAMING:
+		ret = trf7970a_config_framing(trf, param);
+		break;
+	default:
+		dev_dbg(trf->dev, "Unknown type: %d\n", type);
+		ret = -EINVAL;
+	}
+
+err_out:
+	mutex_unlock(&trf->lock);
+	return ret;
+}
+
+static int trf7970a_per_cmd_config(struct trf7970a *trf, struct sk_buff *skb)
+{
+	u8 *req = skb->data;
+	u8 special_fcn_reg1;
+	int ret;
+
+	/* When issuing Type 2 read command, make sure the '4_bit_RX' bit in
+	 * special functions register 1 is cleared; otherwise, its a write or
+	 * sector select command and '4_bit_RX' must be set.
+	 */
+	if ((trf->technology == NFC_DIGITAL_RF_TECH_106A) &&
+			(trf->framing == NFC_DIGITAL_FRAMING_NFCA_T2T)) {
+		if (req[0] == NFC_T2T_CMD_READ)
+			special_fcn_reg1 = 0;
+		else
+			special_fcn_reg1 = TRF7970A_SPECIAL_FCN_REG1_4_BIT_RX;
+
+		if (special_fcn_reg1 != trf->special_fcn_reg1) {
+			ret = trf7970a_write(trf, TRF7970A_SPECIAL_FCN_REG1,
+					special_fcn_reg1);
+			if (ret)
+				return ret;
+
+			trf->special_fcn_reg1 = special_fcn_reg1;
+		}
+	}
+
+	return 0;
+}
+
+static int trf7970a_in_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;
+	unsigned int len;
+	int ret;
+
+	dev_dbg(trf->dev, "New request - state: %d, timeout: %d ms, len: %d\n",
+			trf->state, timeout, skb->len);
+
+	if (skb->len > TRF7970A_TX_MAX)
+		return -EINVAL;
+
+	mutex_lock(&trf->lock);
+
+	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;
+	}
+
+	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) {
+		ret = trf7970a_cmd(trf, TRF7970A_CMD_ENABLE_RX);
+		if (ret)
+			goto out_err;
+
+		trf->state = TRF7970A_ST_IDLE;
+	}
+
+	ret = trf7970a_per_cmd_config(trf, skb);
+	if (ret)
+		goto out_err;
+
+	trf->ddev = ddev;
+	trf->tx_skb = skb;
+	trf->cb = cb;
+	trf->cb_arg = arg;
+	trf->timeout = timeout;
+	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.
+	 */
+	prefix[0] = TRF7970A_CMD_BIT_CTRL |
+			TRF7970A_CMD_BIT_OPCODE(TRF7970A_CMD_FIFO_RESET);
+	prefix[1] = TRF7970A_CMD_BIT_CTRL |
+			TRF7970A_CMD_BIT_OPCODE(trf->tx_cmd);
+	prefix[2] = TRF7970A_CMD_BIT_CONTINUOUS | TRF7970A_TX_LENGTH_BYTE1;
+
+	if (trf->framing == NFC_DIGITAL_FRAMING_NFCA_SHORT) {
+		prefix[3] = 0x00;
+		prefix[4] = 0x0f; /* 7 bits */
+	} else {
+		prefix[3] = (len & 0xf00) >> 4;
+		prefix[3] |= ((len & 0xf0) >> 4);
+		prefix[4] = ((len & 0x0f) << 4);
+	}
+
+	len = min_t(int, skb->len, TRF7970A_FIFO_SIZE);
+
+	usleep_range(1000, 2000);
+
+	ret = trf7970a_transmit(trf, skb, len);
+	if (ret) {
+		kfree_skb(trf->rx_skb);
+		trf->rx_skb = NULL;
+	}
+
+out_err:
+	mutex_unlock(&trf->lock);
+	return ret;
+}
+
+static int trf7970a_tg_configure_hw(struct nfc_digital_dev *ddev,
+		int type, int param)
+{
+	struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+
+	dev_dbg(trf->dev, "Unsupported interface\n");
+
+	return -EINVAL;
+}
+
+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)
+{
+	struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+
+	dev_dbg(trf->dev, "Unsupported interface\n");
+
+	return -EINVAL;
+}
+
+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");
+
+	return -EINVAL;
+}
+
+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)
+{
+	struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+
+	dev_dbg(trf->dev, "Unsupported interface\n");
+
+	return -EINVAL;
+}
+
+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, "state: %d, on: %d\n", trf->state, on);
+
+	mutex_lock(&trf->lock);
+
+	if (on) {
+		switch (trf->state) {
+		case TRF7970A_ST_OFF:
+			ret = trf7970a_switch_rf_on(trf);
+			break;
+		case TRF7970A_ST_IDLE:
+		case TRF7970A_ST_IDLE_RX_BLOCKED:
+			break;
+		default:
+			dev_err(trf->dev, "%s - Invalid request: %d %d\n",
+					__func__, trf->state, on);
+			trf7970a_switch_rf_off(trf);
+		}
+	} else {
+		switch (trf->state) {
+		case TRF7970A_ST_OFF:
+			break;
+		default:
+			dev_err(trf->dev, "%s - Invalid request: %d %d\n",
+					__func__, trf->state, on);
+			/* FALLTHROUGH */
+		case TRF7970A_ST_IDLE:
+		case TRF7970A_ST_IDLE_RX_BLOCKED:
+			trf7970a_switch_rf_off(trf);
+		}
+	}
+
+	mutex_unlock(&trf->lock);
+	return ret;
+}
+
+static void trf7970a_abort_cmd(struct nfc_digital_dev *ddev)
+{
+	struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+
+	mutex_lock(&trf->lock);
+	_trf7970a_abort_cmd(trf);
+	mutex_unlock(&trf->lock);
+}
+
+static struct nfc_digital_ops trf7970a_nfc_ops = {
+	.in_configure_hw	= trf7970a_in_configure_hw,
+	.in_send_cmd		= trf7970a_in_send_cmd,
+	.tg_configure_hw	= trf7970a_tg_configure_hw,
+	.tg_send_cmd		= trf7970a_tg_send_cmd,
+	.tg_listen		= trf7970a_tg_listen,
+	.tg_listen_mdaa		= trf7970a_tg_listen_mdaa,
+	.switch_rf		= trf7970a_switch_rf,
+	.abort_cmd		= trf7970a_abort_cmd,
+};
+
+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 ret;
+
+	if (!np) {
+		dev_err(&spi->dev, "No Device Tree entry\n");
+		return -EINVAL;
+	}
+
+	trf = devm_kzalloc(&spi->dev, sizeof(*trf), GFP_KERNEL);
+	if (!trf)
+		return -ENOMEM;
+
+	trf->state = TRF7970A_ST_OFF;
+	trf->dev = &spi->dev;
+	trf->spi = spi;
+	trf->quirks = id->driver_data;
+	trf->initialized = false;
+
+	spi->mode = SPI_MODE_1;
+	spi->bits_per_word = 8;
+
+	/* Get the optional Slave Select GPIO used for SPI with SS mode */
+	trf->ss_gpio = of_get_named_gpio(np, "ti,ss-gpio", 0);
+	if (trf->ss_gpio >= 0) {
+		ret = devm_gpio_request_one(trf->dev, trf->ss_gpio,
+				GPIOF_DIR_OUT | GPIOF_INIT_LOW, "SS");
+		if (ret) {
+			dev_err(trf->dev, "Can't request SS GPIO: %d\n", ret);
+			return ret;
+		}
+	} else {
+		dev_info(trf->dev, "Using SPI without SS mode\n");
+	}
+
+	/* There are two enable pins - both must be present */
+	trf->en_gpio = of_get_named_gpio(np, "ti,enable-gpios", 0);
+	if (trf->en_gpio < 0) {
+		dev_err(trf->dev, "No EN GPIO property\n");
+		return ret;
+	}
+
+	ret = devm_gpio_request_one(trf->dev, trf->en_gpio,
+			GPIOF_DIR_OUT | GPIOF_INIT_LOW, "EN");
+	if (ret) {
+		dev_err(trf->dev, "Can't request EN GPIO: %d\n", ret);
+		return ret;
+	}
+
+	trf->en2_gpio = of_get_named_gpio(np, "ti,enable-gpios", 1);
+	if (trf->en2_gpio < 0) {
+		dev_err(trf->dev, "No EN2 GPIO property\n");
+		return ret;
+	}
+
+	ret = devm_gpio_request_one(trf->dev, trf->en2_gpio,
+			GPIOF_DIR_OUT | GPIOF_INIT_LOW, "EN2");
+	if (ret) {
+		dev_err(trf->dev, "Can't request EN2 GPIO: %d\n", ret);
+		return ret;
+	}
+
+	usleep_range(2000, 3000);
+	if (trf->ss_gpio >= 0)
+		gpio_set_value(trf->ss_gpio, 1);
+	usleep_range(3000, 4000);
+
+	ret = devm_request_threaded_irq(trf->dev, spi->irq, NULL,
+			trf7970a_irq, IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+			"trf7970a", trf);
+	if (ret) {
+		dev_err(trf->dev, "Can't request IRQ#%d: %d\n", spi->irq, ret);
+		return ret;
+	}
+
+	trf->ddev = nfc_digital_allocate_device(&trf7970a_nfc_ops,
+			TRF7970A_SUPPORTED_PROTOCOLS,
+			NFC_DIGITAL_DRV_CAPS_IN_CRC, TRF7970A_TX_SKB_HEADROOM,
+			0);
+	if (!trf->ddev) {
+		dev_err(trf->dev, "Can't allocate NFC digital device\n");
+		return -ENOMEM;
+	}
+
+	nfc_digital_set_parent_dev(trf->ddev, trf->dev);
+	nfc_digital_set_drvdata(trf->ddev, trf);
+	spi_set_drvdata(spi, trf);
+
+	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;
+	}
+
+	mutex_init(&trf->lock);
+	INIT_DELAYED_WORK(&trf->timeout_work, trf7970a_timeout_work_handler);
+
+	return 0;
+
+err_free_ddev:
+	nfc_digital_free_device(trf->ddev);
+	return ret;
+}
+
+static int trf7970a_remove(struct spi_device *spi)
+{
+	struct trf7970a *trf = spi_get_drvdata(spi);
+
+	_trf7970a_abort_cmd(trf);
+	trf7970a_switch_rf_off(trf);
+
+	if (trf->ss_gpio >= 0)
+		gpio_set_value(trf->ss_gpio, 0);
+
+	mutex_destroy(&trf->lock);
+
+	nfc_digital_unregister_device(trf->ddev);
+	nfc_digital_free_device(trf->ddev);
+
+	return 0;
+}
+
+static const struct spi_device_id trf7970a_id_table[] = {
+	{ "trf7970a", TRF7970A_QUIRK_IRQ_STATUS_READ_ERRATA },
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, trf7970a_id_table);
+
+static struct spi_driver trf7970a_spi_driver = {
+	.probe		= trf7970a_probe,
+	.remove		= trf7970a_remove,
+	.id_table	= trf7970a_id_table,
+	.driver		= {
+		.name	= "trf7970a",
+		.owner	= THIS_MODULE,
+	},
+};
+
+module_spi_driver(trf7970a_spi_driver);
+
+MODULE_AUTHOR("Mark A. Greer <mgreer@animalcreek.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("TI trf7970a RFID/NFC Transceiver Driver");
-- 
1.8.3.4


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH 1/3] NFC: trf7970a: Add driver with ISO/IEC 14443 Type 2 Tag Support
@ 2014-01-31 22:17   ` Mark A. Greer
  0 siblings, 0 replies; 30+ messages in thread
From: Mark A. Greer @ 2014-01-31 22:17 UTC (permalink / raw)
  To: Samuel Ortiz, Lauro Ramos Venancio, Aloisio Almeida Jr
  Cc: Felipe Balbi, Erick Macias, Thierry Escande,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	linux-nfc-hn68Rpc1hR1g9hUCZPvPmw,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Mark A. Greer

Add a driver for the Texas Instruments TRF7970a RFID/NFC/15693
transceiver.  The driver currently supports ISO/IEC 14443 Type 2
tags only (MIFARE Ultralight and Ultralight C but not Classic).

CC: Erick Macias <emacias-l0cyMroinI0@public.gmane.org>
CC: Felipe Balbi <balbi-l0cyMroinI0@public.gmane.org>
Signed-off-by: Mark A. Greer <mgreer-luAo+O/VEmrlveNOaEYElw@public.gmane.org>
---
 drivers/nfc/Kconfig    |   12 +
 drivers/nfc/Makefile   |    1 +
 drivers/nfc/trf7970a.c | 1191 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1204 insertions(+)
 create mode 100644 drivers/nfc/trf7970a.c

diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig
index fe20e1c..65d4ca1 100644
--- a/drivers/nfc/Kconfig
+++ b/drivers/nfc/Kconfig
@@ -26,6 +26,18 @@ config NFC_WILINK
 	  Say Y here to compile support for Texas Instrument's NFC WiLink driver
 	  into the kernel or say M to compile it as module.
 
+config NFC_TRF7970A
+	tristate "Texas Instruments TRF7970a NFC driver"
+	depends on SPI && NFC_DIGITAL
+	help
+	  This option enables the NFC driver for Texas Instruments' TRF7970a
+	  device. Such device supports 5 different protocols: ISO14443A,
+	  ISO14443B, FeLiCa, ISO15693 and ISO18000-3.
+
+	  Say Y here to compile support for TRF7970a into the kernel or
+	  say M  to compile it as a module. The module will be called
+	  trf7970a.ko.
+
 config NFC_MEI_PHY
 	tristate "MEI bus NFC device support"
 	depends on INTEL_MEI && NFC_HCI
diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile
index 56ab822..ae42a3f 100644
--- a/drivers/nfc/Makefile
+++ b/drivers/nfc/Makefile
@@ -10,5 +10,6 @@ obj-$(CONFIG_NFC_MEI_PHY)	+= mei_phy.o
 obj-$(CONFIG_NFC_SIM)		+= nfcsim.o
 obj-$(CONFIG_NFC_PORT100)	+= port100.o
 obj-$(CONFIG_NFC_MRVL)		+= nfcmrvl/
+obj-$(CONFIG_NFC_TRF7970A)	+= trf7970a.o
 
 ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c
new file mode 100644
index 0000000..7b9cfec
--- /dev/null
+++ b/drivers/nfc/trf7970a.c
@@ -0,0 +1,1191 @@
+/*
+ * TI TRF7970a RFID/NFC Transceiver Driver
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Author: Erick Macias <emacias-l0cyMroinI0@public.gmane.org>
+ * Author: Felipe Balbi <balbi-l0cyMroinI0@public.gmane.org>
+ * Author: Mark A. Greer <mgreer-luAo+O/VEmrlveNOaEYElw@public.gmane.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/netdevice.h>
+#include <linux/interrupt.h>
+#include <linux/nfc.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/spi/spi.h>
+
+#include <net/nfc/nfc.h>
+#include <net/nfc/digital.h>
+
+/* There are 3 ways the host can communicate with the trf7970a:
+ * parallel mode, SPI with Slave Select (SS) mode, and SPI without
+ * SS mode.  The driver only supports the two SPI modes.
+ * When the "ti,ss-gpio" device tree property is present, SPI with
+ * SS mode is used; otherwise, SPI without SS mode is used.
+ *
+ * The trf7970a is very timing sensitive and the SS (I/O_4), EN2,
+ * and EN pins must enabled 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.
+ *
+ * Timeouts are implemented using the delayed workqueue kernel facility.
+ * Timeouts are required so things don't hang when there is no response
+ * from the trf7970a (or tag).  Using this mechanism creates a race with
+ * interrupts, however.  That is, an interrupt and a timeout could occur
+ * closely enough together that one is blocked by the mutex while the other
+ * executes.  When the timeout handler executes first and blocks the
+ * interrupt handler, it will eventually set the state to IDLE so the
+ * interrupt handler will check the state and exit with no harm done.
+ * When the interrupt handler executes first and blocks the timeout handler,
+ * the cancel_delayed_work() call will know that it didn't cancel the
+ * work item (i.e., timeout) and will return zero.  That return code is
+ * used by the timer handler to indicate that it should ignore the timeout
+ * once its unblocked.
+ *
+ * When recieving data from a tag and the interrupt status register has
+ * only the SRX bit set, it means that all of the data has been received
+ * (once what's in the fifo has been read).  However, depending on timing
+ * an interrupt status with only the SRX bit set may not be recived.  In
+ * those cases, the timeout mechanism is used to wait 3 ms in case more
+ * data arrives.  After 3 ms, it is assumed that all of the data has been
+ * received and the accumulated rx data is sent upstream.  The
+ * 'TRF7970A_ST_WAIT_FOR_RX_DATA_CONT' state is used for this purpose
+ * (i.e., it indicates that some data has been received but we're not sure
+ * if there is more coming so a timeout in this state means all data has
+ * been received and there isn't an error).  The delay is 3 ms since delays
+ * over 2 ms have been observed during testing.
+ *
+ * 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
+ * to cause an interrupt in that case.  Leaving that bit for a read command
+ * messes up the data returned so it is only enabled when the framing is
+ * 'NFC_DIGITAL_FRAMING_NFCA_T2T' and the command is not a read command.
+ * Unfortunately, that means that the driver has to peek into tx frames
+ * when the framing is 'NFC_DIGITAL_FRAMING_NFCA_T2T'.  This is done by
+ * the trf7970a_per_cmd_config() routine.
+ */
+
+#define TRF7970A_SUPPORTED_PROTOCOLS		NFC_PROTO_MIFARE_MASK
+
+/* 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
+
+/* TX length is 3 nibbles long ==> 4KB - 1 bytes max */
+#define TRF7970A_TX_MAX				(4096 - 1)
+
+#define TRF7970A_WAIT_FOR_RX_DATA_TIMEOUT	3
+#define TRF7970A_WAIT_FOR_FIFO_DRAIN_TIMEOUT	3
+
+/* 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)
+
+/* Direct commands */
+#define TRF7970A_CMD_IDLE			0x00
+#define TRF7970A_CMD_SOFT_INIT			0x03
+#define TRF7970A_CMD_RF_COLLISION		0x04
+#define TRF7970A_CMD_RF_COLLISION_RESPONSE_N	0x05
+#define TRF7970A_CMD_RF_COLLISION_RESPONSE_0	0x06
+#define TRF7970A_CMD_FIFO_RESET			0x0f
+#define TRF7970A_CMD_TRANSMIT_NO_CRC		0x10
+#define TRF7970A_CMD_TRANSMIT			0x11
+#define TRF7970A_CMD_DELAY_TRANSMIT_NO_CRC	0x12
+#define TRF7970A_CMD_DELAY_TRANSMIT		0x13
+#define TRF7970A_CMD_EOF			0x14
+#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_RX_GAIN_ADJUST		0x1a
+
+/* Bits determining whether its a direct command or register R/W,
+ * whether to use a continuous SPI transaction or not, and the actual
+ * direct cmd opcode or regster address.
+ */
+#define TRF7970A_CMD_BIT_CTRL			BIT(7)
+#define TRF7970A_CMD_BIT_RW			BIT(6)
+#define TRF7970A_CMD_BIT_CONTINUOUS		BIT(5)
+#define TRF7970A_CMD_BIT_OPCODE(opcode)		((opcode) & 0x1f)
+
+/* Registers addresses */
+#define TRF7970A_CHIP_STATUS_CTRL		0x00
+#define TRF7970A_ISO_CTRL			0x01
+#define TRF7970A_ISO14443B_TX_OPTIONS		0x02
+#define TRF7970A_ISO14443A_HIGH_BITRATE_OPTIONS	0x03
+#define TRF7970A_TX_TIMER_SETTING_H_BYTE	0x04
+#define TRF7970A_TX_TIMER_SETTING_L_BYTE	0x05
+#define TRF7970A_TX_PULSE_LENGTH_CTRL		0x06
+#define TRF7970A_RX_NO_RESPONSE_WAIT		0x07
+#define TRF7970A_RX_WAIT_TIME			0x08
+#define TRF7970A_MODULATOR_SYS_CLK_CTRL		0x09
+#define TRF7970A_RX_SPECIAL_SETTINGS		0x0a
+#define TRF7970A_REG_IO_CTRL			0x0b
+#define TRF7970A_IRQ_STATUS			0x0c
+#define TRF7970A_COLLISION_IRQ_MASK		0x0d
+#define TRF7970A_COLLISION_POSITION		0x0e
+#define TRF7970A_RSSI_OSC_STATUS		0x0f
+#define TRF7970A_SPECIAL_FCN_REG1		0x10
+#define TRF7970A_SPECIAL_FCN_REG2		0x11
+#define TRF7970A_RAM1				0x12
+#define TRF7970A_RAM2				0x13
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS	0x14
+#define TRF7970A_NFC_LOW_FIELD_LEVEL		0x16
+#define TRF7970A_NFCID1				0x17
+#define TRF7970A_NFC_TARGET_LEVEL		0x18
+#define TRF79070A_NFC_TARGET_PROTOCOL		0x19
+#define TRF7970A_TEST_REGISTER1			0x1a
+#define TRF7970A_TEST_REGISTER2			0x1b
+#define TRF7970A_FIFO_STATUS			0x1c
+#define TRF7970A_TX_LENGTH_BYTE1		0x1d
+#define TRF7970A_TX_LENGTH_BYTE2		0x1e
+#define TRF7970A_FIFO_IO_REGISTER		0x1f
+
+/* Chip Status Control Register Bits */
+#define TRF7970A_CHIP_STATUS_VRS5_3		BIT(0)
+#define TRF7970A_CHIP_STATUS_REC_ON		BIT(1)
+#define TRF7970A_CHIP_STATUS_AGC_ON		BIT(2)
+#define TRF7970A_CHIP_STATUS_PM_ON		BIT(3)
+#define TRF7970A_CHIP_STATUS_RF_PWR		BIT(4)
+#define TRF7970A_CHIP_STATUS_RF_ON		BIT(5)
+#define TRF7970A_CHIP_STATUS_DIRECT		BIT(6)
+#define TRF7970A_CHIP_STATUS_STBY		BIT(7)
+
+/* ISO Control Register Bits */
+#define TRF7970A_ISO_CTRL_15693_SGL_1OF4_662	0x00
+#define TRF7970A_ISO_CTRL_15693_SGL_1OF256_662	0x01
+#define TRF7970A_ISO_CTRL_15693_SGL_1OF4_2648	0x02
+#define TRF7970A_ISO_CTRL_15693_SGL_1OF256_2648	0x03
+#define TRF7970A_ISO_CTRL_15693_DBL_1OF4_667a	0x04
+#define TRF7970A_ISO_CTRL_15693_DBL_1OF256_667	0x05
+#define TRF7970A_ISO_CTRL_15693_DBL_1OF4_2669	0x06
+#define TRF7970A_ISO_CTRL_15693_DBL_1OF256_2669	0x07
+#define TRF7970A_ISO_CTRL_14443A_106		0x08
+#define TRF7970A_ISO_CTRL_14443A_212		0x09
+#define TRF7970A_ISO_CTRL_14443A_424		0x0a
+#define TRF7970A_ISO_CTRL_14443A_848		0x0b
+#define TRF7970A_ISO_CTRL_14443B_106		0x0c
+#define TRF7970A_ISO_CTRL_14443B_212		0x0d
+#define TRF7970A_ISO_CTRL_14443B_424		0x0e
+#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_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_ISO_CTRL_RFID_SPEED_MASK	0x1f
+
+/* Modulator and SYS_CLK Control Register Bits */
+#define TRF7970A_MODULATOR_DEPTH(n)		((n) & 0x7)
+#define TRF7970A_MODULATOR_DEPTH_ASK10		(TRF7970A_MODULATOR_DEPTH(0))
+#define TRF7970A_MODULATOR_DEPTH_OOK		(TRF7970A_MODULATOR_DEPTH(1))
+#define TRF7970A_MODULATOR_DEPTH_ASK7		(TRF7970A_MODULATOR_DEPTH(2))
+#define TRF7970A_MODULATOR_DEPTH_ASK8_5		(TRF7970A_MODULATOR_DEPTH(3))
+#define TRF7970A_MODULATOR_DEPTH_ASK13		(TRF7970A_MODULATOR_DEPTH(4))
+#define TRF7970A_MODULATOR_DEPTH_ASK16		(TRF7970A_MODULATOR_DEPTH(5))
+#define TRF7970A_MODULATOR_DEPTH_ASK22		(TRF7970A_MODULATOR_DEPTH(6))
+#define TRF7970A_MODULATOR_DEPTH_ASK30		(TRF7970A_MODULATOR_DEPTH(7))
+#define TRF7970A_MODULATOR_EN_ANA		BIT(3)
+#define TRF7970A_MODULATOR_CLK(n)		(((n) & 0x3) << 4)
+#define TRF7970A_MODULATOR_CLK_DISABLED		(TRF7970A_MODULATOR_CLK(0))
+#define TRF7970A_MODULATOR_CLK_3_6		(TRF7970A_MODULATOR_CLK(1))
+#define TRF7970A_MODULATOR_CLK_6_13		(TRF7970A_MODULATOR_CLK(2))
+#define TRF7970A_MODULATOR_CLK_13_27		(TRF7970A_MODULATOR_CLK(3))
+#define TRF7970A_MODULATOR_EN_OOK		BIT(6)
+#define TRF7970A_MODULATOR_27MHZ		BIT(7)
+
+/* IRQ Status Register Bits */
+#define TRF7970A_IRQ_STATUS_NORESP		BIT(0) /* ISO15693 only */
+#define TRF7970A_IRQ_STATUS_COL			BIT(1)
+#define TRF7970A_IRQ_STATUS_FRAMING_EOF_ERROR	BIT(2)
+#define TRF7970A_IRQ_STATUS_PARITY_ERROR	BIT(3)
+#define TRF7970A_IRQ_STATUS_CRC_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_IRQ_STATUS_ERROR				\
+		(TRF7970A_IRQ_STATUS_COL |			\
+		 TRF7970A_IRQ_STATUS_FRAMING_EOF_ERROR |	\
+		 TRF7970A_IRQ_STATUS_PARITY_ERROR |		\
+		 TRF7970A_IRQ_STATUS_CRC_ERROR)
+
+#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)
+#define TRF7970A_SPECIAL_FCN_REG1_SP_DIR_MODE		BIT(3)
+#define TRF7970A_SPECIAL_FCN_REG1_NEXT_SLOT_37US	BIT(4)
+#define TRF7970A_SPECIAL_FCN_REG1_PAR43			BIT(5)
+
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLH_124	(0x0 << 2)
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLH_120	(0x1 << 2)
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLH_112	(0x2 << 2)
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLH_96	(0x3 << 2)
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_4	0x0
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_8	0x1
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_16	0x2
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_32	0x3
+
+#define TRF7970A_FIFO_STATUS_OVERFLOW		BIT(7)
+
+/* NFC (ISO/IEC 14443A) Type 2 Tag commands */
+#define NFC_T2T_CMD_READ			0x30
+
+enum trf7970a_state {
+	TRF7970A_ST_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_MAX
+};
+
+struct trf7970a {
+	enum trf7970a_state		state;
+	struct device			*dev;
+	struct spi_device		*spi;
+	struct nfc_digital_dev		*ddev;
+	u32				quirks;
+	bool				initialized;
+	struct sk_buff			*tx_skb;
+	struct sk_buff			*rx_skb;
+	nfc_digital_cmd_complete_t	cb;
+	void				*cb_arg;
+	u8				iso_ctrl;
+	u8				special_fcn_reg1;
+	int				technology;
+	int				framing;
+	u8				tx_cmd;
+	int				ss_gpio;
+	int				en2_gpio;
+	int				en_gpio;
+	struct mutex			lock;
+	unsigned int			timeout;
+	bool				ignore_timeout;
+	struct delayed_work		timeout_work;
+};
+
+
+static int trf7970a_cmd(struct trf7970a *trf, u8 opcode)
+{
+	u8 cmd = TRF7970A_CMD_BIT_CTRL | TRF7970A_CMD_BIT_OPCODE(opcode);
+	int ret;
+
+	dev_dbg(trf->dev, "cmd: 0x%x\n", cmd);
+
+	ret = spi_write(trf->spi, &cmd, 1);
+	if (ret)
+		dev_err(trf->dev, "%s - cmd: 0x%x, ret: %d\n", __func__, cmd,
+				ret);
+	return ret;
+}
+
+static int trf7970a_read(struct trf7970a *trf, u8 reg, u8 *val)
+{
+	u8 addr = TRF7970A_CMD_BIT_RW | reg;
+	int ret;
+
+	ret = spi_write_then_read(trf->spi, &addr, 1, val, 1);
+	if (ret)
+		dev_err(trf->dev, "%s - addr: 0x%x, ret: %d\n", __func__, addr,
+				ret);
+
+	dev_dbg(trf->dev, "read(0x%x): 0x%x\n", addr, *val);
+
+	return ret;
+}
+
+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;
+	int ret;
+
+	dev_dbg(trf->dev, "read_cont(0x%x, %d)\n", addr, len);
+
+	ret = spi_write_then_read(trf->spi, &addr, 1, buf, len);
+	if (ret)
+		dev_err(trf->dev, "%s - addr: 0x%x, ret: %d\n", __func__, addr,
+				ret);
+	return ret;
+}
+
+static int trf7970a_write(struct trf7970a *trf, u8 reg, u8 val)
+{
+	u8 buf[2] = { reg, val };
+	int ret;
+
+	dev_dbg(trf->dev, "write(0x%x): 0x%x\n", reg, val);
+
+	ret = spi_write(trf->spi, buf, 2);
+	if (ret)
+		dev_err(trf->dev, "%s - write: 0x%x 0x%x, ret: %d\n", __func__,
+				buf[0], buf[1], ret);
+
+	return ret;
+}
+
+static int trf7970a_read_irqstatus(struct trf7970a *trf, u8 *status)
+{
+	int ret;
+	u8 buf[2];
+	u8 addr;
+
+	addr = TRF7970A_IRQ_STATUS | TRF7970A_CMD_BIT_RW;
+
+	if (trf->quirks & TRF7970A_QUIRK_IRQ_STATUS_READ_ERRATA) {
+		addr |= TRF7970A_CMD_BIT_CONTINUOUS;
+		ret = spi_write_then_read(trf->spi, &addr, 1, buf, 2);
+	} else {
+		ret = spi_write_then_read(trf->spi, &addr, 1, buf, 1);
+	}
+
+	if (ret)
+		dev_err(trf->dev, "%s - irqstatus: Status read failed: %d\n",
+				__func__, ret);
+	else
+		*status = buf[0];
+
+	return ret;
+}
+
+static void trf7970a_switch_rf_off(struct trf7970a *trf)
+{
+	dev_dbg(trf->dev, "Switching rf off\n");
+
+	gpio_set_value(trf->en_gpio, 0);
+	gpio_set_value(trf->en2_gpio, 0);
+
+	trf->state = TRF7970A_ST_OFF;
+}
+
+static int trf7970a_init(struct trf7970a *trf)
+{
+	int ret;
+
+	dev_dbg(trf->dev, "Initializing device - state: %d\n", trf->state);
+
+	ret = trf7970a_cmd(trf, TRF7970A_CMD_SOFT_INIT);
+	if (ret)
+		goto err_out;
+
+	ret = trf7970a_cmd(trf, TRF7970A_CMD_IDLE);
+	if (ret)
+		goto err_out;
+
+	ret = trf7970a_write(trf, TRF7970A_MODULATOR_SYS_CLK_CTRL,
+			TRF7970A_MODULATOR_DEPTH_OOK);
+	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);
+	if (ret)
+		goto err_out;
+
+	ret = trf7970a_write(trf, TRF7970A_SPECIAL_FCN_REG1, 0);
+	if (ret)
+		goto err_out;
+
+	trf->special_fcn_reg1 = 0;
+
+	ret = trf7970a_write(trf, TRF7970A_CHIP_STATUS_CTRL,
+			TRF7970A_CHIP_STATUS_RF_ON |
+				TRF7970A_CHIP_STATUS_VRS5_3);
+	if (ret)
+		goto err_out;
+
+	trf->state = TRF7970A_ST_IDLE;
+
+	return 0;
+
+err_out:
+	dev_dbg(trf->dev, "Couldn't init device: %d\n", ret);
+
+	trf7970a_switch_rf_off(trf);
+	return ret;
+}
+
+static int trf7970a_switch_rf_on(struct trf7970a *trf)
+{
+	unsigned long delay;
+
+	dev_dbg(trf->dev, "Switching rf on\n");
+
+	gpio_set_value(trf->en2_gpio, 1);
+	usleep_range(1000, 2000);
+	gpio_set_value(trf->en_gpio, 1);
+
+	/* The delay between enabling the trf7970a and issuing the first
+	 * command is significantly longer the very first time after powering
+	 * up.  Make sure the longer delay is only done the first time.
+	 */
+	if (!trf->initialized) {
+		delay = 20000;
+		trf->initialized = true;
+	} else {
+		delay = 5000;
+	}
+
+	usleep_range(delay, delay + 1000);
+
+	return trf7970a_init(trf);
+}
+
+static void _trf7970a_abort_cmd(struct trf7970a *trf)
+{
+	dev_dbg(trf->dev, "Aborting cmd - state: %d\n", trf->state);
+
+	if ((trf->state != TRF7970A_ST_IDLE) &&
+			(trf->state != TRF7970A_ST_IDLE_RX_BLOCKED))
+		trf->ignore_timeout = !cancel_delayed_work(&trf->timeout_work);
+
+	trf7970a_init(trf);
+
+	dev_kfree_skb_any(trf->tx_skb);
+	trf->tx_skb = NULL;
+
+	kfree_skb(trf->rx_skb);
+	trf->rx_skb = NULL;
+
+	trf->state = TRF7970A_ST_IDLE; /* In case trf7970a_init() fails */
+}
+
+static void trf7970a_send_upstream(struct trf7970a *trf)
+{
+	u8 rssi;
+
+	dev_kfree_skb_any(trf->tx_skb);
+	trf->tx_skb = NULL;
+
+	if (trf->rx_skb && !IS_ERR(trf->rx_skb))
+		print_hex_dump_debug("trf7970a rx data: ", DUMP_PREFIX_NONE,
+				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->cb(trf->ddev, trf->cb_arg, trf->rx_skb);
+	trf->rx_skb = NULL;
+
+	trf->state = TRF7970A_ST_IDLE;
+}
+
+static void trf7970a_abort_and_send_err(struct trf7970a *trf, int errno)
+{
+	dev_dbg(trf->dev, "Error - state: %d, errno: %d\n", trf->state, errno);
+
+	_trf7970a_abort_cmd(trf);
+
+	trf->rx_skb = ERR_PTR(errno);
+	trf7970a_send_upstream(trf);
+}
+
+static int trf7970a_transmit(struct trf7970a *trf, struct sk_buff *skb,
+		unsigned int len)
+{
+	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);
+	if (ret) {
+		dev_err(trf->dev, "%s - Can't send tx data: %d\n", __func__,
+				ret);
+		return ret;
+	}
+
+	skb_pull(skb, len);
+
+	if (skb->len > 0) {
+		trf->state = TRF7970A_ST_WAIT_FOR_TX_FIFO;
+		timeout = TRF7970A_WAIT_FOR_FIFO_DRAIN_TIMEOUT;
+	} else {
+		trf->state = TRF7970A_ST_WAIT_FOR_RX_DATA;
+		timeout = trf->timeout;
+	}
+
+	dev_dbg(trf->dev, "Setting timeout for %d ms, state: %d\n", timeout,
+			trf->state);
+
+	schedule_delayed_work(&trf->timeout_work, msecs_to_jiffies(timeout));
+
+	return 0;
+}
+
+static void trf7970a_fill_fifo(struct trf7970a *trf)
+{
+	struct sk_buff *skb = trf->tx_skb;
+	unsigned int len;
+	int ret;
+	u8 fifo_bytes;
+
+	ret = trf7970a_read(trf, TRF7970A_FIFO_STATUS, &fifo_bytes);
+	if (ret) {
+		trf7970a_abort_and_send_err(trf, ret);
+		return;
+	}
+
+	dev_dbg(trf->dev, "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_abort_and_send_err(trf, -EIO);
+		return;
+	}
+
+	/* Calculate how much more data can be written to the fifo */
+	len = TRF7970A_FIFO_SIZE - fifo_bytes;
+	len = min(skb->len, len);
+
+	ret = trf7970a_transmit(trf, skb, len);
+	if (ret)
+		trf7970a_abort_and_send_err(trf, ret);
+}
+
+static void trf7970a_drain_fifo(struct trf7970a *trf, u8 status)
+{
+	struct sk_buff *skb = trf->rx_skb;
+	int ret;
+	u8 fifo_bytes;
+
+	if (status & TRF7970A_IRQ_STATUS_ERROR) {
+		trf7970a_abort_and_send_err(trf, -EIO);
+		return;
+	}
+
+	ret = trf7970a_read(trf, TRF7970A_FIFO_STATUS, &fifo_bytes);
+	if (ret) {
+		trf7970a_abort_and_send_err(trf, ret);
+		return;
+	}
+
+	dev_dbg(trf->dev, "fifo_bytes: 0x%x\n", fifo_bytes);
+
+	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_abort_and_send_err(trf, -EIO);
+		return;
+	}
+
+	if (fifo_bytes > skb_tailroom(skb)) {
+		skb = skb_copy_expand(skb, skb_headroom(skb),
+				max_t(int, fifo_bytes,
+					TRF7970A_RX_SKB_ALLOC_SIZE),
+				GFP_KERNEL);
+		if (!skb) {
+			trf7970a_abort_and_send_err(trf, -ENOMEM);
+			return;
+		}
+
+		kfree_skb(trf->rx_skb);
+		trf->rx_skb = skb;
+	}
+
+	ret = trf7970a_read_cont(trf, TRF7970A_FIFO_IO_REGISTER,
+			skb_put(skb, fifo_bytes), fifo_bytes);
+	if (ret) {
+		trf7970a_abort_and_send_err(trf, ret);
+		return;
+	}
+
+	/* If received Type 2 ACK/NACK, shift right 4 bits and pass up */
+	if ((trf->framing == NFC_DIGITAL_FRAMING_NFCA_T2T) && (skb->len == 1) &&
+			(trf->special_fcn_reg1 ==
+				 TRF7970A_SPECIAL_FCN_REG1_4_BIT_RX)) {
+		skb->data[0] >>= 4;
+		status = TRF7970A_IRQ_STATUS_SRX;
+	} else {
+		trf->state = TRF7970A_ST_WAIT_FOR_RX_DATA_CONT;
+	}
+
+no_rx_data:
+	if (status == TRF7970A_IRQ_STATUS_SRX) { /* Receive complete */
+		trf7970a_send_upstream(trf);
+		return;
+	}
+
+	dev_dbg(trf->dev, "Setting timeout for %d ms\n",
+			TRF7970A_WAIT_FOR_RX_DATA_TIMEOUT);
+
+	schedule_delayed_work(&trf->timeout_work,
+			msecs_to_jiffies(TRF7970A_WAIT_FOR_RX_DATA_TIMEOUT));
+}
+
+static irqreturn_t trf7970a_irq(int irq, void *dev_id)
+{
+	struct trf7970a *trf = dev_id;
+	int ret;
+	u8 status;
+
+	mutex_lock(&trf->lock);
+
+	if (trf->state == TRF7970A_ST_OFF) {
+		mutex_unlock(&trf->lock);
+		return IRQ_NONE;
+	}
+
+	ret = trf7970a_read_irqstatus(trf, &status);
+	if (ret) {
+		mutex_unlock(&trf->lock);
+		return IRQ_NONE;
+	}
+
+	dev_dbg(trf->dev, "IRQ - state: %d, status: 0x%x\n", trf->state,
+			status);
+
+	if (!status) {
+		mutex_unlock(&trf->lock);
+		return IRQ_NONE;
+	}
+
+	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 (status & TRF7970A_IRQ_STATUS_ERROR) {
+			trf7970a_cmd(trf, TRF7970A_CMD_BLOCK_RX);
+			trf->state = TRF7970A_ST_IDLE_RX_BLOCKED;
+		}
+
+		trf7970a_cmd(trf, TRF7970A_CMD_FIFO_RESET);
+		break;
+	case TRF7970A_ST_WAIT_FOR_TX_FIFO:
+		if (status & TRF7970A_IRQ_STATUS_TX) {
+			trf->ignore_timeout =
+				!cancel_delayed_work(&trf->timeout_work);
+			trf7970a_fill_fifo(trf);
+		} else {
+			trf7970a_abort_and_send_err(trf, -EIO);
+		}
+		break;
+	case TRF7970A_ST_WAIT_FOR_RX_DATA:
+	case TRF7970A_ST_WAIT_FOR_RX_DATA_CONT:
+		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_TX)) {
+			trf7970a_abort_and_send_err(trf, -EIO);
+		}
+		break;
+	default:
+		dev_err(trf->dev, "%s - Driver in invalid state: %d\n",
+				__func__, trf->state);
+	}
+
+	mutex_unlock(&trf->lock);
+	return IRQ_HANDLED;
+}
+
+static void trf7970a_timeout_work_handler(struct work_struct *work)
+{
+	struct trf7970a *trf = container_of(work, struct trf7970a,
+			timeout_work.work);
+
+	dev_dbg(trf->dev, "TIMEOUT - state: %d, ignore_timeout: %d\n",
+			trf->state, trf->ignore_timeout);
+
+	mutex_lock(&trf->lock);
+
+	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 */
+	else
+		trf7970a_abort_and_send_err(trf, -ETIMEDOUT);
+
+	mutex_unlock(&trf->lock);
+}
+
+/* ----------------------------------------------------------------- */
+
+static int trf7970a_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 = TRF7970A_ISO_CTRL_14443A_106;
+		break;
+	default:
+		dev_dbg(trf->dev, "Unsupported rf technology: %d\n", tech);
+		return -EINVAL;
+	}
+
+	trf->technology = tech;
+
+	return ret;
+}
+
+static int trf7970a_config_framing(struct trf7970a *trf, int framing)
+{
+	dev_dbg(trf->dev, "framing: %d\n", framing);
+
+	switch (framing) {
+	case NFC_DIGITAL_FRAMING_NFCA_SHORT:
+	case NFC_DIGITAL_FRAMING_NFCA_STANDARD:
+		trf->tx_cmd = TRF7970A_CMD_TRANSMIT_NO_CRC;
+		trf->iso_ctrl |= TRF7970A_ISO_CTRL_RX_CRC_N;
+		break;
+	case NFC_DIGITAL_FRAMING_NFCA_STANDARD_WITH_CRC_A:
+		trf->tx_cmd = TRF7970A_CMD_TRANSMIT;
+		trf->iso_ctrl &= ~TRF7970A_ISO_CTRL_RX_CRC_N;
+		break;
+	case NFC_DIGITAL_FRAMING_NFCA_T2T:
+		trf->tx_cmd = TRF7970A_CMD_TRANSMIT;
+		trf->iso_ctrl |= TRF7970A_ISO_CTRL_RX_CRC_N;
+		break;
+	default:
+		dev_dbg(trf->dev, "Unsupported Framing: %d\n", framing);
+		return -EINVAL;
+	}
+
+	trf->framing = framing;
+
+	return trf7970a_write(trf, TRF7970A_ISO_CTRL, trf->iso_ctrl);
+}
+
+static int trf7970a_in_configure_hw(struct nfc_digital_dev *ddev, int type,
+		int param)
+{
+	struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+	int ret = 0;
+
+	dev_dbg(trf->dev, "Configure hw - type: %d, param: %d\n", type, param);
+
+	mutex_lock(&trf->lock);
+
+	if (trf->state == TRF7970A_ST_OFF) {
+		ret = trf7970a_switch_rf_on(trf);
+		if (ret)
+			goto err_out;
+	}
+
+	switch (type) {
+	case NFC_DIGITAL_CONFIG_RF_TECH:
+		ret = trf7970a_config_rf_tech(trf, param);
+		break;
+	case NFC_DIGITAL_CONFIG_FRAMING:
+		ret = trf7970a_config_framing(trf, param);
+		break;
+	default:
+		dev_dbg(trf->dev, "Unknown type: %d\n", type);
+		ret = -EINVAL;
+	}
+
+err_out:
+	mutex_unlock(&trf->lock);
+	return ret;
+}
+
+static int trf7970a_per_cmd_config(struct trf7970a *trf, struct sk_buff *skb)
+{
+	u8 *req = skb->data;
+	u8 special_fcn_reg1;
+	int ret;
+
+	/* When issuing Type 2 read command, make sure the '4_bit_RX' bit in
+	 * special functions register 1 is cleared; otherwise, its a write or
+	 * sector select command and '4_bit_RX' must be set.
+	 */
+	if ((trf->technology == NFC_DIGITAL_RF_TECH_106A) &&
+			(trf->framing == NFC_DIGITAL_FRAMING_NFCA_T2T)) {
+		if (req[0] == NFC_T2T_CMD_READ)
+			special_fcn_reg1 = 0;
+		else
+			special_fcn_reg1 = TRF7970A_SPECIAL_FCN_REG1_4_BIT_RX;
+
+		if (special_fcn_reg1 != trf->special_fcn_reg1) {
+			ret = trf7970a_write(trf, TRF7970A_SPECIAL_FCN_REG1,
+					special_fcn_reg1);
+			if (ret)
+				return ret;
+
+			trf->special_fcn_reg1 = special_fcn_reg1;
+		}
+	}
+
+	return 0;
+}
+
+static int trf7970a_in_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;
+	unsigned int len;
+	int ret;
+
+	dev_dbg(trf->dev, "New request - state: %d, timeout: %d ms, len: %d\n",
+			trf->state, timeout, skb->len);
+
+	if (skb->len > TRF7970A_TX_MAX)
+		return -EINVAL;
+
+	mutex_lock(&trf->lock);
+
+	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;
+	}
+
+	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) {
+		ret = trf7970a_cmd(trf, TRF7970A_CMD_ENABLE_RX);
+		if (ret)
+			goto out_err;
+
+		trf->state = TRF7970A_ST_IDLE;
+	}
+
+	ret = trf7970a_per_cmd_config(trf, skb);
+	if (ret)
+		goto out_err;
+
+	trf->ddev = ddev;
+	trf->tx_skb = skb;
+	trf->cb = cb;
+	trf->cb_arg = arg;
+	trf->timeout = timeout;
+	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.
+	 */
+	prefix[0] = TRF7970A_CMD_BIT_CTRL |
+			TRF7970A_CMD_BIT_OPCODE(TRF7970A_CMD_FIFO_RESET);
+	prefix[1] = TRF7970A_CMD_BIT_CTRL |
+			TRF7970A_CMD_BIT_OPCODE(trf->tx_cmd);
+	prefix[2] = TRF7970A_CMD_BIT_CONTINUOUS | TRF7970A_TX_LENGTH_BYTE1;
+
+	if (trf->framing == NFC_DIGITAL_FRAMING_NFCA_SHORT) {
+		prefix[3] = 0x00;
+		prefix[4] = 0x0f; /* 7 bits */
+	} else {
+		prefix[3] = (len & 0xf00) >> 4;
+		prefix[3] |= ((len & 0xf0) >> 4);
+		prefix[4] = ((len & 0x0f) << 4);
+	}
+
+	len = min_t(int, skb->len, TRF7970A_FIFO_SIZE);
+
+	usleep_range(1000, 2000);
+
+	ret = trf7970a_transmit(trf, skb, len);
+	if (ret) {
+		kfree_skb(trf->rx_skb);
+		trf->rx_skb = NULL;
+	}
+
+out_err:
+	mutex_unlock(&trf->lock);
+	return ret;
+}
+
+static int trf7970a_tg_configure_hw(struct nfc_digital_dev *ddev,
+		int type, int param)
+{
+	struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+
+	dev_dbg(trf->dev, "Unsupported interface\n");
+
+	return -EINVAL;
+}
+
+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)
+{
+	struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+
+	dev_dbg(trf->dev, "Unsupported interface\n");
+
+	return -EINVAL;
+}
+
+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");
+
+	return -EINVAL;
+}
+
+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)
+{
+	struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+
+	dev_dbg(trf->dev, "Unsupported interface\n");
+
+	return -EINVAL;
+}
+
+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, "state: %d, on: %d\n", trf->state, on);
+
+	mutex_lock(&trf->lock);
+
+	if (on) {
+		switch (trf->state) {
+		case TRF7970A_ST_OFF:
+			ret = trf7970a_switch_rf_on(trf);
+			break;
+		case TRF7970A_ST_IDLE:
+		case TRF7970A_ST_IDLE_RX_BLOCKED:
+			break;
+		default:
+			dev_err(trf->dev, "%s - Invalid request: %d %d\n",
+					__func__, trf->state, on);
+			trf7970a_switch_rf_off(trf);
+		}
+	} else {
+		switch (trf->state) {
+		case TRF7970A_ST_OFF:
+			break;
+		default:
+			dev_err(trf->dev, "%s - Invalid request: %d %d\n",
+					__func__, trf->state, on);
+			/* FALLTHROUGH */
+		case TRF7970A_ST_IDLE:
+		case TRF7970A_ST_IDLE_RX_BLOCKED:
+			trf7970a_switch_rf_off(trf);
+		}
+	}
+
+	mutex_unlock(&trf->lock);
+	return ret;
+}
+
+static void trf7970a_abort_cmd(struct nfc_digital_dev *ddev)
+{
+	struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+
+	mutex_lock(&trf->lock);
+	_trf7970a_abort_cmd(trf);
+	mutex_unlock(&trf->lock);
+}
+
+static struct nfc_digital_ops trf7970a_nfc_ops = {
+	.in_configure_hw	= trf7970a_in_configure_hw,
+	.in_send_cmd		= trf7970a_in_send_cmd,
+	.tg_configure_hw	= trf7970a_tg_configure_hw,
+	.tg_send_cmd		= trf7970a_tg_send_cmd,
+	.tg_listen		= trf7970a_tg_listen,
+	.tg_listen_mdaa		= trf7970a_tg_listen_mdaa,
+	.switch_rf		= trf7970a_switch_rf,
+	.abort_cmd		= trf7970a_abort_cmd,
+};
+
+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 ret;
+
+	if (!np) {
+		dev_err(&spi->dev, "No Device Tree entry\n");
+		return -EINVAL;
+	}
+
+	trf = devm_kzalloc(&spi->dev, sizeof(*trf), GFP_KERNEL);
+	if (!trf)
+		return -ENOMEM;
+
+	trf->state = TRF7970A_ST_OFF;
+	trf->dev = &spi->dev;
+	trf->spi = spi;
+	trf->quirks = id->driver_data;
+	trf->initialized = false;
+
+	spi->mode = SPI_MODE_1;
+	spi->bits_per_word = 8;
+
+	/* Get the optional Slave Select GPIO used for SPI with SS mode */
+	trf->ss_gpio = of_get_named_gpio(np, "ti,ss-gpio", 0);
+	if (trf->ss_gpio >= 0) {
+		ret = devm_gpio_request_one(trf->dev, trf->ss_gpio,
+				GPIOF_DIR_OUT | GPIOF_INIT_LOW, "SS");
+		if (ret) {
+			dev_err(trf->dev, "Can't request SS GPIO: %d\n", ret);
+			return ret;
+		}
+	} else {
+		dev_info(trf->dev, "Using SPI without SS mode\n");
+	}
+
+	/* There are two enable pins - both must be present */
+	trf->en_gpio = of_get_named_gpio(np, "ti,enable-gpios", 0);
+	if (trf->en_gpio < 0) {
+		dev_err(trf->dev, "No EN GPIO property\n");
+		return ret;
+	}
+
+	ret = devm_gpio_request_one(trf->dev, trf->en_gpio,
+			GPIOF_DIR_OUT | GPIOF_INIT_LOW, "EN");
+	if (ret) {
+		dev_err(trf->dev, "Can't request EN GPIO: %d\n", ret);
+		return ret;
+	}
+
+	trf->en2_gpio = of_get_named_gpio(np, "ti,enable-gpios", 1);
+	if (trf->en2_gpio < 0) {
+		dev_err(trf->dev, "No EN2 GPIO property\n");
+		return ret;
+	}
+
+	ret = devm_gpio_request_one(trf->dev, trf->en2_gpio,
+			GPIOF_DIR_OUT | GPIOF_INIT_LOW, "EN2");
+	if (ret) {
+		dev_err(trf->dev, "Can't request EN2 GPIO: %d\n", ret);
+		return ret;
+	}
+
+	usleep_range(2000, 3000);
+	if (trf->ss_gpio >= 0)
+		gpio_set_value(trf->ss_gpio, 1);
+	usleep_range(3000, 4000);
+
+	ret = devm_request_threaded_irq(trf->dev, spi->irq, NULL,
+			trf7970a_irq, IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+			"trf7970a", trf);
+	if (ret) {
+		dev_err(trf->dev, "Can't request IRQ#%d: %d\n", spi->irq, ret);
+		return ret;
+	}
+
+	trf->ddev = nfc_digital_allocate_device(&trf7970a_nfc_ops,
+			TRF7970A_SUPPORTED_PROTOCOLS,
+			NFC_DIGITAL_DRV_CAPS_IN_CRC, TRF7970A_TX_SKB_HEADROOM,
+			0);
+	if (!trf->ddev) {
+		dev_err(trf->dev, "Can't allocate NFC digital device\n");
+		return -ENOMEM;
+	}
+
+	nfc_digital_set_parent_dev(trf->ddev, trf->dev);
+	nfc_digital_set_drvdata(trf->ddev, trf);
+	spi_set_drvdata(spi, trf);
+
+	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;
+	}
+
+	mutex_init(&trf->lock);
+	INIT_DELAYED_WORK(&trf->timeout_work, trf7970a_timeout_work_handler);
+
+	return 0;
+
+err_free_ddev:
+	nfc_digital_free_device(trf->ddev);
+	return ret;
+}
+
+static int trf7970a_remove(struct spi_device *spi)
+{
+	struct trf7970a *trf = spi_get_drvdata(spi);
+
+	_trf7970a_abort_cmd(trf);
+	trf7970a_switch_rf_off(trf);
+
+	if (trf->ss_gpio >= 0)
+		gpio_set_value(trf->ss_gpio, 0);
+
+	mutex_destroy(&trf->lock);
+
+	nfc_digital_unregister_device(trf->ddev);
+	nfc_digital_free_device(trf->ddev);
+
+	return 0;
+}
+
+static const struct spi_device_id trf7970a_id_table[] = {
+	{ "trf7970a", TRF7970A_QUIRK_IRQ_STATUS_READ_ERRATA },
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, trf7970a_id_table);
+
+static struct spi_driver trf7970a_spi_driver = {
+	.probe		= trf7970a_probe,
+	.remove		= trf7970a_remove,
+	.id_table	= trf7970a_id_table,
+	.driver		= {
+		.name	= "trf7970a",
+		.owner	= THIS_MODULE,
+	},
+};
+
+module_spi_driver(trf7970a_spi_driver);
+
+MODULE_AUTHOR("Mark A. Greer <mgreer-luAo+O/VEmrlveNOaEYElw@public.gmane.org>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("TI trf7970a RFID/NFC Transceiver Driver");
-- 
1.8.3.4

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH 2/3] NFC: trf7970a: Add ISO/IEC 15693 Support
@ 2014-01-31 22:17   ` Mark A. Greer
  0 siblings, 0 replies; 30+ messages in thread
From: Mark A. Greer @ 2014-01-31 22:17 UTC (permalink / raw)
  To: Samuel Ortiz, Lauro Ramos Venancio, Aloisio Almeida Jr
  Cc: Felipe Balbi, Erick Macias, Thierry Escande, linux-wireless,
	linux-nfc, devicetree, Mark A. Greer

Add support for ISO/IEC 15693 RF technology and Type V tags.

CC: Erick Macias <emacias@ti.com>
CC: Felipe Balbi <balbi@ti.com>
Signed-off-by: Mark A. Greer <mgreer@animalcreek.com>
---
 drivers/nfc/trf7970a.c | 155 +++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 151 insertions(+), 4 deletions(-)

diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c
index 7b9cfec..5da1e78 100644
--- a/drivers/nfc/trf7970a.c
+++ b/drivers/nfc/trf7970a.c
@@ -74,9 +74,25 @@
  * Unfortunately, that means that the driver has to peek into tx frames
  * when the framing is 'NFC_DIGITAL_FRAMING_NFCA_T2T'.  This is done by
  * the trf7970a_per_cmd_config() routine.
+ *
+ * ISO/IEC 15693 frames specify whether to use single or double sub-carrier
+ * frequencies and whether to use low or high data rates in the flags byte
+ * of the frame.  This means that the driver has to peek at all 15693 frames
+ * to determine what speed to set the communication to.  In addition, Type V
+ * write and lock commands use the OPTION flag to indicate that an EOF must
+ * be sent to the tag before it will send its response.  So the driver has
+ * to examine all Type V frames for that reason too.
+ *
+ * It is unclear how long to wait before sending the EOF.  According to the
+ * 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
+ * reliably.
  */
 
-#define TRF7970A_SUPPORTED_PROTOCOLS		NFC_PROTO_MIFARE_MASK
+#define TRF7970A_SUPPORTED_PROTOCOLS \
+		(NFC_PROTO_MIFARE_MASK | NFC_PROTO_ISO15693_MASK)
 
 /* 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
@@ -94,6 +110,7 @@
 
 #define TRF7970A_WAIT_FOR_RX_DATA_TIMEOUT	3
 #define TRF7970A_WAIT_FOR_FIFO_DRAIN_TIMEOUT	3
+#define TRF7970A_WAIT_TO_ISSUE_ISO15693_EOF	20
 
 /* Quirks */
 /* Erratum: When reading IRQ Status register on trf7970a, we must issue a
@@ -253,6 +270,36 @@
 /* NFC (ISO/IEC 14443A) Type 2 Tag commands */
 #define NFC_T2T_CMD_READ			0x30
 
+/* ISO 15693 commands codes */
+#define ISO15693_CMD_INVENTORY			0x01
+#define ISO15693_CMD_READ_SINGLE_BLOCK		0x20
+#define ISO15693_CMD_WRITE_SINGLE_BLOCK		0x21
+#define ISO15693_CMD_LOCK_BLOCK			0x22
+#define ISO15693_CMD_READ_MULTIPLE_BLOCK	0x23
+#define ISO15693_CMD_WRITE_MULTIPLE_BLOCK	0x24
+#define ISO15693_CMD_SELECT			0x25
+#define ISO15693_CMD_RESET_TO_READY		0x26
+#define ISO15693_CMD_WRITE_AFI			0x27
+#define ISO15693_CMD_LOCK_AFI			0x28
+#define ISO15693_CMD_WRITE_DSFID		0x29
+#define ISO15693_CMD_LOCK_DSFID			0x2a
+#define ISO15693_CMD_GET_SYSTEM_INFO		0x2b
+#define ISO15693_CMD_GET_MULTIPLE_BLOCK_SECURITY_STATUS	0x2c
+
+/* ISO 15693 request and response flags */
+#define ISO15693_REQ_FLAG_SUB_CARRIER		BIT(0)
+#define ISO15693_REQ_FLAG_DATA_RATE		BIT(1)
+#define ISO15693_REQ_FLAG_INVENTORY		BIT(2)
+#define ISO15693_REQ_FLAG_PROTOCOL_EXT		BIT(3)
+#define ISO15693_REQ_FLAG_SELECT		BIT(4)
+#define ISO15693_REQ_FLAG_AFI			BIT(4)
+#define ISO15693_REQ_FLAG_ADDRESS		BIT(5)
+#define ISO15693_REQ_FLAG_NB_SLOTS		BIT(5)
+#define ISO15693_REQ_FLAG_OPTION		BIT(6)
+
+#define ISO15693_REQ_FLAG_SPEED_MASK \
+		(ISO15693_REQ_FLAG_SUB_CARRIER | ISO15693_REQ_FLAG_DATA_RATE)
+
 enum trf7970a_state {
 	TRF7970A_ST_OFF,
 	TRF7970A_ST_IDLE,
@@ -260,6 +307,7 @@ enum trf7970a_state {
 	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_MAX
 };
 
@@ -279,6 +327,7 @@ struct trf7970a {
 	int				technology;
 	int				framing;
 	u8				tx_cmd;
+	bool				issue_eof;
 	int				ss_gpio;
 	int				en2_gpio;
 	int				en_gpio;
@@ -532,8 +581,13 @@ static int trf7970a_transmit(struct trf7970a *trf, struct sk_buff *skb,
 		trf->state = TRF7970A_ST_WAIT_FOR_TX_FIFO;
 		timeout = TRF7970A_WAIT_FOR_FIFO_DRAIN_TIMEOUT;
 	} else {
-		trf->state = TRF7970A_ST_WAIT_FOR_RX_DATA;
-		timeout = trf->timeout;
+		if (trf->issue_eof) {
+			trf->state = TRF7970A_ST_WAIT_TO_ISSUE_EOF;
+			timeout = TRF7970A_WAIT_TO_ISSUE_ISO15693_EOF;
+		} else {
+			trf->state = TRF7970A_ST_WAIT_FOR_RX_DATA;
+			timeout = trf->timeout;
+		}
 	}
 
 	dev_dbg(trf->dev, "Setting timeout for %d ms, state: %d\n", timeout,
@@ -709,6 +763,10 @@ static irqreturn_t trf7970a_irq(int irq, void *dev_id)
 			trf7970a_abort_and_send_err(trf, -EIO);
 		}
 		break;
+	case TRF7970A_ST_WAIT_TO_ISSUE_EOF:
+		if (status != TRF7970A_IRQ_STATUS_TX)
+			trf7970a_abort_and_send_err(trf, -EIO);
+		break;
 	default:
 		dev_err(trf->dev, "%s - Driver in invalid state: %d\n",
 				__func__, trf->state);
@@ -718,6 +776,29 @@ static irqreturn_t trf7970a_irq(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+static void trf7970a_issue_eof(struct trf7970a *trf)
+{
+	int ret;
+
+	dev_dbg(trf->dev, "Issuing EOF\n");
+
+	ret = trf7970a_cmd(trf, TRF7970A_CMD_FIFO_RESET);
+	if (ret)
+		trf7970a_abort_and_send_err(trf, ret);
+
+	ret = trf7970a_cmd(trf, TRF7970A_CMD_EOF);
+	if (ret)
+		trf7970a_abort_and_send_err(trf, ret);
+
+	trf->state = TRF7970A_ST_WAIT_FOR_RX_DATA;
+
+	dev_dbg(trf->dev, "Setting timeout for %d ms, state: %d\n",
+			trf->timeout, trf->state);
+
+	schedule_delayed_work(&trf->timeout_work,
+			msecs_to_jiffies(trf->timeout));
+}
+
 static void trf7970a_timeout_work_handler(struct work_struct *work)
 {
 	struct trf7970a *trf = container_of(work, struct trf7970a,
@@ -732,6 +813,8 @@ static void trf7970a_timeout_work_handler(struct work_struct *work)
 		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 */
+	else if (trf->state == TRF7970A_ST_WAIT_TO_ISSUE_EOF)
+		trf7970a_issue_eof(trf);
 	else
 		trf7970a_abort_and_send_err(trf, -ETIMEDOUT);
 
@@ -750,6 +833,9 @@ static int trf7970a_config_rf_tech(struct trf7970a *trf, int tech)
 	case NFC_DIGITAL_RF_TECH_106A:
 		trf->iso_ctrl = TRF7970A_ISO_CTRL_14443A_106;
 		break;
+	case NFC_DIGITAL_RF_TECH_ISO15693:
+		trf->iso_ctrl = TRF7970A_ISO_CTRL_15693_SGL_1OF4_2648;
+		break;
 	default:
 		dev_dbg(trf->dev, "Unsupported rf technology: %d\n", tech);
 		return -EINVAL;
@@ -771,6 +857,8 @@ static int trf7970a_config_framing(struct trf7970a *trf, int framing)
 		trf->iso_ctrl |= TRF7970A_ISO_CTRL_RX_CRC_N;
 		break;
 	case NFC_DIGITAL_FRAMING_NFCA_STANDARD_WITH_CRC_A:
+	case NFC_DIGITAL_FRAMING_ISO15693_INVENTORY:
+	case NFC_DIGITAL_FRAMING_ISO15693_TVT:
 		trf->tx_cmd = TRF7970A_CMD_TRANSMIT;
 		trf->iso_ctrl &= ~TRF7970A_ISO_CTRL_RX_CRC_N;
 		break;
@@ -821,15 +909,43 @@ err_out:
 	return ret;
 }
 
+static int trf7970a_is_iso15693_write_or_lock(u8 cmd)
+{
+	int ret;
+
+	switch (cmd) {
+	case ISO15693_CMD_WRITE_SINGLE_BLOCK:
+	case ISO15693_CMD_LOCK_BLOCK:
+	case ISO15693_CMD_WRITE_MULTIPLE_BLOCK:
+	case ISO15693_CMD_WRITE_AFI:
+	case ISO15693_CMD_LOCK_AFI:
+	case ISO15693_CMD_WRITE_DSFID:
+	case ISO15693_CMD_LOCK_DSFID:
+		ret = 1;
+		break;
+	default:
+		ret = 0;
+	}
+
+	return ret;
+}
+
 static int trf7970a_per_cmd_config(struct trf7970a *trf, struct sk_buff *skb)
 {
 	u8 *req = skb->data;
-	u8 special_fcn_reg1;
+	u8 special_fcn_reg1, iso_ctrl;
 	int ret;
 
+	trf->issue_eof = false;
+
 	/* When issuing Type 2 read command, make sure the '4_bit_RX' bit in
 	 * special functions register 1 is cleared; otherwise, its a write or
 	 * sector select command and '4_bit_RX' must be set.
+	 *
+	 * When issuing an ISO 15693 command, inspect the flags byte to see
+	 * what speed to use.  Also, remember when the OPTION flag is set on
+	 * a Type V write or lock command so the driver will know that it
+	 * has to send an EOF in order to get a response.
 	 */
 	if ((trf->technology == NFC_DIGITAL_RF_TECH_106A) &&
 			(trf->framing == NFC_DIGITAL_FRAMING_NFCA_T2T)) {
@@ -846,6 +962,37 @@ static int trf7970a_per_cmd_config(struct trf7970a *trf, struct sk_buff *skb)
 
 			trf->special_fcn_reg1 = special_fcn_reg1;
 		}
+	} else if (trf->technology == NFC_DIGITAL_RF_TECH_ISO15693) {
+		iso_ctrl = trf->iso_ctrl & ~TRF7970A_ISO_CTRL_RFID_SPEED_MASK;
+
+		switch (req[0] & ISO15693_REQ_FLAG_SPEED_MASK) {
+		case 0x00:
+			iso_ctrl |= TRF7970A_ISO_CTRL_15693_SGL_1OF4_662;
+			break;
+		case ISO15693_REQ_FLAG_SUB_CARRIER:
+			iso_ctrl |= TRF7970A_ISO_CTRL_15693_DBL_1OF4_667a;
+			break;
+		case ISO15693_REQ_FLAG_DATA_RATE:
+			iso_ctrl |= TRF7970A_ISO_CTRL_15693_SGL_1OF4_2648;
+			break;
+		case (ISO15693_REQ_FLAG_SUB_CARRIER |
+				ISO15693_REQ_FLAG_DATA_RATE):
+			iso_ctrl |= TRF7970A_ISO_CTRL_15693_DBL_1OF4_2669;
+			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;
+		}
+
+		if ((trf->framing == NFC_DIGITAL_FRAMING_ISO15693_TVT) &&
+				trf7970a_is_iso15693_write_or_lock(req[1]) &&
+				(req[0] & ISO15693_REQ_FLAG_OPTION))
+			trf->issue_eof = true;
 	}
 
 	return 0;
-- 
1.8.3.4


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH 2/3] NFC: trf7970a: Add ISO/IEC 15693 Support
@ 2014-01-31 22:17   ` Mark A. Greer
  0 siblings, 0 replies; 30+ messages in thread
From: Mark A. Greer @ 2014-01-31 22:17 UTC (permalink / raw)
  To: Samuel Ortiz, Lauro Ramos Venancio, Aloisio Almeida Jr
  Cc: Felipe Balbi, Erick Macias, Thierry Escande,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	linux-nfc-hn68Rpc1hR1g9hUCZPvPmw,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Mark A. Greer

Add support for ISO/IEC 15693 RF technology and Type V tags.

CC: Erick Macias <emacias-l0cyMroinI0@public.gmane.org>
CC: Felipe Balbi <balbi-l0cyMroinI0@public.gmane.org>
Signed-off-by: Mark A. Greer <mgreer-luAo+O/VEmrlveNOaEYElw@public.gmane.org>
---
 drivers/nfc/trf7970a.c | 155 +++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 151 insertions(+), 4 deletions(-)

diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c
index 7b9cfec..5da1e78 100644
--- a/drivers/nfc/trf7970a.c
+++ b/drivers/nfc/trf7970a.c
@@ -74,9 +74,25 @@
  * Unfortunately, that means that the driver has to peek into tx frames
  * when the framing is 'NFC_DIGITAL_FRAMING_NFCA_T2T'.  This is done by
  * the trf7970a_per_cmd_config() routine.
+ *
+ * ISO/IEC 15693 frames specify whether to use single or double sub-carrier
+ * frequencies and whether to use low or high data rates in the flags byte
+ * of the frame.  This means that the driver has to peek at all 15693 frames
+ * to determine what speed to set the communication to.  In addition, Type V
+ * write and lock commands use the OPTION flag to indicate that an EOF must
+ * be sent to the tag before it will send its response.  So the driver has
+ * to examine all Type V frames for that reason too.
+ *
+ * It is unclear how long to wait before sending the EOF.  According to the
+ * 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
+ * reliably.
  */
 
-#define TRF7970A_SUPPORTED_PROTOCOLS		NFC_PROTO_MIFARE_MASK
+#define TRF7970A_SUPPORTED_PROTOCOLS \
+		(NFC_PROTO_MIFARE_MASK | NFC_PROTO_ISO15693_MASK)
 
 /* 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
@@ -94,6 +110,7 @@
 
 #define TRF7970A_WAIT_FOR_RX_DATA_TIMEOUT	3
 #define TRF7970A_WAIT_FOR_FIFO_DRAIN_TIMEOUT	3
+#define TRF7970A_WAIT_TO_ISSUE_ISO15693_EOF	20
 
 /* Quirks */
 /* Erratum: When reading IRQ Status register on trf7970a, we must issue a
@@ -253,6 +270,36 @@
 /* NFC (ISO/IEC 14443A) Type 2 Tag commands */
 #define NFC_T2T_CMD_READ			0x30
 
+/* ISO 15693 commands codes */
+#define ISO15693_CMD_INVENTORY			0x01
+#define ISO15693_CMD_READ_SINGLE_BLOCK		0x20
+#define ISO15693_CMD_WRITE_SINGLE_BLOCK		0x21
+#define ISO15693_CMD_LOCK_BLOCK			0x22
+#define ISO15693_CMD_READ_MULTIPLE_BLOCK	0x23
+#define ISO15693_CMD_WRITE_MULTIPLE_BLOCK	0x24
+#define ISO15693_CMD_SELECT			0x25
+#define ISO15693_CMD_RESET_TO_READY		0x26
+#define ISO15693_CMD_WRITE_AFI			0x27
+#define ISO15693_CMD_LOCK_AFI			0x28
+#define ISO15693_CMD_WRITE_DSFID		0x29
+#define ISO15693_CMD_LOCK_DSFID			0x2a
+#define ISO15693_CMD_GET_SYSTEM_INFO		0x2b
+#define ISO15693_CMD_GET_MULTIPLE_BLOCK_SECURITY_STATUS	0x2c
+
+/* ISO 15693 request and response flags */
+#define ISO15693_REQ_FLAG_SUB_CARRIER		BIT(0)
+#define ISO15693_REQ_FLAG_DATA_RATE		BIT(1)
+#define ISO15693_REQ_FLAG_INVENTORY		BIT(2)
+#define ISO15693_REQ_FLAG_PROTOCOL_EXT		BIT(3)
+#define ISO15693_REQ_FLAG_SELECT		BIT(4)
+#define ISO15693_REQ_FLAG_AFI			BIT(4)
+#define ISO15693_REQ_FLAG_ADDRESS		BIT(5)
+#define ISO15693_REQ_FLAG_NB_SLOTS		BIT(5)
+#define ISO15693_REQ_FLAG_OPTION		BIT(6)
+
+#define ISO15693_REQ_FLAG_SPEED_MASK \
+		(ISO15693_REQ_FLAG_SUB_CARRIER | ISO15693_REQ_FLAG_DATA_RATE)
+
 enum trf7970a_state {
 	TRF7970A_ST_OFF,
 	TRF7970A_ST_IDLE,
@@ -260,6 +307,7 @@ enum trf7970a_state {
 	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_MAX
 };
 
@@ -279,6 +327,7 @@ struct trf7970a {
 	int				technology;
 	int				framing;
 	u8				tx_cmd;
+	bool				issue_eof;
 	int				ss_gpio;
 	int				en2_gpio;
 	int				en_gpio;
@@ -532,8 +581,13 @@ static int trf7970a_transmit(struct trf7970a *trf, struct sk_buff *skb,
 		trf->state = TRF7970A_ST_WAIT_FOR_TX_FIFO;
 		timeout = TRF7970A_WAIT_FOR_FIFO_DRAIN_TIMEOUT;
 	} else {
-		trf->state = TRF7970A_ST_WAIT_FOR_RX_DATA;
-		timeout = trf->timeout;
+		if (trf->issue_eof) {
+			trf->state = TRF7970A_ST_WAIT_TO_ISSUE_EOF;
+			timeout = TRF7970A_WAIT_TO_ISSUE_ISO15693_EOF;
+		} else {
+			trf->state = TRF7970A_ST_WAIT_FOR_RX_DATA;
+			timeout = trf->timeout;
+		}
 	}
 
 	dev_dbg(trf->dev, "Setting timeout for %d ms, state: %d\n", timeout,
@@ -709,6 +763,10 @@ static irqreturn_t trf7970a_irq(int irq, void *dev_id)
 			trf7970a_abort_and_send_err(trf, -EIO);
 		}
 		break;
+	case TRF7970A_ST_WAIT_TO_ISSUE_EOF:
+		if (status != TRF7970A_IRQ_STATUS_TX)
+			trf7970a_abort_and_send_err(trf, -EIO);
+		break;
 	default:
 		dev_err(trf->dev, "%s - Driver in invalid state: %d\n",
 				__func__, trf->state);
@@ -718,6 +776,29 @@ static irqreturn_t trf7970a_irq(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+static void trf7970a_issue_eof(struct trf7970a *trf)
+{
+	int ret;
+
+	dev_dbg(trf->dev, "Issuing EOF\n");
+
+	ret = trf7970a_cmd(trf, TRF7970A_CMD_FIFO_RESET);
+	if (ret)
+		trf7970a_abort_and_send_err(trf, ret);
+
+	ret = trf7970a_cmd(trf, TRF7970A_CMD_EOF);
+	if (ret)
+		trf7970a_abort_and_send_err(trf, ret);
+
+	trf->state = TRF7970A_ST_WAIT_FOR_RX_DATA;
+
+	dev_dbg(trf->dev, "Setting timeout for %d ms, state: %d\n",
+			trf->timeout, trf->state);
+
+	schedule_delayed_work(&trf->timeout_work,
+			msecs_to_jiffies(trf->timeout));
+}
+
 static void trf7970a_timeout_work_handler(struct work_struct *work)
 {
 	struct trf7970a *trf = container_of(work, struct trf7970a,
@@ -732,6 +813,8 @@ static void trf7970a_timeout_work_handler(struct work_struct *work)
 		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 */
+	else if (trf->state == TRF7970A_ST_WAIT_TO_ISSUE_EOF)
+		trf7970a_issue_eof(trf);
 	else
 		trf7970a_abort_and_send_err(trf, -ETIMEDOUT);
 
@@ -750,6 +833,9 @@ static int trf7970a_config_rf_tech(struct trf7970a *trf, int tech)
 	case NFC_DIGITAL_RF_TECH_106A:
 		trf->iso_ctrl = TRF7970A_ISO_CTRL_14443A_106;
 		break;
+	case NFC_DIGITAL_RF_TECH_ISO15693:
+		trf->iso_ctrl = TRF7970A_ISO_CTRL_15693_SGL_1OF4_2648;
+		break;
 	default:
 		dev_dbg(trf->dev, "Unsupported rf technology: %d\n", tech);
 		return -EINVAL;
@@ -771,6 +857,8 @@ static int trf7970a_config_framing(struct trf7970a *trf, int framing)
 		trf->iso_ctrl |= TRF7970A_ISO_CTRL_RX_CRC_N;
 		break;
 	case NFC_DIGITAL_FRAMING_NFCA_STANDARD_WITH_CRC_A:
+	case NFC_DIGITAL_FRAMING_ISO15693_INVENTORY:
+	case NFC_DIGITAL_FRAMING_ISO15693_TVT:
 		trf->tx_cmd = TRF7970A_CMD_TRANSMIT;
 		trf->iso_ctrl &= ~TRF7970A_ISO_CTRL_RX_CRC_N;
 		break;
@@ -821,15 +909,43 @@ err_out:
 	return ret;
 }
 
+static int trf7970a_is_iso15693_write_or_lock(u8 cmd)
+{
+	int ret;
+
+	switch (cmd) {
+	case ISO15693_CMD_WRITE_SINGLE_BLOCK:
+	case ISO15693_CMD_LOCK_BLOCK:
+	case ISO15693_CMD_WRITE_MULTIPLE_BLOCK:
+	case ISO15693_CMD_WRITE_AFI:
+	case ISO15693_CMD_LOCK_AFI:
+	case ISO15693_CMD_WRITE_DSFID:
+	case ISO15693_CMD_LOCK_DSFID:
+		ret = 1;
+		break;
+	default:
+		ret = 0;
+	}
+
+	return ret;
+}
+
 static int trf7970a_per_cmd_config(struct trf7970a *trf, struct sk_buff *skb)
 {
 	u8 *req = skb->data;
-	u8 special_fcn_reg1;
+	u8 special_fcn_reg1, iso_ctrl;
 	int ret;
 
+	trf->issue_eof = false;
+
 	/* When issuing Type 2 read command, make sure the '4_bit_RX' bit in
 	 * special functions register 1 is cleared; otherwise, its a write or
 	 * sector select command and '4_bit_RX' must be set.
+	 *
+	 * When issuing an ISO 15693 command, inspect the flags byte to see
+	 * what speed to use.  Also, remember when the OPTION flag is set on
+	 * a Type V write or lock command so the driver will know that it
+	 * has to send an EOF in order to get a response.
 	 */
 	if ((trf->technology == NFC_DIGITAL_RF_TECH_106A) &&
 			(trf->framing == NFC_DIGITAL_FRAMING_NFCA_T2T)) {
@@ -846,6 +962,37 @@ static int trf7970a_per_cmd_config(struct trf7970a *trf, struct sk_buff *skb)
 
 			trf->special_fcn_reg1 = special_fcn_reg1;
 		}
+	} else if (trf->technology == NFC_DIGITAL_RF_TECH_ISO15693) {
+		iso_ctrl = trf->iso_ctrl & ~TRF7970A_ISO_CTRL_RFID_SPEED_MASK;
+
+		switch (req[0] & ISO15693_REQ_FLAG_SPEED_MASK) {
+		case 0x00:
+			iso_ctrl |= TRF7970A_ISO_CTRL_15693_SGL_1OF4_662;
+			break;
+		case ISO15693_REQ_FLAG_SUB_CARRIER:
+			iso_ctrl |= TRF7970A_ISO_CTRL_15693_DBL_1OF4_667a;
+			break;
+		case ISO15693_REQ_FLAG_DATA_RATE:
+			iso_ctrl |= TRF7970A_ISO_CTRL_15693_SGL_1OF4_2648;
+			break;
+		case (ISO15693_REQ_FLAG_SUB_CARRIER |
+				ISO15693_REQ_FLAG_DATA_RATE):
+			iso_ctrl |= TRF7970A_ISO_CTRL_15693_DBL_1OF4_2669;
+			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;
+		}
+
+		if ((trf->framing == NFC_DIGITAL_FRAMING_ISO15693_TVT) &&
+				trf7970a_is_iso15693_write_or_lock(req[1]) &&
+				(req[0] & ISO15693_REQ_FLAG_OPTION))
+			trf->issue_eof = true;
 	}
 
 	return 0;
-- 
1.8.3.4

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH 3/3] NFC: trf7970a: Add DTS Documentation
@ 2014-01-31 22:17   ` Mark A. Greer
  0 siblings, 0 replies; 30+ messages in thread
From: Mark A. Greer @ 2014-01-31 22:17 UTC (permalink / raw)
  To: Samuel Ortiz, Lauro Ramos Venancio, Aloisio Almeida Jr
  Cc: Felipe Balbi, Erick Macias, Thierry Escande, linux-wireless,
	linux-nfc, devicetree, Mark A. Greer

Describe the properies used by the trf7970a
RFID/NFC/15693 transceiver driver.

Signed-off-by: Mark A. Greer <mgreer@animalcreek.com>
---
 .../devicetree/bindings/net/nfc/trf7970a.txt       | 37 ++++++++++++++++++++++
 1 file changed, 37 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/nfc/trf7970a.txt

diff --git a/Documentation/devicetree/bindings/net/nfc/trf7970a.txt b/Documentation/devicetree/bindings/net/nfc/trf7970a.txt
new file mode 100644
index 0000000..4256893
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/nfc/trf7970a.txt
@@ -0,0 +1,37 @@
+* Texas Instruments TRF7970A RFID/NFC/15693 Transceiver
+
+Required properties:
+- compatible: Should be "ti,trf7970a".
+- spi-max-frequency: Maximum SPI frequency (<= 2000000).
+- interrupt-parent: phandle of parent interrupt handler.
+- interrupts: A single interrupt specifier.
+- ti,enable-gpios: Two GPIO entries used for 'EN' and 'EN2' pins on the
+  TRF7970A.
+
+Optional properties:
+- ti,ss-gpio: GPIO used for Slave Select pin on TRF7970A.  Its presence
+  indicates that "SPI with SS mode" is used by the TRF7970A.
+
+Optional SoC Specific Properties:
+- pinctrl-names: Contains only one value - "default".
+- pintctrl-0: Specifies the pin control groups used for this controller.
+
+Example (for ARM-based BeagleBone with TRF7970A on SPI1):
+
+&spi1 {
+        status = "okay";
+
+        nfc@0 {
+                compatible = "ti,trf7970a";
+                reg = <0>;
+                pinctrl-names = "default";
+                pinctrl-0 = <&trf7970a_default>;
+                spi-max-frequency = <2000000>;
+                interrupt-parent = <&gpio2>;
+                interrupts = <14 0>;
+                ti,enable-gpios = <&gpio2 2 GPIO_ACTIVE_LOW>,
+                                <&gpio2 5 GPIO_ACTIVE_LOW>;
+                ti,ss-gpio = <&gpio1 30 GPIO_ACTIVE_LOW>;
+                status = "okay";
+        };
+};
-- 
1.8.3.4


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH 3/3] NFC: trf7970a: Add DTS Documentation
@ 2014-01-31 22:17   ` Mark A. Greer
  0 siblings, 0 replies; 30+ messages in thread
From: Mark A. Greer @ 2014-01-31 22:17 UTC (permalink / raw)
  To: Samuel Ortiz, Lauro Ramos Venancio, Aloisio Almeida Jr
  Cc: Felipe Balbi, Erick Macias, Thierry Escande,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	linux-nfc-hn68Rpc1hR1g9hUCZPvPmw,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Mark A. Greer

Describe the properies used by the trf7970a
RFID/NFC/15693 transceiver driver.

Signed-off-by: Mark A. Greer <mgreer-luAo+O/VEmrlveNOaEYElw@public.gmane.org>
---
 .../devicetree/bindings/net/nfc/trf7970a.txt       | 37 ++++++++++++++++++++++
 1 file changed, 37 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/nfc/trf7970a.txt

diff --git a/Documentation/devicetree/bindings/net/nfc/trf7970a.txt b/Documentation/devicetree/bindings/net/nfc/trf7970a.txt
new file mode 100644
index 0000000..4256893
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/nfc/trf7970a.txt
@@ -0,0 +1,37 @@
+* Texas Instruments TRF7970A RFID/NFC/15693 Transceiver
+
+Required properties:
+- compatible: Should be "ti,trf7970a".
+- spi-max-frequency: Maximum SPI frequency (<= 2000000).
+- interrupt-parent: phandle of parent interrupt handler.
+- interrupts: A single interrupt specifier.
+- ti,enable-gpios: Two GPIO entries used for 'EN' and 'EN2' pins on the
+  TRF7970A.
+
+Optional properties:
+- ti,ss-gpio: GPIO used for Slave Select pin on TRF7970A.  Its presence
+  indicates that "SPI with SS mode" is used by the TRF7970A.
+
+Optional SoC Specific Properties:
+- pinctrl-names: Contains only one value - "default".
+- pintctrl-0: Specifies the pin control groups used for this controller.
+
+Example (for ARM-based BeagleBone with TRF7970A on SPI1):
+
+&spi1 {
+        status = "okay";
+
+        nfc@0 {
+                compatible = "ti,trf7970a";
+                reg = <0>;
+                pinctrl-names = "default";
+                pinctrl-0 = <&trf7970a_default>;
+                spi-max-frequency = <2000000>;
+                interrupt-parent = <&gpio2>;
+                interrupts = <14 0>;
+                ti,enable-gpios = <&gpio2 2 GPIO_ACTIVE_LOW>,
+                                <&gpio2 5 GPIO_ACTIVE_LOW>;
+                ti,ss-gpio = <&gpio1 30 GPIO_ACTIVE_LOW>;
+                status = "okay";
+        };
+};
-- 
1.8.3.4

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* Re: [PATCH 1/3] NFC: trf7970a: Add driver with ISO/IEC 14443 Type 2 Tag Support
@ 2014-02-21  0:50     ` Samuel Ortiz
  0 siblings, 0 replies; 30+ messages in thread
From: Samuel Ortiz @ 2014-02-21  0:50 UTC (permalink / raw)
  To: Mark A. Greer
  Cc: Lauro Ramos Venancio, Aloisio Almeida Jr, Felipe Balbi,
	Erick Macias, Thierry Escande, linux-wireless, linux-nfc,
	devicetree

Hi Mark,

Code looks quite nice, especially since this looks like a fairly complex
driver. And the initial coments are quite useful, I appreciate that.
I have a few comments/questions though:


> + * been received and there isn't an error).  The delay is 3 ms since delays
> + * over 2 ms have been observed during testing.
Would you say this timeout depend on the SPI bus bandwidth ?


> +#define TRF7970A_QUIRK_IRQ_STATUS_READ_ERRATA	BIT(0)
Are there actually any TRF970 devices that do not need this quirk ?


> +static void trf7970a_drain_fifo(struct trf7970a *trf, u8 status)
> +{
> +	struct sk_buff *skb = trf->rx_skb;
> +	int ret;
> +	u8 fifo_bytes;
> +
> +	if (status & TRF7970A_IRQ_STATUS_ERROR) {
> +		trf7970a_abort_and_send_err(trf, -EIO);
> +		return;
> +	}
> +
> +	ret = trf7970a_read(trf, TRF7970A_FIFO_STATUS, &fifo_bytes);
> +	if (ret) {
> +		trf7970a_abort_and_send_err(trf, ret);
> +		return;
> +	}
> +
> +	dev_dbg(trf->dev, "fifo_bytes: 0x%x\n", fifo_bytes);
> +
> +	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_abort_and_send_err(trf, -EIO);
> +		return;
> +	}
> +
> +	if (fifo_bytes > skb_tailroom(skb)) {
> +		skb = skb_copy_expand(skb, skb_headroom(skb),
> +				max_t(int, fifo_bytes,
> +					TRF7970A_RX_SKB_ALLOC_SIZE),
> +				GFP_KERNEL);
So there could be more pending bytes in the FIFO than you can accomodate
in your rx_skb ? Could we avoid that by allocating rx_skb to match the
FIFO size ?


> +static void trf7970a_timeout_work_handler(struct work_struct *work)
> +{
> +	struct trf7970a *trf = container_of(work, struct trf7970a,
> +			timeout_work.work);
> +
> +	dev_dbg(trf->dev, "TIMEOUT - state: %d, ignore_timeout: %d\n",
> +			trf->state, trf->ignore_timeout);
> +
> +	mutex_lock(&trf->lock);
> +
> +	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 */
> +	else
> +		trf7970a_abort_and_send_err(trf, -ETIMEDOUT);
> +
> +	mutex_unlock(&trf->lock);
> +}
> +
> +/* ----------------------------------------------------------------- */
Nitpick: I suppose you're separating the internal logic from the digital
ops here ? Please add one comment line for that.


> +static int trf7970a_in_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;
> +	unsigned int len;
> +	int ret;
> +
> +	dev_dbg(trf->dev, "New request - state: %d, timeout: %d ms, len: %d\n",
> +			trf->state, timeout, skb->len);
> +
> +	if (skb->len > TRF7970A_TX_MAX)
> +		return -EINVAL;
> +
> +	mutex_lock(&trf->lock);
> +
> +	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;
> +	}
> +
> +	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) {
> +		ret = trf7970a_cmd(trf, TRF7970A_CMD_ENABLE_RX);
> +		if (ret)
> +			goto out_err;
> +
> +		trf->state = TRF7970A_ST_IDLE;
> +	}
> +
> +	ret = trf7970a_per_cmd_config(trf, skb);
> +	if (ret)
> +		goto out_err;
> +
> +	trf->ddev = ddev;
> +	trf->tx_skb = skb;
As you're going to carry this guy around and may need it from e.g. your
threaded interrupt handler, shouldn't you take a reference (skb_get) on it ?
I'm concerned by the fact that you could see your tx_skb disappear from
abort_cmd and get an IRQ before your state is set to IDLE.
Hmm, I guess that's protected by the mutex and so when you get an abort
from the digital stack you reset the state to IDLE and no one should try
to touch tx_skb after you release the mutex. Is that what you had in
mind ?


> +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 ret;
> +
> +	if (!np) {
> +		dev_err(&spi->dev, "No Device Tree entry\n");
> +		return -EINVAL;
> +	}
> +
> +	trf = devm_kzalloc(&spi->dev, sizeof(*trf), GFP_KERNEL);
> +	if (!trf)
> +		return -ENOMEM;
> +
> +	trf->state = TRF7970A_ST_OFF;
> +	trf->dev = &spi->dev;
> +	trf->spi = spi;
> +	trf->quirks = id->driver_data;
> +	trf->initialized = false;
> +
> +	spi->mode = SPI_MODE_1;
> +	spi->bits_per_word = 8;
> +
> +	/* Get the optional Slave Select GPIO used for SPI with SS mode */
> +	trf->ss_gpio = of_get_named_gpio(np, "ti,ss-gpio", 0);
> +	if (trf->ss_gpio >= 0) {
> +		ret = devm_gpio_request_one(trf->dev, trf->ss_gpio,
> +				GPIOF_DIR_OUT | GPIOF_INIT_LOW, "SS");
> +		if (ret) {
> +			dev_err(trf->dev, "Can't request SS GPIO: %d\n", ret);
> +			return ret;
> +		}
> +	} else {
> +		dev_info(trf->dev, "Using SPI without SS mode\n");
> +	}
> +
> +	/* There are two enable pins - both must be present */
> +	trf->en_gpio = of_get_named_gpio(np, "ti,enable-gpios", 0);
> +	if (trf->en_gpio < 0) {
> +		dev_err(trf->dev, "No EN GPIO property\n");
> +		return ret;
You probably want to return trf->en_gpio or otherwise the devm code
won't release your managed resources.


> +	}
> +
> +	ret = devm_gpio_request_one(trf->dev, trf->en_gpio,
> +			GPIOF_DIR_OUT | GPIOF_INIT_LOW, "EN");
> +	if (ret) {
> +		dev_err(trf->dev, "Can't request EN GPIO: %d\n", ret);
> +		return ret;
> +	}
> +
> +	trf->en2_gpio = of_get_named_gpio(np, "ti,enable-gpios", 1);
> +	if (trf->en2_gpio < 0) {
> +		dev_err(trf->dev, "No EN2 GPIO property\n");
> +		return ret;
Ditto.

Cheers,
Samuel.

-- 
Intel Open Source Technology Centre
http://oss.intel.com/

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 1/3] NFC: trf7970a: Add driver with ISO/IEC 14443 Type 2 Tag Support
@ 2014-02-21  0:50     ` Samuel Ortiz
  0 siblings, 0 replies; 30+ messages in thread
From: Samuel Ortiz @ 2014-02-21  0:50 UTC (permalink / raw)
  To: Mark A. Greer
  Cc: Lauro Ramos Venancio, Aloisio Almeida Jr, Felipe Balbi,
	Erick Macias, Thierry Escande,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	linux-nfc-hn68Rpc1hR1g9hUCZPvPmw,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Hi Mark,

Code looks quite nice, especially since this looks like a fairly complex
driver. And the initial coments are quite useful, I appreciate that.
I have a few comments/questions though:


> + * been received and there isn't an error).  The delay is 3 ms since delays
> + * over 2 ms have been observed during testing.
Would you say this timeout depend on the SPI bus bandwidth ?


> +#define TRF7970A_QUIRK_IRQ_STATUS_READ_ERRATA	BIT(0)
Are there actually any TRF970 devices that do not need this quirk ?


> +static void trf7970a_drain_fifo(struct trf7970a *trf, u8 status)
> +{
> +	struct sk_buff *skb = trf->rx_skb;
> +	int ret;
> +	u8 fifo_bytes;
> +
> +	if (status & TRF7970A_IRQ_STATUS_ERROR) {
> +		trf7970a_abort_and_send_err(trf, -EIO);
> +		return;
> +	}
> +
> +	ret = trf7970a_read(trf, TRF7970A_FIFO_STATUS, &fifo_bytes);
> +	if (ret) {
> +		trf7970a_abort_and_send_err(trf, ret);
> +		return;
> +	}
> +
> +	dev_dbg(trf->dev, "fifo_bytes: 0x%x\n", fifo_bytes);
> +
> +	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_abort_and_send_err(trf, -EIO);
> +		return;
> +	}
> +
> +	if (fifo_bytes > skb_tailroom(skb)) {
> +		skb = skb_copy_expand(skb, skb_headroom(skb),
> +				max_t(int, fifo_bytes,
> +					TRF7970A_RX_SKB_ALLOC_SIZE),
> +				GFP_KERNEL);
So there could be more pending bytes in the FIFO than you can accomodate
in your rx_skb ? Could we avoid that by allocating rx_skb to match the
FIFO size ?


> +static void trf7970a_timeout_work_handler(struct work_struct *work)
> +{
> +	struct trf7970a *trf = container_of(work, struct trf7970a,
> +			timeout_work.work);
> +
> +	dev_dbg(trf->dev, "TIMEOUT - state: %d, ignore_timeout: %d\n",
> +			trf->state, trf->ignore_timeout);
> +
> +	mutex_lock(&trf->lock);
> +
> +	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 */
> +	else
> +		trf7970a_abort_and_send_err(trf, -ETIMEDOUT);
> +
> +	mutex_unlock(&trf->lock);
> +}
> +
> +/* ----------------------------------------------------------------- */
Nitpick: I suppose you're separating the internal logic from the digital
ops here ? Please add one comment line for that.


> +static int trf7970a_in_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;
> +	unsigned int len;
> +	int ret;
> +
> +	dev_dbg(trf->dev, "New request - state: %d, timeout: %d ms, len: %d\n",
> +			trf->state, timeout, skb->len);
> +
> +	if (skb->len > TRF7970A_TX_MAX)
> +		return -EINVAL;
> +
> +	mutex_lock(&trf->lock);
> +
> +	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;
> +	}
> +
> +	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) {
> +		ret = trf7970a_cmd(trf, TRF7970A_CMD_ENABLE_RX);
> +		if (ret)
> +			goto out_err;
> +
> +		trf->state = TRF7970A_ST_IDLE;
> +	}
> +
> +	ret = trf7970a_per_cmd_config(trf, skb);
> +	if (ret)
> +		goto out_err;
> +
> +	trf->ddev = ddev;
> +	trf->tx_skb = skb;
As you're going to carry this guy around and may need it from e.g. your
threaded interrupt handler, shouldn't you take a reference (skb_get) on it ?
I'm concerned by the fact that you could see your tx_skb disappear from
abort_cmd and get an IRQ before your state is set to IDLE.
Hmm, I guess that's protected by the mutex and so when you get an abort
from the digital stack you reset the state to IDLE and no one should try
to touch tx_skb after you release the mutex. Is that what you had in
mind ?


> +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 ret;
> +
> +	if (!np) {
> +		dev_err(&spi->dev, "No Device Tree entry\n");
> +		return -EINVAL;
> +	}
> +
> +	trf = devm_kzalloc(&spi->dev, sizeof(*trf), GFP_KERNEL);
> +	if (!trf)
> +		return -ENOMEM;
> +
> +	trf->state = TRF7970A_ST_OFF;
> +	trf->dev = &spi->dev;
> +	trf->spi = spi;
> +	trf->quirks = id->driver_data;
> +	trf->initialized = false;
> +
> +	spi->mode = SPI_MODE_1;
> +	spi->bits_per_word = 8;
> +
> +	/* Get the optional Slave Select GPIO used for SPI with SS mode */
> +	trf->ss_gpio = of_get_named_gpio(np, "ti,ss-gpio", 0);
> +	if (trf->ss_gpio >= 0) {
> +		ret = devm_gpio_request_one(trf->dev, trf->ss_gpio,
> +				GPIOF_DIR_OUT | GPIOF_INIT_LOW, "SS");
> +		if (ret) {
> +			dev_err(trf->dev, "Can't request SS GPIO: %d\n", ret);
> +			return ret;
> +		}
> +	} else {
> +		dev_info(trf->dev, "Using SPI without SS mode\n");
> +	}
> +
> +	/* There are two enable pins - both must be present */
> +	trf->en_gpio = of_get_named_gpio(np, "ti,enable-gpios", 0);
> +	if (trf->en_gpio < 0) {
> +		dev_err(trf->dev, "No EN GPIO property\n");
> +		return ret;
You probably want to return trf->en_gpio or otherwise the devm code
won't release your managed resources.


> +	}
> +
> +	ret = devm_gpio_request_one(trf->dev, trf->en_gpio,
> +			GPIOF_DIR_OUT | GPIOF_INIT_LOW, "EN");
> +	if (ret) {
> +		dev_err(trf->dev, "Can't request EN GPIO: %d\n", ret);
> +		return ret;
> +	}
> +
> +	trf->en2_gpio = of_get_named_gpio(np, "ti,enable-gpios", 1);
> +	if (trf->en2_gpio < 0) {
> +		dev_err(trf->dev, "No EN2 GPIO property\n");
> +		return ret;
Ditto.

Cheers,
Samuel.

-- 
Intel Open Source Technology Centre
http://oss.intel.com/
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 2/3] NFC: trf7970a: Add ISO/IEC 15693 Support
@ 2014-02-21  1:00     ` Samuel Ortiz
  0 siblings, 0 replies; 30+ messages in thread
From: Samuel Ortiz @ 2014-02-21  1:00 UTC (permalink / raw)
  To: Mark A. Greer
  Cc: Lauro Ramos Venancio, Aloisio Almeida Jr, Felipe Balbi,
	Erick Macias, Thierry Escande, linux-wireless, linux-nfc,
	devicetree

Hi Mark,

Just one nitpick here:

> +static int trf7970a_is_iso15693_write_or_lock(u8 cmd)
> +{
> +	int ret;
> +
> +	switch (cmd) {
> +	case ISO15693_CMD_WRITE_SINGLE_BLOCK:
> +	case ISO15693_CMD_LOCK_BLOCK:
> +	case ISO15693_CMD_WRITE_MULTIPLE_BLOCK:
> +	case ISO15693_CMD_WRITE_AFI:
> +	case ISO15693_CMD_LOCK_AFI:
> +	case ISO15693_CMD_WRITE_DSFID:
> +	case ISO15693_CMD_LOCK_DSFID:
> +		ret = 1;
return 1;

and return 0 on the default case.
Simpler code and you don't need the ret variable.

Cheers,
Samuel.

-- 
Intel Open Source Technology Centre
http://oss.intel.com/

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 2/3] NFC: trf7970a: Add ISO/IEC 15693 Support
@ 2014-02-21  1:00     ` Samuel Ortiz
  0 siblings, 0 replies; 30+ messages in thread
From: Samuel Ortiz @ 2014-02-21  1:00 UTC (permalink / raw)
  To: Mark A. Greer
  Cc: Lauro Ramos Venancio, Aloisio Almeida Jr, Felipe Balbi,
	Erick Macias, Thierry Escande,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	linux-nfc-hn68Rpc1hR1g9hUCZPvPmw,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Hi Mark,

Just one nitpick here:

> +static int trf7970a_is_iso15693_write_or_lock(u8 cmd)
> +{
> +	int ret;
> +
> +	switch (cmd) {
> +	case ISO15693_CMD_WRITE_SINGLE_BLOCK:
> +	case ISO15693_CMD_LOCK_BLOCK:
> +	case ISO15693_CMD_WRITE_MULTIPLE_BLOCK:
> +	case ISO15693_CMD_WRITE_AFI:
> +	case ISO15693_CMD_LOCK_AFI:
> +	case ISO15693_CMD_WRITE_DSFID:
> +	case ISO15693_CMD_LOCK_DSFID:
> +		ret = 1;
return 1;

and return 0 on the default case.
Simpler code and you don't need the ret variable.

Cheers,
Samuel.

-- 
Intel Open Source Technology Centre
http://oss.intel.com/
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 3/3] NFC: trf7970a: Add DTS Documentation
@ 2014-02-21  1:04     ` Samuel Ortiz
  0 siblings, 0 replies; 30+ messages in thread
From: Samuel Ortiz @ 2014-02-21  1:04 UTC (permalink / raw)
  To: Mark A. Greer
  Cc: Lauro Ramos Venancio, Aloisio Almeida Jr, Felipe Balbi,
	Erick Macias, Thierry Escande, linux-wireless, linux-nfc,
	devicetree

Hi Mark,

On Fri, Jan 31, 2014 at 03:17:11PM -0700, Mark A. Greer wrote:
> Describe the properies used by the trf7970a
> RFID/NFC/15693 transceiver driver.
> 
> Signed-off-by: Mark A. Greer <mgreer@animalcreek.com>
> ---
>  .../devicetree/bindings/net/nfc/trf7970a.txt       | 37 ++++++++++++++++++++++
>  1 file changed, 37 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/net/nfc/trf7970a.txt
Not a DT expert, but this looks good to me.
Could you please amend this patch by adding
Documentation/devicetree/bindings/net/nfc/ to the MAINTAINERS NFC
section ?

Cheers,
Samuel.

-- 
Intel Open Source Technology Centre
http://oss.intel.com/

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 3/3] NFC: trf7970a: Add DTS Documentation
@ 2014-02-21  1:04     ` Samuel Ortiz
  0 siblings, 0 replies; 30+ messages in thread
From: Samuel Ortiz @ 2014-02-21  1:04 UTC (permalink / raw)
  To: Mark A. Greer
  Cc: Lauro Ramos Venancio, Aloisio Almeida Jr, Felipe Balbi,
	Erick Macias, Thierry Escande,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	linux-nfc-hn68Rpc1hR1g9hUCZPvPmw,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Hi Mark,

On Fri, Jan 31, 2014 at 03:17:11PM -0700, Mark A. Greer wrote:
> Describe the properies used by the trf7970a
> RFID/NFC/15693 transceiver driver.
> 
> Signed-off-by: Mark A. Greer <mgreer-luAo+O/VEmrlveNOaEYElw@public.gmane.org>
> ---
>  .../devicetree/bindings/net/nfc/trf7970a.txt       | 37 ++++++++++++++++++++++
>  1 file changed, 37 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/net/nfc/trf7970a.txt
Not a DT expert, but this looks good to me.
Could you please amend this patch by adding
Documentation/devicetree/bindings/net/nfc/ to the MAINTAINERS NFC
section ?

Cheers,
Samuel.

-- 
Intel Open Source Technology Centre
http://oss.intel.com/
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 1/3] NFC: trf7970a: Add driver with ISO/IEC 14443 Type 2 Tag Support
  2014-02-21  0:50     ` Samuel Ortiz
@ 2014-02-21  1:20       ` Felipe Balbi
  -1 siblings, 0 replies; 30+ messages in thread
From: Felipe Balbi @ 2014-02-21  1:20 UTC (permalink / raw)
  To: Samuel Ortiz
  Cc: Mark A. Greer, Lauro Ramos Venancio, Aloisio Almeida Jr,
	Felipe Balbi, Erick Macias, Thierry Escande, linux-wireless,
	linux-nfc, devicetree

[-- Attachment #1: Type: text/plain, Size: 233 bytes --]

Hi,

On Fri, Feb 21, 2014 at 01:50:59AM +0100, Samuel Ortiz wrote:
> > +#define TRF7970A_QUIRK_IRQ_STATUS_READ_ERRATA	BIT(0)
> Are there actually any TRF970 devices that do not need this quirk ?

in the oven ;-)

-- 
balbi

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 1/3] NFC: trf7970a: Add driver with ISO/IEC 14443 Type 2 Tag Support
@ 2014-02-21  1:20       ` Felipe Balbi
  0 siblings, 0 replies; 30+ messages in thread
From: Felipe Balbi @ 2014-02-21  1:20 UTC (permalink / raw)
  To: Samuel Ortiz
  Cc: Mark A. Greer, Lauro Ramos Venancio, Aloisio Almeida Jr,
	Felipe Balbi, Erick Macias, Thierry Escande,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	linux-nfc-y27Ovi1pjclAfugRpC6u6w,
	devicetree-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 233 bytes --]

Hi,

On Fri, Feb 21, 2014 at 01:50:59AM +0100, Samuel Ortiz wrote:
> > +#define TRF7970A_QUIRK_IRQ_STATUS_READ_ERRATA	BIT(0)
> Are there actually any TRF970 devices that do not need this quirk ?

in the oven ;-)

-- 
balbi

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 1/3] NFC: trf7970a: Add driver with ISO/IEC 14443 Type 2 Tag Support
  2014-02-21  0:50     ` Samuel Ortiz
@ 2014-02-26 21:53       ` Mark A. Greer
  -1 siblings, 0 replies; 30+ messages in thread
From: Mark A. Greer @ 2014-02-26 21:53 UTC (permalink / raw)
  To: Samuel Ortiz
  Cc: Lauro Ramos Venancio, Aloisio Almeida Jr, Felipe Balbi,
	Erick Macias, Thierry Escande, linux-wireless, linux-nfc,
	devicetree

On Fri, Feb 21, 2014 at 01:50:59AM +0100, Samuel Ortiz wrote:
> Hi Mark,

Hi Samuel - thanks for the feedback.

> Code looks quite nice, especially since this looks like a fairly complex
> driver. And the initial coments are quite useful, I appreciate that.
> I have a few comments/questions though:
> 
> 
> > + * been received and there isn't an error).  The delay is 3 ms since delays
> > + * over 2 ms have been observed during testing.
> Would you say this timeout depend on the SPI bus bandwidth ?

It'll be one of the factors but the tag's response characteristics are
a big factor too.  I can bump it up a bit more if you prefer or do you
want me to somehow calculate it from the SPI bitrate?

> > +#define TRF7970A_QUIRK_IRQ_STATUS_READ_ERRATA	BIT(0)
> Are there actually any TRF970 devices that do not need this quirk ?

Felipe thinks so :)

> > +static void trf7970a_drain_fifo(struct trf7970a *trf, u8 status)
> > +{
> > +	struct sk_buff *skb = trf->rx_skb;
> > +	int ret;
> > +	u8 fifo_bytes;
> > +
> > +	if (status & TRF7970A_IRQ_STATUS_ERROR) {
> > +		trf7970a_abort_and_send_err(trf, -EIO);
> > +		return;
> > +	}
> > +
> > +	ret = trf7970a_read(trf, TRF7970A_FIFO_STATUS, &fifo_bytes);
> > +	if (ret) {
> > +		trf7970a_abort_and_send_err(trf, ret);
> > +		return;
> > +	}
> > +
> > +	dev_dbg(trf->dev, "fifo_bytes: 0x%x\n", fifo_bytes);
> > +
> > +	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_abort_and_send_err(trf, -EIO);
> > +		return;
> > +	}
> > +
> > +	if (fifo_bytes > skb_tailroom(skb)) {
> > +		skb = skb_copy_expand(skb, skb_headroom(skb),
> > +				max_t(int, fifo_bytes,
> > +					TRF7970A_RX_SKB_ALLOC_SIZE),
> > +				GFP_KERNEL);
> So there could be more pending bytes in the FIFO than you can accomodate
> in your rx_skb ?

Yes.

> Could we avoid that by allocating rx_skb to match the
> FIFO size ?

The alloc size (256) is already 2x the FIFO size (128) to try to minimize
this case from executing.  We never know how many total bytes may come in
so we can't eliminate the code altogether.

> > +static void trf7970a_timeout_work_handler(struct work_struct *work)
> > +{
> > +	struct trf7970a *trf = container_of(work, struct trf7970a,
> > +			timeout_work.work);
> > +
> > +	dev_dbg(trf->dev, "TIMEOUT - state: %d, ignore_timeout: %d\n",
> > +			trf->state, trf->ignore_timeout);
> > +
> > +	mutex_lock(&trf->lock);
> > +
> > +	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 */
> > +	else
> > +		trf7970a_abort_and_send_err(trf, -ETIMEDOUT);
> > +
> > +	mutex_unlock(&trf->lock);
> > +}
> > +
> > +/* ----------------------------------------------------------------- */
> Nitpick: I suppose you're separating the internal logic from the digital
> ops here ? Please add one comment line for that.

OK

> > +static int trf7970a_in_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;
> > +	unsigned int len;
> > +	int ret;
> > +
> > +	dev_dbg(trf->dev, "New request - state: %d, timeout: %d ms, len: %d\n",
> > +			trf->state, timeout, skb->len);
> > +
> > +	if (skb->len > TRF7970A_TX_MAX)
> > +		return -EINVAL;
> > +
> > +	mutex_lock(&trf->lock);
> > +
> > +	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;
> > +	}
> > +
> > +	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) {
> > +		ret = trf7970a_cmd(trf, TRF7970A_CMD_ENABLE_RX);
> > +		if (ret)
> > +			goto out_err;
> > +
> > +		trf->state = TRF7970A_ST_IDLE;
> > +	}
> > +
> > +	ret = trf7970a_per_cmd_config(trf, skb);
> > +	if (ret)
> > +		goto out_err;
> > +
> > +	trf->ddev = ddev;
> > +	trf->tx_skb = skb;
> As you're going to carry this guy around and may need it from e.g. your
> threaded interrupt handler, shouldn't you take a reference (skb_get) on it ?
> I'm concerned by the fact that you could see your tx_skb disappear from
> abort_cmd and get an IRQ before your state is set to IDLE.
> Hmm, I guess that's protected by the mutex and so when you get an abort
> from the digital stack you reset the state to IDLE and no one should try
> to touch tx_skb after you release the mutex. Is that what you had in
> mind ?

It is but taking a reference is a good idea.  I'll add that.

> > +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 ret;
> > +
> > +	if (!np) {
> > +		dev_err(&spi->dev, "No Device Tree entry\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	trf = devm_kzalloc(&spi->dev, sizeof(*trf), GFP_KERNEL);
> > +	if (!trf)
> > +		return -ENOMEM;
> > +
> > +	trf->state = TRF7970A_ST_OFF;
> > +	trf->dev = &spi->dev;
> > +	trf->spi = spi;
> > +	trf->quirks = id->driver_data;
> > +	trf->initialized = false;
> > +
> > +	spi->mode = SPI_MODE_1;
> > +	spi->bits_per_word = 8;
> > +
> > +	/* Get the optional Slave Select GPIO used for SPI with SS mode */
> > +	trf->ss_gpio = of_get_named_gpio(np, "ti,ss-gpio", 0);
> > +	if (trf->ss_gpio >= 0) {
> > +		ret = devm_gpio_request_one(trf->dev, trf->ss_gpio,
> > +				GPIOF_DIR_OUT | GPIOF_INIT_LOW, "SS");
> > +		if (ret) {
> > +			dev_err(trf->dev, "Can't request SS GPIO: %d\n", ret);
> > +			return ret;
> > +		}
> > +	} else {
> > +		dev_info(trf->dev, "Using SPI without SS mode\n");
> > +	}
> > +
> > +	/* There are two enable pins - both must be present */
> > +	trf->en_gpio = of_get_named_gpio(np, "ti,enable-gpios", 0);
> > +	if (trf->en_gpio < 0) {
> > +		dev_err(trf->dev, "No EN GPIO property\n");
> > +		return ret;
> You probably want to return trf->en_gpio or otherwise the devm code
> won't release your managed resources.

Oops.  Good catch, thx.

> > +	}
> > +
> > +	ret = devm_gpio_request_one(trf->dev, trf->en_gpio,
> > +			GPIOF_DIR_OUT | GPIOF_INIT_LOW, "EN");
> > +	if (ret) {
> > +		dev_err(trf->dev, "Can't request EN GPIO: %d\n", ret);
> > +		return ret;
> > +	}
> > +
> > +	trf->en2_gpio = of_get_named_gpio(np, "ti,enable-gpios", 1);
> > +	if (trf->en2_gpio < 0) {
> > +		dev_err(trf->dev, "No EN2 GPIO property\n");
> > +		return ret;
> Ditto.

OK

Mark
--

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 1/3] NFC: trf7970a: Add driver with ISO/IEC 14443 Type 2 Tag Support
@ 2014-02-26 21:53       ` Mark A. Greer
  0 siblings, 0 replies; 30+ messages in thread
From: Mark A. Greer @ 2014-02-26 21:53 UTC (permalink / raw)
  To: Samuel Ortiz
  Cc: Lauro Ramos Venancio, Aloisio Almeida Jr, Felipe Balbi,
	Erick Macias, Thierry Escande,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	linux-nfc-hn68Rpc1hR1g9hUCZPvPmw,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On Fri, Feb 21, 2014 at 01:50:59AM +0100, Samuel Ortiz wrote:
> Hi Mark,

Hi Samuel - thanks for the feedback.

> Code looks quite nice, especially since this looks like a fairly complex
> driver. And the initial coments are quite useful, I appreciate that.
> I have a few comments/questions though:
> 
> 
> > + * been received and there isn't an error).  The delay is 3 ms since delays
> > + * over 2 ms have been observed during testing.
> Would you say this timeout depend on the SPI bus bandwidth ?

It'll be one of the factors but the tag's response characteristics are
a big factor too.  I can bump it up a bit more if you prefer or do you
want me to somehow calculate it from the SPI bitrate?

> > +#define TRF7970A_QUIRK_IRQ_STATUS_READ_ERRATA	BIT(0)
> Are there actually any TRF970 devices that do not need this quirk ?

Felipe thinks so :)

> > +static void trf7970a_drain_fifo(struct trf7970a *trf, u8 status)
> > +{
> > +	struct sk_buff *skb = trf->rx_skb;
> > +	int ret;
> > +	u8 fifo_bytes;
> > +
> > +	if (status & TRF7970A_IRQ_STATUS_ERROR) {
> > +		trf7970a_abort_and_send_err(trf, -EIO);
> > +		return;
> > +	}
> > +
> > +	ret = trf7970a_read(trf, TRF7970A_FIFO_STATUS, &fifo_bytes);
> > +	if (ret) {
> > +		trf7970a_abort_and_send_err(trf, ret);
> > +		return;
> > +	}
> > +
> > +	dev_dbg(trf->dev, "fifo_bytes: 0x%x\n", fifo_bytes);
> > +
> > +	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_abort_and_send_err(trf, -EIO);
> > +		return;
> > +	}
> > +
> > +	if (fifo_bytes > skb_tailroom(skb)) {
> > +		skb = skb_copy_expand(skb, skb_headroom(skb),
> > +				max_t(int, fifo_bytes,
> > +					TRF7970A_RX_SKB_ALLOC_SIZE),
> > +				GFP_KERNEL);
> So there could be more pending bytes in the FIFO than you can accomodate
> in your rx_skb ?

Yes.

> Could we avoid that by allocating rx_skb to match the
> FIFO size ?

The alloc size (256) is already 2x the FIFO size (128) to try to minimize
this case from executing.  We never know how many total bytes may come in
so we can't eliminate the code altogether.

> > +static void trf7970a_timeout_work_handler(struct work_struct *work)
> > +{
> > +	struct trf7970a *trf = container_of(work, struct trf7970a,
> > +			timeout_work.work);
> > +
> > +	dev_dbg(trf->dev, "TIMEOUT - state: %d, ignore_timeout: %d\n",
> > +			trf->state, trf->ignore_timeout);
> > +
> > +	mutex_lock(&trf->lock);
> > +
> > +	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 */
> > +	else
> > +		trf7970a_abort_and_send_err(trf, -ETIMEDOUT);
> > +
> > +	mutex_unlock(&trf->lock);
> > +}
> > +
> > +/* ----------------------------------------------------------------- */
> Nitpick: I suppose you're separating the internal logic from the digital
> ops here ? Please add one comment line for that.

OK

> > +static int trf7970a_in_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;
> > +	unsigned int len;
> > +	int ret;
> > +
> > +	dev_dbg(trf->dev, "New request - state: %d, timeout: %d ms, len: %d\n",
> > +			trf->state, timeout, skb->len);
> > +
> > +	if (skb->len > TRF7970A_TX_MAX)
> > +		return -EINVAL;
> > +
> > +	mutex_lock(&trf->lock);
> > +
> > +	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;
> > +	}
> > +
> > +	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) {
> > +		ret = trf7970a_cmd(trf, TRF7970A_CMD_ENABLE_RX);
> > +		if (ret)
> > +			goto out_err;
> > +
> > +		trf->state = TRF7970A_ST_IDLE;
> > +	}
> > +
> > +	ret = trf7970a_per_cmd_config(trf, skb);
> > +	if (ret)
> > +		goto out_err;
> > +
> > +	trf->ddev = ddev;
> > +	trf->tx_skb = skb;
> As you're going to carry this guy around and may need it from e.g. your
> threaded interrupt handler, shouldn't you take a reference (skb_get) on it ?
> I'm concerned by the fact that you could see your tx_skb disappear from
> abort_cmd and get an IRQ before your state is set to IDLE.
> Hmm, I guess that's protected by the mutex and so when you get an abort
> from the digital stack you reset the state to IDLE and no one should try
> to touch tx_skb after you release the mutex. Is that what you had in
> mind ?

It is but taking a reference is a good idea.  I'll add that.

> > +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 ret;
> > +
> > +	if (!np) {
> > +		dev_err(&spi->dev, "No Device Tree entry\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	trf = devm_kzalloc(&spi->dev, sizeof(*trf), GFP_KERNEL);
> > +	if (!trf)
> > +		return -ENOMEM;
> > +
> > +	trf->state = TRF7970A_ST_OFF;
> > +	trf->dev = &spi->dev;
> > +	trf->spi = spi;
> > +	trf->quirks = id->driver_data;
> > +	trf->initialized = false;
> > +
> > +	spi->mode = SPI_MODE_1;
> > +	spi->bits_per_word = 8;
> > +
> > +	/* Get the optional Slave Select GPIO used for SPI with SS mode */
> > +	trf->ss_gpio = of_get_named_gpio(np, "ti,ss-gpio", 0);
> > +	if (trf->ss_gpio >= 0) {
> > +		ret = devm_gpio_request_one(trf->dev, trf->ss_gpio,
> > +				GPIOF_DIR_OUT | GPIOF_INIT_LOW, "SS");
> > +		if (ret) {
> > +			dev_err(trf->dev, "Can't request SS GPIO: %d\n", ret);
> > +			return ret;
> > +		}
> > +	} else {
> > +		dev_info(trf->dev, "Using SPI without SS mode\n");
> > +	}
> > +
> > +	/* There are two enable pins - both must be present */
> > +	trf->en_gpio = of_get_named_gpio(np, "ti,enable-gpios", 0);
> > +	if (trf->en_gpio < 0) {
> > +		dev_err(trf->dev, "No EN GPIO property\n");
> > +		return ret;
> You probably want to return trf->en_gpio or otherwise the devm code
> won't release your managed resources.

Oops.  Good catch, thx.

> > +	}
> > +
> > +	ret = devm_gpio_request_one(trf->dev, trf->en_gpio,
> > +			GPIOF_DIR_OUT | GPIOF_INIT_LOW, "EN");
> > +	if (ret) {
> > +		dev_err(trf->dev, "Can't request EN GPIO: %d\n", ret);
> > +		return ret;
> > +	}
> > +
> > +	trf->en2_gpio = of_get_named_gpio(np, "ti,enable-gpios", 1);
> > +	if (trf->en2_gpio < 0) {
> > +		dev_err(trf->dev, "No EN2 GPIO property\n");
> > +		return ret;
> Ditto.

OK

Mark
--
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 2/3] NFC: trf7970a: Add ISO/IEC 15693 Support
  2014-02-21  1:00     ` Samuel Ortiz
@ 2014-02-26 21:53       ` Mark A. Greer
  -1 siblings, 0 replies; 30+ messages in thread
From: Mark A. Greer @ 2014-02-26 21:53 UTC (permalink / raw)
  To: Samuel Ortiz
  Cc: Lauro Ramos Venancio, Aloisio Almeida Jr, Felipe Balbi,
	Erick Macias, Thierry Escande, linux-wireless, linux-nfc,
	devicetree

On Fri, Feb 21, 2014 at 02:00:44AM +0100, Samuel Ortiz wrote:
> Hi Mark,
> 
> Just one nitpick here:
> 
> > +static int trf7970a_is_iso15693_write_or_lock(u8 cmd)
> > +{
> > +	int ret;
> > +
> > +	switch (cmd) {
> > +	case ISO15693_CMD_WRITE_SINGLE_BLOCK:
> > +	case ISO15693_CMD_LOCK_BLOCK:
> > +	case ISO15693_CMD_WRITE_MULTIPLE_BLOCK:
> > +	case ISO15693_CMD_WRITE_AFI:
> > +	case ISO15693_CMD_LOCK_AFI:
> > +	case ISO15693_CMD_WRITE_DSFID:
> > +	case ISO15693_CMD_LOCK_DSFID:
> > +		ret = 1;
> return 1;
> 
> and return 0 on the default case.
> Simpler code and you don't need the ret variable.

OK

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 2/3] NFC: trf7970a: Add ISO/IEC 15693 Support
@ 2014-02-26 21:53       ` Mark A. Greer
  0 siblings, 0 replies; 30+ messages in thread
From: Mark A. Greer @ 2014-02-26 21:53 UTC (permalink / raw)
  To: Samuel Ortiz
  Cc: Lauro Ramos Venancio, Aloisio Almeida Jr, Felipe Balbi,
	Erick Macias, Thierry Escande,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	linux-nfc-hn68Rpc1hR1g9hUCZPvPmw,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On Fri, Feb 21, 2014 at 02:00:44AM +0100, Samuel Ortiz wrote:
> Hi Mark,
> 
> Just one nitpick here:
> 
> > +static int trf7970a_is_iso15693_write_or_lock(u8 cmd)
> > +{
> > +	int ret;
> > +
> > +	switch (cmd) {
> > +	case ISO15693_CMD_WRITE_SINGLE_BLOCK:
> > +	case ISO15693_CMD_LOCK_BLOCK:
> > +	case ISO15693_CMD_WRITE_MULTIPLE_BLOCK:
> > +	case ISO15693_CMD_WRITE_AFI:
> > +	case ISO15693_CMD_LOCK_AFI:
> > +	case ISO15693_CMD_WRITE_DSFID:
> > +	case ISO15693_CMD_LOCK_DSFID:
> > +		ret = 1;
> return 1;
> 
> and return 0 on the default case.
> Simpler code and you don't need the ret variable.

OK
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 3/3] NFC: trf7970a: Add DTS Documentation
  2014-02-21  1:04     ` Samuel Ortiz
@ 2014-02-26 21:54       ` Mark A. Greer
  -1 siblings, 0 replies; 30+ messages in thread
From: Mark A. Greer @ 2014-02-26 21:54 UTC (permalink / raw)
  To: Samuel Ortiz
  Cc: Lauro Ramos Venancio, Aloisio Almeida Jr, Felipe Balbi,
	Erick Macias, Thierry Escande, linux-wireless, linux-nfc,
	devicetree

On Fri, Feb 21, 2014 at 02:04:07AM +0100, Samuel Ortiz wrote:
> Hi Mark,
> 
> On Fri, Jan 31, 2014 at 03:17:11PM -0700, Mark A. Greer wrote:
> > Describe the properies used by the trf7970a
> > RFID/NFC/15693 transceiver driver.
> > 
> > Signed-off-by: Mark A. Greer <mgreer@animalcreek.com>
> > ---
> >  .../devicetree/bindings/net/nfc/trf7970a.txt       | 37 ++++++++++++++++++++++
> >  1 file changed, 37 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/net/nfc/trf7970a.txt
> Not a DT expert, but this looks good to me.
> Could you please amend this patch by adding
> Documentation/devicetree/bindings/net/nfc/ to the MAINTAINERS NFC
> section ?

Sure.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 3/3] NFC: trf7970a: Add DTS Documentation
@ 2014-02-26 21:54       ` Mark A. Greer
  0 siblings, 0 replies; 30+ messages in thread
From: Mark A. Greer @ 2014-02-26 21:54 UTC (permalink / raw)
  To: Samuel Ortiz
  Cc: Lauro Ramos Venancio, Aloisio Almeida Jr, Felipe Balbi,
	Erick Macias, Thierry Escande,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	linux-nfc-hn68Rpc1hR1g9hUCZPvPmw,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On Fri, Feb 21, 2014 at 02:04:07AM +0100, Samuel Ortiz wrote:
> Hi Mark,
> 
> On Fri, Jan 31, 2014 at 03:17:11PM -0700, Mark A. Greer wrote:
> > Describe the properies used by the trf7970a
> > RFID/NFC/15693 transceiver driver.
> > 
> > Signed-off-by: Mark A. Greer <mgreer-luAo+O/VEmrlveNOaEYElw@public.gmane.org>
> > ---
> >  .../devicetree/bindings/net/nfc/trf7970a.txt       | 37 ++++++++++++++++++++++
> >  1 file changed, 37 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/net/nfc/trf7970a.txt
> Not a DT expert, but this looks good to me.
> Could you please amend this patch by adding
> Documentation/devicetree/bindings/net/nfc/ to the MAINTAINERS NFC
> section ?

Sure.
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 1/3] NFC: trf7970a: Add driver with ISO/IEC 14443 Type 2 Tag Support
@ 2014-03-03 18:11         ` Mark A. Greer
  0 siblings, 0 replies; 30+ messages in thread
From: Mark A. Greer @ 2014-03-03 18:11 UTC (permalink / raw)
  To: Samuel Ortiz
  Cc: Lauro Ramos Venancio, Aloisio Almeida Jr, Felipe Balbi,
	Erick Macias, Thierry Escande, linux-wireless, linux-nfc,
	devicetree

On Wed, Feb 26, 2014 at 02:53:09PM -0700, Mark A. Greer wrote:
> On Fri, Feb 21, 2014 at 01:50:59AM +0100, Samuel Ortiz wrote:
> > Hi Mark,
> 
> Hi Samuel - thanks for the feedback.
> 
> > Code looks quite nice, especially since this looks like a fairly complex
> > driver. And the initial coments are quite useful, I appreciate that.
> > I have a few comments/questions though:
> > 
> > 
> > > + * been received and there isn't an error).  The delay is 3 ms since delays
> > > + * over 2 ms have been observed during testing.
> > Would you say this timeout depend on the SPI bus bandwidth ?
> 
> It'll be one of the factors but the tag's response characteristics are
> a big factor too.  I can bump it up a bit more if you prefer or do you
> want me to somehow calculate it from the SPI bitrate?

Ping.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 1/3] NFC: trf7970a: Add driver with ISO/IEC 14443 Type 2 Tag Support
@ 2014-03-03 18:11         ` Mark A. Greer
  0 siblings, 0 replies; 30+ messages in thread
From: Mark A. Greer @ 2014-03-03 18:11 UTC (permalink / raw)
  To: Samuel Ortiz
  Cc: Lauro Ramos Venancio, Aloisio Almeida Jr, Felipe Balbi,
	Erick Macias, Thierry Escande,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	linux-nfc-hn68Rpc1hR1g9hUCZPvPmw,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On Wed, Feb 26, 2014 at 02:53:09PM -0700, Mark A. Greer wrote:
> On Fri, Feb 21, 2014 at 01:50:59AM +0100, Samuel Ortiz wrote:
> > Hi Mark,
> 
> Hi Samuel - thanks for the feedback.
> 
> > Code looks quite nice, especially since this looks like a fairly complex
> > driver. And the initial coments are quite useful, I appreciate that.
> > I have a few comments/questions though:
> > 
> > 
> > > + * been received and there isn't an error).  The delay is 3 ms since delays
> > > + * over 2 ms have been observed during testing.
> > Would you say this timeout depend on the SPI bus bandwidth ?
> 
> It'll be one of the factors but the tag's response characteristics are
> a big factor too.  I can bump it up a bit more if you prefer or do you
> want me to somehow calculate it from the SPI bitrate?

Ping.
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 1/3] NFC: trf7970a: Add driver with ISO/IEC 14443 Type 2 Tag Support
@ 2014-03-03 20:37           ` Samuel Ortiz
  0 siblings, 0 replies; 30+ messages in thread
From: Samuel Ortiz @ 2014-03-03 20:37 UTC (permalink / raw)
  To: Mark A. Greer
  Cc: Lauro Ramos Venancio, Aloisio Almeida Jr, Felipe Balbi,
	Erick Macias, Thierry Escande, linux-wireless, linux-nfc,
	devicetree

Hi Mark,

On Mon, Mar 03, 2014 at 11:11:12AM -0700, Mark A. Greer wrote:
> > > Would you say this timeout depend on the SPI bus bandwidth ?
> > 
> > It'll be one of the factors but the tag's response characteristics are
> > a big factor too.  I can bump it up a bit more if you prefer or do you
> > want me to somehow calculate it from the SPI bitrate?
> 
> Ping.
Sorry, I missed that one: No, bumping it a bit more just to be on the
safe side will be enough.

Cheers,
Samuel.

-- 
Intel Open Source Technology Centre
http://oss.intel.com/

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 1/3] NFC: trf7970a: Add driver with ISO/IEC 14443 Type 2 Tag Support
@ 2014-03-03 20:37           ` Samuel Ortiz
  0 siblings, 0 replies; 30+ messages in thread
From: Samuel Ortiz @ 2014-03-03 20:37 UTC (permalink / raw)
  To: Mark A. Greer
  Cc: Lauro Ramos Venancio, Aloisio Almeida Jr, Felipe Balbi,
	Erick Macias, Thierry Escande,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	linux-nfc-hn68Rpc1hR1g9hUCZPvPmw,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Hi Mark,

On Mon, Mar 03, 2014 at 11:11:12AM -0700, Mark A. Greer wrote:
> > > Would you say this timeout depend on the SPI bus bandwidth ?
> > 
> > It'll be one of the factors but the tag's response characteristics are
> > a big factor too.  I can bump it up a bit more if you prefer or do you
> > want me to somehow calculate it from the SPI bitrate?
> 
> Ping.
Sorry, I missed that one: No, bumping it a bit more just to be on the
safe side will be enough.

Cheers,
Samuel.

-- 
Intel Open Source Technology Centre
http://oss.intel.com/
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 1/3] NFC: trf7970a: Add driver with ISO/IEC 14443 Type 2 Tag Support
@ 2014-03-05  0:19         ` Mark A. Greer
  0 siblings, 0 replies; 30+ messages in thread
From: Mark A. Greer @ 2014-03-05  0:19 UTC (permalink / raw)
  To: Samuel Ortiz
  Cc: Lauro Ramos Venancio, Aloisio Almeida Jr, Felipe Balbi,
	Erick Macias, Thierry Escande, linux-wireless, linux-nfc,
	devicetree

On Wed, Feb 26, 2014 at 02:53:09PM -0700, Mark A. Greer wrote:
> On Fri, Feb 21, 2014 at 01:50:59AM +0100, Samuel Ortiz wrote:
> 
> > > +static int trf7970a_in_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;
> > > +	unsigned int len;
> > > +	int ret;
> > > +
> > > +	dev_dbg(trf->dev, "New request - state: %d, timeout: %d ms, len: %d\n",
> > > +			trf->state, timeout, skb->len);
> > > +
> > > +	if (skb->len > TRF7970A_TX_MAX)
> > > +		return -EINVAL;
> > > +
> > > +	mutex_lock(&trf->lock);
> > > +
> > > +	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;
> > > +	}
> > > +
> > > +	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) {
> > > +		ret = trf7970a_cmd(trf, TRF7970A_CMD_ENABLE_RX);
> > > +		if (ret)
> > > +			goto out_err;
> > > +
> > > +		trf->state = TRF7970A_ST_IDLE;
> > > +	}
> > > +
> > > +	ret = trf7970a_per_cmd_config(trf, skb);
> > > +	if (ret)
> > > +		goto out_err;
> > > +
> > > +	trf->ddev = ddev;
> > > +	trf->tx_skb = skb;
> > As you're going to carry this guy around and may need it from e.g. your
> > threaded interrupt handler, shouldn't you take a reference (skb_get) on it ?
> > I'm concerned by the fact that you could see your tx_skb disappear from
> > abort_cmd and get an IRQ before your state is set to IDLE.
> > Hmm, I guess that's protected by the mutex and so when you get an abort
> > from the digital stack you reset the state to IDLE and no one should try
> > to touch tx_skb after you release the mutex. Is that what you had in
> > mind ?
> 
> It is but taking a reference is a good idea.  I'll add that.

I've changed my mind on this (hope that's okay).

The driver is in control of freeing that skb and won't free it until
there's an abort or the processing is complete.  I believe that handle
the race with an abort correctly.

Mark
--

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 1/3] NFC: trf7970a: Add driver with ISO/IEC 14443 Type 2 Tag Support
@ 2014-03-05  0:19         ` Mark A. Greer
  0 siblings, 0 replies; 30+ messages in thread
From: Mark A. Greer @ 2014-03-05  0:19 UTC (permalink / raw)
  To: Samuel Ortiz
  Cc: Lauro Ramos Venancio, Aloisio Almeida Jr, Felipe Balbi,
	Erick Macias, Thierry Escande,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	linux-nfc-hn68Rpc1hR1g9hUCZPvPmw,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On Wed, Feb 26, 2014 at 02:53:09PM -0700, Mark A. Greer wrote:
> On Fri, Feb 21, 2014 at 01:50:59AM +0100, Samuel Ortiz wrote:
> 
> > > +static int trf7970a_in_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;
> > > +	unsigned int len;
> > > +	int ret;
> > > +
> > > +	dev_dbg(trf->dev, "New request - state: %d, timeout: %d ms, len: %d\n",
> > > +			trf->state, timeout, skb->len);
> > > +
> > > +	if (skb->len > TRF7970A_TX_MAX)
> > > +		return -EINVAL;
> > > +
> > > +	mutex_lock(&trf->lock);
> > > +
> > > +	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;
> > > +	}
> > > +
> > > +	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) {
> > > +		ret = trf7970a_cmd(trf, TRF7970A_CMD_ENABLE_RX);
> > > +		if (ret)
> > > +			goto out_err;
> > > +
> > > +		trf->state = TRF7970A_ST_IDLE;
> > > +	}
> > > +
> > > +	ret = trf7970a_per_cmd_config(trf, skb);
> > > +	if (ret)
> > > +		goto out_err;
> > > +
> > > +	trf->ddev = ddev;
> > > +	trf->tx_skb = skb;
> > As you're going to carry this guy around and may need it from e.g. your
> > threaded interrupt handler, shouldn't you take a reference (skb_get) on it ?
> > I'm concerned by the fact that you could see your tx_skb disappear from
> > abort_cmd and get an IRQ before your state is set to IDLE.
> > Hmm, I guess that's protected by the mutex and so when you get an abort
> > from the digital stack you reset the state to IDLE and no one should try
> > to touch tx_skb after you release the mutex. Is that what you had in
> > mind ?
> 
> It is but taking a reference is a good idea.  I'll add that.

I've changed my mind on this (hope that's okay).

The driver is in control of freeing that skb and won't free it until
there's an abort or the processing is complete.  I believe that handle
the race with an abort correctly.

Mark
--
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 1/3] NFC: trf7970a: Add driver with ISO/IEC 14443 Type 2 Tag Support
@ 2014-03-05 12:36           ` Samuel Ortiz
  0 siblings, 0 replies; 30+ messages in thread
From: Samuel Ortiz @ 2014-03-05 12:36 UTC (permalink / raw)
  To: Mark A. Greer
  Cc: Lauro Ramos Venancio, Aloisio Almeida Jr, Felipe Balbi,
	Erick Macias, Thierry Escande, linux-wireless, linux-nfc,
	devicetree

On Tue, Mar 04, 2014 at 05:19:43PM -0700, Mark A. Greer wrote:
> On Wed, Feb 26, 2014 at 02:53:09PM -0700, Mark A. Greer wrote:
> > On Fri, Feb 21, 2014 at 01:50:59AM +0100, Samuel Ortiz wrote:
> > 
> > > > +static int trf7970a_in_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;
> > > > +	unsigned int len;
> > > > +	int ret;
> > > > +
> > > > +	dev_dbg(trf->dev, "New request - state: %d, timeout: %d ms, len: %d\n",
> > > > +			trf->state, timeout, skb->len);
> > > > +
> > > > +	if (skb->len > TRF7970A_TX_MAX)
> > > > +		return -EINVAL;
> > > > +
> > > > +	mutex_lock(&trf->lock);
> > > > +
> > > > +	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;
> > > > +	}
> > > > +
> > > > +	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) {
> > > > +		ret = trf7970a_cmd(trf, TRF7970A_CMD_ENABLE_RX);
> > > > +		if (ret)
> > > > +			goto out_err;
> > > > +
> > > > +		trf->state = TRF7970A_ST_IDLE;
> > > > +	}
> > > > +
> > > > +	ret = trf7970a_per_cmd_config(trf, skb);
> > > > +	if (ret)
> > > > +		goto out_err;
> > > > +
> > > > +	trf->ddev = ddev;
> > > > +	trf->tx_skb = skb;
> > > As you're going to carry this guy around and may need it from e.g. your
> > > threaded interrupt handler, shouldn't you take a reference (skb_get) on it ?
> > > I'm concerned by the fact that you could see your tx_skb disappear from
> > > abort_cmd and get an IRQ before your state is set to IDLE.
> > > Hmm, I guess that's protected by the mutex and so when you get an abort
> > > from the digital stack you reset the state to IDLE and no one should try
> > > to touch tx_skb after you release the mutex. Is that what you had in
> > > mind ?
> > 
> > It is but taking a reference is a good idea.  I'll add that.
> 
> I've changed my mind on this (hope that's okay).
> 
> The driver is in control of freeing that skb and won't free it until
> there's an abort or the processing is complete.  I believe that handle
> the race with an abort correctly.
That was my understanding as well, and I wanted to make sure that you
had that in mind too. It seems to be the case.

Cheers,
Samuel.

-- 
Intel Open Source Technology Centre
http://oss.intel.com/

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 1/3] NFC: trf7970a: Add driver with ISO/IEC 14443 Type 2 Tag Support
@ 2014-03-05 12:36           ` Samuel Ortiz
  0 siblings, 0 replies; 30+ messages in thread
From: Samuel Ortiz @ 2014-03-05 12:36 UTC (permalink / raw)
  To: Mark A. Greer
  Cc: Lauro Ramos Venancio, Aloisio Almeida Jr, Felipe Balbi,
	Erick Macias, Thierry Escande,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	linux-nfc-hn68Rpc1hR1g9hUCZPvPmw,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On Tue, Mar 04, 2014 at 05:19:43PM -0700, Mark A. Greer wrote:
> On Wed, Feb 26, 2014 at 02:53:09PM -0700, Mark A. Greer wrote:
> > On Fri, Feb 21, 2014 at 01:50:59AM +0100, Samuel Ortiz wrote:
> > 
> > > > +static int trf7970a_in_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;
> > > > +	unsigned int len;
> > > > +	int ret;
> > > > +
> > > > +	dev_dbg(trf->dev, "New request - state: %d, timeout: %d ms, len: %d\n",
> > > > +			trf->state, timeout, skb->len);
> > > > +
> > > > +	if (skb->len > TRF7970A_TX_MAX)
> > > > +		return -EINVAL;
> > > > +
> > > > +	mutex_lock(&trf->lock);
> > > > +
> > > > +	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;
> > > > +	}
> > > > +
> > > > +	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) {
> > > > +		ret = trf7970a_cmd(trf, TRF7970A_CMD_ENABLE_RX);
> > > > +		if (ret)
> > > > +			goto out_err;
> > > > +
> > > > +		trf->state = TRF7970A_ST_IDLE;
> > > > +	}
> > > > +
> > > > +	ret = trf7970a_per_cmd_config(trf, skb);
> > > > +	if (ret)
> > > > +		goto out_err;
> > > > +
> > > > +	trf->ddev = ddev;
> > > > +	trf->tx_skb = skb;
> > > As you're going to carry this guy around and may need it from e.g. your
> > > threaded interrupt handler, shouldn't you take a reference (skb_get) on it ?
> > > I'm concerned by the fact that you could see your tx_skb disappear from
> > > abort_cmd and get an IRQ before your state is set to IDLE.
> > > Hmm, I guess that's protected by the mutex and so when you get an abort
> > > from the digital stack you reset the state to IDLE and no one should try
> > > to touch tx_skb after you release the mutex. Is that what you had in
> > > mind ?
> > 
> > It is but taking a reference is a good idea.  I'll add that.
> 
> I've changed my mind on this (hope that's okay).
> 
> The driver is in control of freeing that skb and won't free it until
> there's an abort or the processing is complete.  I believe that handle
> the race with an abort correctly.
That was my understanding as well, and I wanted to make sure that you
had that in mind too. It seems to be the case.

Cheers,
Samuel.

-- 
Intel Open Source Technology Centre
http://oss.intel.com/
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 30+ messages in thread

end of thread, other threads:[~2014-03-05 12:36 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-01-31 22:17 [PATCH 0/3] NFC: trf7970a: Add driver with NFC Type 2 and Type V Support Mark A. Greer
2014-01-31 22:17 ` Mark A. Greer
2014-01-31 22:17 ` [PATCH 1/3] NFC: trf7970a: Add driver with ISO/IEC 14443 Type 2 Tag Support Mark A. Greer
2014-01-31 22:17   ` Mark A. Greer
2014-02-21  0:50   ` Samuel Ortiz
2014-02-21  0:50     ` Samuel Ortiz
2014-02-21  1:20     ` Felipe Balbi
2014-02-21  1:20       ` Felipe Balbi
2014-02-26 21:53     ` Mark A. Greer
2014-02-26 21:53       ` Mark A. Greer
2014-03-03 18:11       ` Mark A. Greer
2014-03-03 18:11         ` Mark A. Greer
2014-03-03 20:37         ` Samuel Ortiz
2014-03-03 20:37           ` Samuel Ortiz
2014-03-05  0:19       ` Mark A. Greer
2014-03-05  0:19         ` Mark A. Greer
2014-03-05 12:36         ` Samuel Ortiz
2014-03-05 12:36           ` Samuel Ortiz
2014-01-31 22:17 ` [PATCH 2/3] NFC: trf7970a: Add ISO/IEC 15693 Support Mark A. Greer
2014-01-31 22:17   ` Mark A. Greer
2014-02-21  1:00   ` Samuel Ortiz
2014-02-21  1:00     ` Samuel Ortiz
2014-02-26 21:53     ` Mark A. Greer
2014-02-26 21:53       ` Mark A. Greer
2014-01-31 22:17 ` [PATCH 3/3] NFC: trf7970a: Add DTS Documentation Mark A. Greer
2014-01-31 22:17   ` Mark A. Greer
2014-02-21  1:04   ` Samuel Ortiz
2014-02-21  1:04     ` Samuel Ortiz
2014-02-26 21:54     ` Mark A. Greer
2014-02-26 21:54       ` Mark A. Greer

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.