NFC: Add STMicroelectronics ST95HF driver

This driver supports STMicroelectronics NFC Transceiver
"ST95HF", in in initiator role to read/write ISO14443 Type 4A,
ISO14443 Type 4B and ISO15693 Type5 tags.

The ST95HF datasheet is available here:
http://www.st.com/web/en/resource/technical/document/datasheet/DM00102056.pdf

Signed-off-by: Shikha Singh <shikha.singh@st.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
This commit is contained in:
Shikha Singh 2015-12-22 00:03:30 +01:00 committed by Samuel Ortiz
parent ce2e56cdfb
commit cab47333f0
7 changed files with 1522 additions and 0 deletions

View File

@ -76,4 +76,5 @@ source "drivers/nfc/st21nfca/Kconfig"
source "drivers/nfc/st-nci/Kconfig"
source "drivers/nfc/nxp-nci/Kconfig"
source "drivers/nfc/s3fwrn5/Kconfig"
source "drivers/nfc/st95hf/Kconfig"
endmenu

View File

@ -16,3 +16,4 @@ obj-$(CONFIG_NFC_ST21NFCA) += st21nfca/
obj-$(CONFIG_NFC_ST_NCI) += st-nci/
obj-$(CONFIG_NFC_NXP_NCI) += nxp-nci/
obj-$(CONFIG_NFC_S3FWRN5) += s3fwrn5/
obj-$(CONFIG_NFC_ST95HF) += st95hf/

View File

@ -0,0 +1,10 @@
config NFC_ST95HF
tristate "ST95HF NFC Transceiver driver"
depends on SPI && NFC_DIGITAL
help
This enables the ST NFC driver for ST95HF NFC transceiver.
This makes use of SPI framework to communicate with transceiver
and registered with NFC digital core to support Linux NFC framework.
Say Y here to compile support for ST NFC transceiver ST95HF
linux driver into the kernel or say M to compile it as module.

View File

@ -0,0 +1,6 @@
#
# Makefile for STMicroelectronics NFC transceiver ST95HF
#
obj-$(CONFIG_NFC_ST95HF) += st95hf.o
st95hf-objs := spi.o core.o

1273
drivers/nfc/st95hf/core.c Normal file

File diff suppressed because it is too large Load Diff

167
drivers/nfc/st95hf/spi.c Normal file
View File

