Commit 740215dd authored by David S. Miller's avatar David S. Miller

Merge tag 'nfc-next-4.4-2' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/nfc-next

Samuel Ortiz says:

====================
NFC 4.4 pull request

This is the NFC pull request for 4.4.

It's a bit bigger than usual, the 3 main culprits being:

- A new driver for Intel's Fields Peak NCI chipset. In order to
  support this chipset we had to export a few NCI routines and
  extend the driver NCI ops to not only support proprietary
  commands but also core ones.

- Support for vendor commands for both STM drivers, st-nci
  and st21nfca. Those vendor commands allow to run factory tests
  through the NFC netlink interface.

- New i2c and SPI support for the Marvell driver, together with
  firmware download support for this driver's core.

Besides that we also have:

- A few file renames in the STM drivers, to keep the naming
  consistent between drivers.

- Some improvements and fixes on the NCI HCI layer, mostly to
  properly reach a secure element over a legacy HCI link.

- A few fixes for the s3fwrn5 and trf7970a drivers.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 5bf89211 f1163174
* Marvell International Ltd. NCI NFC Controller * Marvell International Ltd. NCI NFC Controller
Required properties: Required properties:
- compatible: Should be "mrvl,nfc-uart". - compatible: Should be:
- "marvell,nfc-uart" or "mrvl,nfc-uart" for UART devices
- "marvell,nfc-i2c" for I2C devices
- "marvell,nfc-spi" for SPI devices
Optional SoC specific properties: Optional SoC specific properties:
- pinctrl-names: Contains only one value - "default". - pinctrl-names: Contains only one value - "default".
...@@ -13,13 +16,19 @@ Optional UART-based chip specific properties: ...@@ -13,13 +16,19 @@ Optional UART-based chip specific properties:
- flow-control: Specifies that the chip is using RTS/CTS. - flow-control: Specifies that the chip is using RTS/CTS.
- break-control: Specifies that the chip needs specific break management. - break-control: Specifies that the chip needs specific break management.
Optional I2C-based chip specific properties:
- i2c-int-falling: Specifies that the chip read event shall be trigged on
falling edge.
- i2c-int-rising: Specifies that the chip read event shall be trigged on
rising edge.
Example (for ARM-based BeagleBoard Black with 88W8887 on UART5): Example (for ARM-based BeagleBoard Black with 88W8887 on UART5):
&uart5 { &uart5 {
status = "okay"; status = "okay";
nfcmrvluart: nfcmrvluart@5 { nfcmrvluart: nfcmrvluart@5 {
compatible = "mrvl,nfc-uart"; compatible = "marvell,nfc-uart";
reset-n-io = <&gpio3 16 0>; reset-n-io = <&gpio3 16 0>;
...@@ -27,3 +36,51 @@ Example (for ARM-based BeagleBoard Black with 88W8887 on UART5): ...@@ -27,3 +36,51 @@ Example (for ARM-based BeagleBoard Black with 88W8887 on UART5):
flow-control; flow-control;
} }
}; };
Example (for ARM-based BeagleBoard Black with 88W8887 on I2C1):
&i2c1 {
status = "okay";
clock-frequency = <400000>;
nfcmrvli2c0: i2c@1 {
compatible = "marvell,nfc-i2c";
reg = <0x8>;
/* I2C INT configuration */
interrupt-parent = <&gpio3>;
interrupts = <21 0>;
/* I2C INT trigger configuration */
i2c-int-rising;
/* Reset IO */
reset-n-io = <&gpio3 19 0>;
};
};
Example (for ARM-based BeagleBoard Black on SPI0):
&spi0 {
mrvlnfcspi0: spi@0 {
compatible = "marvell,nfc-spi";
reg = <0>;
/* SPI Bus configuration */
spi-max-frequency = <3000000>;
spi-cpha;
spi-cpol;
/* SPI INT configuration */
interrupt-parent = <&gpio1>;
interrupts = <17 0>;
/* Reset IO */
reset-n-io = <&gpio3 19 0>;
};
};
...@@ -11,6 +11,10 @@ Required properties: ...@@ -11,6 +11,10 @@ Required properties:
Optional SoC Specific Properties: Optional SoC Specific Properties:
- pinctrl-names: Contains only one value - "default". - pinctrl-names: Contains only one value - "default".
- pintctrl-0: Specifies the pin control groups used for this controller. - pintctrl-0: Specifies the pin control groups used for this controller.
- ese-present: Specifies that an ese is physically connected to the nfc
controller.
- uicc-present: Specifies that the uicc swp signal can be physically
connected to the nfc controller.
Example (for ARM-based BeagleBoard xM with ST21NFCB on I2C2): Example (for ARM-based BeagleBoard xM with ST21NFCB on I2C2):
...@@ -29,5 +33,8 @@ Example (for ARM-based BeagleBoard xM with ST21NFCB on I2C2): ...@@ -29,5 +33,8 @@ Example (for ARM-based BeagleBoard xM with ST21NFCB on I2C2):
interrupts = <2 IRQ_TYPE_LEVEL_HIGH>; interrupts = <2 IRQ_TYPE_LEVEL_HIGH>;
reset-gpios = <&gpio5 29 GPIO_ACTIVE_HIGH>; reset-gpios = <&gpio5 29 GPIO_ACTIVE_HIGH>;
ese-present;
uicc-present;
}; };
}; };
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
Required properties: Required properties:
- compatible: Should be "st,st21nfcb-spi" - compatible: Should be "st,st21nfcb-spi"
- spi-max-frequency: Maximum SPI frequency (<= 10000000). - spi-max-frequency: Maximum SPI frequency (<= 4000000).
- interrupt-parent: phandle for the interrupt gpio controller - interrupt-parent: phandle for the interrupt gpio controller
- interrupts: GPIO interrupt to which the chip is connected - interrupts: GPIO interrupt to which the chip is connected
- reset-gpios: Output GPIO pin used to reset the ST21NFCB - reset-gpios: Output GPIO pin used to reset the ST21NFCB
...@@ -10,6 +10,10 @@ Required properties: ...@@ -10,6 +10,10 @@ Required properties:
Optional SoC Specific Properties: Optional SoC Specific Properties:
- pinctrl-names: Contains only one value - "default". - pinctrl-names: Contains only one value - "default".
- pintctrl-0: Specifies the pin control groups used for this controller. - pintctrl-0: Specifies the pin control groups used for this controller.
- ese-present: Specifies that an ese is physically connected to the nfc
controller.
- uicc-present: Specifies that the uicc swp signal can be physically
connected to the nfc controller.
Example (for ARM-based BeagleBoard xM with ST21NFCB on SPI4): Example (for ARM-based BeagleBoard xM with ST21NFCB on SPI4):
...@@ -27,5 +31,8 @@ Example (for ARM-based BeagleBoard xM with ST21NFCB on SPI4): ...@@ -27,5 +31,8 @@ Example (for ARM-based BeagleBoard xM with ST21NFCB on SPI4):
interrupts = <2 IRQ_TYPE_EDGE_RISING>; interrupts = <2 IRQ_TYPE_EDGE_RISING>;
reset-gpios = <&gpio5 29 GPIO_ACTIVE_HIGH>; reset-gpios = <&gpio5 29 GPIO_ACTIVE_HIGH>;
ese-present;
uicc-present;
}; };
}; };
...@@ -68,6 +68,7 @@ config NFC_PORT100 ...@@ -68,6 +68,7 @@ config NFC_PORT100
If unsure, say N. If unsure, say N.
source "drivers/nfc/fdp/Kconfig"
source "drivers/nfc/pn544/Kconfig" source "drivers/nfc/pn544/Kconfig"
source "drivers/nfc/microread/Kconfig" source "drivers/nfc/microread/Kconfig"
source "drivers/nfc/nfcmrvl/Kconfig" source "drivers/nfc/nfcmrvl/Kconfig"
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
# Makefile for nfc devices # Makefile for nfc devices
# #
obj-$(CONFIG_NFC_FDP) += fdp/
obj-$(CONFIG_NFC_PN544) += pn544/ obj-$(CONFIG_NFC_PN544) += pn544/
obj-$(CONFIG_NFC_MICROREAD) += microread/ obj-$(CONFIG_NFC_MICROREAD) += microread/
obj-$(CONFIG_NFC_PN533) += pn533.o obj-$(CONFIG_NFC_PN533) += pn533.o
......
config NFC_FDP
tristate "Intel FDP NFC driver"
depends on NFC_NCI
select CRC_CCITT
default n
---help---
Intel Fields Peak NFC controller core driver.
This is a driver based on the NCI NFC kernel layers.
To compile this driver as a module, choose m here. The module will
be called fdp.
Say N if unsure.
config NFC_FDP_I2C
tristate "NFC FDP i2c support"
depends on NFC_FDP && I2C
---help---
This module adds support for the Intel Fields Peak NFC controller
i2c interface.
Select this if your platform is using the i2c bus.
If you choose to build a module, it'll be called fdp_i2c.
Say N if unsure.
#
# Makefile for FDP NCI based NFC driver
#
obj-$(CONFIG_NFC_FDP) += fdp.o
obj-$(CONFIG_NFC_FDP_I2C) += fdp_i2c.o
fdp_i2c-objs = i2c.o
This diff is collapsed.
/* -------------------------------------------------------------------------
* Copyright (C) 2014-2016, Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
* -------------------------------------------------------------------------
*/
#ifndef __LOCAL_FDP_H_
#define __LOCAL_FDP_H_
#include <net/nfc/nci_core.h>
#include <linux/gpio/consumer.h>
struct fdp_i2c_phy {
struct i2c_client *i2c_dev;
struct gpio_desc *power_gpio;
struct nci_dev *ndev;
/* < 0 if i2c error occurred */
int hard_fault;
uint16_t next_read_size;
};
int fdp_nci_probe(struct fdp_i2c_phy *phy, struct nfc_phy_ops *phy_ops,
struct nci_dev **ndev, int tx_headroom, int tx_tailroom,
u8 clock_type, u32 clock_freq, u8 *fw_vsc_cfg);
void fdp_nci_remove(struct nci_dev *ndev);
int fdp_nci_recv_frame(struct nci_dev *ndev, struct sk_buff *skb);
#endif /* __LOCAL_FDP_H_ */
/* -------------------------------------------------------------------------
* Copyright (C) 2014-2016, Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
* -------------------------------------------------------------------------
*/
#include <linux/module.h>
#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/nfc.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <net/nfc/nfc.h>
#include <net/nfc/nci_core.h>
#include "fdp.h"
#define FDP_I2C_DRIVER_NAME "fdp_nci_i2c"
#define FDP_DP_POWER_GPIO_NAME "power"
#define FDP_DP_CLOCK_TYPE_NAME "clock-type"
#define FDP_DP_CLOCK_FREQ_NAME "clock-freq"
#define FDP_DP_FW_VSC_CFG_NAME "fw-vsc-cfg"
#define FDP_FRAME_HEADROOM 2
#define FDP_FRAME_TAILROOM 1
#define FDP_NCI_I2C_MIN_PAYLOAD 5
#define FDP_NCI_I2C_MAX_PAYLOAD 261
#define FDP_POWER_OFF 0
#define FDP_POWER_ON 1
#define fdp_nci_i2c_dump_skb(dev, prefix, skb) \
print_hex_dump(KERN_DEBUG, prefix": ", DUMP_PREFIX_OFFSET, \
16, 1, (skb)->data, (skb)->len, 0)
static void fdp_nci_i2c_reset(struct fdp_i2c_phy *phy)
{
/* Reset RST/WakeUP for at least 100 micro-second */
gpiod_set_value_cansleep(phy->power_gpio, FDP_POWER_OFF);
usleep_range(1000, 4000);
gpiod_set_value_cansleep(phy->power_gpio, FDP_POWER_ON);
usleep_range(10000, 14000);
}
static int fdp_nci_i2c_enable(void *phy_id)
{
struct fdp_i2c_phy *phy = phy_id;
dev_dbg(&phy->i2c_dev->dev, "%s\n", __func__);
fdp_nci_i2c_reset(phy);
return 0;
}
static void fdp_nci_i2c_disable(void *phy_id)
{
struct fdp_i2c_phy *phy = phy_id;
dev_dbg(&phy->i2c_dev->dev, "%s\n", __func__);
fdp_nci_i2c_reset(phy);
}
static void fdp_nci_i2c_add_len_lrc(struct sk_buff *skb)
{
u8 lrc = 0;
u16 len, i;
/* Add length header */
len = skb->len;
*skb_push(skb, 1) = len & 0xff;
*skb_push(skb, 1) = len >> 8;
/* Compute and add lrc */
for (i = 0; i < len + 2; i++)
lrc ^= skb->data[i];
*skb_put(skb, 1) = lrc;
}
static void fdp_nci_i2c_remove_len_lrc(struct sk_buff *skb)
{
skb_pull(skb, FDP_FRAME_HEADROOM);
skb_trim(skb, skb->len - FDP_FRAME_TAILROOM);
}
static int fdp_nci_i2c_write(void *phy_id, struct sk_buff *skb)
{
struct fdp_i2c_phy *phy = phy_id;
struct i2c_client *client = phy->i2c_dev;
int r;
if (phy->hard_fault != 0)
return phy->hard_fault;
fdp_nci_i2c_add_len_lrc(skb);
fdp_nci_i2c_dump_skb(&client->dev, "fdp_wr", skb);
r = i2c_master_send(client, skb->data, skb->len);
if (r == -EREMOTEIO) { /* Retry, chip was in standby */
usleep_range(1000, 4000);
r = i2c_master_send(client, skb->data, skb->len);
}
if (r < 0 || r != skb->len)
dev_dbg(&client->dev, "%s: error err=%d len=%d\n",
__func__, r, skb->len);
if (r >= 0) {
if (r != skb->len) {
phy->hard_fault = r;
r = -EREMOTEIO;
} else {
r = 0;
}
}
fdp_nci_i2c_remove_len_lrc(skb);
return r;
}
static struct nfc_phy_ops i2c_phy_ops = {
.write = fdp_nci_i2c_write,
.enable = fdp_nci_i2c_enable,
.disable = fdp_nci_i2c_disable,
};
static int fdp_nci_i2c_read(struct fdp_i2c_phy *phy, struct sk_buff **skb)
{
int r, len;
u8 tmp[FDP_NCI_I2C_MAX_PAYLOAD], lrc, k;
u16 i;
struct i2c_client *client = phy->i2c_dev;
*skb = NULL;
/* Read the length packet and the data packet */
for (k = 0; k < 2; k++) {
len = phy->next_read_size;
r = i2c_master_recv(client, tmp, len);
if (r != len) {
dev_dbg(&client->dev, "%s: i2c recv err: %d\n",
__func__, r);
goto flush;
}
/* Check packet integruty */
for (lrc = i = 0; i < r; i++)
lrc ^= tmp[i];
/*
* LRC check failed. This may due to transmission error or
* desynchronization between driver and FDP. Drop the paquet
* and force resynchronization
*/
if (lrc) {
dev_dbg(&client->dev, "%s: corrupted packet\n",
__func__);
phy->next_read_size = 5;
goto flush;
}
/* Packet that contains a length */
if (tmp[0] == 0 && tmp[1] == 0) {
phy->next_read_size = (tmp[2] << 8) + tmp[3] + 3;
} else {
phy->next_read_size = FDP_NCI_I2C_MIN_PAYLOAD;
*skb = alloc_skb(len, GFP_KERNEL);
if (*skb == NULL) {
r = -ENOMEM;
goto flush;
}
memcpy(skb_put(*skb, len), tmp, len);
fdp_nci_i2c_dump_skb(&client->dev, "fdp_rd", *skb);
fdp_nci_i2c_remove_len_lrc(*skb);
}
}
return 0;
flush:
/* Flush the remaining data */
if (i2c_master_recv(client, tmp, sizeof(tmp)) < 0)
r = -EREMOTEIO;
return r;
}
static irqreturn_t fdp_nci_i2c_irq_thread_fn(int irq, void *phy_id)
{
struct fdp_i2c_phy *phy = phy_id;
struct i2c_client *client;
struct sk_buff *skb;
int r;
client = phy->i2c_dev;
dev_dbg(&client->dev, "%s\n", __func__);
if (!phy || irq != phy->i2c_dev->irq) {
WARN_ON_ONCE(1);
return IRQ_NONE;
}
r = fdp_nci_i2c_read(phy, &skb);
if (r == -EREMOTEIO)
return IRQ_HANDLED;
else if (r == -ENOMEM || r == -EBADMSG)
return IRQ_HANDLED;
if (skb != NULL)
fdp_nci_recv_frame(phy->ndev, skb);
return IRQ_HANDLED;
}
static void fdp_nci_i2c_read_device_properties(struct device *dev,
u8 *clock_type, u32 *clock_freq,
u8 **fw_vsc_cfg)
{
int r;
u8 len;
r = device_property_read_u8(dev, FDP_DP_CLOCK_TYPE_NAME, clock_type);
if (r) {
dev_dbg(dev, "Using default clock type");
*clock_type = 0;
}
r = device_property_read_u32(dev, FDP_DP_CLOCK_FREQ_NAME, clock_freq);
if (r) {
dev_dbg(dev, "Using default clock frequency\n");
*clock_freq = 26000;
}
if (device_property_present(dev, FDP_DP_FW_VSC_CFG_NAME)) {
r = device_property_read_u8(dev, FDP_DP_FW_VSC_CFG_NAME,
&len);
if (r || len <= 0)
goto vsc_read_err;
/* Add 1 to the length to inclue the length byte itself */
len++;
*fw_vsc_cfg = devm_kmalloc(dev,
len * sizeof(**fw_vsc_cfg),
GFP_KERNEL);
r = device_property_read_u8_array(dev, FDP_DP_FW_VSC_CFG_NAME,
*fw_vsc_cfg, len);
if (r) {
devm_kfree(dev, fw_vsc_cfg);
goto vsc_read_err;
}
} else {
vsc_read_err:
dev_dbg(dev, "FW vendor specific commands not present\n");
*fw_vsc_cfg = NULL;
}
dev_dbg(dev, "Clock type: %d, clock frequency: %d, VSC: %s",
*clock_type, *clock_freq, *fw_vsc_cfg != NULL ? "yes" : "no");
}
static int fdp_nci_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct fdp_i2c_phy *phy;
struct device *dev = &client->dev;
u8 *fw_vsc_cfg;
u8 clock_type;
u32 clock_freq;
int r = 0;
dev_dbg(dev, "%s\n", __func__);
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
nfc_err(dev, "No I2C_FUNC_I2C support\n");
return -ENODEV;
}
phy = devm_kzalloc(dev, sizeof(struct fdp_i2c_phy),
GFP_KERNEL);
if (!phy)
return -ENOMEM;
phy->i2c_dev = client;
phy->next_read_size = FDP_NCI_I2C_MIN_PAYLOAD;
i2c_set_clientdata(client, phy);
/* Checking if we have an irq */
if (client->irq <= 0) {
dev_err(dev, "IRQ not present\n");
return -ENODEV;
}
r = request_threaded_irq(client->irq, NULL, fdp_nci_i2c_irq_thread_fn,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
FDP_I2C_DRIVER_NAME, phy);
if (r < 0) {
nfc_err(&client->dev, "Unable to register IRQ handler\n");
return r;
}
/* Requesting the power gpio */
phy->power_gpio = devm_gpiod_get(dev, FDP_DP_POWER_GPIO_NAME,
GPIOD_OUT_LOW);
if (IS_ERR(phy->power_gpio)) {
nfc_err(dev, "Power GPIO request failed\n");
return PTR_ERR(phy->power_gpio);
}
/* read device properties to get the clock and production settings */
fdp_nci_i2c_read_device_properties(dev, &clock_type, &clock_freq,
&fw_vsc_cfg);
/* Call the NFC specific probe function */
r = fdp_nci_probe(phy, &i2c_phy_ops, &phy->ndev,
FDP_FRAME_HEADROOM, FDP_FRAME_TAILROOM,
clock_type, clock_freq, fw_vsc_cfg);
if (r < 0) {
nfc_err(dev, "NCI probing error\n");
return r;
}
dev_dbg(dev, "I2C driver loaded\n");
return 0;
}
static int fdp_nci_i2c_remove(struct i2c_client *client)
{
struct fdp_i2c_phy *phy = i2c_get_clientdata(client);
dev_dbg(&client->dev, "%s\n", __func__);
fdp_nci_remove(phy->ndev);
fdp_nci_i2c_disable(phy);
return 0;
}
static struct i2c_device_id fdp_nci_i2c_id_table[] = {
{"int339a", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, fdp_nci_i2c_id_table);
static const struct acpi_device_id fdp_nci_i2c_acpi_match[] = {
{"INT339A", 0},
{}
};
MODULE_DEVICE_TABLE(acpi, fdp_nci_i2c_acpi_match);
static struct i2c_driver fdp_nci_i2c_driver = {
.driver = {
.name = FDP_I2C_DRIVER_NAME,
.acpi_match_table = ACPI_PTR(fdp_nci_i2c_acpi_match),
},
.id_table = fdp_nci_i2c_id_table,
.probe = fdp_nci_i2c_probe,
.remove = fdp_nci_i2c_remove,
};
module_i2c_driver(fdp_nci_i2c_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("I2C driver for Intel Fields Peak NFC controller");
MODULE_AUTHOR("Robert Dolca <robert.dolca@intel.com>");
config NFC_MICROREAD config NFC_MICROREAD
tristate "Inside Secure microread NFC driver" tristate
depends on NFC_HCI
select CRC_CCITT select CRC_CCITT
default n
---help--- ---help---
This module contains the main code for Inside Secure microread This module contains the main code for Inside Secure microread
NFC chipsets. It implements the chipset HCI logic and hooks into NFC chipsets. It implements the chipset HCI logic and hooks into
the NFC kernel APIs. Physical layers will register against it. 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 microread.
Say N if unsure.
config NFC_MICROREAD_I2C config NFC_MICROREAD_I2C
tristate "NFC Microread i2c support" tristate "Inside Secure Microread device support (I2C)"
depends on NFC_MICROREAD && I2C && NFC_SHDLC depends on NFC_HCI && I2C && NFC_SHDLC
select NFC_MICROREAD
---help--- ---help---
This module adds support for the i2c interface of adapters using This module adds support for the i2c interface of adapters using
Inside microread chipsets. Select this if your platform is using Inside microread chipsets. Select this if your platform is using
...@@ -24,8 +19,9 @@ config NFC_MICROREAD_I2C ...@@ -24,8 +19,9 @@ config NFC_MICROREAD_I2C
Say N if unsure. Say N if unsure.
config NFC_MICROREAD_MEI config NFC_MICROREAD_MEI
tristate "NFC Microread MEI support" tristate "Inside Secure Microread device support (MEI)"
depends on NFC_MICROREAD && NFC_MEI_PHY depends on NFC_HCI && NFC_MEI_PHY
select NFC_MICROREAD
---help--- ---help---
This module adds support for the mei interface of adapters using This module adds support for the mei interface of adapters using
Inside microread chipsets. Select this if your microread chipset Inside microread chipsets. Select this if your microread chipset
......
config NFC_MRVL config NFC_MRVL
tristate "Marvell NFC driver support" tristate
depends on NFC_NCI
help help
The core driver to support Marvell NFC devices. The core driver to support Marvell NFC devices.
This driver is required if you want to support This driver is required if you want to support
Marvell NFC device 8897. Marvell NFC device 8897.
Say Y here to compile Marvell NFC driver into the kernel or
say M to compile it as module.
config NFC_MRVL_USB config NFC_MRVL_USB
tristate "Marvell NFC-over-USB driver" tristate "Marvell NFC-over-USB driver"
depends on NFC_MRVL && USB depends on NFC_NCI && USB
select NFC_MRVL
help help
Marvell NFC-over-USB driver. Marvell NFC-over-USB driver.
...@@ -24,7 +21,8 @@ config NFC_MRVL_USB ...@@ -24,7 +21,8 @@ config NFC_MRVL_USB
config NFC_MRVL_UART config NFC_MRVL_UART
tristate "Marvell NFC-over-UART driver" tristate "Marvell NFC-over-UART driver"
depends on NFC_MRVL && NFC_NCI_UART depends on NFC_NCI && NFC_NCI_UART
select NFC_MRVL
help help
Marvell NFC-over-UART driver. Marvell NFC-over-UART driver.
...@@ -32,3 +30,25 @@ config NFC_MRVL_UART ...@@ -32,3 +30,25 @@ config NFC_MRVL_UART
Say Y here to compile support for Marvell NFC-over-UART driver Say Y here to compile support for Marvell NFC-over-UART driver
into the kernel or say M to compile it as module. into the kernel or say M to compile it as module.
config NFC_MRVL_I2C
tristate "Marvell NFC-over-I2C driver"
depends on NFC_MRVL && I2C
help
Marvell NFC-over-I2C driver.
This driver provides support for Marvell NFC-over-I2C devices.
Say Y here to compile support for Marvell NFC-over-I2C driver
into the kernel or say M to compile it as module.
config NFC_MRVL_SPI
tristate "Marvell NFC-over-SPI driver"
depends on NFC_MRVL && SPI
help
Marvell NFC-over-SPI driver.
This driver provides support for Marvell NFC-over-SPI devices.
Say Y here to compile support for Marvell NFC-over-SPI driver
into the kernel or say M to compile it as module.
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# Makefile for NFCMRVL NCI based NFC driver # Makefile for NFCMRVL NCI based NFC driver
# #
nfcmrvl-y += main.o nfcmrvl-y += main.o fw_dnld.o
obj-$(CONFIG_NFC_MRVL) += nfcmrvl.o obj-$(CONFIG_NFC_MRVL) += nfcmrvl.o
nfcmrvl_usb-y += usb.o nfcmrvl_usb-y += usb.o
...@@ -10,3 +10,9 @@ obj-$(CONFIG_NFC_MRVL_USB) += nfcmrvl_usb.o ...@@ -10,3 +10,9 @@ obj-$(CONFIG_NFC_MRVL_USB) += nfcmrvl_usb.o
nfcmrvl_uart-y += uart.o nfcmrvl_uart-y += uart.o
obj-$(CONFIG_NFC_MRVL_UART) += nfcmrvl_uart.o obj-$(CONFIG_NFC_MRVL_UART) += nfcmrvl_uart.o
nfcmrvl_i2c-y += i2c.o
obj-$(CONFIG_NFC_MRVL_I2C) += nfcmrvl_i2c.o
nfcmrvl_spi-y += spi.o
obj-$(CONFIG_NFC_MRVL_SPI) += nfcmrvl_spi.o
This diff is collapsed.
/**
* Marvell NFC driver: Firmware downloader
*
* 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.
**/
#ifndef __NFCMRVL_FW_DNLD_H__
#define __NFCMRVL_FW_DNLD_H__
#include <linux/workqueue.h>
#define NFCMRVL_FW_MAGIC 0x88888888
#define NCI_OP_PROP_BOOT_CMD 0x3A
#define NCI_CORE_LC_PROP_FW_DL 0xFD
#define NCI_CORE_LC_CONNID_PROP_FW_DL 0x02
#define HELPER_CMD_ENTRY_POINT 0x04
#define HELPER_CMD_PACKET_FORMAT 0xA5
#define HELPER_ACK_PACKET_FORMAT 0x5A
#define HELPER_RETRY_REQUESTED (1 << 15)
struct nfcmrvl_private;
struct nfcmrvl_fw_uart_config {
uint8_t flow_control;
uint32_t baudrate;
} __packed;
struct nfcmrvl_fw_i2c_config {
uint32_t clk;
} __packed;
struct nfcmrvl_fw_spi_config {
uint32_t clk;
} __packed;
struct nfcmrvl_fw_binary_config {
uint32_t offset;
union {
void *config;
struct nfcmrvl_fw_uart_config uart;
struct nfcmrvl_fw_i2c_config i2c;
struct nfcmrvl_fw_spi_config spi;
uint8_t reserved[64];
};
} __packed;
struct nfcmrvl_fw {
uint32_t magic;
uint32_t ref_clock;
uint32_t phy;
struct nfcmrvl_fw_binary_config bootrom;
struct nfcmrvl_fw_binary_config helper;
struct nfcmrvl_fw_binary_config firmware;
uint8_t reserved[64];
} __packed;
struct nfcmrvl_fw_dnld {
char name[NFC_FIRMWARE_NAME_MAXSIZE + 1];
const struct firmware *fw;
const struct nfcmrvl_fw *header;
const struct nfcmrvl_fw_binary_config *binary_config;
int state;
int substate;
int offset;
int chunk_len;
struct workqueue_struct *rx_wq;
struct work_struct rx_work;
struct sk_buff_head rx_q;
struct timer_list timer;
};
int nfcmrvl_fw_dnld_init(struct nfcmrvl_private *priv);
void nfcmrvl_fw_dnld_deinit(struct nfcmrvl_private *priv);
void nfcmrvl_fw_dnld_abort(struct nfcmrvl_private *priv);
int nfcmrvl_fw_dnld_start(struct nci_dev *ndev, const char *firmware_name);
void nfcmrvl_fw_dnld_recv_frame(struct nfcmrvl_private *priv,
struct sk_buff *skb);
#endif
/**
* Marvell NFC-over-I2C driver: I2C interface related functions
*
* 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/interrupt.h>
#include <linux/i2c.h>
#include <linux/pm_runtime.h>
#include <linux/nfc.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <net/nfc/nci.h>
#include <net/nfc/nci_core.h>
#include "nfcmrvl.h"
struct nfcmrvl_i2c_drv_data {
unsigned long flags;
struct device *dev;
struct i2c_client *i2c;
struct nfcmrvl_private *priv;
};
static int nfcmrvl_i2c_read(struct nfcmrvl_i2c_drv_data *drv_data,
struct sk_buff **skb)
{
int ret;
struct nci_ctrl_hdr nci_hdr;
/* Read NCI header to know the payload size */
ret = i2c_master_recv(drv_data->i2c, (u8 *)&nci_hdr, NCI_CTRL_HDR_SIZE);
if (ret != NCI_CTRL_HDR_SIZE) {
nfc_err(&drv_data->i2c->dev, "cannot read NCI header\n");
return -EBADMSG;
}
if (nci_hdr.plen > NCI_MAX_PAYLOAD_SIZE) {
nfc_err(&drv_data->i2c->dev, "invalid packet payload size\n");
return -EBADMSG;
}
*skb = nci_skb_alloc(drv_data->priv->ndev,
nci_hdr.plen + NCI_CTRL_HDR_SIZE, GFP_KERNEL);
if (!*skb)
return -ENOMEM;
/* Copy NCI header into the SKB */
memcpy(skb_put(*skb, NCI_CTRL_HDR_SIZE), &nci_hdr, NCI_CTRL_HDR_SIZE);
if (nci_hdr.plen) {
/* Read the NCI payload */
ret = i2c_master_recv(drv_data->i2c,
skb_put(*skb, nci_hdr.plen),
nci_hdr.plen);
if (ret != nci_hdr.plen) {
nfc_err(&drv_data->i2c->dev,
"Invalid frame payload length: %u (expected %u)\n",
ret, nci_hdr.plen);
kfree_skb(*skb);
return -EBADMSG;
}
}
return 0;
}
static irqreturn_t nfcmrvl_i2c_int_irq_thread_fn(int irq, void *drv_data_ptr)
{
struct nfcmrvl_i2c_drv_data *drv_data = drv_data_ptr;
struct sk_buff *skb = NULL;
int ret;
if (!drv_data->priv)
return IRQ_HANDLED;
if (test_bit(NFCMRVL_PHY_ERROR, &drv_data->priv->flags))
return IRQ_HANDLED;
ret = nfcmrvl_i2c_read(drv_data, &skb);
switch (ret) {
case -EREMOTEIO:
set_bit(NFCMRVL_PHY_ERROR, &drv_data->priv->flags);
break;
case -ENOMEM:
case -EBADMSG:
nfc_err(&drv_data->i2c->dev, "read failed %d\n", ret);
break;
default:
if (nfcmrvl_nci_recv_frame(drv_data->priv, skb) < 0)
nfc_err(&drv_data->i2c->dev, "corrupted RX packet\n");
break;
}
return IRQ_HANDLED;
}
static int nfcmrvl_i2c_nci_open(struct nfcmrvl_private *priv)
{
struct nfcmrvl_i2c_drv_data *drv_data = priv->drv_data;
if (!drv_data)
return -ENODEV;
return 0;
}
static int nfcmrvl_i2c_nci_close(struct nfcmrvl_private *priv)
{
return 0;
}
static int nfcmrvl_i2c_nci_send(struct nfcmrvl_private *priv,
struct sk_buff *skb)
{
struct nfcmrvl_i2c_drv_data *drv_data = priv->drv_data;
int ret;
if (test_bit(NFCMRVL_PHY_ERROR, &priv->flags))
return -EREMOTEIO;
ret = i2c_master_send(drv_data->i2c, skb->data, skb->len);
/* Retry if chip was in standby */
if (ret == -EREMOTEIO) {
nfc_info(drv_data->dev, "chip may sleep, retry\n");
usleep_range(6000, 10000);
ret = i2c_master_send(drv_data->i2c, skb->data, skb->len);
}
if (ret >= 0) {
if (ret != skb->len) {
nfc_err(drv_data->dev,
"Invalid length sent: %u (expected %u)\n",
ret, skb->len);
ret = -EREMOTEIO;
} else
ret = 0;
kfree_skb(skb);
}
return ret;
}
static void nfcmrvl_i2c_nci_update_config(struct nfcmrvl_private *priv,
const void *param)
{
}
static struct nfcmrvl_if_ops i2c_ops = {
.nci_open = nfcmrvl_i2c_nci_open,
.nci_close = nfcmrvl_i2c_nci_close,
.nci_send = nfcmrvl_i2c_nci_send,
.nci_update_config = nfcmrvl_i2c_nci_update_config,
};
static int nfcmrvl_i2c_parse_dt(struct device_node *node,
struct nfcmrvl_platform_data *pdata)
{
int ret;
ret = nfcmrvl_parse_dt(node, pdata);
if (ret < 0) {
pr_err("Failed to get generic entries\n");
return ret;
}
if (of_find_property(node, "i2c-int-falling", NULL))
pdata->irq_polarity = IRQF_TRIGGER_FALLING;
else
pdata->irq_polarity = IRQF_TRIGGER_RISING;
ret = irq_of_parse_and_map(node, 0);
if (ret < 0) {
pr_err("Unable to get irq, error: %d\n", ret);
return ret;
}
pdata->irq = ret;
return 0;
}
static int nfcmrvl_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct nfcmrvl_i2c_drv_data *drv_data;
struct nfcmrvl_platform_data *pdata;
struct nfcmrvl_platform_data config;
int ret;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
nfc_err(&client->dev, "Need I2C_FUNC_I2C\n");
return -ENODEV;
}
drv_data = devm_kzalloc(&client->dev, sizeof(*drv_data), GFP_KERNEL);
if (!drv_data)
return -ENOMEM;
drv_data->i2c = client;
drv_data->dev = &client->dev;
drv_data->priv = NULL;
i2c_set_clientdata(client, drv_data);
pdata = client->dev.platform_data;
if (!pdata && client->dev.of_node)
if (nfcmrvl_i2c_parse_dt(client->dev.of_node, &config) == 0)
pdata = &config;
if (!pdata)
return -EINVAL;
/* Request the read IRQ */
ret = devm_request_threaded_irq(&drv_data->i2c->dev, pdata->irq,
NULL, nfcmrvl_i2c_int_irq_thread_fn,
pdata->irq_polarity | IRQF_ONESHOT,
"nfcmrvl_i2c_int", drv_data);
if (ret < 0) {
nfc_err(&drv_data->i2c->dev,
"Unable to register IRQ handler\n");
return ret;
}
drv_data->priv = nfcmrvl_nci_register_dev(NFCMRVL_PHY_I2C,
drv_data, &i2c_ops,
&drv_data->i2c->dev, pdata);
if (IS_ERR(drv_data->priv))
return PTR_ERR(drv_data->priv);
drv_data->priv->support_fw_dnld = true;
return 0;
}
static int nfcmrvl_i2c_remove(struct i2c_client *client)
{
struct nfcmrvl_i2c_drv_data *drv_data = i2c_get_clientdata(client);
nfcmrvl_nci_unregister_dev(drv_data->priv);
return 0;
}
static const struct of_device_id of_nfcmrvl_i2c_match[] = {
{ .compatible = "marvell,nfc-i2c", },
{},
};
MODULE_DEVICE_TABLE(of, of_nfcmrvl_i2c_match);
static struct i2c_device_id nfcmrvl_i2c_id_table[] = {
{ "nfcmrvl_i2c", 0 },
{}
};
MODULE_DEVICE_TABLE(i2c, nfcmrvl_i2c_id_table);
static struct i2c_driver nfcmrvl_i2c_driver = {
.probe = nfcmrvl_i2c_probe,
.id_table = nfcmrvl_i2c_id_table,
.remove = nfcmrvl_i2c_remove,
.driver = {
.name = "nfcmrvl_i2c",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(of_nfcmrvl_i2c_match),
},
};
module_i2c_driver(nfcmrvl_i2c_driver);
MODULE_AUTHOR("Marvell International Ltd.");
MODULE_DESCRIPTION("Marvell NFC-over-I2C driver");
MODULE_LICENSE("GPL v2");
/* /*
* Marvell NFC driver: major functions * Marvell NFC driver: major functions
* *
* Copyright (C) 2014, Marvell International Ltd. * Copyright (C) 2014-2015 Marvell International Ltd.
* *
* This software file (the "File") is distributed by Marvell International * This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
...@@ -25,8 +25,6 @@ ...@@ -25,8 +25,6 @@
#include <net/nfc/nci_core.h> #include <net/nfc/nci_core.h>
#include "nfcmrvl.h" #include "nfcmrvl.h"
#define VERSION "1.0"
static int nfcmrvl_nci_open(struct nci_dev *ndev) static int nfcmrvl_nci_open(struct nci_dev *ndev)
{ {
struct nfcmrvl_private *priv = nci_get_drvdata(ndev); struct nfcmrvl_private *priv = nci_get_drvdata(ndev);
...@@ -35,6 +33,9 @@ static int nfcmrvl_nci_open(struct nci_dev *ndev) ...@@ -35,6 +33,9 @@ static int nfcmrvl_nci_open(struct nci_dev *ndev)
if (test_and_set_bit(NFCMRVL_NCI_RUNNING, &priv->flags)) if (test_and_set_bit(NFCMRVL_NCI_RUNNING, &priv->flags))
return 0; return 0;
/* Reset possible fault of previous session */
clear_bit(NFCMRVL_PHY_ERROR, &priv->flags);
err = priv->if_ops->nci_open(priv); err = priv->if_ops->nci_open(priv);
if (err) if (err)
...@@ -63,9 +64,6 @@ static int nfcmrvl_nci_send(struct nci_dev *ndev, struct sk_buff *skb) ...@@ -63,9 +64,6 @@ static int nfcmrvl_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
skb->dev = (void *)ndev; skb->dev = (void *)ndev;
if (!test_bit(NFCMRVL_NCI_RUNNING, &priv->flags))
return -EBUSY;
if (priv->config.hci_muxed) { if (priv->config.hci_muxed) {
unsigned char *hdr; unsigned char *hdr;
unsigned char len = skb->len; unsigned char len = skb->len;
...@@ -88,21 +86,30 @@ static int nfcmrvl_nci_setup(struct nci_dev *ndev) ...@@ -88,21 +86,30 @@ static int nfcmrvl_nci_setup(struct nci_dev *ndev)
return 0; return 0;
} }
static int nfcmrvl_nci_fw_download(struct nci_dev *ndev,
const char *firmware_name)
{
return nfcmrvl_fw_dnld_start(ndev, firmware_name);
}
static struct nci_ops nfcmrvl_nci_ops = { static struct nci_ops nfcmrvl_nci_ops = {
.open = nfcmrvl_nci_open, .open = nfcmrvl_nci_open,
.close = nfcmrvl_nci_close, .close = nfcmrvl_nci_close,
.send = nfcmrvl_nci_send, .send = nfcmrvl_nci_send,
.setup = nfcmrvl_nci_setup, .setup = nfcmrvl_nci_setup,
.fw_download = nfcmrvl_nci_fw_download,
}; };
struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data, struct nfcmrvl_private *nfcmrvl_nci_register_dev(enum nfcmrvl_phy phy,
void *drv_data,
struct nfcmrvl_if_ops *ops, struct nfcmrvl_if_ops *ops,
struct device *dev, struct device *dev,
struct nfcmrvl_platform_data *pdata) struct nfcmrvl_platform_data *pdata)
{ {
struct nfcmrvl_private *priv; struct nfcmrvl_private *priv;
int rc; int rc;
int headroom = 0; int headroom;
int tailroom;
u32 protocols; u32 protocols;
priv = kzalloc(sizeof(*priv), GFP_KERNEL); priv = kzalloc(sizeof(*priv), GFP_KERNEL);
...@@ -112,6 +119,7 @@ struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data, ...@@ -112,6 +119,7 @@ struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data,
priv->drv_data = drv_data; priv->drv_data = drv_data;
priv->if_ops = ops; priv->if_ops = ops;
priv->dev = dev; priv->dev = dev;
priv->phy = phy;
memcpy(&priv->config, pdata, sizeof(*pdata)); memcpy(&priv->config, pdata, sizeof(*pdata));
...@@ -124,8 +132,14 @@ struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data, ...@@ -124,8 +132,14 @@ struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data,
nfc_err(dev, "failed to request reset_n io\n"); nfc_err(dev, "failed to request reset_n io\n");
} }
if (phy == NFCMRVL_PHY_SPI) {
headroom = NCI_SPI_HDR_LEN;
tailroom = 1;
} else
headroom = tailroom = 0;
if (priv->config.hci_muxed) if (priv->config.hci_muxed)
headroom = NFCMRVL_HCI_EVENT_HEADER_SIZE; headroom += NFCMRVL_HCI_EVENT_HEADER_SIZE;
protocols = NFC_PROTO_JEWEL_MASK protocols = NFC_PROTO_JEWEL_MASK
| NFC_PROTO_MIFARE_MASK | NFC_PROTO_MIFARE_MASK
...@@ -136,7 +150,7 @@ struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data, ...@@ -136,7 +150,7 @@ struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data,
| NFC_PROTO_NFC_DEP_MASK; | NFC_PROTO_NFC_DEP_MASK;
priv->ndev = nci_allocate_device(&nfcmrvl_nci_ops, protocols, priv->ndev = nci_allocate_device(&nfcmrvl_nci_ops, protocols,
headroom, 0); headroom, tailroom);
if (!priv->ndev) { if (!priv->ndev) {
nfc_err(dev, "nci_allocate_device failed\n"); nfc_err(dev, "nci_allocate_device failed\n");
rc = -ENOMEM; rc = -ENOMEM;
...@@ -145,18 +159,26 @@ struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data, ...@@ -145,18 +159,26 @@ struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data,
nci_set_drvdata(priv->ndev, priv); nci_set_drvdata(priv->ndev, priv);
nfcmrvl_chip_reset(priv);
rc = nci_register_device(priv->ndev); rc = nci_register_device(priv->ndev);
if (rc) { if (rc) {
nfc_err(dev, "nci_register_device failed %d\n", rc); nfc_err(dev, "nci_register_device failed %d\n", rc);
nci_free_device(priv->ndev); goto error_free_dev;
goto error; }
/* Ensure that controller is powered off */
nfcmrvl_chip_halt(priv);
rc = nfcmrvl_fw_dnld_init(priv);
if (rc) {
nfc_err(dev, "failed to initialize FW download %d\n", rc);
goto error_free_dev;
} }
nfc_info(dev, "registered with nci successfully\n"); nfc_info(dev, "registered with nci successfully\n");
return priv; return priv;
error_free_dev:
nci_free_device(priv->ndev);
error: error:
kfree(priv); kfree(priv);
return ERR_PTR(rc); return ERR_PTR(rc);
...@@ -167,6 +189,11 @@ void nfcmrvl_nci_unregister_dev(struct nfcmrvl_private *priv) ...@@ -167,6 +189,11 @@ void nfcmrvl_nci_unregister_dev(struct nfcmrvl_private *priv)
{ {
struct nci_dev *ndev = priv->ndev; struct nci_dev *ndev = priv->ndev;
if (priv->ndev->nfc_dev->fw_download_in_progress)
nfcmrvl_fw_dnld_abort(priv);
nfcmrvl_fw_dnld_deinit(priv);
nci_unregister_device(ndev); nci_unregister_device(ndev);
nci_free_device(ndev); nci_free_device(ndev);
kfree(priv); kfree(priv);
...@@ -187,6 +214,11 @@ int nfcmrvl_nci_recv_frame(struct nfcmrvl_private *priv, struct sk_buff *skb) ...@@ -187,6 +214,11 @@ int nfcmrvl_nci_recv_frame(struct nfcmrvl_private *priv, struct sk_buff *skb)
} }
} }
if (priv->ndev->nfc_dev->fw_download_in_progress) {
nfcmrvl_fw_dnld_recv_frame(priv, skb);
return 0;
}
if (test_bit(NFCMRVL_NCI_RUNNING, &priv->flags)) if (test_bit(NFCMRVL_NCI_RUNNING, &priv->flags))
nci_recv_frame(priv->ndev, skb); nci_recv_frame(priv->ndev, skb);
else { else {
...@@ -201,10 +233,8 @@ EXPORT_SYMBOL_GPL(nfcmrvl_nci_recv_frame); ...@@ -201,10 +233,8 @@ EXPORT_SYMBOL_GPL(nfcmrvl_nci_recv_frame);
void nfcmrvl_chip_reset(struct nfcmrvl_private *priv) void nfcmrvl_chip_reset(struct nfcmrvl_private *priv)
{ {
/* /* Reset possible fault of previous session */
* This function does not take care if someone is using the device. clear_bit(NFCMRVL_PHY_ERROR, &priv->flags);
* To be improved.
*/
if (priv->config.reset_n_io) { if (priv->config.reset_n_io) {
nfc_info(priv->dev, "reset the chip\n"); nfc_info(priv->dev, "reset the chip\n");
...@@ -215,6 +245,12 @@ void nfcmrvl_chip_reset(struct nfcmrvl_private *priv) ...@@ -215,6 +245,12 @@ void nfcmrvl_chip_reset(struct nfcmrvl_private *priv)
nfc_info(priv->dev, "no reset available on this interface\n"); nfc_info(priv->dev, "no reset available on this interface\n");
} }
void nfcmrvl_chip_halt(struct nfcmrvl_private *priv)
{
if (priv->config.reset_n_io)
gpio_set_value(priv->config.reset_n_io, 0);
}
#ifdef CONFIG_OF #ifdef CONFIG_OF
int nfcmrvl_parse_dt(struct device_node *node, int nfcmrvl_parse_dt(struct device_node *node,
...@@ -252,6 +288,5 @@ int nfcmrvl_parse_dt(struct device_node *node, ...@@ -252,6 +288,5 @@ int nfcmrvl_parse_dt(struct device_node *node,
EXPORT_SYMBOL_GPL(nfcmrvl_parse_dt); EXPORT_SYMBOL_GPL(nfcmrvl_parse_dt);
MODULE_AUTHOR("Marvell International Ltd."); MODULE_AUTHOR("Marvell International Ltd.");
MODULE_DESCRIPTION("Marvell NFC driver ver " VERSION); MODULE_DESCRIPTION("Marvell NFC driver");
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
/** /**
* Marvell NFC driver * Marvell NFC driver
* *
* Copyright (C) 2014, Marvell International Ltd. * Copyright (C) 2014-2015, Marvell International Ltd.
* *
* This software file (the "File") is distributed by Marvell International * This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
...@@ -21,8 +21,11 @@ ...@@ -21,8 +21,11 @@
#include <linux/platform_data/nfcmrvl.h> #include <linux/platform_data/nfcmrvl.h>
#include "fw_dnld.h"
/* Define private flags: */ /* Define private flags: */
#define NFCMRVL_NCI_RUNNING 1 #define NFCMRVL_NCI_RUNNING 1
#define NFCMRVL_PHY_ERROR 2
#define NFCMRVL_EXT_COEX_ID 0xE0 #define NFCMRVL_EXT_COEX_ID 0xE0
#define NFCMRVL_NOT_ALLOWED_ID 0xE1 #define NFCMRVL_NOT_ALLOWED_ID 0xE1
...@@ -37,6 +40,8 @@ ...@@ -37,6 +40,8 @@
*/ */
#define NFCMRVL_PB_BAIL_OUT 0x11 #define NFCMRVL_PB_BAIL_OUT 0x11
#define NFCMRVL_PROP_REF_CLOCK 0xF0
#define NFCMRVL_PROP_SET_HI_CONFIG 0xF1
/* /*
** HCI defines ** HCI defines
...@@ -52,9 +57,10 @@ ...@@ -52,9 +57,10 @@
enum nfcmrvl_phy { enum nfcmrvl_phy {
NFCMRVL_PHY_USB = 0, NFCMRVL_PHY_USB = 0,
NFCMRVL_PHY_UART = 1, NFCMRVL_PHY_UART = 1,
NFCMRVL_PHY_I2C = 2,
NFCMRVL_PHY_SPI = 3,
}; };
struct nfcmrvl_private { struct nfcmrvl_private {
unsigned long flags; unsigned long flags;
...@@ -62,8 +68,15 @@ struct nfcmrvl_private { ...@@ -62,8 +68,15 @@ struct nfcmrvl_private {
/* Platform configuration */ /* Platform configuration */
struct nfcmrvl_platform_data config; struct nfcmrvl_platform_data config;
/* Parent dev */
struct nci_dev *ndev; struct nci_dev *ndev;
/* FW download context */
struct nfcmrvl_fw_dnld fw_dnld;
/* FW download support */
bool support_fw_dnld;
/* /*
** PHY related information ** PHY related information
*/ */
...@@ -82,17 +95,21 @@ struct nfcmrvl_if_ops { ...@@ -82,17 +95,21 @@ struct nfcmrvl_if_ops {
int (*nci_open) (struct nfcmrvl_private *priv); int (*nci_open) (struct nfcmrvl_private *priv);
int (*nci_close) (struct nfcmrvl_private *priv); int (*nci_close) (struct nfcmrvl_private *priv);
int (*nci_send) (struct nfcmrvl_private *priv, struct sk_buff *skb); int (*nci_send) (struct nfcmrvl_private *priv, struct sk_buff *skb);
void (*nci_update_config)(struct nfcmrvl_private *priv,
const void *param);
}; };
void nfcmrvl_nci_unregister_dev(struct nfcmrvl_private *priv); void nfcmrvl_nci_unregister_dev(struct nfcmrvl_private *priv);
int nfcmrvl_nci_recv_frame(struct nfcmrvl_private *priv, struct sk_buff *skb); 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_private *nfcmrvl_nci_register_dev(enum nfcmrvl_phy phy,
void *drv_data,
struct nfcmrvl_if_ops *ops, struct nfcmrvl_if_ops *ops,
struct device *dev, struct device *dev,
struct nfcmrvl_platform_data *pdata); struct nfcmrvl_platform_data *pdata);
void nfcmrvl_chip_reset(struct nfcmrvl_private *priv); void nfcmrvl_chip_reset(struct nfcmrvl_private *priv);
void nfcmrvl_chip_halt(struct nfcmrvl_private *priv);
int nfcmrvl_parse_dt(struct device_node *node, int nfcmrvl_parse_dt(struct device_node *node,
struct nfcmrvl_platform_data *pdata); struct nfcmrvl_platform_data *pdata);
......
/**
* Marvell NFC-over-SPI driver: SPI interface related functions
*
* 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/interrupt.h>
#include <linux/pm_runtime.h>
#include <linux/nfc.h>
#include <linux/gpio.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <net/nfc/nci.h>
#include <net/nfc/nci_core.h>
#include <linux/spi/spi.h>
#include <linux/gpio.h>
#include "nfcmrvl.h"
#define SPI_WAIT_HANDSHAKE 1
struct nfcmrvl_spi_drv_data {
unsigned long flags;
struct spi_device *spi;
struct nci_spi *nci_spi;
struct completion handshake_completion;
struct nfcmrvl_private *priv;
};
static irqreturn_t nfcmrvl_spi_int_irq_thread_fn(int irq, void *drv_data_ptr)
{
struct nfcmrvl_spi_drv_data *drv_data = drv_data_ptr;
struct sk_buff *skb;
/*
* Special case where we are waiting for SPI_INT deassertion to start a
* transfer.
*/
if (test_and_clear_bit(SPI_WAIT_HANDSHAKE, &drv_data->flags)) {
complete(&drv_data->handshake_completion);
return IRQ_HANDLED;
}
/* Normal case, SPI_INT deasserted by slave to trigger a master read */
skb = nci_spi_read(drv_data->nci_spi);
if (!skb) {
nfc_err(&drv_data->spi->dev, "failed to read spi packet");
return IRQ_HANDLED;
}
if (nfcmrvl_nci_recv_frame(drv_data->priv, skb) < 0)
nfc_err(&drv_data->spi->dev, "corrupted RX packet");
return IRQ_HANDLED;
}
static int nfcmrvl_spi_nci_open(struct nfcmrvl_private *priv)
{
return 0;
}
static int nfcmrvl_spi_nci_close(struct nfcmrvl_private *priv)
{
return 0;
}
static int nfcmrvl_spi_nci_send(struct nfcmrvl_private *priv,
struct sk_buff *skb)
{
struct nfcmrvl_spi_drv_data *drv_data = priv->drv_data;
int err;
/* Reinit completion for slave handshake */
reinit_completion(&drv_data->handshake_completion);
set_bit(SPI_WAIT_HANDSHAKE, &drv_data->flags);
/*
* Append a dummy byte at the end of SPI frame. This is due to a
* specific DMA implementation in the controller
*/
skb_put(skb, 1);
/* Send the SPI packet */
err = nci_spi_send(drv_data->nci_spi, &drv_data->handshake_completion,
skb);
if (err != 0) {
nfc_err(priv->dev, "spi_send failed %d", err);
kfree_skb(skb);
}
return err;
}
static void nfcmrvl_spi_nci_update_config(struct nfcmrvl_private *priv,
const void *param)
{
struct nfcmrvl_spi_drv_data *drv_data = priv->drv_data;
const struct nfcmrvl_fw_spi_config *config = param;
drv_data->nci_spi->xfer_speed_hz = config->clk;
}
static struct nfcmrvl_if_ops spi_ops = {
.nci_open = nfcmrvl_spi_nci_open,
.nci_close = nfcmrvl_spi_nci_close,
.nci_send = nfcmrvl_spi_nci_send,
.nci_update_config = nfcmrvl_spi_nci_update_config,
};
static int nfcmrvl_spi_parse_dt(struct device_node *node,
struct nfcmrvl_platform_data *pdata)
{
int ret;
ret = nfcmrvl_parse_dt(node, pdata);
if (ret < 0) {
pr_err("Failed to get generic entries\n");
return ret;
}
ret = irq_of_parse_and_map(node, 0);
if (ret < 0) {
pr_err("Unable to get irq, error: %d\n", ret);
return ret;
}
pdata->irq = ret;
return 0;
}
static int nfcmrvl_spi_probe(struct spi_device *spi)
{
struct nfcmrvl_platform_data *pdata;
struct nfcmrvl_platform_data config;
struct nfcmrvl_spi_drv_data *drv_data;
int ret = 0;
drv_data = devm_kzalloc(&spi->dev, sizeof(*drv_data), GFP_KERNEL);
if (!drv_data)
return -ENOMEM;
drv_data->spi = spi;
drv_data->priv = NULL;
spi_set_drvdata(spi, drv_data);
pdata = spi->dev.platform_data;
if (!pdata && spi->dev.of_node)
if (nfcmrvl_spi_parse_dt(spi->dev.of_node, &config) == 0)
pdata = &config;
if (!pdata)
return -EINVAL;
ret = devm_request_threaded_irq(&drv_data->spi->dev, pdata->irq,
NULL, nfcmrvl_spi_int_irq_thread_fn,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"nfcmrvl_spi_int", drv_data);
if (ret < 0) {
nfc_err(&drv_data->spi->dev, "Unable to register IRQ handler");
return -ENODEV;
}
drv_data->priv = nfcmrvl_nci_register_dev(NFCMRVL_PHY_SPI,
drv_data, &spi_ops,
&drv_data->spi->dev,
pdata);
if (IS_ERR(drv_data->priv))
return PTR_ERR(drv_data->priv);
drv_data->priv->support_fw_dnld = true;
drv_data->nci_spi = nci_spi_allocate_spi(drv_data->spi, 0, 10,
drv_data->priv->ndev);
/* Init completion for slave handshake */
init_completion(&drv_data->handshake_completion);
return 0;
}
static int nfcmrvl_spi_remove(struct spi_device *spi)
{
struct nfcmrvl_spi_drv_data *drv_data = spi_get_drvdata(spi);
nfcmrvl_nci_unregister_dev(drv_data->priv);
return 0;
}
static const struct of_device_id of_nfcmrvl_spi_match[] = {
{ .compatible = "marvell,nfc-spi", },
{},
};
MODULE_DEVICE_TABLE(of, of_nfcmrvl_spi_match);
static const struct spi_device_id nfcmrvl_spi_id_table[] = {
{ "nfcmrvl_spi", 0 },
{ }
};
MODULE_DEVICE_TABLE(spi, nfcmrvl_spi_id_table);
static struct spi_driver nfcmrvl_spi_driver = {
.probe = nfcmrvl_spi_probe,
.remove = nfcmrvl_spi_remove,
.id_table = nfcmrvl_spi_id_table,
.driver = {
.name = "nfcmrvl_spi",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(of_nfcmrvl_spi_match),
},
};
module_spi_driver(nfcmrvl_spi_driver);
MODULE_AUTHOR("Marvell International Ltd.");
MODULE_DESCRIPTION("Marvell NFC-over-SPI driver");
MODULE_LICENSE("GPL v2");
...@@ -50,10 +50,21 @@ static int nfcmrvl_uart_nci_send(struct nfcmrvl_private *priv, ...@@ -50,10 +50,21 @@ static int nfcmrvl_uart_nci_send(struct nfcmrvl_private *priv,
return nu->ops.send(nu, skb); return nu->ops.send(nu, skb);
} }
static void nfcmrvl_uart_nci_update_config(struct nfcmrvl_private *priv,
const void *param)
{
struct nci_uart *nu = priv->drv_data;
const struct nfcmrvl_fw_uart_config *config = param;
nci_uart_set_config(nu, le32_to_cpu(config->baudrate),
config->flow_control);
}
static struct nfcmrvl_if_ops uart_ops = { static struct nfcmrvl_if_ops uart_ops = {
.nci_open = nfcmrvl_uart_nci_open, .nci_open = nfcmrvl_uart_nci_open,
.nci_close = nfcmrvl_uart_nci_close, .nci_close = nfcmrvl_uart_nci_close,
.nci_send = nfcmrvl_uart_nci_send, .nci_send = nfcmrvl_uart_nci_send,
.nci_update_config = nfcmrvl_uart_nci_update_config
}; };
#ifdef CONFIG_OF #ifdef CONFIG_OF
...@@ -64,9 +75,13 @@ static int nfcmrvl_uart_parse_dt(struct device_node *node, ...@@ -64,9 +75,13 @@ static int nfcmrvl_uart_parse_dt(struct device_node *node,
struct device_node *matched_node; struct device_node *matched_node;
int ret; int ret;
matched_node = of_find_compatible_node(node, NULL, "mrvl,nfc-uart"); matched_node = of_find_compatible_node(node, NULL, "marvell,nfc-uart");
if (!matched_node) {
matched_node = of_find_compatible_node(node, NULL,
"mrvl,nfc-uart");
if (!matched_node) if (!matched_node)
return -ENODEV; return -ENODEV;
}
ret = nfcmrvl_parse_dt(matched_node, pdata); ret = nfcmrvl_parse_dt(matched_node, pdata);
if (ret < 0) { if (ret < 0) {
...@@ -127,11 +142,12 @@ static int nfcmrvl_nci_uart_open(struct nci_uart *nu) ...@@ -127,11 +142,12 @@ static int nfcmrvl_nci_uart_open(struct nci_uart *nu)
pdata = &config; pdata = &config;
} }
priv = nfcmrvl_nci_register_dev(nu, &uart_ops, nu->tty->dev, pdata); priv = nfcmrvl_nci_register_dev(NFCMRVL_PHY_UART, nu, &uart_ops,
nu->tty->dev, pdata);
if (IS_ERR(priv)) if (IS_ERR(priv))
return PTR_ERR(priv); return PTR_ERR(priv);
priv->phy = NFCMRVL_PHY_UART; priv->support_fw_dnld = true;
nu->drv_data = priv; nu->drv_data = priv;
nu->ndev = priv->ndev; nu->ndev = priv->ndev;
......
...@@ -23,8 +23,6 @@ ...@@ -23,8 +23,6 @@
#include <net/nfc/nci_core.h> #include <net/nfc/nci_core.h>
#include "nfcmrvl.h" #include "nfcmrvl.h"
#define VERSION "1.0"
static struct usb_device_id nfcmrvl_table[] = { static struct usb_device_id nfcmrvl_table[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(0x1286, 0x2046, { USB_DEVICE_AND_INTERFACE_INFO(0x1286, 0x2046,
USB_CLASS_VENDOR_SPEC, 4, 1) }, USB_CLASS_VENDOR_SPEC, 4, 1) },
...@@ -342,13 +340,14 @@ static int nfcmrvl_probe(struct usb_interface *intf, ...@@ -342,13 +340,14 @@ static int nfcmrvl_probe(struct usb_interface *intf,
init_usb_anchor(&drv_data->bulk_anchor); init_usb_anchor(&drv_data->bulk_anchor);
init_usb_anchor(&drv_data->deferred); init_usb_anchor(&drv_data->deferred);
priv = nfcmrvl_nci_register_dev(drv_data, &usb_ops, priv = nfcmrvl_nci_register_dev(NFCMRVL_PHY_USB, drv_data, &usb_ops,
&drv_data->udev->dev, &config); &drv_data->udev->dev, &config);
if (IS_ERR(priv)) if (IS_ERR(priv))
return PTR_ERR(priv); return PTR_ERR(priv);
drv_data->priv = priv; drv_data->priv = priv;
drv_data->priv->phy = NFCMRVL_PHY_USB; drv_data->priv->support_fw_dnld = false;
priv->dev = &drv_data->udev->dev; priv->dev = &drv_data->udev->dev;
usb_set_intfdata(intf, drv_data); usb_set_intfdata(intf, drv_data);
...@@ -469,6 +468,5 @@ static struct usb_driver nfcmrvl_usb_driver = { ...@@ -469,6 +468,5 @@ static struct usb_driver nfcmrvl_usb_driver = {
module_usb_driver(nfcmrvl_usb_driver); module_usb_driver(nfcmrvl_usb_driver);
MODULE_AUTHOR("Marvell International Ltd."); MODULE_AUTHOR("Marvell International Ltd.");
MODULE_DESCRIPTION("Marvell NFC-over-USB driver ver " VERSION); MODULE_DESCRIPTION("Marvell NFC-over-USB driver");
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
...@@ -246,7 +246,7 @@ static int nfcsim_activate_target(struct nfc_dev *nfc_dev, ...@@ -246,7 +246,7 @@ static int nfcsim_activate_target(struct nfc_dev *nfc_dev,
} }
static void nfcsim_deactivate_target(struct nfc_dev *nfc_dev, static void nfcsim_deactivate_target(struct nfc_dev *nfc_dev,
struct nfc_target *target) struct nfc_target *target, u8 mode)
{ {
struct nfcsim *dev = nfc_get_drvdata(nfc_dev); struct nfcsim *dev = nfc_get_drvdata(nfc_dev);
......
...@@ -497,7 +497,7 @@ static struct nci_ops nfcwilink_ops = { ...@@ -497,7 +497,7 @@ static struct nci_ops nfcwilink_ops = {
static int nfcwilink_probe(struct platform_device *pdev) static int nfcwilink_probe(struct platform_device *pdev)
{ {
static struct nfcwilink *drv; struct nfcwilink *drv;
int rc; int rc;
__u32 protocols; __u32 protocols;
......
...@@ -109,7 +109,8 @@ static struct nci_ops nxp_nci_ops = { ...@@ -109,7 +109,8 @@ static struct nci_ops nxp_nci_ops = {
}; };
int nxp_nci_probe(void *phy_id, struct device *pdev, int nxp_nci_probe(void *phy_id, struct device *pdev,
struct nxp_nci_phy_ops *phy_ops, unsigned int max_payload, const struct nxp_nci_phy_ops *phy_ops,
unsigned int max_payload,
struct nci_dev **ndev) struct nci_dev **ndev)
{ {
struct nxp_nci_info *info; struct nxp_nci_info *info;
......
...@@ -106,7 +106,7 @@ static int nxp_nci_i2c_write(void *phy_id, struct sk_buff *skb) ...@@ -106,7 +106,7 @@ static int nxp_nci_i2c_write(void *phy_id, struct sk_buff *skb)
return r; return r;
} }
static struct nxp_nci_phy_ops i2c_phy_ops = { static const struct nxp_nci_phy_ops i2c_phy_ops = {
.set_mode = nxp_nci_i2c_set_mode, .set_mode = nxp_nci_i2c_set_mode,
.write = nxp_nci_i2c_write, .write = nxp_nci_i2c_write,
}; };
......
...@@ -68,7 +68,7 @@ struct nxp_nci_info { ...@@ -68,7 +68,7 @@ struct nxp_nci_info {
enum nxp_nci_mode mode; enum nxp_nci_mode mode;
struct nxp_nci_phy_ops *phy_ops; const struct nxp_nci_phy_ops *phy_ops;
unsigned int max_payload; unsigned int max_payload;
struct mutex info_lock; struct mutex info_lock;
...@@ -82,7 +82,8 @@ void nxp_nci_fw_recv_frame(struct nci_dev *ndev, struct sk_buff *skb); ...@@ -82,7 +82,8 @@ void nxp_nci_fw_recv_frame(struct nci_dev *ndev, struct sk_buff *skb);
void nxp_nci_fw_work_complete(struct nxp_nci_info *info, int result); void nxp_nci_fw_work_complete(struct nxp_nci_info *info, int result);
int nxp_nci_probe(void *phy_id, struct device *pdev, int nxp_nci_probe(void *phy_id, struct device *pdev,
struct nxp_nci_phy_ops *phy_ops, unsigned int max_payload, const struct nxp_nci_phy_ops *phy_ops,
unsigned int max_payload,
struct nci_dev **ndev); struct nci_dev **ndev);
void nxp_nci_remove(struct nci_dev *ndev); void nxp_nci_remove(struct nci_dev *ndev);
......
...@@ -2263,7 +2263,7 @@ static int pn533_activate_target(struct nfc_dev *nfc_dev, ...@@ -2263,7 +2263,7 @@ static int pn533_activate_target(struct nfc_dev *nfc_dev,
} }
static void pn533_deactivate_target(struct nfc_dev *nfc_dev, static void pn533_deactivate_target(struct nfc_dev *nfc_dev,
struct nfc_target *target) struct nfc_target *target, u8 mode)
{ {
struct pn533 *dev = nfc_get_drvdata(nfc_dev); struct pn533 *dev = nfc_get_drvdata(nfc_dev);
struct sk_buff *skb; struct sk_buff *skb;
......
config NFC_PN544 config NFC_PN544
tristate "NXP PN544 NFC driver" tristate
depends on NFC_HCI
select CRC_CCITT select CRC_CCITT
default n
---help--- ---help---
NXP PN544 core driver. NXP PN544 core driver.
This is a driver based on the HCI NFC kernel layers and This is a driver based on the HCI NFC kernel layers and
will thus not work with NXP libnfc library. will thus not work with NXP libnfc library.
To compile this driver as a module, choose m here. The module will
be called pn544.
Say N if unsure.
config NFC_PN544_I2C config NFC_PN544_I2C
tristate "NFC PN544 i2c support" tristate "NXP PN544 device support (I2C)"
depends on NFC_PN544 && I2C && NFC_SHDLC depends on NFC_HCI && I2C && NFC_SHDLC
select NFC_PN544
---help--- ---help---
This module adds support for the NXP pn544 i2c interface. This module adds support for the NXP pn544 i2c interface.
Select this if your platform is using the i2c bus. Select this if your platform is using the i2c bus.
...@@ -23,8 +18,9 @@ config NFC_PN544_I2C ...@@ -23,8 +18,9 @@ config NFC_PN544_I2C
Say N if unsure. Say N if unsure.
config NFC_PN544_MEI config NFC_PN544_MEI
tristate "NFC PN544 MEI support" tristate "NXP PN544 device support (MEI)"
depends on NFC_PN544 && NFC_MEI_PHY depends on NFC_HCI && NFC_MEI_PHY
select NFC_PN544
---help--- ---help---
This module adds support for the mei interface of adapters using This module adds support for the mei interface of adapters using
NXP pn544 chipsets. Select this if your pn544 chipset NXP pn544 chipsets. Select this if your pn544 chipset
......
config NFC_S3FWRN5 config NFC_S3FWRN5
tristate tristate
select CRYPTO
---help--- ---help---
Core driver for Samsung S3FWRN5 NFC chip. Contains core utilities Core driver for Samsung S3FWRN5 NFC chip. Contains core utilities
of chip. It's intended to be used by PHYs to avoid duplicating lots of chip. It's intended to be used by PHYs to avoid duplicating lots
......
...@@ -7,5 +7,3 @@ s3fwrn5_i2c-objs = i2c.o ...@@ -7,5 +7,3 @@ s3fwrn5_i2c-objs = i2c.o
obj-$(CONFIG_NFC_S3FWRN5) += s3fwrn5.o obj-$(CONFIG_NFC_S3FWRN5) += s3fwrn5.o
obj-$(CONFIG_NFC_S3FWRN5_I2C) += s3fwrn5_i2c.o obj-$(CONFIG_NFC_S3FWRN5_I2C) += s3fwrn5_i2c.o
ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
...@@ -258,7 +258,7 @@ static int s3fwrn5_i2c_probe(struct i2c_client *client, ...@@ -258,7 +258,7 @@ static int s3fwrn5_i2c_probe(struct i2c_client *client,
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = request_threaded_irq(phy->i2c_dev->irq, NULL, ret = devm_request_threaded_irq(&client->dev, phy->i2c_dev->irq, NULL,
s3fwrn5_i2c_irq_thread_fn, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, s3fwrn5_i2c_irq_thread_fn, IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
S3FWRN5_I2C_DRIVER_NAME, phy); S3FWRN5_I2C_DRIVER_NAME, phy);
if (ret) if (ret)
......
...@@ -31,7 +31,7 @@ static int s3fwrn5_nci_prop_rsp(struct nci_dev *ndev, struct sk_buff *skb) ...@@ -31,7 +31,7 @@ static int s3fwrn5_nci_prop_rsp(struct nci_dev *ndev, struct sk_buff *skb)
return 0; return 0;
} }
static struct nci_prop_ops s3fwrn5_nci_prop_ops[] = { static struct nci_driver_ops s3fwrn5_nci_prop_ops[] = {
{ {
.opcode = nci_opcode_pack(NCI_GID_PROPRIETARY, .opcode = nci_opcode_pack(NCI_GID_PROPRIETARY,
NCI_PROP_AGAIN), NCI_PROP_AGAIN),
...@@ -79,7 +79,7 @@ static struct nci_prop_ops s3fwrn5_nci_prop_ops[] = { ...@@ -79,7 +79,7 @@ static struct nci_prop_ops s3fwrn5_nci_prop_ops[] = {
}, },
}; };
void s3fwrn5_nci_get_prop_ops(struct nci_prop_ops **ops, size_t *n) void s3fwrn5_nci_get_prop_ops(struct nci_driver_ops **ops, size_t *n)
{ {
*ops = s3fwrn5_nci_prop_ops; *ops = s3fwrn5_nci_prop_ops;
*n = ARRAY_SIZE(s3fwrn5_nci_prop_ops); *n = ARRAY_SIZE(s3fwrn5_nci_prop_ops);
......
...@@ -83,7 +83,7 @@ struct nci_prop_fw_cfg_rsp { ...@@ -83,7 +83,7 @@ struct nci_prop_fw_cfg_rsp {
#define NCI_PROP_WR_RESET 0x2f #define NCI_PROP_WR_RESET 0x2f
void s3fwrn5_nci_get_prop_ops(struct nci_prop_ops **ops, size_t *n); void s3fwrn5_nci_get_prop_ops(struct nci_driver_ops **ops, size_t *n);
int s3fwrn5_nci_rf_configure(struct s3fwrn5_info *info, const char *fw_name); int s3fwrn5_nci_rf_configure(struct s3fwrn5_info *info, const char *fw_name);
#endif /* __LOCAL_S3FWRN5_NCI_H_ */ #endif /* __LOCAL_S3FWRN5_NCI_H_ */
# #
# Makefile for ST21NFCB NCI based NFC driver # Makefile for ST_NCI NCI based NFC driver
# #
st-nci-objs = ndlc.o core.o st-nci_se.o st-nci-objs = ndlc.o core.o se.o vendor_cmds.o
obj-$(CONFIG_NFC_ST_NCI) += st-nci.o obj-$(CONFIG_NFC_ST_NCI) += st-nci.o
st-nci_i2c-objs = i2c.o st-nci_i2c-objs = i2c.o
......
...@@ -24,7 +24,6 @@ ...@@ -24,7 +24,6 @@
#include <linux/delay.h> #include <linux/delay.h>
#include "st-nci.h" #include "st-nci.h"
#include "st-nci_se.h"
#define DRIVER_DESC "NCI NFC driver for ST_NCI" #define DRIVER_DESC "NCI NFC driver for ST_NCI"
...@@ -98,7 +97,7 @@ static int st_nci_prop_rsp_packet(struct nci_dev *ndev, ...@@ -98,7 +97,7 @@ static int st_nci_prop_rsp_packet(struct nci_dev *ndev,
return 0; return 0;
} }
static struct nci_prop_ops st_nci_prop_ops[] = { static struct nci_driver_ops st_nci_prop_ops[] = {
{ {
.opcode = nci_opcode_pack(NCI_GID_PROPRIETARY, .opcode = nci_opcode_pack(NCI_GID_PROPRIETARY,
ST_NCI_CORE_PROP), ST_NCI_CORE_PROP),
...@@ -124,7 +123,7 @@ static struct nci_ops st_nci_ops = { ...@@ -124,7 +123,7 @@ static struct nci_ops st_nci_ops = {
}; };
int st_nci_probe(struct llt_ndlc *ndlc, int phy_headroom, int st_nci_probe(struct llt_ndlc *ndlc, int phy_headroom,
int phy_tailroom) int phy_tailroom, struct st_nci_se_status *se_status)
{ {
struct st_nci_info *info; struct st_nci_info *info;
int r; int r;
...@@ -153,14 +152,23 @@ int st_nci_probe(struct llt_ndlc *ndlc, int phy_headroom, ...@@ -153,14 +152,23 @@ int st_nci_probe(struct llt_ndlc *ndlc, int phy_headroom,
nci_set_drvdata(ndlc->ndev, info); nci_set_drvdata(ndlc->ndev, info);
r = st_nci_vendor_cmds_init(ndlc->ndev);
if (r) {
pr_err("Cannot register proprietary vendor cmds\n");
goto err_reg_dev;
}
r = nci_register_device(ndlc->ndev); r = nci_register_device(ndlc->ndev);
if (r) { if (r) {
pr_err("Cannot register nfc device to nci core\n"); pr_err("Cannot register nfc device to nci core\n");
nci_free_device(ndlc->ndev); goto err_reg_dev;
return r;
} }
return st_nci_se_init(ndlc->ndev); return st_nci_se_init(ndlc->ndev, se_status);
err_reg_dev:
nci_free_device(ndlc->ndev);
return r;
} }
EXPORT_SYMBOL_GPL(st_nci_probe); EXPORT_SYMBOL_GPL(st_nci_probe);
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#include <linux/nfc.h> #include <linux/nfc.h>
#include <linux/platform_data/st-nci.h> #include <linux/platform_data/st-nci.h>
#include "ndlc.h" #include "st-nci.h"
#define DRIVER_DESC "NCI NFC driver for ST_NCI" #define DRIVER_DESC "NCI NFC driver for ST_NCI"
...@@ -50,16 +50,13 @@ struct st_nci_i2c_phy { ...@@ -50,16 +50,13 @@ struct st_nci_i2c_phy {
struct i2c_client *i2c_dev; struct i2c_client *i2c_dev;
struct llt_ndlc *ndlc; struct llt_ndlc *ndlc;
bool irq_active;
unsigned int gpio_reset; unsigned int gpio_reset;
unsigned int irq_polarity; unsigned int irq_polarity;
};
#define I2C_DUMP_SKB(info, skb) \ struct st_nci_se_status se_status;
do { \ };
pr_debug("%s:\n", info); \
print_hex_dump(KERN_DEBUG, "i2c: ", DUMP_PREFIX_OFFSET, \
16, 1, (skb)->data, (skb)->len, 0); \
} while (0)
static int st_nci_i2c_enable(void *phy_id) static int st_nci_i2c_enable(void *phy_id)
{ {
...@@ -70,8 +67,10 @@ static int st_nci_i2c_enable(void *phy_id) ...@@ -70,8 +67,10 @@ static int st_nci_i2c_enable(void *phy_id)
gpio_set_value(phy->gpio_reset, 1); gpio_set_value(phy->gpio_reset, 1);
usleep_range(80000, 85000); usleep_range(80000, 85000);
if (phy->ndlc->powered == 0) if (phy->ndlc->powered == 0 && phy->irq_active == 0) {
enable_irq(phy->i2c_dev->irq); enable_irq(phy->i2c_dev->irq);
phy->irq_active = true;
}
return 0; return 0;
} }
...@@ -81,6 +80,7 @@ static void st_nci_i2c_disable(void *phy_id) ...@@ -81,6 +80,7 @@ static void st_nci_i2c_disable(void *phy_id)
struct st_nci_i2c_phy *phy = phy_id; struct st_nci_i2c_phy *phy = phy_id;
disable_irq_nosync(phy->i2c_dev->irq); disable_irq_nosync(phy->i2c_dev->irq);
phy->irq_active = false;
} }
/* /*
...@@ -94,8 +94,6 @@ static int st_nci_i2c_write(void *phy_id, struct sk_buff *skb) ...@@ -94,8 +94,6 @@ static int st_nci_i2c_write(void *phy_id, struct sk_buff *skb)
struct st_nci_i2c_phy *phy = phy_id; struct st_nci_i2c_phy *phy = phy_id;
struct i2c_client *client = phy->i2c_dev; struct i2c_client *client = phy->i2c_dev;
I2C_DUMP_SKB("st_nci_i2c_write", skb);
if (phy->ndlc->hard_fault != 0) if (phy->ndlc->hard_fault != 0)
return phy->ndlc->hard_fault; return phy->ndlc->hard_fault;
...@@ -166,8 +164,6 @@ static int st_nci_i2c_read(struct st_nci_i2c_phy *phy, ...@@ -166,8 +164,6 @@ static int st_nci_i2c_read(struct st_nci_i2c_phy *phy,
skb_put(*skb, len); skb_put(*skb, len);
memcpy((*skb)->data + ST_NCI_I2C_MIN_SIZE, buf, len); memcpy((*skb)->data + ST_NCI_I2C_MIN_SIZE, buf, len);
I2C_DUMP_SKB("i2c frame read", *skb);
return 0; return 0;
} }
...@@ -245,6 +241,11 @@ static int st_nci_i2c_of_request_resources(struct i2c_client *client) ...@@ -245,6 +241,11 @@ static int st_nci_i2c_of_request_resources(struct i2c_client *client)
phy->irq_polarity = irq_get_trigger_type(client->irq); phy->irq_polarity = irq_get_trigger_type(client->irq);
phy->se_status.is_ese_present =
of_property_read_bool(pp, "ese-present");
phy->se_status.is_uicc_present =
of_property_read_bool(pp, "uicc-present");
return 0; return 0;
} }
#else #else
...@@ -277,6 +278,9 @@ static int st_nci_i2c_request_resources(struct i2c_client *client) ...@@ -277,6 +278,9 @@ static int st_nci_i2c_request_resources(struct i2c_client *client)
return r; return r;
} }
phy->se_status.is_ese_present = pdata->is_ese_present;
phy->se_status.is_uicc_present = pdata->is_uicc_present;
return 0; return 0;
} }
...@@ -326,12 +330,13 @@ static int st_nci_i2c_probe(struct i2c_client *client, ...@@ -326,12 +330,13 @@ static int st_nci_i2c_probe(struct i2c_client *client,
r = ndlc_probe(phy, &i2c_phy_ops, &client->dev, r = ndlc_probe(phy, &i2c_phy_ops, &client->dev,
ST_NCI_FRAME_HEADROOM, ST_NCI_FRAME_TAILROOM, ST_NCI_FRAME_HEADROOM, ST_NCI_FRAME_TAILROOM,
&phy->ndlc); &phy->ndlc, &phy->se_status);
if (r < 0) { if (r < 0) {
nfc_err(&client->dev, "Unable to register ndlc layer\n"); nfc_err(&client->dev, "Unable to register ndlc layer\n");
return r; return r;
} }
phy->irq_active = true;
r = devm_request_threaded_irq(&client->dev, client->irq, NULL, r = devm_request_threaded_irq(&client->dev, client->irq, NULL,
st_nci_irq_thread_fn, st_nci_irq_thread_fn,
phy->irq_polarity | IRQF_ONESHOT, phy->irq_polarity | IRQF_ONESHOT,
......
...@@ -19,8 +19,8 @@ ...@@ -19,8 +19,8 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <net/nfc/nci_core.h> #include <net/nfc/nci_core.h>
#include "ndlc.h"
#include "st-nci.h" #include "st-nci.h"
#include "ndlc.h"
#define NDLC_TIMER_T1 100 #define NDLC_TIMER_T1 100
#define NDLC_TIMER_T1_WAIT 400 #define NDLC_TIMER_T1_WAIT 400
...@@ -266,7 +266,8 @@ static void ndlc_t2_timeout(unsigned long data) ...@@ -266,7 +266,8 @@ static void ndlc_t2_timeout(unsigned long data)
} }
int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev, int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev,
int phy_headroom, int phy_tailroom, struct llt_ndlc **ndlc_id) int phy_headroom, int phy_tailroom, struct llt_ndlc **ndlc_id,
struct st_nci_se_status *se_status)
{ {
struct llt_ndlc *ndlc; struct llt_ndlc *ndlc;
...@@ -296,7 +297,7 @@ int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev, ...@@ -296,7 +297,7 @@ int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev,
INIT_WORK(&ndlc->sm_work, llt_ndlc_sm_work); INIT_WORK(&ndlc->sm_work, llt_ndlc_sm_work);
return st_nci_probe(ndlc, phy_headroom, phy_tailroom); return st_nci_probe(ndlc, phy_headroom, phy_tailroom, se_status);
} }
EXPORT_SYMBOL(ndlc_probe); EXPORT_SYMBOL(ndlc_probe);
......
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <net/nfc/nfc.h> #include <net/nfc/nfc.h>
struct st_nci_se_status;
/* Low Level Transport description */ /* Low Level Transport description */
struct llt_ndlc { struct llt_ndlc {
struct nci_dev *ndev; struct nci_dev *ndev;
...@@ -55,6 +57,7 @@ void ndlc_close(struct llt_ndlc *ndlc); ...@@ -55,6 +57,7 @@ void ndlc_close(struct llt_ndlc *ndlc);
int ndlc_send(struct llt_ndlc *ndlc, struct sk_buff *skb); int ndlc_send(struct llt_ndlc *ndlc, struct sk_buff *skb);
void ndlc_recv(struct llt_ndlc *ndlc, struct sk_buff *skb); void ndlc_recv(struct llt_ndlc *ndlc, struct sk_buff *skb);
int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev, int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev,
int phy_headroom, int phy_tailroom, struct llt_ndlc **ndlc_id); int phy_headroom, int phy_tailroom, struct llt_ndlc **ndlc_id,
struct st_nci_se_status *se_status);
void ndlc_remove(struct llt_ndlc *ndlc); void ndlc_remove(struct llt_ndlc *ndlc);
#endif /* __LOCAL_NDLC_H__ */ #endif /* __LOCAL_NDLC_H__ */
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
#include <net/nfc/nci_core.h> #include <net/nfc/nci_core.h>
#include "st-nci.h" #include "st-nci.h"
#include "st-nci_se.h"
struct st_nci_pipe_info { struct st_nci_pipe_info {
u8 pipe_state; u8 pipe_state;
...@@ -40,7 +39,6 @@ struct st_nci_pipe_info { ...@@ -40,7 +39,6 @@ struct st_nci_pipe_info {
#define ST_NCI_ESE_HOST_ID 0xc0 #define ST_NCI_ESE_HOST_ID 0xc0
/* Gates */ /* Gates */
#define ST_NCI_DEVICE_MGNT_GATE 0x01
#define ST_NCI_APDU_READER_GATE 0xf0 #define ST_NCI_APDU_READER_GATE 0xf0
#define ST_NCI_CONNECTIVITY_GATE 0x41 #define ST_NCI_CONNECTIVITY_GATE 0x41
...@@ -113,6 +111,11 @@ static struct nci_hci_gate st_nci_gates[] = { ...@@ -113,6 +111,11 @@ static struct nci_hci_gate st_nci_gates[] = {
{ST_NCI_DEVICE_MGNT_GATE, ST_NCI_DEVICE_MGNT_PIPE, {ST_NCI_DEVICE_MGNT_GATE, ST_NCI_DEVICE_MGNT_PIPE,
ST_NCI_HOST_CONTROLLER_ID}, ST_NCI_HOST_CONTROLLER_ID},
{NCI_HCI_IDENTITY_MGMT_GATE, NCI_HCI_INVALID_PIPE,
ST_NCI_HOST_CONTROLLER_ID},
{NCI_HCI_LOOPBACK_GATE, NCI_HCI_INVALID_PIPE,
ST_NCI_HOST_CONTROLLER_ID},
/* Secure element pipes are created by secure element host */ /* Secure element pipes are created by secure element host */
{ST_NCI_CONNECTIVITY_GATE, NCI_HCI_DO_NOT_OPEN_PIPE, {ST_NCI_CONNECTIVITY_GATE, NCI_HCI_DO_NOT_OPEN_PIPE,
ST_NCI_HOST_CONTROLLER_ID}, ST_NCI_HOST_CONTROLLER_ID},
...@@ -226,27 +229,32 @@ int st_nci_hci_load_session(struct nci_dev *ndev) ...@@ -226,27 +229,32 @@ int st_nci_hci_load_session(struct nci_dev *ndev)
continue; continue;
} }
for (j = 0; (j < ARRAY_SIZE(st_nci_gates)) && for (j = 3; (j < ARRAY_SIZE(st_nci_gates)) &&
(st_nci_gates[j].gate != dm_pipe_info->dst_gate_id); j++) (st_nci_gates[j].gate != dm_pipe_info->dst_gate_id); j++)
; ;
if (j < ARRAY_SIZE(st_nci_gates) && if (j < ARRAY_SIZE(st_nci_gates) &&
st_nci_gates[j].gate == dm_pipe_info->dst_gate_id && st_nci_gates[j].gate == dm_pipe_info->dst_gate_id &&
ST_NCI_DM_IS_PIPE_OPEN(dm_pipe_info->pipe_state)) { ST_NCI_DM_IS_PIPE_OPEN(dm_pipe_info->pipe_state)) {
st_nci_gates[j].pipe = pipe_info[2]; ndev->hci_dev->init_data.gates[j].pipe = pipe_info[2];
ndev->hci_dev->gate2pipe[st_nci_gates[j].gate] = ndev->hci_dev->gate2pipe[st_nci_gates[j].gate] =
st_nci_gates[j].pipe; pipe_info[2];
ndev->hci_dev->pipes[st_nci_gates[j].pipe].gate = ndev->hci_dev->pipes[pipe_info[2]].gate =
st_nci_gates[j].gate; st_nci_gates[j].gate;
ndev->hci_dev->pipes[st_nci_gates[j].pipe].host = ndev->hci_dev->pipes[pipe_info[2]].host =
dm_pipe_info->src_host_id; dm_pipe_info->src_host_id;
} }
kfree_skb(skb_pipe_info); kfree_skb(skb_pipe_info);
} }
memcpy(ndev->hci_dev->init_data.gates, st_nci_gates, /*
sizeof(st_nci_gates)); * 3 gates have a well known pipe ID. Only NCI_HCI_LINK_MGMT_GATE
* is not yet open at this stage.
*/
r = nci_hci_connect_gate(ndev, ST_NCI_HOST_CONTROLLER_ID,
NCI_HCI_LINK_MGMT_GATE,
NCI_HCI_LINK_MGMT_PIPE);
kfree_skb(skb_pipe_list); kfree_skb(skb_pipe_list);
return r; return r;
...@@ -272,6 +280,8 @@ static void st_nci_hci_admin_event_received(struct nci_dev *ndev, ...@@ -272,6 +280,8 @@ static void st_nci_hci_admin_event_received(struct nci_dev *ndev,
} }
} }
break; break;
default:
nfc_err(&ndev->nfc_dev->dev, "Unexpected event on admin gate\n");
} }
} }
...@@ -295,6 +305,9 @@ static int st_nci_hci_apdu_reader_event_received(struct nci_dev *ndev, ...@@ -295,6 +305,9 @@ static int st_nci_hci_apdu_reader_event_received(struct nci_dev *ndev,
mod_timer(&info->se_info.bwi_timer, jiffies + mod_timer(&info->se_info.bwi_timer, jiffies +
msecs_to_jiffies(info->se_info.wt_timeout)); msecs_to_jiffies(info->se_info.wt_timeout));
break; break;
default:
nfc_err(&ndev->nfc_dev->dev, "Unexpected event on apdu reader gate\n");
return 1;
} }
kfree_skb(skb); kfree_skb(skb);
...@@ -349,6 +362,7 @@ static int st_nci_hci_connectivity_event_received(struct nci_dev *ndev, ...@@ -349,6 +362,7 @@ static int st_nci_hci_connectivity_event_received(struct nci_dev *ndev,
r = nfc_se_transaction(ndev->nfc_dev, host, transaction); r = nfc_se_transaction(ndev->nfc_dev, host, transaction);
break; break;
default: default:
nfc_err(&ndev->nfc_dev->dev, "Unexpected event on connectivity gate\n");
return 1; return 1;
} }
kfree_skb(skb); kfree_skb(skb);
...@@ -369,8 +383,10 @@ void st_nci_hci_event_received(struct nci_dev *ndev, u8 pipe, ...@@ -369,8 +383,10 @@ void st_nci_hci_event_received(struct nci_dev *ndev, u8 pipe,
st_nci_hci_apdu_reader_event_received(ndev, event, skb); st_nci_hci_apdu_reader_event_received(ndev, event, skb);
break; break;
case ST_NCI_CONNECTIVITY_GATE: case ST_NCI_CONNECTIVITY_GATE:
st_nci_hci_connectivity_event_received(ndev, host, event, st_nci_hci_connectivity_event_received(ndev, host, event, skb);
skb); break;
case NCI_HCI_LOOPBACK_GATE:
st_nci_hci_loopback_event_received(ndev, event, skb);
break; break;
} }
} }
...@@ -403,15 +419,11 @@ void st_nci_hci_cmd_received(struct nci_dev *ndev, u8 pipe, u8 cmd, ...@@ -403,15 +419,11 @@ void st_nci_hci_cmd_received(struct nci_dev *ndev, u8 pipe, u8 cmd,
} }
EXPORT_SYMBOL_GPL(st_nci_hci_cmd_received); EXPORT_SYMBOL_GPL(st_nci_hci_cmd_received);
/*
* Remarks: On some early st_nci firmware, nci_nfcee_mode_set(0)
* is rejected
*/
static int st_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) u8 state)
{ {
struct st_nci_info *info = nci_get_drvdata(ndev); struct st_nci_info *info = nci_get_drvdata(ndev);
int r; int r, i;
struct sk_buff *sk_host_list; struct sk_buff *sk_host_list;
u8 host_id; u8 host_id;
...@@ -433,7 +445,7 @@ static int st_nci_control_se(struct nci_dev *ndev, u8 se_idx, ...@@ -433,7 +445,7 @@ static int st_nci_control_se(struct nci_dev *ndev, u8 se_idx,
* retrieve a relevant host list. * retrieve a relevant host list.
*/ */
reinit_completion(&info->se_info.req_completion); reinit_completion(&info->se_info.req_completion);
r = nci_nfcee_mode_set(ndev, se_idx, NCI_NFCEE_ENABLE); r = nci_nfcee_mode_set(ndev, se_idx, state);
if (r != NCI_STATUS_OK) if (r != NCI_STATUS_OK)
return r; return r;
...@@ -449,14 +461,19 @@ static int st_nci_control_se(struct nci_dev *ndev, u8 se_idx, ...@@ -449,14 +461,19 @@ static int st_nci_control_se(struct nci_dev *ndev, u8 se_idx,
* There is no possible synchronization to prevent this. * There is no possible synchronization to prevent this.
* Adding a small delay is the only way to solve the issue. * Adding a small delay is the only way to solve the issue.
*/ */
usleep_range(3000, 5000); if (info->se_info.se_status->is_ese_present &&
info->se_info.se_status->is_uicc_present)
usleep_range(15000, 20000);
r = nci_hci_get_param(ndev, NCI_HCI_ADMIN_GATE, r = nci_hci_get_param(ndev, NCI_HCI_ADMIN_GATE,
NCI_HCI_ADMIN_PARAM_HOST_LIST, &sk_host_list); NCI_HCI_ADMIN_PARAM_HOST_LIST, &sk_host_list);
if (r != NCI_HCI_ANY_OK) if (r != NCI_HCI_ANY_OK)
return r; return r;
host_id = sk_host_list->data[sk_host_list->len - 1]; for (i = 0; i < sk_host_list->len &&
sk_host_list->data[i] != se_idx; i++)
;
host_id = sk_host_list->data[i];
kfree_skb(sk_host_list); kfree_skb(sk_host_list);
if (state == ST_NCI_SE_MODE_ON && host_id == se_idx) if (state == ST_NCI_SE_MODE_ON && host_id == se_idx)
return se_idx; return se_idx;
...@@ -472,10 +489,19 @@ int st_nci_disable_se(struct nci_dev *ndev, u32 se_idx) ...@@ -472,10 +489,19 @@ int st_nci_disable_se(struct nci_dev *ndev, u32 se_idx)
pr_debug("st_nci_disable_se\n"); pr_debug("st_nci_disable_se\n");
/*
* According to upper layer, se_idx == NFC_SE_UICC when
* info->se_info.se_status->is_uicc_enable is true should never happen
* Same for eSE.
*/
r = st_nci_control_se(ndev, se_idx, ST_NCI_SE_MODE_OFF);
if (r < 0) {
/* Do best effort to release SWP */
if (se_idx == NFC_SE_EMBEDDED) { if (se_idx == NFC_SE_EMBEDDED) {
r = nci_hci_send_event(ndev, ST_NCI_APDU_READER_GATE, r = nci_hci_send_event(ndev, ST_NCI_APDU_READER_GATE,
ST_NCI_EVT_SE_END_OF_APDU_TRANSFER, NULL, 0); ST_NCI_EVT_SE_END_OF_APDU_TRANSFER,
if (r < 0) NULL, 0);
}
return r; return r;
} }
...@@ -489,10 +515,24 @@ int st_nci_enable_se(struct nci_dev *ndev, u32 se_idx) ...@@ -489,10 +515,24 @@ int st_nci_enable_se(struct nci_dev *ndev, u32 se_idx)
pr_debug("st_nci_enable_se\n"); pr_debug("st_nci_enable_se\n");
if (se_idx == ST_NCI_HCI_HOST_ID_ESE) { /*
* According to upper layer, se_idx == NFC_SE_UICC when
* info->se_info.se_status->is_uicc_enable is true should never happen.
* Same for eSE.
*/
r = st_nci_control_se(ndev, se_idx, ST_NCI_SE_MODE_ON);
if (r == ST_NCI_HCI_HOST_ID_ESE) {
st_nci_se_get_atr(ndev);
r = nci_hci_send_event(ndev, ST_NCI_APDU_READER_GATE, r = nci_hci_send_event(ndev, ST_NCI_APDU_READER_GATE,
ST_NCI_EVT_SE_SOFT_RESET, NULL, 0); ST_NCI_EVT_SE_SOFT_RESET, NULL, 0);
if (r < 0) }
if (r < 0) {
/*
* The activation procedure failed, the secure element
* is not connected. Remove from the list.
*/
nfc_remove_se(ndev->nfc_dev, se_idx);
return r; return r;
} }
...@@ -502,6 +542,7 @@ EXPORT_SYMBOL_GPL(st_nci_enable_se); ...@@ -502,6 +542,7 @@ EXPORT_SYMBOL_GPL(st_nci_enable_se);
static int st_nci_hci_network_init(struct nci_dev *ndev) static int st_nci_hci_network_init(struct nci_dev *ndev)
{ {
struct st_nci_info *info = nci_get_drvdata(ndev);
struct core_conn_create_dest_spec_params *dest_params; struct core_conn_create_dest_spec_params *dest_params;
struct dest_spec_params spec_params; struct dest_spec_params spec_params;
struct nci_conn_info *conn_info; struct nci_conn_info *conn_info;
...@@ -532,6 +573,7 @@ static int st_nci_hci_network_init(struct nci_dev *ndev) ...@@ -532,6 +573,7 @@ static int st_nci_hci_network_init(struct nci_dev *ndev)
if (!conn_info) if (!conn_info)
goto free_dest_params; goto free_dest_params;
ndev->hci_dev->init_data.gate_count = ARRAY_SIZE(st_nci_gates);
memcpy(ndev->hci_dev->init_data.gates, st_nci_gates, memcpy(ndev->hci_dev->init_data.gates, st_nci_gates,
sizeof(st_nci_gates)); sizeof(st_nci_gates));
...@@ -553,10 +595,17 @@ static int st_nci_hci_network_init(struct nci_dev *ndev) ...@@ -553,10 +595,17 @@ static int st_nci_hci_network_init(struct nci_dev *ndev)
if (r != NCI_HCI_ANY_OK) if (r != NCI_HCI_ANY_OK)
goto free_dest_params; goto free_dest_params;
/*
* In factory mode, we prevent secure elements activation
* by disabling nfcee on the current HCI connection id.
* HCI will be used here only for proprietary commands.
*/
if (test_bit(ST_NCI_FACTORY_MODE, &info->flags))
r = nci_nfcee_mode_set(ndev, ndev->hci_dev->conn_info->id,
NCI_NFCEE_DISABLE);
else
r = nci_nfcee_mode_set(ndev, ndev->hci_dev->conn_info->id, r = nci_nfcee_mode_set(ndev, ndev->hci_dev->conn_info->id,
NCI_NFCEE_ENABLE); NCI_NFCEE_ENABLE);
if (r != NCI_STATUS_OK)
goto free_dest_params;
free_dest_params: free_dest_params:
kfree(dest_params); kfree(dest_params);
...@@ -567,9 +616,10 @@ static int st_nci_hci_network_init(struct nci_dev *ndev) ...@@ -567,9 +616,10 @@ static int st_nci_hci_network_init(struct nci_dev *ndev)
int st_nci_discover_se(struct nci_dev *ndev) int st_nci_discover_se(struct nci_dev *ndev)
{ {
u8 param[2]; u8 white_list[2];
int r; int r, wl_size = 0;
int se_count = 0; int se_count = 0;
struct st_nci_info *info = nci_get_drvdata(ndev);
pr_debug("st_nci_discover_se\n"); pr_debug("st_nci_discover_se\n");
...@@ -577,29 +627,37 @@ int st_nci_discover_se(struct nci_dev *ndev) ...@@ -577,29 +627,37 @@ int st_nci_discover_se(struct nci_dev *ndev)
if (r != 0) if (r != 0)
return r; return r;
param[0] = ST_NCI_UICC_HOST_ID; if (test_bit(ST_NCI_FACTORY_MODE, &info->flags))
param[1] = ST_NCI_HCI_HOST_ID_ESE; return 0;
if (info->se_info.se_status->is_ese_present &&
info->se_info.se_status->is_uicc_present) {
white_list[wl_size++] = ST_NCI_UICC_HOST_ID;
white_list[wl_size++] = ST_NCI_ESE_HOST_ID;
} else if (!info->se_info.se_status->is_ese_present &&
info->se_info.se_status->is_uicc_present) {
white_list[wl_size++] = ST_NCI_UICC_HOST_ID;
} else if (info->se_info.se_status->is_ese_present &&
!info->se_info.se_status->is_uicc_present) {
white_list[wl_size++] = ST_NCI_ESE_HOST_ID;
}
if (wl_size) {
r = nci_hci_set_param(ndev, NCI_HCI_ADMIN_GATE, r = nci_hci_set_param(ndev, NCI_HCI_ADMIN_GATE,
NCI_HCI_ADMIN_PARAM_WHITELIST, NCI_HCI_ADMIN_PARAM_WHITELIST,
param, sizeof(param)); white_list, wl_size);
if (r != NCI_HCI_ANY_OK) if (r != NCI_HCI_ANY_OK)
return r; return r;
}
r = st_nci_control_se(ndev, ST_NCI_UICC_HOST_ID, if (info->se_info.se_status->is_uicc_present) {
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); nfc_add_se(ndev->nfc_dev, ST_NCI_UICC_HOST_ID, NFC_SE_UICC);
se_count++; se_count++;
} }
/* Try to enable eSE in order to check availability */ if (info->se_info.se_status->is_ese_present) {
r = st_nci_control_se(ndev, ST_NCI_HCI_HOST_ID_ESE, nfc_add_se(ndev->nfc_dev, ST_NCI_ESE_HOST_ID, NFC_SE_EMBEDDED);
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++; se_count++;
st_nci_se_get_atr(ndev);
} }
return !se_count; return !se_count;
...@@ -672,7 +730,7 @@ static void st_nci_se_activation_timeout(unsigned long data) ...@@ -672,7 +730,7 @@ static void st_nci_se_activation_timeout(unsigned long data)
complete(&info->se_info.req_completion); complete(&info->se_info.req_completion);
} }
int st_nci_se_init(struct nci_dev *ndev) int st_nci_se_init(struct nci_dev *ndev, struct st_nci_se_status *se_status)
{ {
struct st_nci_info *info = nci_get_drvdata(ndev); struct st_nci_info *info = nci_get_drvdata(ndev);
...@@ -694,6 +752,8 @@ int st_nci_se_init(struct nci_dev *ndev) ...@@ -694,6 +752,8 @@ int st_nci_se_init(struct nci_dev *ndev)
info->se_info.wt_timeout = info->se_info.wt_timeout =
ST_NCI_BWI_TO_TIMEOUT(ST_NCI_ATR_DEFAULT_BWI); ST_NCI_BWI_TO_TIMEOUT(ST_NCI_ATR_DEFAULT_BWI);
info->se_info.se_status = se_status;
return 0; return 0;
} }
EXPORT_SYMBOL(st_nci_se_init); EXPORT_SYMBOL(st_nci_se_init);
......
...@@ -25,9 +25,10 @@ ...@@ -25,9 +25,10 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/nfc.h> #include <linux/nfc.h>
#include <net/nfc/nci.h>
#include <linux/platform_data/st-nci.h> #include <linux/platform_data/st-nci.h>
#include "ndlc.h" #include "st-nci.h"
#define DRIVER_DESC "NCI NFC driver for ST_NCI" #define DRIVER_DESC "NCI NFC driver for ST_NCI"
...@@ -50,16 +51,13 @@ struct st_nci_spi_phy { ...@@ -50,16 +51,13 @@ struct st_nci_spi_phy {
struct spi_device *spi_dev; struct spi_device *spi_dev;
struct llt_ndlc *ndlc; struct llt_ndlc *ndlc;
bool irq_active;
unsigned int gpio_reset; unsigned int gpio_reset;
unsigned int irq_polarity; unsigned int irq_polarity;
};
#define SPI_DUMP_SKB(info, skb) \ struct st_nci_se_status se_status;
do { \ };
pr_debug("%s:\n", info); \
print_hex_dump(KERN_DEBUG, "spi: ", DUMP_PREFIX_OFFSET, \
16, 1, (skb)->data, (skb)->len, 0); \
} while (0)
static int st_nci_spi_enable(void *phy_id) static int st_nci_spi_enable(void *phy_id)
{ {
...@@ -70,8 +68,10 @@ static int st_nci_spi_enable(void *phy_id) ...@@ -70,8 +68,10 @@ static int st_nci_spi_enable(void *phy_id)
gpio_set_value(phy->gpio_reset, 1); gpio_set_value(phy->gpio_reset, 1);
usleep_range(80000, 85000); usleep_range(80000, 85000);
if (phy->ndlc->powered == 0) if (phy->ndlc->powered == 0 && phy->irq_active == 0) {
enable_irq(phy->spi_dev->irq); enable_irq(phy->spi_dev->irq);
phy->irq_active = true;
}
return 0; return 0;
} }
...@@ -81,6 +81,7 @@ static void st_nci_spi_disable(void *phy_id) ...@@ -81,6 +81,7 @@ static void st_nci_spi_disable(void *phy_id)
struct st_nci_spi_phy *phy = phy_id; struct st_nci_spi_phy *phy = phy_id;
disable_irq_nosync(phy->spi_dev->irq); disable_irq_nosync(phy->spi_dev->irq);
phy->irq_active = false;
} }
/* /*
...@@ -94,15 +95,14 @@ static int st_nci_spi_write(void *phy_id, struct sk_buff *skb) ...@@ -94,15 +95,14 @@ static int st_nci_spi_write(void *phy_id, struct sk_buff *skb)
struct st_nci_spi_phy *phy = phy_id; struct st_nci_spi_phy *phy = phy_id;
struct spi_device *dev = phy->spi_dev; struct spi_device *dev = phy->spi_dev;
struct sk_buff *skb_rx; struct sk_buff *skb_rx;
u8 buf[ST_NCI_SPI_MAX_SIZE]; u8 buf[ST_NCI_SPI_MAX_SIZE + NCI_DATA_HDR_SIZE +
ST_NCI_FRAME_HEADROOM + ST_NCI_FRAME_TAILROOM];
struct spi_transfer spi_xfer = { struct spi_transfer spi_xfer = {
.tx_buf = skb->data, .tx_buf = skb->data,
.rx_buf = buf, .rx_buf = buf,
.len = skb->len, .len = skb->len,
}; };
SPI_DUMP_SKB("st_nci_spi_write", skb);
if (phy->ndlc->hard_fault != 0) if (phy->ndlc->hard_fault != 0)
return phy->ndlc->hard_fault; return phy->ndlc->hard_fault;
...@@ -179,8 +179,6 @@ static int st_nci_spi_read(struct st_nci_spi_phy *phy, ...@@ -179,8 +179,6 @@ static int st_nci_spi_read(struct st_nci_spi_phy *phy,
skb_put(*skb, len); skb_put(*skb, len);
memcpy((*skb)->data + ST_NCI_SPI_MIN_SIZE, buf, len); memcpy((*skb)->data + ST_NCI_SPI_MIN_SIZE, buf, len);
SPI_DUMP_SKB("spi frame read", *skb);
return 0; return 0;
} }
...@@ -258,6 +256,11 @@ static int st_nci_spi_of_request_resources(struct spi_device *dev) ...@@ -258,6 +256,11 @@ static int st_nci_spi_of_request_resources(struct spi_device *dev)
phy->irq_polarity = irq_get_trigger_type(dev->irq); phy->irq_polarity = irq_get_trigger_type(dev->irq);
phy->se_status.is_ese_present =
of_property_read_bool(pp, "ese-present");
phy->se_status.is_uicc_present =
of_property_read_bool(pp, "uicc-present");
return 0; return 0;
} }
#else #else
...@@ -290,6 +293,9 @@ static int st_nci_spi_request_resources(struct spi_device *dev) ...@@ -290,6 +293,9 @@ static int st_nci_spi_request_resources(struct spi_device *dev)
return r; return r;
} }
phy->se_status.is_ese_present = pdata->is_ese_present;
phy->se_status.is_uicc_present = pdata->is_uicc_present;
return 0; return 0;
} }
...@@ -340,12 +346,13 @@ static int st_nci_spi_probe(struct spi_device *dev) ...@@ -340,12 +346,13 @@ static int st_nci_spi_probe(struct spi_device *dev)
r = ndlc_probe(phy, &spi_phy_ops, &dev->dev, r = ndlc_probe(phy, &spi_phy_ops, &dev->dev,
ST_NCI_FRAME_HEADROOM, ST_NCI_FRAME_TAILROOM, ST_NCI_FRAME_HEADROOM, ST_NCI_FRAME_TAILROOM,
&phy->ndlc); &phy->ndlc, &phy->se_status);
if (r < 0) { if (r < 0) {
nfc_err(&dev->dev, "Unable to register ndlc layer\n"); nfc_err(&dev->dev, "Unable to register ndlc layer\n");
return r; return r;
} }
phy->irq_active = true;
r = devm_request_threaded_irq(&dev->dev, dev->irq, NULL, r = devm_request_threaded_irq(&dev->dev, dev->irq, NULL,
st_nci_irq_thread_fn, st_nci_irq_thread_fn,
phy->irq_polarity | IRQF_ONESHOT, phy->irq_polarity | IRQF_ONESHOT,
......
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
#ifndef __LOCAL_ST_NCI_H_ #ifndef __LOCAL_ST_NCI_H_
#define __LOCAL_ST_NCI_H_ #define __LOCAL_ST_NCI_H_
#include "st-nci_se.h"
#include "ndlc.h" #include "ndlc.h"
/* Define private flags: */ /* Define private flags: */
...@@ -28,6 +27,18 @@ ...@@ -28,6 +27,18 @@
#define ST_NCI_CORE_PROP 0x01 #define ST_NCI_CORE_PROP 0x01
#define ST_NCI_SET_NFC_MODE 0x02 #define ST_NCI_SET_NFC_MODE 0x02
/*
* 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
#define ST_NCI_DEVICE_MGNT_GATE 0x01
#define ST_NCI_VENDOR_OUI 0x0080E1 /* STMicroelectronics */
#define ST_NCI_FACTORY_MODE 2
struct nci_mode_set_cmd { struct nci_mode_set_cmd {
u8 cmd_type; u8 cmd_type;
u8 mode; u8 mode;
...@@ -37,14 +48,116 @@ struct nci_mode_set_rsp { ...@@ -37,14 +48,116 @@ struct nci_mode_set_rsp {
u8 status; u8 status;
} __packed; } __packed;
struct st_nci_se_status {
bool is_ese_present;
bool is_uicc_present;
};
struct st_nci_se_info {
struct st_nci_se_status *se_status;
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;
};
/**
* enum nfc_vendor_cmds - supported nfc vendor commands
*
* @FACTORY_MODE: Allow to set the driver into a mode where no secure element
* are activated. It does not consider any NFC_ATTR_VENDOR_DATA.
* @HCI_CLEAR_ALL_PIPES: Allow to execute a HCI clear all pipes command.
* It does not consider any NFC_ATTR_VENDOR_DATA.
* @HCI_DM_PUT_DATA: Allow to configure specific CLF registry as for example
* RF trimmings or low level drivers configurations (I2C, SPI, SWP).
* @HCI_DM_UPDATE_AID: Allow to configure an AID routing into the CLF routing
* table following RF technology, CLF mode or protocol.
* @HCI_DM_GET_INFO: Allow to retrieve CLF information.
* @HCI_DM_GET_DATA: Allow to retrieve CLF configurable data such as low
* level drivers configurations or RF trimmings.
* @HCI_DM_DIRECT_LOAD: Allow to load a firmware into the CLF. A complete
* packet can be more than 8KB.
* @HCI_DM_RESET: Allow to run a CLF reset in order to "commit" CLF
* configuration changes without CLF power off.
* @HCI_GET_PARAM: Allow to retrieve an HCI CLF parameter (for example the
* white list).
* @HCI_DM_FIELD_GENERATOR: Allow to generate different kind of RF
* technology. When using this command to anti-collision is done.
* @HCI_LOOPBACK: Allow to echo a command and test the Dh to CLF
* connectivity.
* @HCI_DM_VDC_MEASUREMENT_VALUE: Allow to measure the field applied on the
* CLF antenna. A value between 0 and 0x0f is returned. 0 is maximum.
* @HCI_DM_FWUPD_START: Allow to put CLF into firmware update mode. It is a
* specific CLF command as there is no GPIO for this.
* @HCI_DM_FWUPD_END: Allow to complete firmware update.
* @HCI_DM_VDC_VALUE_COMPARISON: Allow to compare the field applied on the
* CLF antenna to a reference value.
* @MANUFACTURER_SPECIFIC: Allow to retrieve manufacturer specific data
* received during a NCI_CORE_INIT_CMD.
*/
enum nfc_vendor_cmds {
FACTORY_MODE,
HCI_CLEAR_ALL_PIPES,
HCI_DM_PUT_DATA,
HCI_DM_UPDATE_AID,
HCI_DM_GET_INFO,
HCI_DM_GET_DATA,
HCI_DM_DIRECT_LOAD,
HCI_DM_RESET,
HCI_GET_PARAM,
HCI_DM_FIELD_GENERATOR,
HCI_LOOPBACK,
HCI_DM_FWUPD_START,
HCI_DM_FWUPD_END,
HCI_DM_VDC_MEASUREMENT_VALUE,
HCI_DM_VDC_VALUE_COMPARISON,
MANUFACTURER_SPECIFIC,
};
struct st_nci_vendor_info {
struct completion req_completion;
struct sk_buff *rx_skb;
};
struct st_nci_info { struct st_nci_info {
struct llt_ndlc *ndlc; struct llt_ndlc *ndlc;
unsigned long flags; unsigned long flags;
struct st_nci_se_info se_info; struct st_nci_se_info se_info;
struct st_nci_vendor_info vendor_info;
}; };
void st_nci_remove(struct nci_dev *ndev); void st_nci_remove(struct nci_dev *ndev);
int st_nci_probe(struct llt_ndlc *ndlc, int phy_headroom, int st_nci_probe(struct llt_ndlc *ndlc, int phy_headroom,
int phy_tailroom); int phy_tailroom, struct st_nci_se_status *se_status);
int st_nci_se_init(struct nci_dev *ndev, struct st_nci_se_status *se_status);
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);
void st_nci_hci_loopback_event_received(struct nci_dev *ndev, u8 event,
struct sk_buff *skb);
int st_nci_vendor_cmds_init(struct nci_dev *ndev);
#endif /* __LOCAL_ST_NCI_H_ */ #endif /* __LOCAL_ST_NCI_H_ */
/*
* 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_ */
This diff is collapsed.
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# Makefile for ST21NFCA HCI based NFC driver # Makefile for ST21NFCA HCI based NFC driver
# #
st21nfca_hci-objs = st21nfca.o st21nfca_dep.o st21nfca_se.o st21nfca_hci-objs = core.o dep.o se.o vendor_cmds.o
obj-$(CONFIG_NFC_ST21NFCA) += st21nfca_hci.o obj-$(CONFIG_NFC_ST21NFCA) += st21nfca_hci.o
st21nfca_i2c-objs = i2c.o st21nfca_i2c-objs = i2c.o
......
...@@ -22,8 +22,6 @@ ...@@ -22,8 +22,6 @@
#include <net/nfc/llc.h> #include <net/nfc/llc.h>
#include "st21nfca.h" #include "st21nfca.h"
#include "st21nfca_dep.h"
#include "st21nfca_se.h"
#define DRIVER_DESC "HCI NFC driver for ST21NFCA" #define DRIVER_DESC "HCI NFC driver for ST21NFCA"
...@@ -87,12 +85,13 @@ static DECLARE_BITMAP(dev_mask, ST21NFCA_NUM_DEVICES); ...@@ -87,12 +85,13 @@ static DECLARE_BITMAP(dev_mask, ST21NFCA_NUM_DEVICES);
static struct nfc_hci_gate st21nfca_gates[] = { static struct nfc_hci_gate st21nfca_gates[] = {
{NFC_HCI_ADMIN_GATE, NFC_HCI_ADMIN_PIPE}, {NFC_HCI_ADMIN_GATE, NFC_HCI_ADMIN_PIPE},
{NFC_HCI_LINK_MGMT_GATE, NFC_HCI_LINK_MGMT_PIPE},
{ST21NFCA_DEVICE_MGNT_GATE, ST21NFCA_DEVICE_MGNT_PIPE},
{NFC_HCI_LOOPBACK_GATE, NFC_HCI_INVALID_PIPE}, {NFC_HCI_LOOPBACK_GATE, NFC_HCI_INVALID_PIPE},
{NFC_HCI_ID_MGMT_GATE, NFC_HCI_INVALID_PIPE}, {NFC_HCI_ID_MGMT_GATE, NFC_HCI_INVALID_PIPE},
{NFC_HCI_LINK_MGMT_GATE, NFC_HCI_LINK_MGMT_PIPE},
{NFC_HCI_RF_READER_B_GATE, NFC_HCI_INVALID_PIPE}, {NFC_HCI_RF_READER_B_GATE, NFC_HCI_INVALID_PIPE},
{NFC_HCI_RF_READER_A_GATE, NFC_HCI_INVALID_PIPE}, {NFC_HCI_RF_READER_A_GATE, NFC_HCI_INVALID_PIPE},
{ST21NFCA_DEVICE_MGNT_GATE, ST21NFCA_DEVICE_MGNT_PIPE},
{ST21NFCA_RF_READER_F_GATE, NFC_HCI_INVALID_PIPE}, {ST21NFCA_RF_READER_F_GATE, NFC_HCI_INVALID_PIPE},
{ST21NFCA_RF_READER_14443_3_A_GATE, NFC_HCI_INVALID_PIPE}, {ST21NFCA_RF_READER_14443_3_A_GATE, NFC_HCI_INVALID_PIPE},
{ST21NFCA_RF_READER_ISO15693_GATE, NFC_HCI_INVALID_PIPE}, {ST21NFCA_RF_READER_ISO15693_GATE, NFC_HCI_INVALID_PIPE},
...@@ -163,7 +162,6 @@ static int st21nfca_hci_load_session(struct nfc_hci_dev *hdev) ...@@ -163,7 +162,6 @@ static int st21nfca_hci_load_session(struct nfc_hci_dev *hdev)
r = nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE, r = nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
ST21NFCA_DM_GETINFO, pipe_info, ST21NFCA_DM_GETINFO, pipe_info,
sizeof(pipe_info), &skb_pipe_info); sizeof(pipe_info), &skb_pipe_info);
if (r) if (r)
continue; continue;
...@@ -185,43 +183,33 @@ static int st21nfca_hci_load_session(struct nfc_hci_dev *hdev) ...@@ -185,43 +183,33 @@ static int st21nfca_hci_load_session(struct nfc_hci_dev *hdev)
continue; continue;
} }
for (j = 0; (j < ARRAY_SIZE(st21nfca_gates)) && for (j = 3; (j < ARRAY_SIZE(st21nfca_gates)) &&
(st21nfca_gates[j].gate != info->dst_gate_id) ; j++) (st21nfca_gates[j].gate != info->dst_gate_id) ; j++)
; ;
if (j < ARRAY_SIZE(st21nfca_gates) && if (j < ARRAY_SIZE(st21nfca_gates) &&
st21nfca_gates[j].gate == info->dst_gate_id && st21nfca_gates[j].gate == info->dst_gate_id &&
ST21NFCA_DM_IS_PIPE_OPEN(info->pipe_state)) { ST21NFCA_DM_IS_PIPE_OPEN(info->pipe_state)) {
st21nfca_gates[j].pipe = pipe_info[2]; hdev->init_data.gates[j].pipe = pipe_info[2];
hdev->gate2pipe[st21nfca_gates[j].gate] = hdev->gate2pipe[st21nfca_gates[j].gate] =
st21nfca_gates[j].pipe; pipe_info[2];
hdev->pipes[st21nfca_gates[j].pipe].gate = hdev->pipes[pipe_info[2]].gate =
st21nfca_gates[j].gate; st21nfca_gates[j].gate;
hdev->pipes[st21nfca_gates[j].pipe].dest_host = hdev->pipes[pipe_info[2]].dest_host =
info->src_host_id; info->src_host_id;
} }
kfree_skb(skb_pipe_info); kfree_skb(skb_pipe_info);
} }
/* /*
* 3 gates have a well known pipe ID. * 3 gates have a well known pipe ID. Only NFC_HCI_LINK_MGMT_GATE
* They will never appear in the pipe list * is not yet open at this stage.
*/ */
if (skb_pipe_list->len + 3 < ARRAY_SIZE(st21nfca_gates)) { r = nfc_hci_connect_gate(hdev, NFC_HCI_HOST_CONTROLLER_ID,
for (i = skb_pipe_list->len + 3; NFC_HCI_LINK_MGMT_GATE,
i < ARRAY_SIZE(st21nfca_gates) - 2; i++) { NFC_HCI_LINK_MGMT_PIPE);
r = nfc_hci_connect_gate(hdev,
NFC_HCI_HOST_CONTROLLER_ID,
st21nfca_gates[i].gate,
st21nfca_gates[i].pipe);
if (r < 0)
goto free_list;
}
}
memcpy(hdev->init_data.gates, st21nfca_gates, sizeof(st21nfca_gates));
free_list:
kfree_skb(skb_pipe_list); kfree_skb(skb_pipe_list);
return r; return r;
} }
...@@ -905,6 +893,8 @@ static int st21nfca_admin_event_received(struct nfc_hci_dev *hdev, u8 event, ...@@ -905,6 +893,8 @@ static int st21nfca_admin_event_received(struct nfc_hci_dev *hdev, u8 event,
} }
} }
break; break;
default:
nfc_err(&hdev->ndev->dev, "Unexpected event on admin gate\n");
} }
kfree_skb(skb); kfree_skb(skb);
return 0; return 0;
...@@ -933,6 +923,8 @@ static int st21nfca_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, ...@@ -933,6 +923,8 @@ static int st21nfca_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe,
event, skb); event, skb);
case ST21NFCA_APDU_READER_GATE: case ST21NFCA_APDU_READER_GATE:
return st21nfca_apdu_reader_event_received(hdev, event, skb); return st21nfca_apdu_reader_event_received(hdev, event, skb);
case NFC_HCI_LOOPBACK_GATE:
return st21nfca_hci_loopback_event_received(hdev, event, skb);
default: default:
return 1; return 1;
} }
...@@ -993,7 +985,6 @@ int st21nfca_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, ...@@ -993,7 +985,6 @@ int st21nfca_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops,
* persistent info to discriminate 2 identical chips * persistent info to discriminate 2 identical chips
*/ */
dev_num = find_first_zero_bit(dev_mask, ST21NFCA_NUM_DEVICES); dev_num = find_first_zero_bit(dev_mask, ST21NFCA_NUM_DEVICES);
if (dev_num >= ST21NFCA_NUM_DEVICES) if (dev_num >= ST21NFCA_NUM_DEVICES)
return -ENODEV; return -ENODEV;
...@@ -1035,6 +1026,7 @@ int st21nfca_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, ...@@ -1035,6 +1026,7 @@ int st21nfca_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops,
*hdev = info->hdev; *hdev = info->hdev;
st21nfca_dep_init(info->hdev); st21nfca_dep_init(info->hdev);
st21nfca_se_init(info->hdev); st21nfca_se_init(info->hdev);
st21nfca_vendor_cmds_init(info->hdev);
return 0; return 0;
......
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
#include <net/nfc/hci.h> #include <net/nfc/hci.h>
#include "st21nfca.h" #include "st21nfca.h"
#include "st21nfca_dep.h"
#define ST21NFCA_NFCIP1_INITIATOR 0x00 #define ST21NFCA_NFCIP1_INITIATOR 0x00
#define ST21NFCA_NFCIP1_REQ 0xd4 #define ST21NFCA_NFCIP1_REQ 0xd4
...@@ -436,6 +435,7 @@ int st21nfca_dep_event_received(struct nfc_hci_dev *hdev, ...@@ -436,6 +435,7 @@ int st21nfca_dep_event_received(struct nfc_hci_dev *hdev,
return r; return r;
return 0; return 0;
default: default:
nfc_err(&hdev->ndev->dev, "Unexpected event on card f gate\n");
return 1; return 1;
} }
kfree_skb(skb); kfree_skb(skb);
......
...@@ -94,6 +94,7 @@ struct st21nfca_i2c_phy { ...@@ -94,6 +94,7 @@ struct st21nfca_i2c_phy {
int hard_fault; int hard_fault;
struct mutex phy_lock; struct mutex phy_lock;
}; };
static u8 len_seq[] = { 16, 24, 12, 29 }; static u8 len_seq[] = { 16, 24, 12, 29 };
static u16 wait_tab[] = { 2, 3, 5, 15, 20, 40}; static u16 wait_tab[] = { 2, 3, 5, 15, 20, 40};
......
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
#include <net/nfc/hci.h> #include <net/nfc/hci.h>
#include "st21nfca.h" #include "st21nfca.h"
#include "st21nfca_se.h"
#define ST21NFCA_EVT_UICC_ACTIVATE 0x10 #define ST21NFCA_EVT_UICC_ACTIVATE 0x10
#define ST21NFCA_EVT_UICC_DEACTIVATE 0x13 #define ST21NFCA_EVT_UICC_DEACTIVATE 0x13
...@@ -101,7 +100,7 @@ static int st21nfca_hci_control_se(struct nfc_hci_dev *hdev, u32 se_idx, ...@@ -101,7 +100,7 @@ static int st21nfca_hci_control_se(struct nfc_hci_dev *hdev, u32 se_idx,
u8 state) u8 state)
{ {
struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
int r; int r, i;
struct sk_buff *sk_host_list; struct sk_buff *sk_host_list;
u8 se_event, host_id; u8 se_event, host_id;
...@@ -149,7 +148,10 @@ static int st21nfca_hci_control_se(struct nfc_hci_dev *hdev, u32 se_idx, ...@@ -149,7 +148,10 @@ static int st21nfca_hci_control_se(struct nfc_hci_dev *hdev, u32 se_idx,
if (r < 0) if (r < 0)
return r; return r;
host_id = sk_host_list->data[sk_host_list->len - 1]; for (i = 0; i < sk_host_list->len &&
sk_host_list->data[i] != se_idx; i++)
;
host_id = sk_host_list->data[i];
kfree_skb(sk_host_list); kfree_skb(sk_host_list);
if (state == ST21NFCA_SE_MODE_ON && host_id == se_idx) if (state == ST21NFCA_SE_MODE_ON && host_id == se_idx)
...@@ -165,6 +167,9 @@ int st21nfca_hci_discover_se(struct nfc_hci_dev *hdev) ...@@ -165,6 +167,9 @@ int st21nfca_hci_discover_se(struct nfc_hci_dev *hdev)
struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
int se_count = 0; int se_count = 0;
if (test_bit(ST21NFCA_FACTORY_MODE, &hdev->quirks))
return 0;
if (info->se_status->is_uicc_present) { if (info->se_status->is_uicc_present) {
nfc_add_se(hdev->ndev, NFC_HCI_UICC_HOST_ID, NFC_SE_UICC); nfc_add_se(hdev->ndev, NFC_HCI_UICC_HOST_ID, NFC_SE_UICC);
se_count++; se_count++;
...@@ -189,7 +194,6 @@ int st21nfca_hci_enable_se(struct nfc_hci_dev *hdev, u32 se_idx) ...@@ -189,7 +194,6 @@ int st21nfca_hci_enable_se(struct nfc_hci_dev *hdev, u32 se_idx)
* Same for eSE. * Same for eSE.
*/ */
r = st21nfca_hci_control_se(hdev, se_idx, ST21NFCA_SE_MODE_ON); r = st21nfca_hci_control_se(hdev, se_idx, ST21NFCA_SE_MODE_ON);
if (r == ST21NFCA_ESE_HOST_ID) { if (r == ST21NFCA_ESE_HOST_ID) {
st21nfca_se_get_atr(hdev); st21nfca_se_get_atr(hdev);
r = nfc_hci_send_event(hdev, ST21NFCA_APDU_READER_GATE, r = nfc_hci_send_event(hdev, ST21NFCA_APDU_READER_GATE,
...@@ -340,6 +344,7 @@ int st21nfca_connectivity_event_received(struct nfc_hci_dev *hdev, u8 host, ...@@ -340,6 +344,7 @@ int st21nfca_connectivity_event_received(struct nfc_hci_dev *hdev, u8 host,
r = nfc_se_transaction(hdev->ndev, host, transaction); r = nfc_se_transaction(hdev->ndev, host, transaction);
break; break;
default: default:
nfc_err(&hdev->ndev->dev, "Unexpected event on connectivity gate\n");
return 1; return 1;
} }
kfree_skb(skb); kfree_skb(skb);
...@@ -371,6 +376,9 @@ int st21nfca_apdu_reader_event_received(struct nfc_hci_dev *hdev, ...@@ -371,6 +376,9 @@ int st21nfca_apdu_reader_event_received(struct nfc_hci_dev *hdev,
mod_timer(&info->se_info.bwi_timer, jiffies + mod_timer(&info->se_info.bwi_timer, jiffies +
msecs_to_jiffies(info->se_info.wt_timeout)); msecs_to_jiffies(info->se_info.wt_timeout));
break; break;
default:
nfc_err(&hdev->ndev->dev, "Unexpected event on apdu reader gate\n");
return 1;
} }
exit: exit:
......
...@@ -18,9 +18,8 @@ ...@@ -18,9 +18,8 @@
#define __LOCAL_ST21NFCA_H_ #define __LOCAL_ST21NFCA_H_
#include <net/nfc/hci.h> #include <net/nfc/hci.h>
#include <linux/skbuff.h>
#include "st21nfca_dep.h" #include <linux/workqueue.h>
#include "st21nfca_se.h"
#define HCI_MODE 0 #define HCI_MODE 0
...@@ -46,28 +45,115 @@ ...@@ -46,28 +45,115 @@
#define ST21NFCA_HCI_LLC_MAX_SIZE (ST21NFCA_HCI_LLC_LEN_CRC + 1 + \ #define ST21NFCA_HCI_LLC_MAX_SIZE (ST21NFCA_HCI_LLC_LEN_CRC + 1 + \
ST21NFCA_HCI_LLC_MAX_PAYLOAD) ST21NFCA_HCI_LLC_MAX_PAYLOAD)
/* Reader RF commands */
#define ST21NFCA_WR_XCHG_DATA 0x10
#define ST21NFCA_DEVICE_MGNT_GATE 0x01
#define ST21NFCA_RF_READER_F_GATE 0x14
#define ST21NFCA_RF_CARD_F_GATE 0x24
#define ST21NFCA_APDU_READER_GATE 0xf0
#define ST21NFCA_CONNECTIVITY_GATE 0x41
/*
* ref ISO7816-3 chap 8.1. the initial character TS is followed by a
* sequence of at most 32 characters.
*/
#define ST21NFCA_ESE_MAX_LENGTH 33
#define ST21NFCA_ESE_HOST_ID 0xc0
#define DRIVER_DESC "HCI NFC driver for ST21NFCA" #define DRIVER_DESC "HCI NFC driver for ST21NFCA"
#define ST21NFCA_HCI_MODE 0 #define ST21NFCA_HCI_MODE 0
#define ST21NFCA_NUM_DEVICES 256 #define ST21NFCA_NUM_DEVICES 256
#define ST21NFCA_VENDOR_OUI 0x0080E1 /* STMicroelectronics */
#define ST21NFCA_FACTORY_MODE 2
struct st21nfca_se_status { struct st21nfca_se_status {
bool is_ese_present; bool is_ese_present;
bool is_uicc_present; bool is_uicc_present;
}; };
int st21nfca_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops,
char *llc_name, int phy_headroom, int phy_tailroom,
int phy_payload, struct nfc_hci_dev **hdev,
struct st21nfca_se_status *se_status);
void st21nfca_hci_remove(struct nfc_hci_dev *hdev);
enum st21nfca_state { enum st21nfca_state {
ST21NFCA_ST_COLD, ST21NFCA_ST_COLD,
ST21NFCA_ST_READY, ST21NFCA_ST_READY,
}; };
/**
* enum nfc_vendor_cmds - supported nfc vendor commands
*
* @FACTORY_MODE: Allow to set the driver into a mode where no secure element
* are activated. It does not consider any NFC_ATTR_VENDOR_DATA.
* @HCI_CLEAR_ALL_PIPES: Allow to execute a HCI clear all pipes command.
* It does not consider any NFC_ATTR_VENDOR_DATA.
* @HCI_DM_PUT_DATA: Allow to configure specific CLF registry as for example
* RF trimmings or low level drivers configurations (I2C, SPI, SWP).
* @HCI_DM_UPDATE_AID: Allow to configure an AID routing into the CLF routing
* table following RF technology, CLF mode or protocol.
* @HCI_DM_GET_INFO: Allow to retrieve CLF information.
* @HCI_DM_GET_DATA: Allow to retrieve CLF configurable data such as low
* level drivers configurations or RF trimmings.
* @HCI_DM_LOAD: Allow to load a firmware into the CLF. A complete
* packet can be more than 8KB.
* @HCI_DM_RESET: Allow to run a CLF reset in order to "commit" CLF
* configuration changes without CLF power off.
* @HCI_GET_PARAM: Allow to retrieve an HCI CLF parameter (for example the
* white list).
* @HCI_DM_FIELD_GENERATOR: Allow to generate different kind of RF
* technology. When using this command to anti-collision is done.
* @HCI_LOOPBACK: Allow to echo a command and test the Dh to CLF
* connectivity.
*/
enum nfc_vendor_cmds {
FACTORY_MODE,
HCI_CLEAR_ALL_PIPES,
HCI_DM_PUT_DATA,
HCI_DM_UPDATE_AID,
HCI_DM_GET_INFO,
HCI_DM_GET_DATA,
HCI_DM_LOAD,
HCI_DM_RESET,
HCI_GET_PARAM,
HCI_DM_FIELD_GENERATOR,
HCI_LOOPBACK,
};
struct st21nfca_vendor_info {
struct completion req_completion;
struct sk_buff *rx_skb;
};
struct st21nfca_dep_info {
struct sk_buff *tx_pending;
struct work_struct tx_work;
u8 curr_nfc_dep_pni;
u32 idx;
u8 to;
u8 did;
u8 bsi;
u8 bri;
u8 lri;
} __packed;
struct st21nfca_se_info {
u8 atr[ST21NFCA_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;
int expected_pipes;
int count_pipes;
bool xch_error;
se_io_cb_t cb;
void *cb_context;
};
struct st21nfca_hci_info { struct st21nfca_hci_info {
struct nfc_phy_ops *phy_ops; struct nfc_phy_ops *phy_ops;
void *phy_id; void *phy_id;
...@@ -85,15 +171,41 @@ struct st21nfca_hci_info { ...@@ -85,15 +171,41 @@ struct st21nfca_hci_info {
struct st21nfca_dep_info dep_info; struct st21nfca_dep_info dep_info;
struct st21nfca_se_info se_info; struct st21nfca_se_info se_info;
struct st21nfca_vendor_info vendor_info;
}; };
/* Reader RF commands */ int st21nfca_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops,
#define ST21NFCA_WR_XCHG_DATA 0x10 char *llc_name, int phy_headroom, int phy_tailroom,
int phy_payload, struct nfc_hci_dev **hdev,
struct st21nfca_se_status *se_status);
void st21nfca_hci_remove(struct nfc_hci_dev *hdev);
#define ST21NFCA_DEVICE_MGNT_GATE 0x01 int st21nfca_dep_event_received(struct nfc_hci_dev *hdev,
#define ST21NFCA_RF_READER_F_GATE 0x14 u8 event, struct sk_buff *skb);
#define ST21NFCA_RF_CARD_F_GATE 0x24 int st21nfca_tm_send_dep_res(struct nfc_hci_dev *hdev, struct sk_buff *skb);
#define ST21NFCA_APDU_READER_GATE 0xf0
#define ST21NFCA_CONNECTIVITY_GATE 0x41 int st21nfca_im_send_atr_req(struct nfc_hci_dev *hdev, u8 *gb, size_t gb_len);
int st21nfca_im_send_dep_req(struct nfc_hci_dev *hdev, struct sk_buff *skb);
void st21nfca_dep_init(struct nfc_hci_dev *hdev);
void st21nfca_dep_deinit(struct nfc_hci_dev *hdev);
int st21nfca_connectivity_event_received(struct nfc_hci_dev *hdev, u8 host,
u8 event, struct sk_buff *skb);
int st21nfca_apdu_reader_event_received(struct nfc_hci_dev *hdev,
u8 event, struct sk_buff *skb);
int st21nfca_hci_discover_se(struct nfc_hci_dev *hdev);
int st21nfca_hci_enable_se(struct nfc_hci_dev *hdev, u32 se_idx);
int st21nfca_hci_disable_se(struct nfc_hci_dev *hdev, u32 se_idx);
int st21nfca_hci_se_io(struct nfc_hci_dev *hdev, u32 se_idx,
u8 *apdu, size_t apdu_length,
se_io_cb_t cb, void *cb_context);
void st21nfca_se_init(struct nfc_hci_dev *hdev);
void st21nfca_se_deinit(struct nfc_hci_dev *hdev);
int st21nfca_hci_loopback_event_received(struct nfc_hci_dev *ndev, u8 event,
struct sk_buff *skb);
int st21nfca_vendor_cmds_init(struct nfc_hci_dev *ndev);
#endif /* __LOCAL_ST21NFCA_H_ */ #endif /* __LOCAL_ST21NFCA_H_ */
/*
* 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 __ST21NFCA_DEP_H
#define __ST21NFCA_DEP_H
#include <linux/skbuff.h>
#include <linux/workqueue.h>
struct st21nfca_dep_info {
struct sk_buff *tx_pending;
struct work_struct tx_work;
u8 curr_nfc_dep_pni;
u32 idx;
u8 to;
u8 did;
u8 bsi;
u8 bri;
u8 lri;
} __packed;
int st21nfca_dep_event_received(struct nfc_hci_dev *hdev,
u8 event, struct sk_buff *skb);
int st21nfca_tm_send_dep_res(struct nfc_hci_dev *hdev, struct sk_buff *skb);
int st21nfca_im_send_atr_req(struct nfc_hci_dev *hdev, u8 *gb, size_t gb_len);
int st21nfca_im_send_dep_req(struct nfc_hci_dev *hdev, struct sk_buff *skb);
void st21nfca_dep_init(struct nfc_hci_dev *hdev);
void st21nfca_dep_deinit(struct nfc_hci_dev *hdev);
#endif /* __ST21NFCA_DEP_H */
/*
* 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 __ST21NFCA_SE_H
#define __ST21NFCA_SE_H
#include <linux/skbuff.h>
#include <linux/workqueue.h>
/*
* ref ISO7816-3 chap 8.1. the initial character TS is followed by a
* sequence of at most 32 characters.
*/
#define ST21NFCA_ESE_MAX_LENGTH 33
#define ST21NFCA_ESE_HOST_ID 0xc0
struct st21nfca_se_info {
u8 atr[ST21NFCA_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;
int expected_pipes;
int count_pipes;
bool xch_error;
se_io_cb_t cb;
void *cb_context;
};
int st21nfca_connectivity_event_received(struct nfc_hci_dev *hdev, u8 host,
u8 event, struct sk_buff *skb);
int st21nfca_apdu_reader_event_received(struct nfc_hci_dev *hdev,
u8 event, struct sk_buff *skb);
int st21nfca_hci_discover_se(struct nfc_hci_dev *hdev);
int st21nfca_hci_enable_se(struct nfc_hci_dev *hdev, u32 se_idx);
int st21nfca_hci_disable_se(struct nfc_hci_dev *hdev, u32 se_idx);
int st21nfca_hci_se_io(struct nfc_hci_dev *hdev, u32 se_idx,
u8 *apdu, size_t apdu_length,
se_io_cb_t cb, void *cb_context);
void st21nfca_se_init(struct nfc_hci_dev *hdev);
void st21nfca_se_deinit(struct nfc_hci_dev *hdev);
#endif /* __ST21NFCA_SE_H */
This diff is collapsed.
...@@ -2211,6 +2211,12 @@ static const struct dev_pm_ops trf7970a_pm_ops = { ...@@ -2211,6 +2211,12 @@ static const struct dev_pm_ops trf7970a_pm_ops = {
trf7970a_pm_runtime_resume, NULL) trf7970a_pm_runtime_resume, NULL)
}; };
static const struct of_device_id trf7970a_of_match[] = {
{ .compatible = "ti,trf7970a", },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, trf7970a_of_match);
static const struct spi_device_id trf7970a_id_table[] = { static const struct spi_device_id trf7970a_id_table[] = {
{ "trf7970a", 0 }, { "trf7970a", 0 },
{ } { }
...@@ -2223,6 +2229,7 @@ static struct spi_driver trf7970a_spi_driver = { ...@@ -2223,6 +2229,7 @@ static struct spi_driver trf7970a_spi_driver = {
.id_table = trf7970a_id_table, .id_table = trf7970a_id_table,
.driver = { .driver = {
.name = "trf7970a", .name = "trf7970a",
.of_match_table = of_match_ptr(trf7970a_of_match),
.owner = THIS_MODULE, .owner = THIS_MODULE,
.pm = &trf7970a_pm_ops, .pm = &trf7970a_pm_ops,
}, },
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment