Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ee9596d4 authored by Frederic Danis's avatar Frederic Danis Committed by Samuel Ortiz
Browse files

NFC: Add NCI over SPI send



Before any operation, driver interruption is de-asserted to prevent
race condition between TX and RX.

The NCI over SPI header is added in front of NCI packet.
If acknowledged mode is set, CRC-16-CCITT is added to the packet.
Then the packet is forwarded to SPI module to be sent.

A delay after the transaction is added.
This delay is determined by the driver during nci_spi_allocate_device()
call and can be 0.

After data has been sent, driver interruption is re-asserted.

If acknowledged mode is set, nci_spi_send will block until
acknowledgment is received.

Signed-off-by: default avatarFrederic Danis <frederic.danis@linux.intel.com>
Signed-off-by: default avatarSamuel Ortiz <sameo@linux.intel.com>
parent 8a00a61b
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -226,6 +226,9 @@ struct nci_spi_dev {
						  transactions */
						  transactions */
	u8			acknowledge_mode;
	u8			acknowledge_mode;


	struct completion	req_completion;
	u8			req_result;

	void			*driver_data;
	void			*driver_data;
};
};


+70 −1
Original line number Original line Diff line number Diff line
@@ -20,12 +20,25 @@


#include <linux/export.h>
#include <linux/export.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi.h>
#include <linux/crc-ccitt.h>
#include <linux/nfc.h>
#include <linux/nfc.h>
#include <net/nfc/nci_core.h>
#include <net/nfc/nci_core.h>


#define NCI_SPI_HDR_LEN			4
#define NCI_SPI_HDR_LEN			4
#define NCI_SPI_CRC_LEN			2
#define NCI_SPI_CRC_LEN			2


#define NCI_SPI_SEND_TIMEOUT	(NCI_CMD_TIMEOUT > NCI_DATA_TIMEOUT ? \
					NCI_CMD_TIMEOUT : NCI_DATA_TIMEOUT)

#define NCI_SPI_DIRECT_WRITE	0x01
#define NCI_SPI_DIRECT_READ	0x02

#define ACKNOWLEDGE_NONE	0
#define ACKNOWLEDGE_ACK		1
#define ACKNOWLEDGE_NACK	2

#define CRC_INIT		0xFFFF

static int nci_spi_open(struct nci_dev *nci_dev)
static int nci_spi_open(struct nci_dev *nci_dev)
{
{
	struct nci_spi_dev *ndev = nci_get_drvdata(nci_dev);
	struct nci_spi_dev *ndev = nci_get_drvdata(nci_dev);
@@ -40,9 +53,65 @@ static int nci_spi_close(struct nci_dev *nci_dev)
	return ndev->ops->close(ndev);
	return ndev->ops->close(ndev);
}
}


static int __nci_spi_send(struct nci_spi_dev *ndev, struct sk_buff *skb)
{
	struct spi_message m;
	struct spi_transfer t;

	t.tx_buf = skb->data;
	t.len = skb->len;
	t.cs_change = 0;
	t.delay_usecs = ndev->xfer_udelay;

	spi_message_init(&m);
	spi_message_add_tail(&t, &m);

	return spi_sync(ndev->spi, &m);
}

static int nci_spi_send(struct nci_dev *nci_dev, struct sk_buff *skb)
static int nci_spi_send(struct nci_dev *nci_dev, struct sk_buff *skb)
{
{
	return 0;
	struct nci_spi_dev *ndev = nci_get_drvdata(nci_dev);
	unsigned int payload_len = skb->len;
	unsigned char *hdr;
	int ret;
	long completion_rc;

	ndev->ops->deassert_int(ndev);

	/* add the NCI SPI header to the start of the buffer */
	hdr = skb_push(skb, NCI_SPI_HDR_LEN);
	hdr[0] = NCI_SPI_DIRECT_WRITE;
	hdr[1] = ndev->acknowledge_mode;
	hdr[2] = payload_len >> 8;
	hdr[3] = payload_len & 0xFF;

	if (ndev->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
		u16 crc;

		crc = crc_ccitt(CRC_INIT, skb->data, skb->len);
		*skb_put(skb, 1) = crc >> 8;
		*skb_put(skb, 1) = crc & 0xFF;
	}

	ret = __nci_spi_send(ndev, skb);

	kfree_skb(skb);
	ndev->ops->assert_int(ndev);

	if (ret != 0 || ndev->acknowledge_mode == NCI_SPI_CRC_DISABLED)
		goto done;

	init_completion(&ndev->req_completion);
	completion_rc =
		wait_for_completion_interruptible_timeout(&ndev->req_completion,
							  NCI_SPI_SEND_TIMEOUT);

	if (completion_rc <= 0 || ndev->req_result == ACKNOWLEDGE_NACK)
		ret = -EIO;

done:
	return ret;
}
}


static struct nci_ops nci_spi_ops = {
static struct nci_ops nci_spi_ops = {