summaryrefslogtreecommitdiff
path: root/drivers/nfc
diff options
context:
space:
mode:
authorAndré Fabian Silva Delgado <emulatorman@parabola.nu>2015-09-08 01:01:14 -0300
committerAndré Fabian Silva Delgado <emulatorman@parabola.nu>2015-09-08 01:01:14 -0300
commite5fd91f1ef340da553f7a79da9540c3db711c937 (patch)
treeb11842027dc6641da63f4bcc524f8678263304a3 /drivers/nfc
parent2a9b0348e685a63d97486f6749622b61e9e3292f (diff)
Linux-libre 4.2-gnu
Diffstat (limited to 'drivers/nfc')
-rw-r--r--drivers/nfc/Kconfig2
-rw-r--r--drivers/nfc/Makefile4
-rw-r--r--drivers/nfc/mei_phy.c295
-rw-r--r--drivers/nfc/mei_phy.h38
-rw-r--r--drivers/nfc/microread/i2c.c3
-rw-r--r--drivers/nfc/microread/mei.c2
-rw-r--r--drivers/nfc/nfcmrvl/Kconfig11
-rw-r--r--drivers/nfc/nfcmrvl/Makefile3
-rw-r--r--drivers/nfc/nfcmrvl/main.c134
-rw-r--r--drivers/nfc/nfcmrvl/nfcmrvl.h60
-rw-r--r--drivers/nfc/nfcmrvl/uart.c225
-rw-r--r--drivers/nfc/nfcmrvl/usb.c27
-rw-r--r--drivers/nfc/nxp-nci/Makefile2
-rw-r--r--drivers/nfc/nxp-nci/i2c.c52
-rw-r--r--drivers/nfc/pn544/i2c.c43
-rw-r--r--drivers/nfc/pn544/mei.c2
-rw-r--r--drivers/nfc/st-nci/Kconfig23
-rw-r--r--drivers/nfc/st-nci/Makefile9
-rw-r--r--drivers/nfc/st-nci/core.c179
-rw-r--r--drivers/nfc/st-nci/i2c.c (renamed from drivers/nfc/st21nfcb/i2c.c)137
-rw-r--r--drivers/nfc/st-nci/ndlc.c (renamed from drivers/nfc/st21nfcb/ndlc.c)23
-rw-r--r--drivers/nfc/st-nci/ndlc.h (renamed from drivers/nfc/st21nfcb/ndlc.h)5
-rw-r--r--drivers/nfc/st-nci/st-nci.h (renamed from drivers/nfc/st21nfcb/st21nfcb.h)30
-rw-r--r--drivers/nfc/st-nci/st-nci_se.c (renamed from drivers/nfc/st21nfcb/st21nfcb_se.c)383
-rw-r--r--drivers/nfc/st-nci/st-nci_se.h61
-rw-r--r--drivers/nfc/st21nfcb/Kconfig22
-rw-r--r--drivers/nfc/st21nfcb/Makefile9
-rw-r--r--drivers/nfc/st21nfcb/st21nfcb.c140
-rw-r--r--drivers/nfc/st21nfcb/st21nfcb_se.h61
-rw-r--r--drivers/nfc/trf7970a.c23
30 files changed, 1387 insertions, 621 deletions
diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig
index 107714e44..722673cb7 100644
--- a/drivers/nfc/Kconfig
+++ b/drivers/nfc/Kconfig
@@ -72,6 +72,6 @@ source "drivers/nfc/pn544/Kconfig"
source "drivers/nfc/microread/Kconfig"
source "drivers/nfc/nfcmrvl/Kconfig"
source "drivers/nfc/st21nfca/Kconfig"
-source "drivers/nfc/st21nfcb/Kconfig"
+source "drivers/nfc/st-nci/Kconfig"
source "drivers/nfc/nxp-nci/Kconfig"
endmenu
diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile
index a4292d790..368b6dfe7 100644
--- a/drivers/nfc/Makefile
+++ b/drivers/nfc/Makefile
@@ -12,7 +12,5 @@ obj-$(CONFIG_NFC_PORT100) += port100.o
obj-$(CONFIG_NFC_MRVL) += nfcmrvl/
obj-$(CONFIG_NFC_TRF7970A) += trf7970a.o
obj-$(CONFIG_NFC_ST21NFCA) += st21nfca/
-obj-$(CONFIG_NFC_ST21NFCB) += st21nfcb/
+obj-$(CONFIG_NFC_ST_NCI) += st-nci/
obj-$(CONFIG_NFC_NXP_NCI) += nxp-nci/
-
-ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
diff --git a/drivers/nfc/mei_phy.c b/drivers/nfc/mei_phy.c
index 11c7cbdad..2b77ccf77 100644
--- a/drivers/nfc/mei_phy.c
+++ b/drivers/nfc/mei_phy.c
@@ -32,6 +32,51 @@ struct mei_nfc_hdr {
u16 data_size;
} __packed;
+struct mei_nfc_cmd {
+ struct mei_nfc_hdr hdr;
+ u8 sub_command;
+ u8 data[];
+} __packed;
+
+struct mei_nfc_reply {
+ struct mei_nfc_hdr hdr;
+ u8 sub_command;
+ u8 reply_status;
+ u8 data[];
+} __packed;
+
+struct mei_nfc_if_version {
+ u8 radio_version_sw[3];
+ u8 reserved[3];
+ u8 radio_version_hw[3];
+ u8 i2c_addr;
+ u8 fw_ivn;
+ u8 vendor_id;
+ u8 radio_type;
+} __packed;
+
+struct mei_nfc_connect {
+ u8 fw_ivn;
+ u8 vendor_id;
+} __packed;
+
+struct mei_nfc_connect_resp {
+ u8 fw_ivn;
+ u8 vendor_id;
+ u16 me_major;
+ u16 me_minor;
+ u16 me_hotfix;
+ u16 me_build;
+} __packed;
+
+
+#define MEI_NFC_CMD_MAINTENANCE 0x00
+#define MEI_NFC_CMD_HCI_SEND 0x01
+#define MEI_NFC_CMD_HCI_RECV 0x02
+
+#define MEI_NFC_SUBCMD_CONNECT 0x00
+#define MEI_NFC_SUBCMD_IF_VERSION 0x01
+
#define MEI_NFC_MAX_READ (MEI_NFC_HEADER_SIZE + MEI_NFC_MAX_HCI_PAYLOAD)
#define MEI_DUMP_SKB_IN(info, skb) \
@@ -45,51 +90,169 @@ do { \
do { \
pr_debug("%s:\n", info); \
print_hex_dump_debug("mei out: ", DUMP_PREFIX_OFFSET, \
- 16, 1, (skb)->data, (skb)->len, false); \
+ 16, 1, (skb)->data, (skb)->len, false); \
} while (0)
-int nfc_mei_phy_enable(void *phy_id)
+#define MEI_DUMP_NFC_HDR(info, _hdr) \
+do { \
+ pr_debug("%s:\n", info); \
+ pr_debug("cmd=%02d status=%d req_id=%d rsvd=%d size=%d\n", \
+ (_hdr)->cmd, (_hdr)->status, (_hdr)->req_id, \
+ (_hdr)->reserved, (_hdr)->data_size); \
+} while (0)
+
+static int mei_nfc_if_version(struct nfc_mei_phy *phy)
{
- int r;
- struct nfc_mei_phy *phy = phy_id;
+
+ struct mei_nfc_cmd cmd;
+ struct mei_nfc_reply *reply = NULL;
+ struct mei_nfc_if_version *version;
+ size_t if_version_length;
+ int bytes_recv, r;
pr_info("%s\n", __func__);
- if (phy->powered == 1)
- return 0;
+ memset(&cmd, 0, sizeof(struct mei_nfc_cmd));
+ cmd.hdr.cmd = MEI_NFC_CMD_MAINTENANCE;
+ cmd.hdr.data_size = 1;
+ cmd.sub_command = MEI_NFC_SUBCMD_IF_VERSION;
- r = mei_cl_enable_device(phy->device);
+ MEI_DUMP_NFC_HDR("version", &cmd.hdr);
+ r = mei_cl_send(phy->device, (u8 *)&cmd, sizeof(struct mei_nfc_cmd));
if (r < 0) {
- pr_err("Could not enable device\n");
+ pr_err("Could not send IF version cmd\n");
return r;
}
- r = mei_cl_register_event_cb(phy->device, nfc_mei_event_cb, phy);
- if (r) {
- pr_err("Event cb registration failed\n");
- mei_cl_disable_device(phy->device);
- phy->powered = 0;
+ /* to be sure on the stack we alloc memory */
+ if_version_length = sizeof(struct mei_nfc_reply) +
+ sizeof(struct mei_nfc_if_version);
- return r;
+ reply = kzalloc(if_version_length, GFP_KERNEL);
+ if (!reply)
+ return -ENOMEM;
+
+ bytes_recv = mei_cl_recv(phy->device, (u8 *)reply, if_version_length);
+ if (bytes_recv < 0 || bytes_recv < sizeof(struct mei_nfc_reply)) {
+ pr_err("Could not read IF version\n");
+ r = -EIO;
+ goto err;
}
- phy->powered = 1;
+ version = (struct mei_nfc_if_version *)reply->data;
- return 0;
+ phy->fw_ivn = version->fw_ivn;
+ phy->vendor_id = version->vendor_id;
+ phy->radio_type = version->radio_type;
+
+err:
+ kfree(reply);
+ return r;
}
-EXPORT_SYMBOL_GPL(nfc_mei_phy_enable);
-void nfc_mei_phy_disable(void *phy_id)
+static int mei_nfc_connect(struct nfc_mei_phy *phy)
{
- struct nfc_mei_phy *phy = phy_id;
+ struct mei_nfc_cmd *cmd, *reply;
+ struct mei_nfc_connect *connect;
+ struct mei_nfc_connect_resp *connect_resp;
+ size_t connect_length, connect_resp_length;
+ int bytes_recv, r;
pr_info("%s\n", __func__);
- mei_cl_disable_device(phy->device);
+ connect_length = sizeof(struct mei_nfc_cmd) +
+ sizeof(struct mei_nfc_connect);
- phy->powered = 0;
+ connect_resp_length = sizeof(struct mei_nfc_cmd) +
+ sizeof(struct mei_nfc_connect_resp);
+
+ cmd = kzalloc(connect_length, GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+ connect = (struct mei_nfc_connect *)cmd->data;
+
+ reply = kzalloc(connect_resp_length, GFP_KERNEL);
+ if (!reply) {
+ kfree(cmd);
+ return -ENOMEM;
+ }
+
+ connect_resp = (struct mei_nfc_connect_resp *)reply->data;
+
+ cmd->hdr.cmd = MEI_NFC_CMD_MAINTENANCE;
+ cmd->hdr.data_size = 3;
+ cmd->sub_command = MEI_NFC_SUBCMD_CONNECT;
+ connect->fw_ivn = phy->fw_ivn;
+ connect->vendor_id = phy->vendor_id;
+
+ MEI_DUMP_NFC_HDR("connect request", &cmd->hdr);
+ r = mei_cl_send(phy->device, (u8 *)cmd, connect_length);
+ if (r < 0) {
+ pr_err("Could not send connect cmd %d\n", r);
+ goto err;
+ }
+
+ bytes_recv = mei_cl_recv(phy->device, (u8 *)reply, connect_resp_length);
+ if (bytes_recv < 0) {
+ r = bytes_recv;
+ pr_err("Could not read connect response %d\n", r);
+ goto err;
+ }
+
+ MEI_DUMP_NFC_HDR("connect reply", &reply->hdr);
+
+ pr_info("IVN 0x%x Vendor ID 0x%x\n",
+ connect_resp->fw_ivn, connect_resp->vendor_id);
+
+ pr_info("ME FW %d.%d.%d.%d\n",
+ connect_resp->me_major, connect_resp->me_minor,
+ connect_resp->me_hotfix, connect_resp->me_build);
+
+ r = 0;
+
+err:
+ kfree(reply);
+ kfree(cmd);
+
+ return r;
+}
+
+static int mei_nfc_send(struct nfc_mei_phy *phy, u8 *buf, size_t length)
+{
+ struct mei_nfc_hdr *hdr;
+ u8 *mei_buf;
+ int err;
+
+ err = -ENOMEM;
+ mei_buf = kzalloc(length + MEI_NFC_HEADER_SIZE, GFP_KERNEL);
+ if (!mei_buf)
+ goto out;
+
+ hdr = (struct mei_nfc_hdr *)mei_buf;
+ hdr->cmd = MEI_NFC_CMD_HCI_SEND;
+ hdr->status = 0;
+ hdr->req_id = phy->req_id;
+ hdr->reserved = 0;
+ hdr->data_size = length;
+
+ MEI_DUMP_NFC_HDR("send", hdr);
+
+ memcpy(mei_buf + MEI_NFC_HEADER_SIZE, buf, length);
+ err = mei_cl_send(phy->device, mei_buf, length + MEI_NFC_HEADER_SIZE);
+ if (err < 0)
+ goto out;
+
+ if (!wait_event_interruptible_timeout(phy->send_wq,
+ phy->recv_req_id == phy->req_id, HZ)) {
+ pr_err("NFC MEI command timeout\n");
+ err = -ETIME;
+ } else {
+ phy->req_id++;
+ }
+out:
+ kfree(mei_buf);
+ return err;
}
-EXPORT_SYMBOL_GPL(nfc_mei_phy_disable);
/*
* Writing a frame must not return the number of written bytes.
@@ -103,14 +266,38 @@ static int nfc_mei_phy_write(void *phy_id, struct sk_buff *skb)
MEI_DUMP_SKB_OUT("mei frame sent", skb);
- r = mei_cl_send(phy->device, skb->data, skb->len);
+ r = mei_nfc_send(phy, skb->data, skb->len);
if (r > 0)
r = 0;
return r;
}
-void nfc_mei_event_cb(struct mei_cl_device *device, u32 events, void *context)
+static int mei_nfc_recv(struct nfc_mei_phy *phy, u8 *buf, size_t length)
+{
+ struct mei_nfc_hdr *hdr;
+ int received_length;
+
+ received_length = mei_cl_recv(phy->device, buf, length);
+ if (received_length < 0)
+ return received_length;
+
+ hdr = (struct mei_nfc_hdr *) buf;
+
+ MEI_DUMP_NFC_HDR("receive", hdr);
+ if (hdr->cmd == MEI_NFC_CMD_HCI_SEND) {
+ phy->recv_req_id = hdr->req_id;
+ wake_up(&phy->send_wq);
+
+ return 0;
+ }
+
+ return received_length;
+}
+
+
+static void nfc_mei_event_cb(struct mei_cl_device *device, u32 events,
+ void *context)
{
struct nfc_mei_phy *phy = context;
@@ -125,7 +312,7 @@ void nfc_mei_event_cb(struct mei_cl_device *device, u32 events, void *context)
if (!skb)
return;
- reply_size = mei_cl_recv(device, skb->data, MEI_NFC_MAX_READ);
+ reply_size = mei_nfc_recv(phy, skb->data, MEI_NFC_MAX_READ);
if (reply_size < MEI_NFC_HEADER_SIZE) {
kfree_skb(skb);
return;
@@ -139,7 +326,61 @@ void nfc_mei_event_cb(struct mei_cl_device *device, u32 events, void *context)
nfc_hci_recv_frame(phy->hdev, skb);
}
}
-EXPORT_SYMBOL_GPL(nfc_mei_event_cb);
+
+static int nfc_mei_phy_enable(void *phy_id)
+{
+ int r;
+ struct nfc_mei_phy *phy = phy_id;
+
+ pr_info("%s\n", __func__);
+
+ if (phy->powered == 1)
+ return 0;
+
+ r = mei_cl_enable_device(phy->device);
+ if (r < 0) {
+ pr_err("Could not enable device %d\n", r);
+ return r;
+ }
+
+ r = mei_nfc_if_version(phy);
+ if (r < 0) {
+ pr_err("Could not enable device %d\n", r);
+ goto err;
+ }
+
+ r = mei_nfc_connect(phy);
+ if (r < 0) {
+ pr_err("Could not connect to device %d\n", r);
+ goto err;
+ }
+
+ r = mei_cl_register_event_cb(phy->device, nfc_mei_event_cb, phy);
+ if (r) {
+ pr_err("Event cb registration failed %d\n", r);
+ goto err;
+ }
+
+ phy->powered = 1;
+
+ return 0;
+
+err:
+ phy->powered = 0;
+ mei_cl_disable_device(phy->device);
+ return r;
+}
+
+static void nfc_mei_phy_disable(void *phy_id)
+{
+ struct nfc_mei_phy *phy = phy_id;
+
+ pr_info("%s\n", __func__);
+
+ mei_cl_disable_device(phy->device);
+
+ phy->powered = 0;
+}
struct nfc_phy_ops mei_phy_ops = {
.write = nfc_mei_phy_write,
@@ -157,6 +398,7 @@ struct nfc_mei_phy *nfc_mei_phy_alloc(struct mei_cl_device *device)
return NULL;
phy->device = device;
+ init_waitqueue_head(&phy->send_wq);
mei_cl_set_drvdata(device, phy);
return phy;
@@ -165,6 +407,7 @@ EXPORT_SYMBOL_GPL(nfc_mei_phy_alloc);
void nfc_mei_phy_free(struct nfc_mei_phy *phy)
{
+ mei_cl_disable_device(phy->device);
kfree(phy);
}
EXPORT_SYMBOL_GPL(nfc_mei_phy_free);
diff --git a/drivers/nfc/mei_phy.h b/drivers/nfc/mei_phy.h
index d669900f8..fbfa3e617 100644
--- a/drivers/nfc/mei_phy.h
+++ b/drivers/nfc/mei_phy.h
@@ -3,27 +3,49 @@
#include <linux/mei_cl_bus.h>
#include <net/nfc/hci.h>
+#include <linux/uuid.h>
+#define MEI_NFC_UUID UUID_LE(0x0bb17a78, 0x2a8e, 0x4c50, \
+ 0x94, 0xd4, 0x50, 0x26, 0x67, 0x23, 0x77, 0x5c)
#define MEI_NFC_HEADER_SIZE 10
#define MEI_NFC_MAX_HCI_PAYLOAD 300
+/**
+ * struct nfc_mei_phy
+ *
+ * @device: mei device
+ * @hdev: nfc hci device
+
+ * @send_wq: send completion wait queue
+ * @fw_ivn: NFC Interface Version Number
+ * @vendor_id: NFC manufacturer ID
+ * @radio_type: NFC radio type
+ * @reserved: reserved for alignment
+ * @req_id: message counter
+ * @recv_req_id: reception message counter
+ * @powered: the device is in powered state
+ * @hard_fault: < 0 if hardware error occurred
+ * and prevents normal operation.
+ */
struct nfc_mei_phy {
struct mei_cl_device *device;
struct nfc_hci_dev *hdev;
- int powered;
+ wait_queue_head_t send_wq;
+ u8 fw_ivn;
+ u8 vendor_id;
+ u8 radio_type;
+ u8 reserved;
+
+ u16 req_id;
+ u16 recv_req_id;
- int hard_fault; /*
- * < 0 if hardware error occured
- * and prevents normal operation.
- */
+ int powered;
+ int hard_fault;
};
extern struct nfc_phy_ops mei_phy_ops;
-int nfc_mei_phy_enable(void *phy_id);
-void nfc_mei_phy_disable(void *phy_id);
-void nfc_mei_event_cb(struct mei_cl_device *device, u32 events, void *context);
struct nfc_mei_phy *nfc_mei_phy_alloc(struct mei_cl_device *device);
void nfc_mei_phy_free(struct nfc_mei_phy *phy);
diff --git a/drivers/nfc/microread/i2c.c b/drivers/nfc/microread/i2c.c
index 661e2c814..daf352597 100644
--- a/drivers/nfc/microread/i2c.c
+++ b/drivers/nfc/microread/i2c.c
@@ -211,7 +211,6 @@ flush:
static irqreturn_t microread_i2c_irq_thread_fn(int irq, void *phy_id)
{
struct microread_i2c_phy *phy = phy_id;
- struct i2c_client *client;
struct sk_buff *skb = NULL;
int r;
@@ -220,8 +219,6 @@ static irqreturn_t microread_i2c_irq_thread_fn(int irq, void *phy_id)
return IRQ_NONE;
}
- client = phy->i2c_dev;
-
if (phy->hard_fault != 0)
return IRQ_HANDLED;
diff --git a/drivers/nfc/microread/mei.c b/drivers/nfc/microread/mei.c
index 2d1395be6..f9f5fc97c 100644
--- a/drivers/nfc/microread/mei.c
+++ b/drivers/nfc/microread/mei.c
@@ -67,7 +67,7 @@ static int microread_mei_remove(struct mei_cl_device *device)
}
static struct mei_cl_device_id microread_mei_tbl[] = {
- { MICROREAD_DRIVER_NAME },
+ { MICROREAD_DRIVER_NAME, MEI_NFC_UUID},
/* required last entry */
{ }
diff --git a/drivers/nfc/nfcmrvl/Kconfig b/drivers/nfc/nfcmrvl/Kconfig
index 5e18afd9a..796be2411 100644
--- a/drivers/nfc/nfcmrvl/Kconfig
+++ b/drivers/nfc/nfcmrvl/Kconfig
@@ -21,3 +21,14 @@ config NFC_MRVL_USB
Say Y here to compile support for Marvell NFC-over-USB driver
into the kernel or say M to compile it as module.
+
+config NFC_MRVL_UART
+ tristate "Marvell NFC-over-UART driver"
+ depends on NFC_MRVL && NFC_NCI_UART
+ help
+ Marvell NFC-over-UART driver.
+
+ This driver provides support for Marvell NFC-over-UART devices
+
+ Say Y here to compile support for Marvell NFC-over-UART driver
+ into the kernel or say M to compile it as module.
diff --git a/drivers/nfc/nfcmrvl/Makefile b/drivers/nfc/nfcmrvl/Makefile
index 97a0de72d..775196274 100644
--- a/drivers/nfc/nfcmrvl/Makefile
+++ b/drivers/nfc/nfcmrvl/Makefile
@@ -7,3 +7,6 @@ obj-$(CONFIG_NFC_MRVL) += nfcmrvl.o
nfcmrvl_usb-y += usb.o
obj-$(CONFIG_NFC_MRVL_USB) += nfcmrvl_usb.o
+
+nfcmrvl_uart-y += uart.o
+obj-$(CONFIG_NFC_MRVL_UART) += nfcmrvl_uart.o
diff --git a/drivers/nfc/nfcmrvl/main.c b/drivers/nfc/nfcmrvl/main.c
index ad4933cef..4a8866d62 100644
--- a/drivers/nfc/nfcmrvl/main.c
+++ b/drivers/nfc/nfcmrvl/main.c
@@ -17,6 +17,9 @@
*/
#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/of_gpio.h>
#include <linux/nfc.h>
#include <net/nfc/nci.h>
#include <net/nfc/nci_core.h>
@@ -63,20 +66,25 @@ static int nfcmrvl_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
if (!test_bit(NFCMRVL_NCI_RUNNING, &priv->flags))
return -EBUSY;
+ if (priv->config.hci_muxed) {
+ unsigned char *hdr;
+ unsigned char len = skb->len;
+
+ hdr = (char *) skb_push(skb, NFCMRVL_HCI_EVENT_HEADER_SIZE);
+ hdr[0] = NFCMRVL_HCI_COMMAND_CODE;
+ hdr[1] = NFCMRVL_HCI_OGF;
+ hdr[2] = NFCMRVL_HCI_OCF;
+ hdr[3] = len;
+ }
+
return priv->if_ops->nci_send(priv, skb);
}
static int nfcmrvl_nci_setup(struct nci_dev *ndev)
{
- __u8 val;
-
- val = NFCMRVL_GPIO_PIN_NFC_NOT_ALLOWED;
- nci_set_config(ndev, NFCMRVL_NOT_ALLOWED_ID, 1, &val);
- val = NFCMRVL_GPIO_PIN_NFC_ACTIVE;
- nci_set_config(ndev, NFCMRVL_ACTIVE_ID, 1, &val);
- val = NFCMRVL_EXT_COEX_ENABLE;
- nci_set_config(ndev, NFCMRVL_EXT_COEX_ID, 1, &val);
+ __u8 val = 1;
+ nci_set_config(ndev, NFCMRVL_PB_BAIL_OUT, 1, &val);
return 0;
}
@@ -88,11 +96,13 @@ static struct nci_ops nfcmrvl_nci_ops = {
};
struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data,
- struct nfcmrvl_if_ops *ops,
- struct device *dev)
+ struct nfcmrvl_if_ops *ops,
+ struct device *dev,
+ struct nfcmrvl_platform_data *pdata)
{
struct nfcmrvl_private *priv;
int rc;
+ int headroom = 0;
u32 protocols;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
@@ -103,13 +113,30 @@ struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data,
priv->if_ops = ops;
priv->dev = dev;
+ memcpy(&priv->config, pdata, sizeof(*pdata));
+
+ if (priv->config.reset_n_io) {
+ rc = devm_gpio_request_one(dev,
+ priv->config.reset_n_io,
+ GPIOF_OUT_INIT_LOW,
+ "nfcmrvl_reset_n");
+ if (rc < 0)
+ nfc_err(dev, "failed to request reset_n io\n");
+ }
+
+ if (priv->config.hci_muxed)
+ headroom = NFCMRVL_HCI_EVENT_HEADER_SIZE;
+
protocols = NFC_PROTO_JEWEL_MASK
- | NFC_PROTO_MIFARE_MASK | NFC_PROTO_FELICA_MASK
+ | NFC_PROTO_MIFARE_MASK
+ | NFC_PROTO_FELICA_MASK
| NFC_PROTO_ISO14443_MASK
| NFC_PROTO_ISO14443_B_MASK
+ | NFC_PROTO_ISO15693_MASK
| NFC_PROTO_NFC_DEP_MASK;
- priv->ndev = nci_allocate_device(&nfcmrvl_nci_ops, protocols, 0, 0);
+ priv->ndev = nci_allocate_device(&nfcmrvl_nci_ops, protocols,
+ headroom, 0);
if (!priv->ndev) {
nfc_err(dev, "nci_allocate_device failed\n");
rc = -ENOMEM;
@@ -118,6 +145,8 @@ struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data,
nci_set_drvdata(priv->ndev, priv);
+ nfcmrvl_chip_reset(priv);
+
rc = nci_register_device(priv->ndev);
if (rc) {
nfc_err(dev, "nci_register_device failed %d\n", rc);
@@ -144,21 +173,84 @@ void nfcmrvl_nci_unregister_dev(struct nfcmrvl_private *priv)
}
EXPORT_SYMBOL_GPL(nfcmrvl_nci_unregister_dev);
-int nfcmrvl_nci_recv_frame(struct nfcmrvl_private *priv, void *data, int count)
+int nfcmrvl_nci_recv_frame(struct nfcmrvl_private *priv, struct sk_buff *skb)
{
- struct sk_buff *skb;
-
- skb = nci_skb_alloc(priv->ndev, count, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
+ if (priv->config.hci_muxed) {
+ if (skb->data[0] == NFCMRVL_HCI_EVENT_CODE &&
+ skb->data[1] == NFCMRVL_HCI_NFC_EVENT_CODE) {
+ /* Data packet, let's extract NCI payload */
+ skb_pull(skb, NFCMRVL_HCI_EVENT_HEADER_SIZE);
+ } else {
+ /* Skip this packet */
+ kfree_skb(skb);
+ return 0;
+ }
+ }
- memcpy(skb_put(skb, count), data, count);
- nci_recv_frame(priv->ndev, skb);
+ if (test_bit(NFCMRVL_NCI_RUNNING, &priv->flags))
+ nci_recv_frame(priv->ndev, skb);
+ else {
+ /* Drop this packet since nobody wants it */
+ kfree_skb(skb);
+ return 0;
+ }
- return count;
+ return 0;
}
EXPORT_SYMBOL_GPL(nfcmrvl_nci_recv_frame);
+void nfcmrvl_chip_reset(struct nfcmrvl_private *priv)
+{
+ /*
+ * This function does not take care if someone is using the device.
+ * To be improved.
+ */
+
+ if (priv->config.reset_n_io) {
+ nfc_info(priv->dev, "reset the chip\n");
+ gpio_set_value(priv->config.reset_n_io, 0);
+ usleep_range(5000, 10000);
+ gpio_set_value(priv->config.reset_n_io, 1);
+ } else
+ nfc_info(priv->dev, "no reset available on this interface\n");
+}
+
+#ifdef CONFIG_OF
+
+int nfcmrvl_parse_dt(struct device_node *node,
+ struct nfcmrvl_platform_data *pdata)
+{
+ int reset_n_io;
+
+ reset_n_io = of_get_named_gpio(node, "reset-n-io", 0);
+ if (reset_n_io < 0) {
+ pr_info("no reset-n-io config\n");
+ reset_n_io = 0;
+ } else if (!gpio_is_valid(reset_n_io)) {
+ pr_err("invalid reset-n-io GPIO\n");
+ return reset_n_io;
+ }
+ pdata->reset_n_io = reset_n_io;
+
+ if (of_find_property(node, "hci-muxed", NULL))
+ pdata->hci_muxed = 1;
+ else
+ pdata->hci_muxed = 0;
+
+ return 0;
+}
+
+#else
+
+int nfcmrvl_parse_dt(struct device_node *node,
+ struct nfcmrvl_platform_data *pdata)
+{
+ return -ENODEV;
+}
+
+#endif
+EXPORT_SYMBOL_GPL(nfcmrvl_parse_dt);
+
MODULE_AUTHOR("Marvell International Ltd.");
MODULE_DESCRIPTION("Marvell NFC driver ver " VERSION);
MODULE_VERSION(VERSION);
diff --git a/drivers/nfc/nfcmrvl/nfcmrvl.h b/drivers/nfc/nfcmrvl/nfcmrvl.h
index 54c4a956b..e5a7e5464 100644
--- a/drivers/nfc/nfcmrvl/nfcmrvl.h
+++ b/drivers/nfc/nfcmrvl/nfcmrvl.h
@@ -16,6 +16,11 @@
* this warranty disclaimer.
**/
+#ifndef _NFCMRVL_H_
+#define _NFCMRVL_H_
+
+#include <linux/platform_data/nfcmrvl.h>
+
/* Define private flags: */
#define NFCMRVL_NCI_RUNNING 1
@@ -27,11 +32,49 @@
#define NFCMRVL_GPIO_PIN_NFC_ACTIVE 0xB
#define NFCMRVL_NCI_MAX_EVENT_SIZE 260
+/*
+** NCI FW Parmaters
+*/
+
+#define NFCMRVL_PB_BAIL_OUT 0x11
+
+/*
+** HCI defines
+*/
+
+#define NFCMRVL_HCI_EVENT_HEADER_SIZE 0x04
+#define NFCMRVL_HCI_EVENT_CODE 0x04
+#define NFCMRVL_HCI_NFC_EVENT_CODE 0xFF
+#define NFCMRVL_HCI_COMMAND_CODE 0x01
+#define NFCMRVL_HCI_OGF 0x81
+#define NFCMRVL_HCI_OCF 0xFE
+
+enum nfcmrvl_phy {
+ NFCMRVL_PHY_USB = 0,
+ NFCMRVL_PHY_UART = 1,
+};
+
+
struct nfcmrvl_private {
- struct nci_dev *ndev;
+
unsigned long flags;
+
+ /* Platform configuration */
+ struct nfcmrvl_platform_data config;
+
+ struct nci_dev *ndev;
+
+ /*
+ ** PHY related information
+ */
+
+ /* PHY driver context */
void *drv_data;
+ /* PHY device */
struct device *dev;
+ /* PHY type */
+ enum nfcmrvl_phy phy;
+ /* Low level driver ops */
struct nfcmrvl_if_ops *if_ops;
};
@@ -42,7 +85,16 @@ struct nfcmrvl_if_ops {
};
void nfcmrvl_nci_unregister_dev(struct nfcmrvl_private *priv);
-int nfcmrvl_nci_recv_frame(struct nfcmrvl_private *priv, void *data, int count);
+int nfcmrvl_nci_recv_frame(struct nfcmrvl_private *priv, struct sk_buff *skb);
struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data,
- struct nfcmrvl_if_ops *ops,
- struct device *dev);
+ struct nfcmrvl_if_ops *ops,
+ struct device *dev,
+ struct nfcmrvl_platform_data *pdata);
+
+
+void nfcmrvl_chip_reset(struct nfcmrvl_private *priv);
+
+int nfcmrvl_parse_dt(struct device_node *node,
+ struct nfcmrvl_platform_data *pdata);
+
+#endif
diff --git a/drivers/nfc/nfcmrvl/uart.c b/drivers/nfc/nfcmrvl/uart.c
new file mode 100644
index 000000000..61442d652
--- /dev/null
+++ b/drivers/nfc/nfcmrvl/uart.c
@@ -0,0 +1,225 @@
+/**
+ * Marvell NFC-over-UART driver
+ *
+ * Copyright (C) 2015, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available on the worldwide web at
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/of_gpio.h>
+#include <net/nfc/nci.h>
+#include <net/nfc/nci_core.h>
+#include "nfcmrvl.h"
+
+static unsigned int hci_muxed;
+static unsigned int flow_control;
+static unsigned int break_control;
+static unsigned int reset_n_io;
+
+/*
+** NFCMRVL NCI OPS
+*/
+
+static int nfcmrvl_uart_nci_open(struct nfcmrvl_private *priv)
+{
+ return 0;
+}
+
+static int nfcmrvl_uart_nci_close(struct nfcmrvl_private *priv)
+{
+ return 0;
+}
+
+static int nfcmrvl_uart_nci_send(struct nfcmrvl_private *priv,
+ struct sk_buff *skb)
+{
+ struct nci_uart *nu = priv->drv_data;
+
+ return nu->ops.send(nu, skb);
+}
+
+static struct nfcmrvl_if_ops uart_ops = {
+ .nci_open = nfcmrvl_uart_nci_open,
+ .nci_close = nfcmrvl_uart_nci_close,
+ .nci_send = nfcmrvl_uart_nci_send,
+};
+
+#ifdef CONFIG_OF
+
+static int nfcmrvl_uart_parse_dt(struct device_node *node,
+ struct nfcmrvl_platform_data *pdata)
+{
+ struct device_node *matched_node;
+ int ret;
+
+ matched_node = of_find_compatible_node(node, NULL, "mrvl,nfc-uart");
+ if (!matched_node)
+ return -ENODEV;
+
+ ret = nfcmrvl_parse_dt(matched_node, pdata);
+ if (ret < 0) {
+ pr_err("Failed to get generic entries\n");
+ return ret;
+ }
+
+ if (of_find_property(matched_node, "flow-control", NULL))
+ pdata->flow_control = 1;
+ else
+ pdata->flow_control = 0;
+
+ if (of_find_property(matched_node, "break-control", NULL))
+ pdata->break_control = 1;
+ else
+ pdata->break_control = 0;
+
+ return 0;
+}
+
+#else
+
+static int nfcmrvl_uart_parse_dt(struct device_node *node,
+ struct nfcmrvl_platform_data *pdata)
+{
+ return -ENODEV;
+}
+
+#endif
+
+/*
+** NCI UART OPS
+*/
+
+static int nfcmrvl_nci_uart_open(struct nci_uart *nu)
+{
+ struct nfcmrvl_private *priv;
+ struct nfcmrvl_platform_data *pdata = NULL;
+ struct nfcmrvl_platform_data config;
+
+ /*
+ * Platform data cannot be used here since usually it is already used
+ * by low level serial driver. We can try to retrieve serial device
+ * and check if DT entries were added.
+ */
+
+ if (nu->tty->dev->parent && nu->tty->dev->parent->of_node)
+ if (nfcmrvl_uart_parse_dt(nu->tty->dev->parent->of_node,
+ &config) == 0)
+ pdata = &config;
+
+ if (!pdata) {
+ pr_info("No platform data / DT -> fallback to module params\n");
+ config.hci_muxed = hci_muxed;
+ config.reset_n_io = reset_n_io;
+ config.flow_control = flow_control;
+ config.break_control = break_control;
+ pdata = &config;
+ }
+
+ priv = nfcmrvl_nci_register_dev(nu, &uart_ops, nu->tty->dev, pdata);
+ if (IS_ERR(priv))
+ return PTR_ERR(priv);
+
+ priv->phy = NFCMRVL_PHY_UART;
+
+ nu->drv_data = priv;
+ nu->ndev = priv->ndev;
+
+ /* Set BREAK */
+ if (priv->config.break_control && nu->tty->ops->break_ctl)
+ nu->tty->ops->break_ctl(nu->tty, -1);
+
+ return 0;
+}
+
+static void nfcmrvl_nci_uart_close(struct nci_uart *nu)
+{
+ nfcmrvl_nci_unregister_dev((struct nfcmrvl_private *)nu->drv_data);
+}
+
+static int nfcmrvl_nci_uart_recv(struct nci_uart *nu, struct sk_buff *skb)
+{
+ return nfcmrvl_nci_recv_frame((struct nfcmrvl_private *)nu->drv_data,
+ skb);
+}
+
+static void nfcmrvl_nci_uart_tx_start(struct nci_uart *nu)
+{
+ struct nfcmrvl_private *priv = (struct nfcmrvl_private *)nu->drv_data;
+
+ /* Remove BREAK to wake up the NFCC */
+ if (priv->config.break_control && nu->tty->ops->break_ctl) {
+ nu->tty->ops->break_ctl(nu->tty, 0);
+ usleep_range(3000, 5000);
+ }
+}
+
+static void nfcmrvl_nci_uart_tx_done(struct nci_uart *nu)
+{
+ struct nfcmrvl_private *priv = (struct nfcmrvl_private *)nu->drv_data;
+
+ /*
+ ** To ensure that if the NFCC goes in DEEP SLEEP sate we can wake him
+ ** up. we set BREAK. Once we will be ready to send again we will remove
+ ** it.
+ */
+ if (priv->config.break_control && nu->tty->ops->break_ctl)
+ nu->tty->ops->break_ctl(nu->tty, -1);
+}
+
+static struct nci_uart nfcmrvl_nci_uart = {
+ .owner = THIS_MODULE,
+ .name = "nfcmrvl_uart",
+ .driver = NCI_UART_DRIVER_MARVELL,
+ .ops = {
+ .open = nfcmrvl_nci_uart_open,
+ .close = nfcmrvl_nci_uart_close,
+ .recv = nfcmrvl_nci_uart_recv,
+ .tx_start = nfcmrvl_nci_uart_tx_start,
+ .tx_done = nfcmrvl_nci_uart_tx_done,
+ }
+};
+
+/*
+** Module init
+*/
+
+static int nfcmrvl_uart_init_module(void)
+{
+ return nci_uart_register(&nfcmrvl_nci_uart);
+}
+
+static void nfcmrvl_uart_exit_module(void)
+{
+ nci_uart_unregister(&nfcmrvl_nci_uart);
+}
+
+module_init(nfcmrvl_uart_init_module);
+module_exit(nfcmrvl_uart_exit_module);
+
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_DESCRIPTION("Marvell NFC-over-UART");
+MODULE_LICENSE("GPL v2");
+
+module_param(flow_control, uint, 0);
+MODULE_PARM_DESC(flow_control, "Tell if UART needs flow control at init.");
+
+module_param(break_control, uint, 0);
+MODULE_PARM_DESC(break_control, "Tell if UART driver must drive break signal.");
+
+module_param(hci_muxed, uint, 0);
+MODULE_PARM_DESC(hci_muxed, "Tell if transport is muxed in HCI one.");
+
+module_param(reset_n_io, uint, 0);
+MODULE_PARM_DESC(reset_n_io, "GPIO that is wired to RESET_N signal.");
diff --git a/drivers/nfc/nfcmrvl/usb.c b/drivers/nfc/nfcmrvl/usb.c
index 6cf15c1a2..7d1fe436c 100644
--- a/drivers/nfc/nfcmrvl/usb.c
+++ b/drivers/nfc/nfcmrvl/usb.c
@@ -26,7 +26,8 @@
#define VERSION "1.0"
static struct usb_device_id nfcmrvl_table[] = {
- { USB_DEVICE_INTERFACE_CLASS(0x1286, 0x2046, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(0x1286, 0x2046,
+ USB_CLASS_VENDOR_SPEC, 4, 1) },
{ } /* Terminating entry */
};
@@ -69,18 +70,27 @@ static int nfcmrvl_inc_tx(struct nfcmrvl_usb_drv_data *drv_data)
static void nfcmrvl_bulk_complete(struct urb *urb)
{
struct nfcmrvl_usb_drv_data *drv_data = urb->context;
+ struct sk_buff *skb;
int err;
- dev_dbg(&drv_data->udev->dev, "urb %p status %d count %d",
+ dev_dbg(&drv_data->udev->dev, "urb %p status %d count %d\n",
urb, urb->status, urb->actual_length);
if (!test_bit(NFCMRVL_NCI_RUNNING, &drv_data->flags))
return;
if (!urb->status) {
- if (nfcmrvl_nci_recv_frame(drv_data->priv, urb->transfer_buffer,
- urb->actual_length) < 0)
- nfc_err(&drv_data->udev->dev, "corrupted Rx packet\n");
+ skb = nci_skb_alloc(drv_data->priv->ndev, urb->actual_length,
+ GFP_ATOMIC);
+ if (!skb) {
+ nfc_err(&drv_data->udev->dev, "failed to alloc mem\n");
+ } else {
+ memcpy(skb_put(skb, urb->actual_length),
+ urb->transfer_buffer, urb->actual_length);
+ if (nfcmrvl_nci_recv_frame(drv_data->priv, skb) < 0)
+ nfc_err(&drv_data->udev->dev,
+ "corrupted Rx packet\n");
+ }
}
if (!test_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags))
@@ -292,6 +302,10 @@ static int nfcmrvl_probe(struct usb_interface *intf,
struct nfcmrvl_private *priv;
int i;
struct usb_device *udev = interface_to_usbdev(intf);
+ struct nfcmrvl_platform_data config;
+
+ /* No configuration for USB */
+ memset(&config, 0, sizeof(config));
nfc_info(&udev->dev, "intf %p id %p\n", intf, id);
@@ -329,11 +343,12 @@ static int nfcmrvl_probe(struct usb_interface *intf,
init_usb_anchor(&drv_data->deferred);
priv = nfcmrvl_nci_register_dev(drv_data, &usb_ops,
- &drv_data->udev->dev);
+ &drv_data->udev->dev, &config);
if (IS_ERR(priv))
return PTR_ERR(priv);
drv_data->priv = priv;
+ drv_data->priv->phy = NFCMRVL_PHY_USB;
priv->dev = &drv_data->udev->dev;
usb_set_intfdata(intf, drv_data);
diff --git a/drivers/nfc/nxp-nci/Makefile b/drivers/nfc/nxp-nci/Makefile
index c008be30b..c9ec7869d 100644
--- a/drivers/nfc/nxp-nci/Makefile
+++ b/drivers/nfc/nxp-nci/Makefile
@@ -7,5 +7,3 @@ nxp-nci_i2c-objs = i2c.o
obj-$(CONFIG_NFC_NXP_NCI) += nxp-nci.o
obj-$(CONFIG_NFC_NXP_NCI_I2C) += nxp-nci_i2c.o
-
-ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
diff --git a/drivers/nfc/nxp-nci/i2c.c b/drivers/nfc/nxp-nci/i2c.c
index 17bd67dbe..2f77f1d03 100644
--- a/drivers/nfc/nxp-nci/i2c.c
+++ b/drivers/nfc/nxp-nci/i2c.c
@@ -2,8 +2,10 @@
* I2C link layer for the NXP NCI driver
*
* Copyright (C) 2014 NXP Semiconductors All rights reserved.
+ * Copyright (C) 2012-2015 Intel Corporation. All rights reserved.
*
* Authors: Clément Perrochaud <clement.perrochaud@nxp.com>
+ * Authors: Oleg Zhurakivskyy <oleg.zhurakivskyy@intel.com>
*
* Derived from PN544 device driver:
* Copyright (C) 2012 Intel Corporation. All rights reserved.
@@ -23,12 +25,14 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/nfc.h>
+#include <linux/gpio/consumer.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/platform_data/nxp-nci.h>
@@ -48,6 +52,7 @@ struct nxp_nci_i2c_phy {
unsigned int gpio_en;
unsigned int gpio_fw;
+ unsigned int gpio_irq;
int hard_fault; /*
* < 0 if hardware error occurred (e.g. i2c err)
@@ -308,6 +313,37 @@ static int nxp_nci_i2c_parse_devtree(struct i2c_client *client)
#endif
+static int nxp_nci_i2c_acpi_config(struct nxp_nci_i2c_phy *phy)
+{
+ struct i2c_client *client = phy->i2c_dev;
+ struct gpio_desc *gpiod_en, *gpiod_fw, *gpiod_irq;
+
+ gpiod_en = devm_gpiod_get_index(&client->dev, NULL, 2);
+ gpiod_fw = devm_gpiod_get_index(&client->dev, NULL, 1);
+ gpiod_irq = devm_gpiod_get_index(&client->dev, NULL, 0);
+
+ if (IS_ERR(gpiod_en) || IS_ERR(gpiod_fw) || IS_ERR(gpiod_irq)) {
+ nfc_err(&client->dev, "No GPIOs\n");
+ return -EINVAL;
+ }
+
+ gpiod_direction_output(gpiod_en, 0);
+ gpiod_direction_output(gpiod_fw, 0);
+ gpiod_direction_input(gpiod_irq);
+
+ client->irq = gpiod_to_irq(gpiod_irq);
+ if (client->irq < 0) {
+ nfc_err(&client->dev, "No IRQ\n");
+ return -EINVAL;
+ }
+
+ phy->gpio_en = desc_to_gpio(gpiod_en);
+ phy->gpio_fw = desc_to_gpio(gpiod_fw);
+ phy->gpio_irq = desc_to_gpio(gpiod_irq);
+
+ return 0;
+}
+
static int nxp_nci_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -343,6 +379,11 @@ static int nxp_nci_i2c_probe(struct i2c_client *client,
phy->gpio_en = pdata->gpio_en;
phy->gpio_fw = pdata->gpio_fw;
client->irq = pdata->irq;
+ } else if (ACPI_HANDLE(&client->dev)) {
+ r = nxp_nci_i2c_acpi_config(phy);
+ if (r < 0)
+ goto probe_exit;
+ goto nci_probe;
} else {
nfc_err(&client->dev, "No platform data\n");
r = -EINVAL;
@@ -359,6 +400,7 @@ static int nxp_nci_i2c_probe(struct i2c_client *client,
if (r < 0)
goto probe_exit;
+nci_probe:
r = nxp_nci_probe(phy, &client->dev, &i2c_phy_ops,
NXP_NCI_I2C_MAX_PAYLOAD, &phy->ndev);
if (r < 0)
@@ -397,10 +439,19 @@ static const struct of_device_id of_nxp_nci_i2c_match[] = {
};
MODULE_DEVICE_TABLE(of, of_nxp_nci_i2c_match);
+#ifdef CONFIG_ACPI
+static struct acpi_device_id acpi_id[] = {
+ { "NXP7471" },
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, acpi_id);
+#endif
+
static struct i2c_driver nxp_nci_i2c_driver = {
.driver = {
.name = NXP_NCI_I2C_DRIVER_NAME,
.owner = THIS_MODULE,
+ .acpi_match_table = ACPI_PTR(acpi_id),
.of_match_table = of_match_ptr(of_nxp_nci_i2c_match),
},
.probe = nxp_nci_i2c_probe,
@@ -413,3 +464,4 @@ module_i2c_driver(nxp_nci_i2c_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("I2C driver for NXP NCI NFC controllers");
MODULE_AUTHOR("Clément Perrochaud <clement.perrochaud@nxp.com>");
+MODULE_AUTHOR("Oleg Zhurakivskyy <oleg.zhurakivskyy@intel.com>");
diff --git a/drivers/nfc/pn544/i2c.c b/drivers/nfc/pn544/i2c.c
index 6acc85a0e..3629a7056 100644
--- a/drivers/nfc/pn544/i2c.c
+++ b/drivers/nfc/pn544/i2c.c
@@ -895,56 +895,35 @@ static int pn544_hci_i2c_acpi_request_resources(struct i2c_client *client)
return -ENODEV;
/* Get EN GPIO from ACPI */
- gpiod_en = devm_gpiod_get_index(dev, PN544_GPIO_NAME_EN, 1);
+ gpiod_en = devm_gpiod_get_index(dev, PN544_GPIO_NAME_EN, 1,
+ GPIOD_OUT_LOW);
if (IS_ERR(gpiod_en)) {
- nfc_err(dev,
- "Unable to get EN GPIO\n");
+ nfc_err(dev, "Unable to get EN GPIO\n");
return -ENODEV;
}
- phy->gpio_en = desc_to_gpio(gpiod_en);
-
- /* Configuration EN GPIO */
- ret = gpiod_direction_output(gpiod_en, 0);
- if (ret) {
- nfc_err(dev, "Fail EN pin direction\n");
- return ret;
- }
+ phy->gpio_en = desc_to_gpio(gpiod_en);
/* Get FW GPIO from ACPI */
- gpiod_fw = devm_gpiod_get_index(dev, PN544_GPIO_NAME_FW, 2);
+ gpiod_fw = devm_gpiod_get_index(dev, PN544_GPIO_NAME_FW, 2,
+ GPIOD_OUT_LOW);
if (IS_ERR(gpiod_fw)) {
- nfc_err(dev,
- "Unable to get FW GPIO\n");
+ nfc_err(dev, "Unable to get FW GPIO\n");
return -ENODEV;
}
- phy->gpio_fw = desc_to_gpio(gpiod_fw);
-
- /* Configuration FW GPIO */
- ret = gpiod_direction_output(gpiod_fw, 0);
- if (ret) {
- nfc_err(dev, "Fail FW pin direction\n");
- return ret;
- }
+ phy->gpio_fw = desc_to_gpio(gpiod_fw);
/* Get IRQ GPIO */
- gpiod_irq = devm_gpiod_get_index(dev, PN544_GPIO_NAME_IRQ, 0);
+ gpiod_irq = devm_gpiod_get_index(dev, PN544_GPIO_NAME_IRQ, 0,
+ GPIOD_IN);
if (IS_ERR(gpiod_irq)) {
- nfc_err(dev,
- "Unable to get IRQ GPIO\n");
+ nfc_err(dev, "Unable to get IRQ GPIO\n");
return -ENODEV;
}
phy->gpio_irq = desc_to_gpio(gpiod_irq);
- /* Configure IRQ GPIO */
- ret = gpiod_direction_input(gpiod_irq);
- if (ret) {
- nfc_err(dev, "Fail IRQ pin direction\n");
- return ret;
- }
-
/* Map the pin to an IRQ */
ret = gpiod_to_irq(gpiod_irq);
if (ret < 0) {
diff --git a/drivers/nfc/pn544/mei.c b/drivers/nfc/pn544/mei.c
index 330cd4031..101a37e12 100644
--- a/drivers/nfc/pn544/mei.c
+++ b/drivers/nfc/pn544/mei.c
@@ -67,7 +67,7 @@ static int pn544_mei_remove(struct mei_cl_device *device)
}
static struct mei_cl_device_id pn544_mei_tbl[] = {
- { PN544_DRIVER_NAME },
+ { PN544_DRIVER_NAME, MEI_NFC_UUID},
/* required last entry */
{ }
diff --git a/drivers/nfc/st-nci/Kconfig b/drivers/nfc/st-nci/Kconfig
new file mode 100644
index 000000000..fc3904c94
--- /dev/null
+++ b/drivers/nfc/st-nci/Kconfig
@@ -0,0 +1,23 @@
+config NFC_ST_NCI
+ tristate "STMicroelectronics ST NCI NFC driver"
+ depends on NFC_NCI
+ default n
+ ---help---
+ STMicroelectronics NFC NCI chips core driver. It implements the chipset
+ NCI logic and hooks into the NFC kernel APIs. Physical layers will
+ register against it.
+
+ To compile this driver as a module, choose m here. The module will
+ be called st-nci.
+ Say N if unsure.
+
+config NFC_ST_NCI_I2C
+ tristate "NFC ST NCI i2c support"
+ depends on NFC_ST_NCI && I2C
+ ---help---
+ This module adds support for an I2C interface to the
+ STMicroelectronics NFC NCI chips familly.
+ Select this if your platform is using the i2c bus.
+
+ If you choose to build a module, it'll be called st-nci_i2c.
+ Say N if unsure.
diff --git a/drivers/nfc/st-nci/Makefile b/drivers/nfc/st-nci/Makefile
new file mode 100644
index 000000000..0df157df3
--- /dev/null
+++ b/drivers/nfc/st-nci/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for ST21NFCB NCI based NFC driver
+#
+
+st-nci-objs = ndlc.o core.o st-nci_se.o
+obj-$(CONFIG_NFC_ST_NCI) += st-nci.o
+
+st-nci_i2c-objs = i2c.o
+obj-$(CONFIG_NFC_ST_NCI_I2C) += st-nci_i2c.o
diff --git a/drivers/nfc/st-nci/core.c b/drivers/nfc/st-nci/core.c
new file mode 100644
index 000000000..c419d3943
--- /dev/null
+++ b/drivers/nfc/st-nci/core.c
@@ -0,0 +1,179 @@
+/*
+ * NCI based Driver for STMicroelectronics NFC Chip
+ *
+ * Copyright (C) 2014-2015 STMicroelectronics SAS. 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 <linux/module.h>
+#include <linux/nfc.h>
+#include <net/nfc/nci.h>
+#include <net/nfc/nci_core.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+
+#include "st-nci.h"
+#include "st-nci_se.h"
+
+#define DRIVER_DESC "NCI NFC driver for ST_NCI"
+
+#define ST_NCI1_X_PROPRIETARY_ISO15693 0x83
+
+static int st_nci_init(struct nci_dev *ndev)
+{
+ struct nci_mode_set_cmd cmd;
+
+ cmd.cmd_type = ST_NCI_SET_NFC_MODE;
+ cmd.mode = 1;
+
+ return nci_prop_cmd(ndev, ST_NCI_CORE_PROP,
+ sizeof(struct nci_mode_set_cmd), (__u8 *)&cmd);
+}
+
+static int st_nci_open(struct nci_dev *ndev)
+{
+ struct st_nci_info *info = nci_get_drvdata(ndev);
+ int r;
+
+ if (test_and_set_bit(ST_NCI_RUNNING, &info->flags))
+ return 0;
+
+ r = ndlc_open(info->ndlc);
+ if (r)
+ clear_bit(ST_NCI_RUNNING, &info->flags);
+
+ return r;
+}
+
+static int st_nci_close(struct nci_dev *ndev)
+{
+ struct st_nci_info *info = nci_get_drvdata(ndev);
+
+ if (!test_bit(ST_NCI_RUNNING, &info->flags))
+ return 0;
+
+ ndlc_close(info->ndlc);
+
+ clear_bit(ST_NCI_RUNNING, &info->flags);
+
+ return 0;
+}
+
+static int st_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
+{
+ struct st_nci_info *info = nci_get_drvdata(ndev);
+
+ skb->dev = (void *)ndev;
+
+ if (!test_bit(ST_NCI_RUNNING, &info->flags))
+ return -EBUSY;
+
+ return ndlc_send(info->ndlc, skb);
+}
+
+static __u32 st_nci_get_rfprotocol(struct nci_dev *ndev,
+ __u8 rf_protocol)
+{
+ return rf_protocol == ST_NCI1_X_PROPRIETARY_ISO15693 ?
+ NFC_PROTO_ISO15693_MASK : 0;
+}
+
+static int st_nci_prop_rsp_packet(struct nci_dev *ndev,
+ struct sk_buff *skb)
+{
+ __u8 status = skb->data[0];
+
+ nci_req_complete(ndev, status);
+ return 0;
+}
+
+static struct nci_prop_ops st_nci_prop_ops[] = {
+ {
+ .opcode = nci_opcode_pack(NCI_GID_PROPRIETARY,
+ ST_NCI_CORE_PROP),
+ .rsp = st_nci_prop_rsp_packet,
+ },
+};
+
+static struct nci_ops st_nci_ops = {
+ .init = st_nci_init,
+ .open = st_nci_open,
+ .close = st_nci_close,
+ .send = st_nci_send,
+ .get_rfprotocol = st_nci_get_rfprotocol,
+ .discover_se = st_nci_discover_se,
+ .enable_se = st_nci_enable_se,
+ .disable_se = st_nci_disable_se,
+ .se_io = st_nci_se_io,
+ .hci_load_session = st_nci_hci_load_session,
+ .hci_event_received = st_nci_hci_event_received,
+ .hci_cmd_received = st_nci_hci_cmd_received,
+ .prop_ops = st_nci_prop_ops,
+ .n_prop_ops = ARRAY_SIZE(st_nci_prop_ops),
+};
+
+int st_nci_probe(struct llt_ndlc *ndlc, int phy_headroom,
+ int phy_tailroom)
+{
+ struct st_nci_info *info;
+ int r;
+ u32 protocols;
+
+ info = devm_kzalloc(ndlc->dev,
+ sizeof(struct st_nci_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ protocols = NFC_PROTO_JEWEL_MASK
+ | NFC_PROTO_MIFARE_MASK
+ | NFC_PROTO_FELICA_MASK
+ | NFC_PROTO_ISO14443_MASK
+ | NFC_PROTO_ISO14443_B_MASK
+ | NFC_PROTO_ISO15693_MASK
+ | NFC_PROTO_NFC_DEP_MASK;
+
+ ndlc->ndev = nci_allocate_device(&st_nci_ops, protocols,
+ phy_headroom, phy_tailroom);
+ if (!ndlc->ndev) {
+ pr_err("Cannot allocate nfc ndev\n");
+ return -ENOMEM;
+ }
+ info->ndlc = ndlc;
+
+ nci_set_drvdata(ndlc->ndev, info);
+
+ r = nci_register_device(ndlc->ndev);
+ if (r) {
+ pr_err("Cannot register nfc device to nci core\n");
+ nci_free_device(ndlc->ndev);
+ return r;
+ }
+
+ return st_nci_se_init(ndlc->ndev);
+}
+EXPORT_SYMBOL_GPL(st_nci_probe);
+
+void st_nci_remove(struct nci_dev *ndev)
+{
+ struct st_nci_info *info = nci_get_drvdata(ndev);
+
+ ndlc_close(info->ndlc);
+
+ nci_unregister_device(ndev);
+ nci_free_device(ndev);
+}
+EXPORT_SYMBOL_GPL(st_nci_remove);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/nfc/st21nfcb/i2c.c b/drivers/nfc/st-nci/i2c.c
index c44f8cf53..06175ce76 100644
--- a/drivers/nfc/st21nfcb/i2c.c
+++ b/drivers/nfc/st-nci/i2c.c
@@ -1,6 +1,6 @@
/*
- * I2C Link Layer for ST21NFCB NCI based Driver
- * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved.
+ * I2C Link Layer for ST NCI NFC controller familly based Driver
+ * Copyright (C) 2014-2015 STMicroelectronics SAS. 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,
@@ -25,7 +25,7 @@
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/nfc.h>
-#include <linux/platform_data/st21nfcb.h>
+#include <linux/platform_data/st_nci.h>
#include "ndlc.h"
@@ -35,25 +35,23 @@
#define ST21NFCB_FRAME_HEADROOM 1
#define ST21NFCB_FRAME_TAILROOM 0
-#define ST21NFCB_NCI_I2C_MIN_SIZE 4 /* PCB(1) + NCI Packet header(3) */
-#define ST21NFCB_NCI_I2C_MAX_SIZE 250 /* req 4.2.1 */
+#define ST_NCI_I2C_MIN_SIZE 4 /* PCB(1) + NCI Packet header(3) */
+#define ST_NCI_I2C_MAX_SIZE 250 /* req 4.2.1 */
-#define ST21NFCB_NCI_I2C_DRIVER_NAME "st21nfcb_nci_i2c"
+#define ST_NCI_I2C_DRIVER_NAME "st_nci_i2c"
-static struct i2c_device_id st21nfcb_nci_i2c_id_table[] = {
- {ST21NFCB_NCI_DRIVER_NAME, 0},
+static struct i2c_device_id st_nci_i2c_id_table[] = {
+ {ST_NCI_DRIVER_NAME, 0},
{}
};
-MODULE_DEVICE_TABLE(i2c, st21nfcb_nci_i2c_id_table);
+MODULE_DEVICE_TABLE(i2c, st_nci_i2c_id_table);
-struct st21nfcb_i2c_phy {
+struct st_nci_i2c_phy {
struct i2c_client *i2c_dev;
struct llt_ndlc *ndlc;
unsigned int gpio_reset;
unsigned int irq_polarity;
-
- int powered;
};
#define I2C_DUMP_SKB(info, skb) \
@@ -63,28 +61,26 @@ do { \
16, 1, (skb)->data, (skb)->len, 0); \
} while (0)
-static int st21nfcb_nci_i2c_enable(void *phy_id)
+static int st_nci_i2c_enable(void *phy_id)
{
- struct st21nfcb_i2c_phy *phy = phy_id;
+ struct st_nci_i2c_phy *phy = phy_id;
gpio_set_value(phy->gpio_reset, 0);
usleep_range(10000, 15000);
gpio_set_value(phy->gpio_reset, 1);
- phy->powered = 1;
usleep_range(80000, 85000);
+ if (phy->ndlc->powered == 0)
+ enable_irq(phy->i2c_dev->irq);
+
return 0;
}
-static void st21nfcb_nci_i2c_disable(void *phy_id)
+static void st_nci_i2c_disable(void *phy_id)
{
- struct st21nfcb_i2c_phy *phy = phy_id;
+ struct st_nci_i2c_phy *phy = phy_id;
- phy->powered = 0;
- /* reset chip in order to flush clf */
- gpio_set_value(phy->gpio_reset, 0);
- usleep_range(10000, 15000);
- gpio_set_value(phy->gpio_reset, 1);
+ disable_irq_nosync(phy->i2c_dev->irq);
}
/*
@@ -92,13 +88,13 @@ static void st21nfcb_nci_i2c_disable(void *phy_id)
* It must return either zero for success, or <0 for error.
* In addition, it must not alter the skb
*/
-static int st21nfcb_nci_i2c_write(void *phy_id, struct sk_buff *skb)
+static int st_nci_i2c_write(void *phy_id, struct sk_buff *skb)
{
int r = -1;
- struct st21nfcb_i2c_phy *phy = phy_id;
+ struct st_nci_i2c_phy *phy = phy_id;
struct i2c_client *client = phy->i2c_dev;
- I2C_DUMP_SKB("st21nfcb_nci_i2c_write", skb);
+ I2C_DUMP_SKB("st_nci_i2c_write", skb);
if (phy->ndlc->hard_fault != 0)
return phy->ndlc->hard_fault;
@@ -128,40 +124,40 @@ static int st21nfcb_nci_i2c_write(void *phy_id, struct sk_buff *skb)
* at end of read)
* -EREMOTEIO : i2c read error (fatal)
* -EBADMSG : frame was incorrect and discarded
- * (value returned from st21nfcb_nci_i2c_repack)
+ * (value returned from st_nci_i2c_repack)
* -EIO : if no ST21NFCB_SOF_EOF is found after reaching
* the read length end sequence
*/
-static int st21nfcb_nci_i2c_read(struct st21nfcb_i2c_phy *phy,
+static int st_nci_i2c_read(struct st_nci_i2c_phy *phy,
struct sk_buff **skb)
{
int r;
u8 len;
- u8 buf[ST21NFCB_NCI_I2C_MAX_SIZE];
+ u8 buf[ST_NCI_I2C_MAX_SIZE];
struct i2c_client *client = phy->i2c_dev;
- r = i2c_master_recv(client, buf, ST21NFCB_NCI_I2C_MIN_SIZE);
+ r = i2c_master_recv(client, buf, ST_NCI_I2C_MIN_SIZE);
if (r < 0) { /* Retry, chip was in standby */
usleep_range(1000, 4000);
- r = i2c_master_recv(client, buf, ST21NFCB_NCI_I2C_MIN_SIZE);
+ r = i2c_master_recv(client, buf, ST_NCI_I2C_MIN_SIZE);
}
- if (r != ST21NFCB_NCI_I2C_MIN_SIZE)
+ if (r != ST_NCI_I2C_MIN_SIZE)
return -EREMOTEIO;
len = be16_to_cpu(*(__be16 *) (buf + 2));
- if (len > ST21NFCB_NCI_I2C_MAX_SIZE) {
+ if (len > ST_NCI_I2C_MAX_SIZE) {
nfc_err(&client->dev, "invalid frame len\n");
return -EBADMSG;
}
- *skb = alloc_skb(ST21NFCB_NCI_I2C_MIN_SIZE + len, GFP_KERNEL);
+ *skb = alloc_skb(ST_NCI_I2C_MIN_SIZE + len, GFP_KERNEL);
if (*skb == NULL)
return -ENOMEM;
- skb_reserve(*skb, ST21NFCB_NCI_I2C_MIN_SIZE);
- skb_put(*skb, ST21NFCB_NCI_I2C_MIN_SIZE);
- memcpy((*skb)->data, buf, ST21NFCB_NCI_I2C_MIN_SIZE);
+ skb_reserve(*skb, ST_NCI_I2C_MIN_SIZE);
+ skb_put(*skb, ST_NCI_I2C_MIN_SIZE);
+ memcpy((*skb)->data, buf, ST_NCI_I2C_MIN_SIZE);
if (!len)
return 0;
@@ -173,7 +169,7 @@ static int st21nfcb_nci_i2c_read(struct st21nfcb_i2c_phy *phy,
}
skb_put(*skb, len);
- memcpy((*skb)->data + ST21NFCB_NCI_I2C_MIN_SIZE, buf, len);
+ memcpy((*skb)->data + ST_NCI_I2C_MIN_SIZE, buf, len);
I2C_DUMP_SKB("i2c frame read", *skb);
@@ -185,9 +181,9 @@ static int st21nfcb_nci_i2c_read(struct st21nfcb_i2c_phy *phy,
*
* On ST21NFCB, IRQ goes in idle state when read starts.
*/
-static irqreturn_t st21nfcb_nci_irq_thread_fn(int irq, void *phy_id)
+static irqreturn_t st_nci_irq_thread_fn(int irq, void *phy_id)
{
- struct st21nfcb_i2c_phy *phy = phy_id;
+ struct st_nci_i2c_phy *phy = phy_id;
struct i2c_client *client;
struct sk_buff *skb = NULL;
int r;
@@ -203,12 +199,12 @@ static irqreturn_t st21nfcb_nci_irq_thread_fn(int irq, void *phy_id)
if (phy->ndlc->hard_fault)
return IRQ_HANDLED;
- if (!phy->powered) {
- st21nfcb_nci_i2c_disable(phy);
+ if (!phy->ndlc->powered) {
+ st_nci_i2c_disable(phy);
return IRQ_HANDLED;
}
- r = st21nfcb_nci_i2c_read(phy, &skb);
+ r = st_nci_i2c_read(phy, &skb);
if (r == -EREMOTEIO || r == -ENOMEM || r == -EBADMSG)
return IRQ_HANDLED;
@@ -218,15 +214,15 @@ static irqreturn_t st21nfcb_nci_irq_thread_fn(int irq, void *phy_id)
}
static struct nfc_phy_ops i2c_phy_ops = {
- .write = st21nfcb_nci_i2c_write,
- .enable = st21nfcb_nci_i2c_enable,
- .disable = st21nfcb_nci_i2c_disable,
+ .write = st_nci_i2c_write,
+ .enable = st_nci_i2c_enable,
+ .disable = st_nci_i2c_disable,
};
#ifdef CONFIG_OF
-static int st21nfcb_nci_i2c_of_request_resources(struct i2c_client *client)
+static int st_nci_i2c_of_request_resources(struct i2c_client *client)
{
- struct st21nfcb_i2c_phy *phy = i2c_get_clientdata(client);
+ struct st_nci_i2c_phy *phy = i2c_get_clientdata(client);
struct device_node *pp;
int gpio;
int r;
@@ -257,16 +253,16 @@ static int st21nfcb_nci_i2c_of_request_resources(struct i2c_client *client)
return 0;
}
#else
-static int st21nfcb_nci_i2c_of_request_resources(struct i2c_client *client)
+static int st_nci_i2c_of_request_resources(struct i2c_client *client)
{
return -ENODEV;
}
#endif
-static int st21nfcb_nci_i2c_request_resources(struct i2c_client *client)
+static int st_nci_i2c_request_resources(struct i2c_client *client)
{
- struct st21nfcb_nfc_platform_data *pdata;
- struct st21nfcb_i2c_phy *phy = i2c_get_clientdata(client);
+ struct st_nci_nfc_platform_data *pdata;
+ struct st_nci_i2c_phy *phy = i2c_get_clientdata(client);
int r;
pdata = client->dev.platform_data;
@@ -289,11 +285,11 @@ static int st21nfcb_nci_i2c_request_resources(struct i2c_client *client)
return 0;
}
-static int st21nfcb_nci_i2c_probe(struct i2c_client *client,
+static int st_nci_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct st21nfcb_i2c_phy *phy;
- struct st21nfcb_nfc_platform_data *pdata;
+ struct st_nci_i2c_phy *phy;
+ struct st_nci_nfc_platform_data *pdata;
int r;
dev_dbg(&client->dev, "%s\n", __func__);
@@ -304,7 +300,7 @@ static int st21nfcb_nci_i2c_probe(struct i2c_client *client,
return -ENODEV;
}
- phy = devm_kzalloc(&client->dev, sizeof(struct st21nfcb_i2c_phy),
+ phy = devm_kzalloc(&client->dev, sizeof(struct st_nci_i2c_phy),
GFP_KERNEL);
if (!phy)
return -ENOMEM;
@@ -315,13 +311,13 @@ static int st21nfcb_nci_i2c_probe(struct i2c_client *client,
pdata = client->dev.platform_data;
if (!pdata && client->dev.of_node) {
- r = st21nfcb_nci_i2c_of_request_resources(client);
+ r = st_nci_i2c_of_request_resources(client);
if (r) {
nfc_err(&client->dev, "No platform data\n");
return r;
}
} else if (pdata) {
- r = st21nfcb_nci_i2c_request_resources(client);
+ r = st_nci_i2c_request_resources(client);
if (r) {
nfc_err(&client->dev,
"Cannot get platform resources\n");
@@ -342,18 +338,18 @@ static int st21nfcb_nci_i2c_probe(struct i2c_client *client,
}
r = devm_request_threaded_irq(&client->dev, client->irq, NULL,
- st21nfcb_nci_irq_thread_fn,
+ st_nci_irq_thread_fn,
phy->irq_polarity | IRQF_ONESHOT,
- ST21NFCB_NCI_DRIVER_NAME, phy);
+ ST_NCI_DRIVER_NAME, phy);
if (r < 0)
nfc_err(&client->dev, "Unable to register IRQ handler\n");
return r;
}
-static int st21nfcb_nci_i2c_remove(struct i2c_client *client)
+static int st_nci_i2c_remove(struct i2c_client *client)
{
- struct st21nfcb_i2c_phy *phy = i2c_get_clientdata(client);
+ struct st_nci_i2c_phy *phy = i2c_get_clientdata(client);
dev_dbg(&client->dev, "%s\n", __func__);
@@ -363,26 +359,27 @@ static int st21nfcb_nci_i2c_remove(struct i2c_client *client)
}
#ifdef CONFIG_OF
-static const struct of_device_id of_st21nfcb_i2c_match[] = {
+static const struct of_device_id of_st_nci_i2c_match[] = {
{ .compatible = "st,st21nfcb-i2c", },
{ .compatible = "st,st21nfcb_i2c", },
+ { .compatible = "st,st21nfcc-i2c", },
{}
};
-MODULE_DEVICE_TABLE(of, of_st21nfcb_i2c_match);
+MODULE_DEVICE_TABLE(of, of_st_nci_i2c_match);
#endif
-static struct i2c_driver st21nfcb_nci_i2c_driver = {
+static struct i2c_driver st_nci_i2c_driver = {
.driver = {
.owner = THIS_MODULE,
- .name = ST21NFCB_NCI_I2C_DRIVER_NAME,
- .of_match_table = of_match_ptr(of_st21nfcb_i2c_match),
+ .name = ST_NCI_I2C_DRIVER_NAME,
+ .of_match_table = of_match_ptr(of_st_nci_i2c_match),
},
- .probe = st21nfcb_nci_i2c_probe,
- .id_table = st21nfcb_nci_i2c_id_table,
- .remove = st21nfcb_nci_i2c_remove,
+ .probe = st_nci_i2c_probe,
+ .id_table = st_nci_i2c_id_table,
+ .remove = st_nci_i2c_remove,
};
-module_i2c_driver(st21nfcb_nci_i2c_driver);
+module_i2c_driver(st_nci_i2c_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/nfc/st21nfcb/ndlc.c b/drivers/nfc/st-nci/ndlc.c
index 6014b5859..56c6a4cb4 100644
--- a/drivers/nfc/st21nfcb/ndlc.c
+++ b/drivers/nfc/st-nci/ndlc.c
@@ -1,7 +1,7 @@
/*
* Low Level Transport (NDLC) Driver for STMicroelectronics NFC Chip
*
- * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved.
+ * Copyright (C) 2014-2015 STMicroelectronics SAS. 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,
@@ -20,7 +20,7 @@
#include <net/nfc/nci_core.h>
#include "ndlc.h"
-#include "st21nfcb.h"
+#include "st-nci.h"
#define NDLC_TIMER_T1 100
#define NDLC_TIMER_T1_WAIT 400
@@ -59,13 +59,25 @@ int ndlc_open(struct llt_ndlc *ndlc)
{
/* toggle reset pin */
ndlc->ops->enable(ndlc->phy_id);
+ ndlc->powered = 1;
return 0;
}
EXPORT_SYMBOL(ndlc_open);
void ndlc_close(struct llt_ndlc *ndlc)
{
+ struct nci_mode_set_cmd cmd;
+
+ cmd.cmd_type = ST_NCI_SET_NFC_MODE;
+ cmd.mode = 0;
+
/* toggle reset pin */
+ ndlc->ops->enable(ndlc->phy_id);
+
+ nci_prop_cmd(ndlc->ndev, ST_NCI_CORE_PROP,
+ sizeof(struct nci_mode_set_cmd), (__u8 *)&cmd);
+
+ ndlc->powered = 0;
ndlc->ops->disable(ndlc->phy_id);
}
EXPORT_SYMBOL(ndlc_close);
@@ -262,6 +274,7 @@ int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev,
ndlc->ops = phy_ops;
ndlc->phy_id = phy_id;
ndlc->dev = dev;
+ ndlc->powered = 0;
*ndlc_id = ndlc;
@@ -280,12 +293,14 @@ int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev,
INIT_WORK(&ndlc->sm_work, llt_ndlc_sm_work);
- return st21nfcb_nci_probe(ndlc, phy_headroom, phy_tailroom);
+ return st_nci_probe(ndlc, phy_headroom, phy_tailroom);
}
EXPORT_SYMBOL(ndlc_probe);
void ndlc_remove(struct llt_ndlc *ndlc)
{
+ st_nci_remove(ndlc->ndev);
+
/* cancel timers */
del_timer_sync(&ndlc->t1_timer);
del_timer_sync(&ndlc->t2_timer);
@@ -294,7 +309,5 @@ void ndlc_remove(struct llt_ndlc *ndlc)
skb_queue_purge(&ndlc->rcv_q);
skb_queue_purge(&ndlc->send_q);
-
- st21nfcb_nci_remove(ndlc->ndev);
}
EXPORT_SYMBOL(ndlc_remove);
diff --git a/drivers/nfc/st21nfcb/ndlc.h b/drivers/nfc/st-nci/ndlc.h
index b28140e0c..6361005ef 100644
--- a/drivers/nfc/st21nfcb/ndlc.h
+++ b/drivers/nfc/st-nci/ndlc.h
@@ -1,7 +1,7 @@
/*
* NCI based Driver for STMicroelectronics NFC Chip
*
- * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved.
+ * Copyright (C) 2014-2015 STMicroelectronics SAS. 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,
@@ -43,10 +43,11 @@ struct llt_ndlc {
struct device *dev;
/*
- * < 0 if hardware error occured
+ * < 0 if hardware error occurred
* and prevents normal operation.
*/
int hard_fault;
+ int powered;
};
int ndlc_open(struct llt_ndlc *ndlc);
diff --git a/drivers/nfc/st21nfcb/st21nfcb.h b/drivers/nfc/st-nci/st-nci.h
index 5ef8a58c9..850a2395d 100644
--- a/drivers/nfc/st21nfcb/st21nfcb.h
+++ b/drivers/nfc/st-nci/st-nci.h
@@ -16,23 +16,35 @@
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef __LOCAL_ST21NFCB_H_
-#define __LOCAL_ST21NFCB_H_
+#ifndef __LOCAL_ST_NCI_H_
+#define __LOCAL_ST_NCI_H_
-#include "st21nfcb_se.h"
+#include "st-nci_se.h"
#include "ndlc.h"
/* Define private flags: */
-#define ST21NFCB_NCI_RUNNING 1
+#define ST_NCI_RUNNING 1
-struct st21nfcb_nci_info {
+#define ST_NCI_CORE_PROP 0x01
+#define ST_NCI_SET_NFC_MODE 0x02
+
+struct nci_mode_set_cmd {
+ u8 cmd_type;
+ u8 mode;
+} __packed;
+
+struct nci_mode_set_rsp {
+ u8 status;
+} __packed;
+
+struct st_nci_info {
struct llt_ndlc *ndlc;
unsigned long flags;
- struct st21nfcb_se_info se_info;
+ struct st_nci_se_info se_info;
};
-void st21nfcb_nci_remove(struct nci_dev *ndev);
-int st21nfcb_nci_probe(struct llt_ndlc *ndlc, int phy_headroom,
+void st_nci_remove(struct nci_dev *ndev);
+int st_nci_probe(struct llt_ndlc *ndlc, int phy_headroom,
int phy_tailroom);
-#endif /* __LOCAL_ST21NFCB_H_ */
+#endif /* __LOCAL_ST_NCI_H_ */
diff --git a/drivers/nfc/st21nfcb/st21nfcb_se.c b/drivers/nfc/st-nci/st-nci_se.c
index 24862a525..97addfa96 100644
--- a/drivers/nfc/st21nfcb/st21nfcb_se.c
+++ b/drivers/nfc/st-nci/st-nci_se.c
@@ -1,7 +1,7 @@
/*
- * NCI based Driver for STMicroelectronics NFC Chip
+ * Secure Element driver for STMicroelectronics NFC NCI chip
*
- * Copyright (C) 2014 STMicroelectronics SAS. All rights reserved.
+ * Copyright (C) 2014-2015 STMicroelectronics SAS. 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,
@@ -22,10 +22,10 @@
#include <net/nfc/nci.h>
#include <net/nfc/nci_core.h>
-#include "st21nfcb.h"
-#include "st21nfcb_se.h"
+#include "st-nci.h"
+#include "st-nci_se.h"
-struct st21nfcb_pipe_info {
+struct st_nci_pipe_info {
u8 pipe_state;
u8 src_host_id;
u8 src_gate_id;
@@ -34,166 +34,166 @@ struct st21nfcb_pipe_info {
} __packed;
/* Hosts */
-#define ST21NFCB_HOST_CONTROLLER_ID 0x00
-#define ST21NFCB_TERMINAL_HOST_ID 0x01
-#define ST21NFCB_UICC_HOST_ID 0x02
-#define ST21NFCB_ESE_HOST_ID 0xc0
+#define ST_NCI_HOST_CONTROLLER_ID 0x00
+#define ST_NCI_TERMINAL_HOST_ID 0x01
+#define ST_NCI_UICC_HOST_ID 0x02
+#define ST_NCI_ESE_HOST_ID 0xc0
/* Gates */
-#define ST21NFCB_DEVICE_MGNT_GATE 0x01
-#define ST21NFCB_APDU_READER_GATE 0xf0
-#define ST21NFCB_CONNECTIVITY_GATE 0x41
+#define ST_NCI_DEVICE_MGNT_GATE 0x01
+#define ST_NCI_APDU_READER_GATE 0xf0
+#define ST_NCI_CONNECTIVITY_GATE 0x41
/* Pipes */
-#define ST21NFCB_DEVICE_MGNT_PIPE 0x02
+#define ST_NCI_DEVICE_MGNT_PIPE 0x02
/* Connectivity pipe only */
-#define ST21NFCB_SE_COUNT_PIPE_UICC 0x01
+#define ST_NCI_SE_COUNT_PIPE_UICC 0x01
/* Connectivity + APDU Reader pipe */
-#define ST21NFCB_SE_COUNT_PIPE_EMBEDDED 0x02
+#define ST_NCI_SE_COUNT_PIPE_EMBEDDED 0x02
-#define ST21NFCB_SE_TO_HOT_PLUG 1000 /* msecs */
-#define ST21NFCB_SE_TO_PIPES 2000
+#define ST_NCI_SE_TO_HOT_PLUG 1000 /* msecs */
+#define ST_NCI_SE_TO_PIPES 2000
-#define ST21NFCB_EVT_HOT_PLUG_IS_INHIBITED(x) (x->data[0] & 0x80)
+#define ST_NCI_EVT_HOT_PLUG_IS_INHIBITED(x) (x->data[0] & 0x80)
#define NCI_HCI_APDU_PARAM_ATR 0x01
#define NCI_HCI_ADMIN_PARAM_SESSION_IDENTITY 0x01
#define NCI_HCI_ADMIN_PARAM_WHITELIST 0x03
#define NCI_HCI_ADMIN_PARAM_HOST_LIST 0x04
-#define ST21NFCB_EVT_SE_HARD_RESET 0x20
-#define ST21NFCB_EVT_TRANSMIT_DATA 0x10
-#define ST21NFCB_EVT_WTX_REQUEST 0x11
-#define ST21NFCB_EVT_SE_SOFT_RESET 0x11
-#define ST21NFCB_EVT_SE_END_OF_APDU_TRANSFER 0x21
-#define ST21NFCB_EVT_HOT_PLUG 0x03
+#define ST_NCI_EVT_SE_HARD_RESET 0x20
+#define ST_NCI_EVT_TRANSMIT_DATA 0x10
+#define ST_NCI_EVT_WTX_REQUEST 0x11
+#define ST_NCI_EVT_SE_SOFT_RESET 0x11
+#define ST_NCI_EVT_SE_END_OF_APDU_TRANSFER 0x21
+#define ST_NCI_EVT_HOT_PLUG 0x03
-#define ST21NFCB_SE_MODE_OFF 0x00
-#define ST21NFCB_SE_MODE_ON 0x01
+#define ST_NCI_SE_MODE_OFF 0x00
+#define ST_NCI_SE_MODE_ON 0x01
-#define ST21NFCB_EVT_CONNECTIVITY 0x10
-#define ST21NFCB_EVT_TRANSACTION 0x12
+#define ST_NCI_EVT_CONNECTIVITY 0x10
+#define ST_NCI_EVT_TRANSACTION 0x12
-#define ST21NFCB_DM_GETINFO 0x13
-#define ST21NFCB_DM_GETINFO_PIPE_LIST 0x02
-#define ST21NFCB_DM_GETINFO_PIPE_INFO 0x01
-#define ST21NFCB_DM_PIPE_CREATED 0x02
-#define ST21NFCB_DM_PIPE_OPEN 0x04
-#define ST21NFCB_DM_RF_ACTIVE 0x80
-#define ST21NFCB_DM_DISCONNECT 0x30
+#define ST_NCI_DM_GETINFO 0x13
+#define ST_NCI_DM_GETINFO_PIPE_LIST 0x02
+#define ST_NCI_DM_GETINFO_PIPE_INFO 0x01
+#define ST_NCI_DM_PIPE_CREATED 0x02
+#define ST_NCI_DM_PIPE_OPEN 0x04
+#define ST_NCI_DM_RF_ACTIVE 0x80
+#define ST_NCI_DM_DISCONNECT 0x30
-#define ST21NFCB_DM_IS_PIPE_OPEN(p) \
- ((p & 0x0f) == (ST21NFCB_DM_PIPE_CREATED | ST21NFCB_DM_PIPE_OPEN))
+#define ST_NCI_DM_IS_PIPE_OPEN(p) \
+ ((p & 0x0f) == (ST_NCI_DM_PIPE_CREATED | ST_NCI_DM_PIPE_OPEN))
-#define ST21NFCB_ATR_DEFAULT_BWI 0x04
+#define ST_NCI_ATR_DEFAULT_BWI 0x04
/*
* WT = 2^BWI/10[s], convert into msecs and add a secure
* room by increasing by 2 this timeout
*/
-#define ST21NFCB_BWI_TO_TIMEOUT(x) ((1 << x) * 200)
-#define ST21NFCB_ATR_GET_Y_FROM_TD(x) (x >> 4)
+#define ST_NCI_BWI_TO_TIMEOUT(x) ((1 << x) * 200)
+#define ST_NCI_ATR_GET_Y_FROM_TD(x) (x >> 4)
/* If TA is present bit 0 is set */
-#define ST21NFCB_ATR_TA_PRESENT(x) (x & 0x01)
+#define ST_NCI_ATR_TA_PRESENT(x) (x & 0x01)
/* If TB is present bit 1 is set */
-#define ST21NFCB_ATR_TB_PRESENT(x) (x & 0x02)
+#define ST_NCI_ATR_TB_PRESENT(x) (x & 0x02)
-#define ST21NFCB_NUM_DEVICES 256
+#define ST_NCI_NUM_DEVICES 256
-static DECLARE_BITMAP(dev_mask, ST21NFCB_NUM_DEVICES);
+static DECLARE_BITMAP(dev_mask, ST_NCI_NUM_DEVICES);
-/* Here are the mandatory pipe for st21nfcb */
-static struct nci_hci_gate st21nfcb_gates[] = {
+/* Here are the mandatory pipe for st_nci */
+static struct nci_hci_gate st_nci_gates[] = {
{NCI_HCI_ADMIN_GATE, NCI_HCI_ADMIN_PIPE,
- ST21NFCB_HOST_CONTROLLER_ID},
+ ST_NCI_HOST_CONTROLLER_ID},
{NCI_HCI_LINK_MGMT_GATE, NCI_HCI_LINK_MGMT_PIPE,
- ST21NFCB_HOST_CONTROLLER_ID},
- {ST21NFCB_DEVICE_MGNT_GATE, ST21NFCB_DEVICE_MGNT_PIPE,
- ST21NFCB_HOST_CONTROLLER_ID},
+ ST_NCI_HOST_CONTROLLER_ID},
+ {ST_NCI_DEVICE_MGNT_GATE, ST_NCI_DEVICE_MGNT_PIPE,
+ ST_NCI_HOST_CONTROLLER_ID},
/* Secure element pipes are created by secure element host */
- {ST21NFCB_CONNECTIVITY_GATE, NCI_HCI_DO_NOT_OPEN_PIPE,
- ST21NFCB_HOST_CONTROLLER_ID},
- {ST21NFCB_APDU_READER_GATE, NCI_HCI_DO_NOT_OPEN_PIPE,
- ST21NFCB_HOST_CONTROLLER_ID},
+ {ST_NCI_CONNECTIVITY_GATE, NCI_HCI_DO_NOT_OPEN_PIPE,
+ ST_NCI_HOST_CONTROLLER_ID},
+ {ST_NCI_APDU_READER_GATE, NCI_HCI_DO_NOT_OPEN_PIPE,
+ ST_NCI_HOST_CONTROLLER_ID},
};
-static u8 st21nfcb_se_get_bwi(struct nci_dev *ndev)
+static u8 st_nci_se_get_bwi(struct nci_dev *ndev)
{
int i;
u8 td;
- struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
+ struct st_nci_info *info = nci_get_drvdata(ndev);
/* Bits 8 to 5 of the first TB for T=1 encode BWI from zero to nine */
- for (i = 1; i < ST21NFCB_ESE_MAX_LENGTH; i++) {
- td = ST21NFCB_ATR_GET_Y_FROM_TD(info->se_info.atr[i]);
- if (ST21NFCB_ATR_TA_PRESENT(td))
+ for (i = 1; i < ST_NCI_ESE_MAX_LENGTH; i++) {
+ td = ST_NCI_ATR_GET_Y_FROM_TD(info->se_info.atr[i]);
+ if (ST_NCI_ATR_TA_PRESENT(td))
i++;
- if (ST21NFCB_ATR_TB_PRESENT(td)) {
+ if (ST_NCI_ATR_TB_PRESENT(td)) {
i++;
return info->se_info.atr[i] >> 4;
}
}
- return ST21NFCB_ATR_DEFAULT_BWI;
+ return ST_NCI_ATR_DEFAULT_BWI;
}
-static void st21nfcb_se_get_atr(struct nci_dev *ndev)
+static void st_nci_se_get_atr(struct nci_dev *ndev)
{
- struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
+ struct st_nci_info *info = nci_get_drvdata(ndev);
int r;
struct sk_buff *skb;
- r = nci_hci_get_param(ndev, ST21NFCB_APDU_READER_GATE,
+ r = nci_hci_get_param(ndev, ST_NCI_APDU_READER_GATE,
NCI_HCI_APDU_PARAM_ATR, &skb);
if (r < 0)
return;
- if (skb->len <= ST21NFCB_ESE_MAX_LENGTH) {
+ if (skb->len <= ST_NCI_ESE_MAX_LENGTH) {
memcpy(info->se_info.atr, skb->data, skb->len);
info->se_info.wt_timeout =
- ST21NFCB_BWI_TO_TIMEOUT(st21nfcb_se_get_bwi(ndev));
+ ST_NCI_BWI_TO_TIMEOUT(st_nci_se_get_bwi(ndev));
}
kfree_skb(skb);
}
-int st21nfcb_hci_load_session(struct nci_dev *ndev)
+int st_nci_hci_load_session(struct nci_dev *ndev)
{
int i, j, r;
struct sk_buff *skb_pipe_list, *skb_pipe_info;
- struct st21nfcb_pipe_info *dm_pipe_info;
- u8 pipe_list[] = { ST21NFCB_DM_GETINFO_PIPE_LIST,
- ST21NFCB_TERMINAL_HOST_ID};
- u8 pipe_info[] = { ST21NFCB_DM_GETINFO_PIPE_INFO,
- ST21NFCB_TERMINAL_HOST_ID, 0};
+ struct st_nci_pipe_info *dm_pipe_info;
+ u8 pipe_list[] = { ST_NCI_DM_GETINFO_PIPE_LIST,
+ ST_NCI_TERMINAL_HOST_ID};
+ u8 pipe_info[] = { ST_NCI_DM_GETINFO_PIPE_INFO,
+ ST_NCI_TERMINAL_HOST_ID, 0};
- /* On ST21NFCB device pipes number are dynamics
+ /* On ST_NCI device pipes number are dynamics
* If pipes are already created, hci_dev_up will fail.
* Doing a clear all pipe is a bad idea because:
* - It does useless EEPROM cycling
* - It might cause issue for secure elements support
* (such as removing connectivity or APDU reader pipe)
- * A better approach on ST21NFCB is to:
+ * A better approach on ST_NCI is to:
* - get a pipe list for each host.
- * (eg: ST21NFCB_HOST_CONTROLLER_ID for now).
+ * (eg: ST_NCI_HOST_CONTROLLER_ID for now).
* (TODO Later on UICC HOST and eSE HOST)
* - get pipe information
- * - match retrieved pipe list in st21nfcb_gates
- * ST21NFCB_DEVICE_MGNT_GATE is a proprietary gate
- * with ST21NFCB_DEVICE_MGNT_PIPE.
+ * - match retrieved pipe list in st_nci_gates
+ * ST_NCI_DEVICE_MGNT_GATE is a proprietary gate
+ * with ST_NCI_DEVICE_MGNT_PIPE.
* Pipe can be closed and need to be open.
*/
- r = nci_hci_connect_gate(ndev, ST21NFCB_HOST_CONTROLLER_ID,
- ST21NFCB_DEVICE_MGNT_GATE,
- ST21NFCB_DEVICE_MGNT_PIPE);
+ r = nci_hci_connect_gate(ndev, ST_NCI_HOST_CONTROLLER_ID,
+ ST_NCI_DEVICE_MGNT_GATE,
+ ST_NCI_DEVICE_MGNT_PIPE);
if (r < 0)
goto free_info;
/* Get pipe list */
- r = nci_hci_send_cmd(ndev, ST21NFCB_DEVICE_MGNT_GATE,
- ST21NFCB_DM_GETINFO, pipe_list, sizeof(pipe_list),
+ r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE,
+ ST_NCI_DM_GETINFO, pipe_list, sizeof(pipe_list),
&skb_pipe_list);
if (r < 0)
goto free_info;
@@ -201,8 +201,8 @@ int st21nfcb_hci_load_session(struct nci_dev *ndev)
/* Complete the existing gate_pipe table */
for (i = 0; i < skb_pipe_list->len; i++) {
pipe_info[2] = skb_pipe_list->data[i];
- r = nci_hci_send_cmd(ndev, ST21NFCB_DEVICE_MGNT_GATE,
- ST21NFCB_DM_GETINFO, pipe_info,
+ r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE,
+ ST_NCI_DM_GETINFO, pipe_info,
sizeof(pipe_info), &skb_pipe_info);
if (r)
@@ -217,81 +217,81 @@ int st21nfcb_hci_load_session(struct nci_dev *ndev)
* - destination hid (1byte)
* - destination gid (1byte)
*/
- dm_pipe_info = (struct st21nfcb_pipe_info *)skb_pipe_info->data;
- if (dm_pipe_info->dst_gate_id == ST21NFCB_APDU_READER_GATE &&
- dm_pipe_info->src_host_id != ST21NFCB_ESE_HOST_ID) {
+ dm_pipe_info = (struct st_nci_pipe_info *)skb_pipe_info->data;
+ if (dm_pipe_info->dst_gate_id == ST_NCI_APDU_READER_GATE &&
+ dm_pipe_info->src_host_id != ST_NCI_ESE_HOST_ID) {
pr_err("Unexpected apdu_reader pipe on host %x\n",
dm_pipe_info->src_host_id);
continue;
}
- for (j = 0; (j < ARRAY_SIZE(st21nfcb_gates)) &&
- (st21nfcb_gates[j].gate != dm_pipe_info->dst_gate_id); j++)
+ for (j = 0; (j < ARRAY_SIZE(st_nci_gates)) &&
+ (st_nci_gates[j].gate != dm_pipe_info->dst_gate_id); j++)
;
- if (j < ARRAY_SIZE(st21nfcb_gates) &&
- st21nfcb_gates[j].gate == dm_pipe_info->dst_gate_id &&
- ST21NFCB_DM_IS_PIPE_OPEN(dm_pipe_info->pipe_state)) {
- st21nfcb_gates[j].pipe = pipe_info[2];
+ if (j < ARRAY_SIZE(st_nci_gates) &&
+ st_nci_gates[j].gate == dm_pipe_info->dst_gate_id &&
+ ST_NCI_DM_IS_PIPE_OPEN(dm_pipe_info->pipe_state)) {
+ st_nci_gates[j].pipe = pipe_info[2];
- ndev->hci_dev->gate2pipe[st21nfcb_gates[j].gate] =
- st21nfcb_gates[j].pipe;
- ndev->hci_dev->pipes[st21nfcb_gates[j].pipe].gate =
- st21nfcb_gates[j].gate;
- ndev->hci_dev->pipes[st21nfcb_gates[j].pipe].host =
+ ndev->hci_dev->gate2pipe[st_nci_gates[j].gate] =
+ st_nci_gates[j].pipe;
+ ndev->hci_dev->pipes[st_nci_gates[j].pipe].gate =
+ st_nci_gates[j].gate;
+ ndev->hci_dev->pipes[st_nci_gates[j].pipe].host =
dm_pipe_info->src_host_id;
}
}
- memcpy(ndev->hci_dev->init_data.gates, st21nfcb_gates,
- sizeof(st21nfcb_gates));
+ memcpy(ndev->hci_dev->init_data.gates, st_nci_gates,
+ sizeof(st_nci_gates));
free_info:
kfree_skb(skb_pipe_info);
kfree_skb(skb_pipe_list);
return r;
}
-EXPORT_SYMBOL_GPL(st21nfcb_hci_load_session);
+EXPORT_SYMBOL_GPL(st_nci_hci_load_session);
-static void st21nfcb_hci_admin_event_received(struct nci_dev *ndev,
+static void st_nci_hci_admin_event_received(struct nci_dev *ndev,
u8 event, struct sk_buff *skb)
{
- struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
+ struct st_nci_info *info = nci_get_drvdata(ndev);
switch (event) {
- case ST21NFCB_EVT_HOT_PLUG:
+ case ST_NCI_EVT_HOT_PLUG:
if (info->se_info.se_active) {
- if (!ST21NFCB_EVT_HOT_PLUG_IS_INHIBITED(skb)) {
+ if (!ST_NCI_EVT_HOT_PLUG_IS_INHIBITED(skb)) {
del_timer_sync(&info->se_info.se_active_timer);
info->se_info.se_active = false;
complete(&info->se_info.req_completion);
} else {
mod_timer(&info->se_info.se_active_timer,
jiffies +
- msecs_to_jiffies(ST21NFCB_SE_TO_PIPES));
+ msecs_to_jiffies(ST_NCI_SE_TO_PIPES));
}
}
break;
}
}
-static int st21nfcb_hci_apdu_reader_event_received(struct nci_dev *ndev,
+static int st_nci_hci_apdu_reader_event_received(struct nci_dev *ndev,
u8 event,
struct sk_buff *skb)
{
int r = 0;
- struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
+ struct st_nci_info *info = nci_get_drvdata(ndev);
pr_debug("apdu reader gate event: %x\n", event);
switch (event) {
- case ST21NFCB_EVT_TRANSMIT_DATA:
+ case ST_NCI_EVT_TRANSMIT_DATA:
del_timer_sync(&info->se_info.bwi_timer);
info->se_info.bwi_active = false;
info->se_info.cb(info->se_info.cb_context,
skb->data, skb->len, 0);
break;
- case ST21NFCB_EVT_WTX_REQUEST:
+ case ST_NCI_EVT_WTX_REQUEST:
mod_timer(&info->se_info.bwi_timer, jiffies +
msecs_to_jiffies(info->se_info.wt_timeout));
break;
@@ -306,7 +306,7 @@ static int st21nfcb_hci_apdu_reader_event_received(struct nci_dev *ndev,
* <= 0: driver handled the event, skb consumed
* 1: driver does not handle the event, please do standard processing
*/
-static int st21nfcb_hci_connectivity_event_received(struct nci_dev *ndev,
+static int st_nci_hci_connectivity_event_received(struct nci_dev *ndev,
u8 host, u8 event,
struct sk_buff *skb)
{
@@ -317,10 +317,10 @@ static int st21nfcb_hci_connectivity_event_received(struct nci_dev *ndev,
pr_debug("connectivity gate event: %x\n", event);
switch (event) {
- case ST21NFCB_EVT_CONNECTIVITY:
+ case ST_NCI_EVT_CONNECTIVITY:
break;
- case ST21NFCB_EVT_TRANSACTION:
+ case ST_NCI_EVT_TRANSACTION:
/* According to specification etsi 102 622
* 11.2.2.4 EVT_TRANSACTION Table 52
* Description Tag Length
@@ -355,7 +355,7 @@ static int st21nfcb_hci_connectivity_event_received(struct nci_dev *ndev,
return r;
}
-void st21nfcb_hci_event_received(struct nci_dev *ndev, u8 pipe,
+void st_nci_hci_event_received(struct nci_dev *ndev, u8 pipe,
u8 event, struct sk_buff *skb)
{
u8 gate = ndev->hci_dev->pipes[pipe].gate;
@@ -363,32 +363,32 @@ void st21nfcb_hci_event_received(struct nci_dev *ndev, u8 pipe,
switch (gate) {
case NCI_HCI_ADMIN_GATE:
- st21nfcb_hci_admin_event_received(ndev, event, skb);
+ st_nci_hci_admin_event_received(ndev, event, skb);
break;
- case ST21NFCB_APDU_READER_GATE:
- st21nfcb_hci_apdu_reader_event_received(ndev, event, skb);
+ case ST_NCI_APDU_READER_GATE:
+ st_nci_hci_apdu_reader_event_received(ndev, event, skb);
break;
- case ST21NFCB_CONNECTIVITY_GATE:
- st21nfcb_hci_connectivity_event_received(ndev, host, event,
+ case ST_NCI_CONNECTIVITY_GATE:
+ st_nci_hci_connectivity_event_received(ndev, host, event,
skb);
break;
}
}
-EXPORT_SYMBOL_GPL(st21nfcb_hci_event_received);
+EXPORT_SYMBOL_GPL(st_nci_hci_event_received);
-void st21nfcb_hci_cmd_received(struct nci_dev *ndev, u8 pipe, u8 cmd,
+void st_nci_hci_cmd_received(struct nci_dev *ndev, u8 pipe, u8 cmd,
struct sk_buff *skb)
{
- struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
+ struct st_nci_info *info = nci_get_drvdata(ndev);
u8 gate = ndev->hci_dev->pipes[pipe].gate;
pr_debug("cmd: %x\n", cmd);
switch (cmd) {
case NCI_HCI_ANY_OPEN_PIPE:
- if (gate != ST21NFCB_APDU_READER_GATE &&
- ndev->hci_dev->pipes[pipe].host != ST21NFCB_UICC_HOST_ID)
+ if (gate != ST_NCI_APDU_READER_GATE &&
+ ndev->hci_dev->pipes[pipe].host != ST_NCI_UICC_HOST_ID)
ndev->hci_dev->count_pipes++;
if (ndev->hci_dev->count_pipes ==
@@ -401,28 +401,28 @@ void st21nfcb_hci_cmd_received(struct nci_dev *ndev, u8 pipe, u8 cmd,
break;
}
}
-EXPORT_SYMBOL_GPL(st21nfcb_hci_cmd_received);
+EXPORT_SYMBOL_GPL(st_nci_hci_cmd_received);
/*
- * Remarks: On some early st21nfcb firmware, nci_nfcee_mode_set(0)
+ * Remarks: On some early st_nci firmware, nci_nfcee_mode_set(0)
* is rejected
*/
-static int st21nfcb_nci_control_se(struct nci_dev *ndev, u8 se_idx,
+static int st_nci_control_se(struct nci_dev *ndev, u8 se_idx,
u8 state)
{
- struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
+ struct st_nci_info *info = nci_get_drvdata(ndev);
int r;
struct sk_buff *sk_host_list;
u8 host_id;
switch (se_idx) {
- case ST21NFCB_UICC_HOST_ID:
+ case ST_NCI_UICC_HOST_ID:
ndev->hci_dev->count_pipes = 0;
- ndev->hci_dev->expected_pipes = ST21NFCB_SE_COUNT_PIPE_UICC;
+ ndev->hci_dev->expected_pipes = ST_NCI_SE_COUNT_PIPE_UICC;
break;
- case ST21NFCB_ESE_HOST_ID:
+ case ST_NCI_ESE_HOST_ID:
ndev->hci_dev->count_pipes = 0;
- ndev->hci_dev->expected_pipes = ST21NFCB_SE_COUNT_PIPE_EMBEDDED;
+ ndev->hci_dev->expected_pipes = ST_NCI_SE_COUNT_PIPE_EMBEDDED;
break;
default:
return -EINVAL;
@@ -438,7 +438,7 @@ static int st21nfcb_nci_control_se(struct nci_dev *ndev, u8 se_idx,
return r;
mod_timer(&info->se_info.se_active_timer, jiffies +
- msecs_to_jiffies(ST21NFCB_SE_TO_HOT_PLUG));
+ msecs_to_jiffies(ST_NCI_SE_TO_HOT_PLUG));
info->se_info.se_active = true;
/* Ignore return value and check in any case the host_list */
@@ -458,49 +458,49 @@ static int st21nfcb_nci_control_se(struct nci_dev *ndev, u8 se_idx,
host_id = sk_host_list->data[sk_host_list->len - 1];
kfree_skb(sk_host_list);
- if (state == ST21NFCB_SE_MODE_ON && host_id == se_idx)
+ if (state == ST_NCI_SE_MODE_ON && host_id == se_idx)
return se_idx;
- else if (state == ST21NFCB_SE_MODE_OFF && host_id != se_idx)
+ else if (state == ST_NCI_SE_MODE_OFF && host_id != se_idx)
return se_idx;
return -1;
}
-int st21nfcb_nci_disable_se(struct nci_dev *ndev, u32 se_idx)
+int st_nci_disable_se(struct nci_dev *ndev, u32 se_idx)
{
int r;
- pr_debug("st21nfcb_nci_disable_se\n");
+ pr_debug("st_nci_disable_se\n");
if (se_idx == NFC_SE_EMBEDDED) {
- r = nci_hci_send_event(ndev, ST21NFCB_APDU_READER_GATE,
- ST21NFCB_EVT_SE_END_OF_APDU_TRANSFER, NULL, 0);
+ r = nci_hci_send_event(ndev, ST_NCI_APDU_READER_GATE,
+ ST_NCI_EVT_SE_END_OF_APDU_TRANSFER, NULL, 0);
if (r < 0)
return r;
}
return 0;
}
-EXPORT_SYMBOL_GPL(st21nfcb_nci_disable_se);
+EXPORT_SYMBOL_GPL(st_nci_disable_se);
-int st21nfcb_nci_enable_se(struct nci_dev *ndev, u32 se_idx)
+int st_nci_enable_se(struct nci_dev *ndev, u32 se_idx)
{
int r;
- pr_debug("st21nfcb_nci_enable_se\n");
+ pr_debug("st_nci_enable_se\n");
- if (se_idx == ST21NFCB_HCI_HOST_ID_ESE) {
- r = nci_hci_send_event(ndev, ST21NFCB_APDU_READER_GATE,
- ST21NFCB_EVT_SE_SOFT_RESET, NULL, 0);
+ if (se_idx == ST_NCI_HCI_HOST_ID_ESE) {
+ r = nci_hci_send_event(ndev, ST_NCI_APDU_READER_GATE,
+ ST_NCI_EVT_SE_SOFT_RESET, NULL, 0);
if (r < 0)
return r;
}
return 0;
}
-EXPORT_SYMBOL_GPL(st21nfcb_nci_enable_se);
+EXPORT_SYMBOL_GPL(st_nci_enable_se);
-static int st21nfcb_hci_network_init(struct nci_dev *ndev)
+static int st_nci_hci_network_init(struct nci_dev *ndev)
{
struct core_conn_create_dest_spec_params *dest_params;
struct dest_spec_params spec_params;
@@ -519,7 +519,8 @@ static int st21nfcb_hci_network_init(struct nci_dev *ndev)
dest_params->length = sizeof(struct dest_spec_params);
spec_params.id = ndev->hci_dev->nfcee_id;
spec_params.protocol = NCI_NFCEE_INTERFACE_HCI_ACCESS;
- memcpy(dest_params->value, &spec_params, sizeof(struct dest_spec_params));
+ memcpy(dest_params->value, &spec_params,
+ sizeof(struct dest_spec_params));
r = nci_core_conn_create(ndev, NCI_DESTINATION_NFCEE, 1,
sizeof(struct core_conn_create_dest_spec_params) +
sizeof(struct dest_spec_params),
@@ -531,15 +532,15 @@ static int st21nfcb_hci_network_init(struct nci_dev *ndev)
if (!conn_info)
goto free_dest_params;
- memcpy(ndev->hci_dev->init_data.gates, st21nfcb_gates,
- sizeof(st21nfcb_gates));
+ memcpy(ndev->hci_dev->init_data.gates, st_nci_gates,
+ sizeof(st_nci_gates));
/*
* Session id must include the driver name + i2c bus addr
* persistent info to discriminate 2 identical chips
*/
- dev_num = find_first_zero_bit(dev_mask, ST21NFCB_NUM_DEVICES);
- if (dev_num >= ST21NFCB_NUM_DEVICES) {
+ dev_num = find_first_zero_bit(dev_mask, ST_NCI_NUM_DEVICES);
+ if (dev_num >= ST_NCI_NUM_DEVICES) {
r = -ENODEV;
goto free_dest_params;
}
@@ -564,72 +565,72 @@ exit:
return r;
}
-int st21nfcb_nci_discover_se(struct nci_dev *ndev)
+int st_nci_discover_se(struct nci_dev *ndev)
{
u8 param[2];
int r;
int se_count = 0;
- pr_debug("st21nfcb_nci_discover_se\n");
+ pr_debug("st_nci_discover_se\n");
- r = st21nfcb_hci_network_init(ndev);
+ r = st_nci_hci_network_init(ndev);
if (r != 0)
return r;
- param[0] = ST21NFCB_UICC_HOST_ID;
- param[1] = ST21NFCB_HCI_HOST_ID_ESE;
+ param[0] = ST_NCI_UICC_HOST_ID;
+ param[1] = ST_NCI_HCI_HOST_ID_ESE;
r = nci_hci_set_param(ndev, NCI_HCI_ADMIN_GATE,
NCI_HCI_ADMIN_PARAM_WHITELIST,
param, sizeof(param));
if (r != NCI_HCI_ANY_OK)
return r;
- r = st21nfcb_nci_control_se(ndev, ST21NFCB_UICC_HOST_ID,
- ST21NFCB_SE_MODE_ON);
- if (r == ST21NFCB_UICC_HOST_ID) {
- nfc_add_se(ndev->nfc_dev, ST21NFCB_UICC_HOST_ID, NFC_SE_UICC);
+ r = st_nci_control_se(ndev, ST_NCI_UICC_HOST_ID,
+ ST_NCI_SE_MODE_ON);
+ if (r == ST_NCI_UICC_HOST_ID) {
+ nfc_add_se(ndev->nfc_dev, ST_NCI_UICC_HOST_ID, NFC_SE_UICC);
se_count++;
}
/* Try to enable eSE in order to check availability */
- r = st21nfcb_nci_control_se(ndev, ST21NFCB_HCI_HOST_ID_ESE,
- ST21NFCB_SE_MODE_ON);
- if (r == ST21NFCB_HCI_HOST_ID_ESE) {
- nfc_add_se(ndev->nfc_dev, ST21NFCB_HCI_HOST_ID_ESE,
+ r = st_nci_control_se(ndev, ST_NCI_HCI_HOST_ID_ESE,
+ ST_NCI_SE_MODE_ON);
+ if (r == ST_NCI_HCI_HOST_ID_ESE) {
+ nfc_add_se(ndev->nfc_dev, ST_NCI_HCI_HOST_ID_ESE,
NFC_SE_EMBEDDED);
se_count++;
- st21nfcb_se_get_atr(ndev);
+ st_nci_se_get_atr(ndev);
}
return !se_count;
}
-EXPORT_SYMBOL_GPL(st21nfcb_nci_discover_se);
+EXPORT_SYMBOL_GPL(st_nci_discover_se);
-int st21nfcb_nci_se_io(struct nci_dev *ndev, u32 se_idx,
+int st_nci_se_io(struct nci_dev *ndev, u32 se_idx,
u8 *apdu, size_t apdu_length,
se_io_cb_t cb, void *cb_context)
{
- struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
+ struct st_nci_info *info = nci_get_drvdata(ndev);
pr_debug("\n");
switch (se_idx) {
- case ST21NFCB_HCI_HOST_ID_ESE:
+ case ST_NCI_HCI_HOST_ID_ESE:
info->se_info.cb = cb;
info->se_info.cb_context = cb_context;
mod_timer(&info->se_info.bwi_timer, jiffies +
msecs_to_jiffies(info->se_info.wt_timeout));
info->se_info.bwi_active = true;
- return nci_hci_send_event(ndev, ST21NFCB_APDU_READER_GATE,
- ST21NFCB_EVT_TRANSMIT_DATA, apdu,
+ return nci_hci_send_event(ndev, ST_NCI_APDU_READER_GATE,
+ ST_NCI_EVT_TRANSMIT_DATA, apdu,
apdu_length);
default:
return -ENODEV;
}
}
-EXPORT_SYMBOL(st21nfcb_nci_se_io);
+EXPORT_SYMBOL(st_nci_se_io);
-static void st21nfcb_se_wt_timeout(unsigned long data)
+static void st_nci_se_wt_timeout(unsigned long data)
{
/*
* No answer from the secure element
@@ -642,7 +643,7 @@ static void st21nfcb_se_wt_timeout(unsigned long data)
*/
/* hardware reset managed through VCC_UICC_OUT power supply */
u8 param = 0x01;
- struct st21nfcb_nci_info *info = (struct st21nfcb_nci_info *) data;
+ struct st_nci_info *info = (struct st_nci_info *) data;
pr_debug("\n");
@@ -650,19 +651,19 @@ static void st21nfcb_se_wt_timeout(unsigned long data)
if (!info->se_info.xch_error) {
info->se_info.xch_error = true;
- nci_hci_send_event(info->ndlc->ndev, ST21NFCB_APDU_READER_GATE,
- ST21NFCB_EVT_SE_SOFT_RESET, NULL, 0);
+ nci_hci_send_event(info->ndlc->ndev, ST_NCI_APDU_READER_GATE,
+ ST_NCI_EVT_SE_SOFT_RESET, NULL, 0);
} else {
info->se_info.xch_error = false;
- nci_hci_send_event(info->ndlc->ndev, ST21NFCB_DEVICE_MGNT_GATE,
- ST21NFCB_EVT_SE_HARD_RESET, &param, 1);
+ nci_hci_send_event(info->ndlc->ndev, ST_NCI_DEVICE_MGNT_GATE,
+ ST_NCI_EVT_SE_HARD_RESET, &param, 1);
}
info->se_info.cb(info->se_info.cb_context, NULL, 0, -ETIME);
}
-static void st21nfcb_se_activation_timeout(unsigned long data)
+static void st_nci_se_activation_timeout(unsigned long data)
{
- struct st21nfcb_nci_info *info = (struct st21nfcb_nci_info *) data;
+ struct st_nci_info *info = (struct st_nci_info *) data;
pr_debug("\n");
@@ -671,35 +672,35 @@ static void st21nfcb_se_activation_timeout(unsigned long data)
complete(&info->se_info.req_completion);
}
-int st21nfcb_se_init(struct nci_dev *ndev)
+int st_nci_se_init(struct nci_dev *ndev)
{
- struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
+ struct st_nci_info *info = nci_get_drvdata(ndev);
init_completion(&info->se_info.req_completion);
/* initialize timers */
init_timer(&info->se_info.bwi_timer);
info->se_info.bwi_timer.data = (unsigned long)info;
- info->se_info.bwi_timer.function = st21nfcb_se_wt_timeout;
+ info->se_info.bwi_timer.function = st_nci_se_wt_timeout;
info->se_info.bwi_active = false;
init_timer(&info->se_info.se_active_timer);
info->se_info.se_active_timer.data = (unsigned long)info;
info->se_info.se_active_timer.function =
- st21nfcb_se_activation_timeout;
+ st_nci_se_activation_timeout;
info->se_info.se_active = false;
info->se_info.xch_error = false;
info->se_info.wt_timeout =
- ST21NFCB_BWI_TO_TIMEOUT(ST21NFCB_ATR_DEFAULT_BWI);
+ ST_NCI_BWI_TO_TIMEOUT(ST_NCI_ATR_DEFAULT_BWI);
return 0;
}
-EXPORT_SYMBOL(st21nfcb_se_init);
+EXPORT_SYMBOL(st_nci_se_init);
-void st21nfcb_se_deinit(struct nci_dev *ndev)
+void st_nci_se_deinit(struct nci_dev *ndev)
{
- struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
+ struct st_nci_info *info = nci_get_drvdata(ndev);
if (info->se_info.bwi_active)
del_timer_sync(&info->se_info.bwi_timer);
@@ -709,5 +710,5 @@ void st21nfcb_se_deinit(struct nci_dev *ndev)
info->se_info.se_active = false;
info->se_info.bwi_active = false;
}
-EXPORT_SYMBOL(st21nfcb_se_deinit);
+EXPORT_SYMBOL(st_nci_se_deinit);
diff --git a/drivers/nfc/st-nci/st-nci_se.h b/drivers/nfc/st-nci/st-nci_se.h
new file mode 100644
index 000000000..ea66e879d
--- /dev/null
+++ b/drivers/nfc/st-nci/st-nci_se.h
@@ -0,0 +1,61 @@
+/*
+ * Secure Element Driver for STMicroelectronics NFC NCI Chip
+ *
+ * Copyright (C) 2014-2015 STMicroelectronics SAS. 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 __LOCAL_ST_NCI_SE_H_
+#define __LOCAL_ST_NCI_SE_H_
+
+/*
+ * ref ISO7816-3 chap 8.1. the initial character TS is followed by a
+ * sequence of at most 32 characters.
+ */
+#define ST_NCI_ESE_MAX_LENGTH 33
+#define ST_NCI_HCI_HOST_ID_ESE 0xc0
+
+struct st_nci_se_info {
+ u8 atr[ST_NCI_ESE_MAX_LENGTH];
+ struct completion req_completion;
+
+ struct timer_list bwi_timer;
+ int wt_timeout; /* in msecs */
+ bool bwi_active;
+
+ struct timer_list se_active_timer;
+ bool se_active;
+
+ bool xch_error;
+
+ se_io_cb_t cb;
+ void *cb_context;
+};
+
+int st_nci_se_init(struct nci_dev *ndev);
+void st_nci_se_deinit(struct nci_dev *ndev);
+
+int st_nci_discover_se(struct nci_dev *ndev);
+int st_nci_enable_se(struct nci_dev *ndev, u32 se_idx);
+int st_nci_disable_se(struct nci_dev *ndev, u32 se_idx);
+int st_nci_se_io(struct nci_dev *ndev, u32 se_idx,
+ u8 *apdu, size_t apdu_length,
+ se_io_cb_t cb, void *cb_context);
+int st_nci_hci_load_session(struct nci_dev *ndev);
+void st_nci_hci_event_received(struct nci_dev *ndev, u8 pipe,
+ u8 event, struct sk_buff *skb);
+void st_nci_hci_cmd_received(struct nci_dev *ndev, u8 pipe, u8 cmd,
+ struct sk_buff *skb);
+
+
+#endif /* __LOCAL_ST_NCI_SE_H_ */
diff --git a/drivers/nfc/st21nfcb/Kconfig b/drivers/nfc/st21nfcb/Kconfig
deleted file mode 100644
index e0322dd03..000000000
--- a/drivers/nfc/st21nfcb/Kconfig
+++ /dev/null
@@ -1,22 +0,0 @@
-config NFC_ST21NFCB
- tristate "STMicroelectronics ST21NFCB NFC driver"
- depends on NFC_NCI
- default n
- ---help---
- STMicroelectronics ST21NFCB core driver. It implements the chipset
- NCI logic and hooks into the NFC kernel APIs. Physical layers will
- register against it.
-
- To compile this driver as a module, choose m here. The module will
- be called st21nfcb.
- Say N if unsure.
-
-config NFC_ST21NFCB_I2C
- tristate "NFC ST21NFCB i2c support"
- depends on NFC_ST21NFCB && I2C
- ---help---
- This module adds support for the STMicroelectronics st21nfcb i2c interface.
- Select this if your platform is using the i2c bus.
-
- If you choose to build a module, it'll be called st21nfcb_i2c.
- Say N if unsure.
diff --git a/drivers/nfc/st21nfcb/Makefile b/drivers/nfc/st21nfcb/Makefile
deleted file mode 100644
index ce659a9e5..000000000
--- a/drivers/nfc/st21nfcb/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Makefile for ST21NFCB NCI based NFC driver
-#
-
-st21nfcb_nci-objs = ndlc.o st21nfcb.o st21nfcb_se.o
-obj-$(CONFIG_NFC_ST21NFCB) += st21nfcb_nci.o
-
-st21nfcb_i2c-objs = i2c.o
-obj-$(CONFIG_NFC_ST21NFCB_I2C) += st21nfcb_i2c.o
diff --git a/drivers/nfc/st21nfcb/st21nfcb.c b/drivers/nfc/st21nfcb/st21nfcb.c
deleted file mode 100644
index c7dc282d5..000000000
--- a/drivers/nfc/st21nfcb/st21nfcb.c
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * NCI based Driver for STMicroelectronics NFC Chip
- *
- * Copyright (C) 2014 STMicroelectronics SAS. 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 <linux/module.h>
-#include <linux/nfc.h>
-#include <net/nfc/nci.h>
-#include <net/nfc/nci_core.h>
-
-#include "st21nfcb.h"
-#include "st21nfcb_se.h"
-
-#define DRIVER_DESC "NCI NFC driver for ST21NFCB"
-
-#define ST21NFCB_NCI1_X_PROPRIETARY_ISO15693 0x83
-
-static int st21nfcb_nci_open(struct nci_dev *ndev)
-{
- struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
- int r;
-
- if (test_and_set_bit(ST21NFCB_NCI_RUNNING, &info->flags))
- return 0;
-
- r = ndlc_open(info->ndlc);
- if (r)
- clear_bit(ST21NFCB_NCI_RUNNING, &info->flags);
-
- return r;
-}
-
-static int st21nfcb_nci_close(struct nci_dev *ndev)
-{
- struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
-
- if (!test_and_clear_bit(ST21NFCB_NCI_RUNNING, &info->flags))
- return 0;
-
- ndlc_close(info->ndlc);
-
- return 0;
-}
-
-static int st21nfcb_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
-{
- struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
-
- skb->dev = (void *)ndev;
-
- if (!test_bit(ST21NFCB_NCI_RUNNING, &info->flags))
- return -EBUSY;
-
- return ndlc_send(info->ndlc, skb);
-}
-
-static __u32 st21nfcb_nci_get_rfprotocol(struct nci_dev *ndev,
- __u8 rf_protocol)
-{
- return rf_protocol == ST21NFCB_NCI1_X_PROPRIETARY_ISO15693 ?
- NFC_PROTO_ISO15693_MASK : 0;
-}
-
-static struct nci_ops st21nfcb_nci_ops = {
- .open = st21nfcb_nci_open,
- .close = st21nfcb_nci_close,
- .send = st21nfcb_nci_send,
- .get_rfprotocol = st21nfcb_nci_get_rfprotocol,
- .discover_se = st21nfcb_nci_discover_se,
- .enable_se = st21nfcb_nci_enable_se,
- .disable_se = st21nfcb_nci_disable_se,
- .se_io = st21nfcb_nci_se_io,
- .hci_load_session = st21nfcb_hci_load_session,
- .hci_event_received = st21nfcb_hci_event_received,
- .hci_cmd_received = st21nfcb_hci_cmd_received,
-};
-
-int st21nfcb_nci_probe(struct llt_ndlc *ndlc, int phy_headroom,
- int phy_tailroom)
-{
- struct st21nfcb_nci_info *info;
- int r;
- u32 protocols;
-
- info = devm_kzalloc(ndlc->dev,
- sizeof(struct st21nfcb_nci_info), GFP_KERNEL);
- if (!info)
- return -ENOMEM;
-
- protocols = NFC_PROTO_JEWEL_MASK
- | NFC_PROTO_MIFARE_MASK
- | NFC_PROTO_FELICA_MASK
- | NFC_PROTO_ISO14443_MASK
- | NFC_PROTO_ISO14443_B_MASK
- | NFC_PROTO_ISO15693_MASK
- | NFC_PROTO_NFC_DEP_MASK;
-
- ndlc->ndev = nci_allocate_device(&st21nfcb_nci_ops, protocols,
- phy_headroom, phy_tailroom);
- if (!ndlc->ndev) {
- pr_err("Cannot allocate nfc ndev\n");
- return -ENOMEM;
- }
- info->ndlc = ndlc;
-
- nci_set_drvdata(ndlc->ndev, info);
-
- r = nci_register_device(ndlc->ndev);
- if (r) {
- pr_err("Cannot register nfc device to nci core\n");
- nci_free_device(ndlc->ndev);
- return r;
- }
-
- return st21nfcb_se_init(ndlc->ndev);
-}
-EXPORT_SYMBOL_GPL(st21nfcb_nci_probe);
-
-void st21nfcb_nci_remove(struct nci_dev *ndev)
-{
- nci_unregister_device(ndev);
- nci_free_device(ndev);
-}
-EXPORT_SYMBOL_GPL(st21nfcb_nci_remove);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/nfc/st21nfcb/st21nfcb_se.h b/drivers/nfc/st21nfcb/st21nfcb_se.h
deleted file mode 100644
index 52a323872..000000000
--- a/drivers/nfc/st21nfcb/st21nfcb_se.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * NCI based Driver for STMicroelectronics NFC Chip
- *
- * Copyright (C) 2014 STMicroelectronics SAS. 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 __LOCAL_ST21NFCB_SE_H_
-#define __LOCAL_ST21NFCB_SE_H_
-
-/*
- * ref ISO7816-3 chap 8.1. the initial character TS is followed by a
- * sequence of at most 32 characters.
- */
-#define ST21NFCB_ESE_MAX_LENGTH 33
-#define ST21NFCB_HCI_HOST_ID_ESE 0xc0
-
-struct st21nfcb_se_info {
- u8 atr[ST21NFCB_ESE_MAX_LENGTH];
- struct completion req_completion;
-
- struct timer_list bwi_timer;
- int wt_timeout; /* in msecs */
- bool bwi_active;
-
- struct timer_list se_active_timer;
- bool se_active;
-
- bool xch_error;
-
- se_io_cb_t cb;
- void *cb_context;
-};
-
-int st21nfcb_se_init(struct nci_dev *ndev);
-void st21nfcb_se_deinit(struct nci_dev *ndev);
-
-int st21nfcb_nci_discover_se(struct nci_dev *ndev);
-int st21nfcb_nci_enable_se(struct nci_dev *ndev, u32 se_idx);
-int st21nfcb_nci_disable_se(struct nci_dev *ndev, u32 se_idx);
-int st21nfcb_nci_se_io(struct nci_dev *ndev, u32 se_idx,
- u8 *apdu, size_t apdu_length,
- se_io_cb_t cb, void *cb_context);
-int st21nfcb_hci_load_session(struct nci_dev *ndev);
-void st21nfcb_hci_event_received(struct nci_dev *ndev, u8 pipe,
- u8 event, struct sk_buff *skb);
-void st21nfcb_hci_cmd_received(struct nci_dev *ndev, u8 pipe, u8 cmd,
- struct sk_buff *skb);
-
-
-#endif /* __LOCAL_ST21NFCB_NCI_H_ */
diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c
index aa6a333b2..85b4d8677 100644
--- a/drivers/nfc/trf7970a.c
+++ b/drivers/nfc/trf7970a.c
@@ -149,6 +149,7 @@
*/
#define TRF7970A_QUIRK_IRQ_STATUS_READ BIT(0)
#define TRF7970A_QUIRK_EN2_MUST_STAY_LOW BIT(1)
+#define TRF7970A_QUIRK_T5T_RMB_EXTRA_BYTE BIT(2)
/* Direct commands */
#define TRF7970A_CMD_IDLE 0x00
@@ -446,6 +447,7 @@ struct trf7970a {
u8 md_rf_tech;
u8 tx_cmd;
bool issue_eof;
+ bool adjust_resp_len;
int en2_gpio;
int en_gpio;
struct mutex lock;
@@ -626,6 +628,11 @@ static void trf7970a_send_upstream(struct trf7970a *trf)
trf->aborting = false;
}
+ if (trf->adjust_resp_len) {
+ skb_trim(trf->rx_skb, trf->rx_skb->len - 1);
+ trf->adjust_resp_len = false;
+ }
+
trf->cb(trf->ddev, trf->cb_arg, trf->rx_skb);
trf->rx_skb = NULL;
@@ -1429,10 +1436,15 @@ static int trf7970a_per_cmd_config(struct trf7970a *trf, struct sk_buff *skb)
trf->iso_ctrl = iso_ctrl;
}
- if ((trf->framing == NFC_DIGITAL_FRAMING_ISO15693_T5T) &&
- trf7970a_is_iso15693_write_or_lock(req[1]) &&
- (req[0] & ISO15693_REQ_FLAG_OPTION))
- trf->issue_eof = true;
+ if (trf->framing == NFC_DIGITAL_FRAMING_ISO15693_T5T) {
+ if (trf7970a_is_iso15693_write_or_lock(req[1]) &&
+ (req[0] & ISO15693_REQ_FLAG_OPTION))
+ trf->issue_eof = true;
+ else if ((trf->quirks &
+ TRF7970A_QUIRK_T5T_RMB_EXTRA_BYTE) &&
+ (req[1] == ISO15693_CMD_READ_MULTIPLE_BLOCK))
+ trf->adjust_resp_len = true;
+ }
}
return 0;
@@ -1992,6 +2004,9 @@ static int trf7970a_probe(struct spi_device *spi)
return ret;
}
+ if (of_property_read_bool(np, "t5t-rmb-extra-byte-quirk"))
+ trf->quirks |= TRF7970A_QUIRK_T5T_RMB_EXTRA_BYTE;
+
if (of_property_read_bool(np, "irq-status-read-quirk"))
trf->quirks |= TRF7970A_QUIRK_IRQ_STATUS_READ;