@ -0,0 +1,167 @@
/*
* ----------------------------------------------------------------------------
* drivers/nfc/st95hf/spi.c function definitions for SPI communication
* ----------------------------------------------------------------------------
* Copyright (C) 2015 STMicroelectronics Pvt. Ltd. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "spi.h"
/* Function to send user provided buffer to ST95HF through SPI */
int st95hf_spi_send(struct st95hf_spi_context *spicontext,
unsigned char *buffertx,
int datalen,
enum req_type reqtype)
{
struct spi_message m;
int result = 0;
struct spi_device *spidev = spicontext->spidev;
struct spi_transfer tx_transfer = {
.tx_buf = buffertx,
.len = datalen,
};
mutex_lock(&spicontext->spi_lock);
if (reqtype == SYNC) {
spicontext->req_issync = true;
reinit_completion(&spicontext->done);
} else {
spicontext->req_issync = false;
}
spi_message_init(&m);
spi_message_add_tail(&tx_transfer, &m);
result = spi_sync(spidev, &m);
if (result) {
dev_err(&spidev->dev, "error: sending cmd to st95hf using SPI = %d\n",
result);
mutex_unlock(&spicontext->spi_lock);
return result;
}
/* return for asynchronous or no-wait case */
if (reqtype == ASYNC) {
mutex_unlock(&spicontext->spi_lock);
return 0;
}
result = wait_for_completion_timeout(&spicontext->done,
msecs_to_jiffies(1000));
/* check for timeout or success */
if (!result) {
dev_err(&spidev->dev, "error: response not ready timeout\n");
result = -ETIMEDOUT;
} else {
result = 0;
}
mutex_unlock(&spicontext->spi_lock);
return result;
}
EXPORT_SYMBOL_GPL(st95hf_spi_send);
/* Function to Receive command Response */
int st95hf_spi_recv_response(struct st95hf_spi_context *spicontext,
unsigned char *receivebuff)
{
int len = 0;
struct spi_transfer tx_takedata;
struct spi_message m;
struct spi_device *spidev = spicontext->spidev;
unsigned char readdata_cmd = ST95HF_COMMAND_RECEIVE;
struct spi_transfer t[2] = {
{.tx_buf = &readdata_cmd, .len = 1,},
{.rx_buf = receivebuff, .len = 2, .cs_change = 1,},
};
int ret = 0;
memset(&tx_takedata, 0x0, sizeof(struct spi_transfer));
mutex_lock(&spicontext->spi_lock);
/* First spi transfer to know the length of valid data */
spi_message_init(&m);
spi_message_add_tail(&t[0], &m);
spi_message_add_tail(&t[1], &m);
ret = spi_sync(spidev, &m);
if (ret) {
dev_err(&spidev->dev, "spi_recv_resp, data length error = %d\n",
ret);
mutex_unlock(&spicontext->spi_lock);
return ret;
}
/* As 2 bytes are already read */
len = 2;
/* Support of long frame */
if (receivebuff[0] & 0x60)
len += (((receivebuff[0] & 0x60) >> 5) << 8) | receivebuff[1];
else
len += receivebuff[1];
/* Now make a transfer to read only relevant bytes */
tx_takedata.rx_buf = &receivebuff[2];
tx_takedata.len = len - 2;
spi_message_init(&m);
spi_message_add_tail(&tx_takedata, &m);
ret = spi_sync(spidev, &m);
mutex_unlock(&spicontext->spi_lock);
if (ret) {
dev_err(&spidev->dev, "spi_recv_resp, data read error = %d\n",
ret);
return ret;
}
return len;
}
EXPORT_SYMBOL_GPL(st95hf_spi_recv_response);
int st95hf_spi_recv_echo_res(struct st95hf_spi_context *spicontext,
unsigned char *receivebuff)
{
unsigned char readdata_cmd = ST95HF_COMMAND_RECEIVE;
struct spi_transfer t[2] = {
{.tx_buf = &readdata_cmd, .len = 1,},
{.rx_buf = receivebuff, .len = 1,},
};
struct spi_message m;
struct spi_device *spidev = spicontext->spidev;
int ret = 0;
mutex_lock(&spicontext->spi_lock);
spi_message_init(&m);
spi_message_add_tail(&t[0], &m);
spi_message_add_tail(&t[1], &m);
ret = spi_sync(spidev, &m);
mutex_unlock(&spicontext->spi_lock);
if (ret)
dev_err(&spidev->dev, "recv_echo_res, data read error = %d\n",
ret);
return ret;
}
EXPORT_SYMBOL_GPL(st95hf_spi_recv_echo_res);

64
drivers/nfc/st95hf/spi.h Normal file
View File

@ -0,0 +1,64 @@
/*
* ---------------------------------------------------------------------------
* drivers/nfc/st95hf/spi.h functions declarations for SPI communication
* ---------------------------------------------------------------------------
* Copyright (C) 2015 STMicroelectronics All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __LINUX_ST95HF_SPI_H
#define __LINUX_ST95HF_SPI_H
#include <linux/spi/spi.h>
/* Basic ST95HF SPI CMDs */
#define ST95HF_COMMAND_SEND 0x0
#define ST95HF_COMMAND_RESET 0x1
#define ST95HF_COMMAND_RECEIVE 0x2
#define ST95HF_RESET_CMD_LEN 0x1
/*
* structure to contain st95hf spi communication specific information.
* @req_issync: true for synchronous calls.
* @spidev: st95hf spi device object.
* @done: completion structure to wait for st95hf response
* for synchronous calls.
* @spi_lock: mutex to allow only one spi transfer at a time.
*/
struct st95hf_spi_context {
bool req_issync;
struct spi_device *spidev;
struct completion done;
struct mutex spi_lock;
};
/* flag to differentiate synchronous & asynchronous spi request */
enum req_type {
SYNC,
ASYNC,
};
int st95hf_spi_send(struct st95hf_spi_context *spicontext,
unsigned char *buffertx,
int datalen,
enum req_type reqtype);
int st95hf_spi_recv_response(struct st95hf_spi_context *spicontext,
unsigned char *receivebuff);
int st95hf_spi_recv_echo_res(struct st95hf_spi_context *spicontext,
unsigned char *receivebuff);
#endif