diff mbox

[1/3] NFC: trf7970a: Add driver with ISO/IEC 14443 Type 2 Tag Support

Message ID 1391206631-9862-2-git-send-email-mgreer@animalcreek.com (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Mark Greer Jan. 31, 2014, 10:17 p.m. UTC
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

Comments

Samuel Ortiz Feb. 21, 2014, 12:50 a.m. UTC | #1
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.
Felipe Balbi Feb. 21, 2014, 1:20 a.m. UTC | #2
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 ;-)
Mark Greer Feb. 26, 2014, 9:53 p.m. UTC | #3
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@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mark Greer March 3, 2014, 6:11 p.m. UTC | #4
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@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Samuel Ortiz March 3, 2014, 8:37 p.m. UTC | #5
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.
Mark Greer March 5, 2014, 12:19 a.m. UTC | #6
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@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Samuel Ortiz March 5, 2014, 12:36 p.m. UTC | #7
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.
diff mbox

Patch

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");