NFC 4.12 pull request
This is the NFC pull request for 4.12. We have: - Improvements for the pn533 command queue handling and device registration order. - Removal of platform data for the pn544 and st21nfca drivers. - Additional device tree options to support more trf7970a hardware options. - Support for Sony's RC-S380P through the port100 driver. - Removal of the obsolte nfcwilink driver. - Headers inclusion cleanups (miscdevice.h, unaligned.h) for many drivers. -----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJY8//bAAoJEIqAPN1PVmxKYVsP/0d9V98WuvBiyNffRwNLbol1 w37Er17cIma4Tzrm9jWzwGFCAd4k5Bn3K6rEXejsnSCkvSPZaRvlsd9itpmxmYhs SkWPl9IoPi9wWrHkr20p34n1OdZdqx+R6CtKNB4B7t7EASWlZ6BMl4RgeO03QckA FHZSGszOWMr9OF/+ZLBJm66JlNTkNiaumjFXeayXEzkv2JhnZqxdLqR8117Ycwa1 MvSYzvcOAV1OWlaiyc3VzyF49D3DcxweC4lgx3JkQ1CPzcIIgPYaws1QGLraSwUT JSVWn3P0WFM8sPJEGDa7XKjVPfy7mW2wgQ2oJVZJR5TOygyonkNuTK2ohEXp0SUI xzH/qbQmvKb/VbwdXWj4N7rnfpdry/C52S5+nn/pLV6Y2S7LF4FGvUMWUQmh2uu3 kw2SQqEHLcbHnDz3G50UfTJ9mH1CVP8a4HsM39Wtm79H3IVmnS2+owm/wdSrqq6h 5i/nL7L/6XDj+yg+2th1BdHxhA6F7aTDxxFpgF25K+y79tm2Fvnic6pQBfwRTpvv FfvTMpJAdC9OkLppNb3PLUT+YnSN1YgH7Hgv6rFc/KiVJ4rMFMXV1EaWdzWWuRd5 U8Obl1Nag2SmSSVrRAr56yfltkJlhqcoLk01Go3d/qYF4GO7LFrmSoODH0L0JDaE mH/vYF47mkFvWicF950v =Zy1M -----END PGP SIGNATURE----- Merge tag 'nfc-next-4.12-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/nfc-next Samuel Ortiz says: ==================== NFC 4.12 pull request This is the NFC pull request for 4.12. We have: - Improvements for the pn533 command queue handling and device registration order. - Removal of platform data for the pn544 and st21nfca drivers. - Additional device tree options to support more trf7970a hardware options. - Support for Sony's RC-S380P through the port100 driver. - Removal of the obsolte nfcwilink driver. - Headers inclusion cleanups (miscdevice.h, unaligned.h) for many drivers. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Коммит
69e3948aaa
|
@ -5,8 +5,8 @@ Required properties:
|
|||
- spi-max-frequency: Maximum SPI frequency (<= 2000000).
|
||||
- interrupt-parent: phandle of parent interrupt handler.
|
||||
- interrupts: A single interrupt specifier.
|
||||
- ti,enable-gpios: Two GPIO entries used for 'EN' and 'EN2' pins on the
|
||||
TRF7970A.
|
||||
- ti,enable-gpios: One or two GPIO entries used for 'EN' and 'EN2' pins on the
|
||||
TRF7970A. EN2 is optional.
|
||||
- vin-supply: Regulator for supply voltage to VIN pin
|
||||
|
||||
Optional SoC Specific Properties:
|
||||
|
@ -21,6 +21,8 @@ Optional SoC Specific Properties:
|
|||
- t5t-rmb-extra-byte-quirk: Specify that the trf7970a has the erratum
|
||||
where an extra byte is returned by Read Multiple Block commands issued
|
||||
to Type 5 tags.
|
||||
- vdd-io-supply: Regulator specifying voltage for vdd-io
|
||||
- clock-frequency: Set to specify that the input frequency to the trf7970a is 13560000Hz or 27120000Hz
|
||||
|
||||
Example (for ARM-based BeagleBone with TRF7970A on SPI1):
|
||||
|
||||
|
@ -39,10 +41,12 @@ Example (for ARM-based BeagleBone with TRF7970A on SPI1):
|
|||
<&gpio2 5 GPIO_ACTIVE_LOW>;
|
||||
vin-supply = <&ldo3_reg>;
|
||||
vin-voltage-override = <5000000>;
|
||||
vdd-io-supply = <&ldo2_reg>;
|
||||
autosuspend-delay = <30000>;
|
||||
irq-status-read-quirk;
|
||||
en2-rf-quirk;
|
||||
t5t-rmb-extra-byte-quirk;
|
||||
clock-frequency = <27120000>;
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
|
|
|
@ -8876,8 +8876,6 @@ S: Supported
|
|||
F: drivers/net/ethernet/qlogic/netxen/
|
||||
|
||||
NFC SUBSYSTEM
|
||||
M: Lauro Ramos Venancio <lauro.venancio@openbossa.org>
|
||||
M: Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
|
||||
M: Samuel Ortiz <sameo@linux.intel.com>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
L: linux-nfc@lists.01.org (subscribers-only)
|
||||
|
|
|
@ -5,17 +5,6 @@
|
|||
menu "Near Field Communication (NFC) devices"
|
||||
depends on NFC
|
||||
|
||||
config NFC_WILINK
|
||||
tristate "Texas Instruments NFC WiLink driver"
|
||||
depends on TI_ST && NFC_NCI
|
||||
help
|
||||
This enables the NFC driver for Texas Instrument's BT/FM/GPS/NFC
|
||||
combo devices. This makes use of shared transport line discipline
|
||||
core driver to communicate with the NFC core of the combo chip.
|
||||
|
||||
Say Y here to compile support for Texas Instrument's NFC WiLink driver
|
||||
into the kernel or say M to compile it as module.
|
||||
|
||||
config NFC_TRF7970A
|
||||
tristate "Texas Instruments TRF7970a NFC driver"
|
||||
depends on SPI && NFC_DIGITAL
|
||||
|
|
|
@ -6,7 +6,6 @@ obj-$(CONFIG_NFC_FDP) += fdp/
|
|||
obj-$(CONFIG_NFC_PN544) += pn544/
|
||||
obj-$(CONFIG_NFC_MICROREAD) += microread/
|
||||
obj-$(CONFIG_NFC_PN533) += pn533/
|
||||
obj-$(CONFIG_NFC_WILINK) += nfcwilink.o
|
||||
obj-$(CONFIG_NFC_MEI_PHY) += mei_phy.o
|
||||
obj-$(CONFIG_NFC_SIM) += nfcsim.o
|
||||
obj-$(CONFIG_NFC_PORT100) += port100.o
|
||||
|
|
|
@ -210,14 +210,14 @@ static irqreturn_t fdp_nci_i2c_irq_thread_fn(int irq, void *phy_id)
|
|||
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;
|
||||
}
|
||||
|
||||
client = phy->i2c_dev;
|
||||
dev_dbg(&client->dev, "%s\n", __func__);
|
||||
|
||||
r = fdp_nci_i2c_read(phy, &skb);
|
||||
|
||||
if (r == -EREMOTEIO)
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/unaligned/access_ok.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/nfc.h>
|
||||
#include <net/nfc/nci.h>
|
||||
|
@ -281,12 +281,11 @@ static int process_state_fw_dnld(struct nfcmrvl_private *priv,
|
|||
return -EINVAL;
|
||||
}
|
||||
skb_pull(skb, 1);
|
||||
memcpy(&len, skb->data, 2);
|
||||
len = get_unaligned_le16(skb->data);
|
||||
skb_pull(skb, 2);
|
||||
comp_len = get_unaligned_le16(skb->data);
|
||||
memcpy(&comp_len, skb->data, 2);
|
||||
skb_pull(skb, 2);
|
||||
len = get_unaligned_le16(&len);
|
||||
comp_len = get_unaligned_le16(&comp_len);
|
||||
if (((~len) & 0xFFFF) != comp_len) {
|
||||
nfc_err(priv->dev, "bad len complement: %x %x %x",
|
||||
len, comp_len, (~len & 0xFFFF));
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
#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
|
||||
|
@ -96,10 +95,9 @@ static int nfcmrvl_spi_nci_send(struct nfcmrvl_private *priv,
|
|||
/* Send the SPI packet */
|
||||
err = nci_spi_send(drv_data->nci_spi, &drv_data->handshake_completion,
|
||||
skb);
|
||||
if (err != 0) {
|
||||
if (err)
|
||||
nfc_err(priv->dev, "spi_send failed %d", err);
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,578 +0,0 @@
|
|||
/*
|
||||
* Texas Instrument's NFC Driver For Shared Transport.
|
||||
*
|
||||
* NFC Driver acts as interface between NCI core and
|
||||
* TI Shared Transport Layer.
|
||||
*
|
||||
* Copyright (C) 2011 Texas Instruments, Inc.
|
||||
*
|
||||
* Written by Ilan Elias <ilane@ti.com>
|
||||
*
|
||||
* Acknowledgements:
|
||||
* This file is based on btwilink.c, which was written
|
||||
* by Raja Mani and Pavan Savoy.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/nfc.h>
|
||||
#include <net/nfc/nci.h>
|
||||
#include <net/nfc/nci_core.h>
|
||||
#include <linux/ti_wilink_st.h>
|
||||
|
||||
#define NFCWILINK_CHNL 12
|
||||
#define NFCWILINK_OPCODE 7
|
||||
#define NFCWILINK_MAX_FRAME_SIZE 300
|
||||
#define NFCWILINK_HDR_LEN 4
|
||||
#define NFCWILINK_OFFSET_LEN_IN_HDR 1
|
||||
#define NFCWILINK_LEN_SIZE 2
|
||||
#define NFCWILINK_REGISTER_TIMEOUT 8000 /* 8 sec */
|
||||
#define NFCWILINK_CMD_TIMEOUT 5000 /* 5 sec */
|
||||
|
||||
#define BTS_FILE_NAME_MAX_SIZE 40
|
||||
#define BTS_FILE_HDR_MAGIC 0x42535442
|
||||
#define BTS_FILE_CMD_MAX_LEN 0xff
|
||||
#define BTS_FILE_ACTION_TYPE_SEND_CMD 1
|
||||
|
||||
#define NCI_VS_NFCC_INFO_CMD_GID 0x2f
|
||||
#define NCI_VS_NFCC_INFO_CMD_OID 0x12
|
||||
#define NCI_VS_NFCC_INFO_RSP_GID 0x4f
|
||||
#define NCI_VS_NFCC_INFO_RSP_OID 0x12
|
||||
|
||||
struct nfcwilink_hdr {
|
||||
__u8 chnl;
|
||||
__u8 opcode;
|
||||
__le16 len;
|
||||
} __packed;
|
||||
|
||||
struct nci_vs_nfcc_info_cmd {
|
||||
__u8 gid;
|
||||
__u8 oid;
|
||||
__u8 plen;
|
||||
} __packed;
|
||||
|
||||
struct nci_vs_nfcc_info_rsp {
|
||||
__u8 gid;
|
||||
__u8 oid;
|
||||
__u8 plen;
|
||||
__u8 status;
|
||||
__u8 hw_id;
|
||||
__u8 sw_ver_x;
|
||||
__u8 sw_ver_z;
|
||||
__u8 patch_id;
|
||||
} __packed;
|
||||
|
||||
struct bts_file_hdr {
|
||||
__le32 magic;
|
||||
__le32 ver;
|
||||
__u8 rfu[24];
|
||||
__u8 actions[0];
|
||||
} __packed;
|
||||
|
||||
struct bts_file_action {
|
||||
__le16 type;
|
||||
__le16 len;
|
||||
__u8 data[0];
|
||||
} __packed;
|
||||
|
||||
struct nfcwilink {
|
||||
struct platform_device *pdev;
|
||||
struct nci_dev *ndev;
|
||||
unsigned long flags;
|
||||
|
||||
int st_register_cb_status;
|
||||
long (*st_write) (struct sk_buff *);
|
||||
|
||||
struct completion completed;
|
||||
|
||||
struct nci_vs_nfcc_info_rsp nfcc_info;
|
||||
};
|
||||
|
||||
/* NFCWILINK driver flags */
|
||||
enum {
|
||||
NFCWILINK_RUNNING,
|
||||
NFCWILINK_FW_DOWNLOAD,
|
||||
};
|
||||
|
||||
static int nfcwilink_send(struct nci_dev *ndev, struct sk_buff *skb);
|
||||
|
||||
static inline struct sk_buff *nfcwilink_skb_alloc(unsigned int len, gfp_t how)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = alloc_skb(len + NFCWILINK_HDR_LEN, how);
|
||||
if (skb)
|
||||
skb_reserve(skb, NFCWILINK_HDR_LEN);
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
static void nfcwilink_fw_download_receive(struct nfcwilink *drv,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct nci_vs_nfcc_info_rsp *rsp = (void *)skb->data;
|
||||
|
||||
/* Detect NCI_VS_NFCC_INFO_RSP and store the result */
|
||||
if ((skb->len > 3) && (rsp->gid == NCI_VS_NFCC_INFO_RSP_GID) &&
|
||||
(rsp->oid == NCI_VS_NFCC_INFO_RSP_OID)) {
|
||||
memcpy(&drv->nfcc_info, rsp,
|
||||
sizeof(struct nci_vs_nfcc_info_rsp));
|
||||
}
|
||||
|
||||
kfree_skb(skb);
|
||||
|
||||
complete(&drv->completed);
|
||||
}
|
||||
|
||||
static int nfcwilink_get_bts_file_name(struct nfcwilink *drv, char *file_name)
|
||||
{
|
||||
struct nci_vs_nfcc_info_cmd *cmd;
|
||||
struct sk_buff *skb;
|
||||
unsigned long comp_ret;
|
||||
int rc;
|
||||
|
||||
skb = nfcwilink_skb_alloc(sizeof(struct nci_vs_nfcc_info_cmd),
|
||||
GFP_KERNEL);
|
||||
if (!skb) {
|
||||
nfc_err(&drv->pdev->dev,
|
||||
"no memory for nci_vs_nfcc_info_cmd\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
cmd = (struct nci_vs_nfcc_info_cmd *)
|
||||
skb_put(skb, sizeof(struct nci_vs_nfcc_info_cmd));
|
||||
cmd->gid = NCI_VS_NFCC_INFO_CMD_GID;
|
||||
cmd->oid = NCI_VS_NFCC_INFO_CMD_OID;
|
||||
cmd->plen = 0;
|
||||
|
||||
drv->nfcc_info.plen = 0;
|
||||
|
||||
rc = nfcwilink_send(drv->ndev, skb);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
comp_ret = wait_for_completion_timeout(&drv->completed,
|
||||
msecs_to_jiffies(NFCWILINK_CMD_TIMEOUT));
|
||||
dev_dbg(&drv->pdev->dev, "wait_for_completion_timeout returned %ld\n",
|
||||
comp_ret);
|
||||
if (comp_ret == 0) {
|
||||
nfc_err(&drv->pdev->dev,
|
||||
"timeout on wait_for_completion_timeout\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
dev_dbg(&drv->pdev->dev, "nci_vs_nfcc_info_rsp: plen %d, status %d\n",
|
||||
drv->nfcc_info.plen, drv->nfcc_info.status);
|
||||
|
||||
if ((drv->nfcc_info.plen != 5) || (drv->nfcc_info.status != 0)) {
|
||||
nfc_err(&drv->pdev->dev, "invalid nci_vs_nfcc_info_rsp\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snprintf(file_name, BTS_FILE_NAME_MAX_SIZE,
|
||||
"TINfcInit_%d.%d.%d.%d.bts",
|
||||
drv->nfcc_info.hw_id,
|
||||
drv->nfcc_info.sw_ver_x,
|
||||
drv->nfcc_info.sw_ver_z,
|
||||
drv->nfcc_info.patch_id);
|
||||
|
||||
nfc_info(&drv->pdev->dev, "nfcwilink FW file name: %s\n", file_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nfcwilink_send_bts_cmd(struct nfcwilink *drv, __u8 *data, int len)
|
||||
{
|
||||
struct nfcwilink_hdr *hdr = (struct nfcwilink_hdr *)data;
|
||||
struct sk_buff *skb;
|
||||
unsigned long comp_ret;
|
||||
int rc;
|
||||
|
||||
/* verify valid cmd for the NFC channel */
|
||||
if ((len <= sizeof(struct nfcwilink_hdr)) ||
|
||||
(len > BTS_FILE_CMD_MAX_LEN) ||
|
||||
(hdr->chnl != NFCWILINK_CHNL) ||
|
||||
(hdr->opcode != NFCWILINK_OPCODE)) {
|
||||
nfc_err(&drv->pdev->dev,
|
||||
"ignoring invalid bts cmd, len %d, chnl %d, opcode %d\n",
|
||||
len, hdr->chnl, hdr->opcode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* remove the ST header */
|
||||
len -= sizeof(struct nfcwilink_hdr);
|
||||
data += sizeof(struct nfcwilink_hdr);
|
||||
|
||||
skb = nfcwilink_skb_alloc(len, GFP_KERNEL);
|
||||
if (!skb) {
|
||||
nfc_err(&drv->pdev->dev, "no memory for bts cmd\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memcpy(skb_put(skb, len), data, len);
|
||||
|
||||
rc = nfcwilink_send(drv->ndev, skb);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
comp_ret = wait_for_completion_timeout(&drv->completed,
|
||||
msecs_to_jiffies(NFCWILINK_CMD_TIMEOUT));
|
||||
dev_dbg(&drv->pdev->dev, "wait_for_completion_timeout returned %ld\n",
|
||||
comp_ret);
|
||||
if (comp_ret == 0) {
|
||||
nfc_err(&drv->pdev->dev,
|
||||
"timeout on wait_for_completion_timeout\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nfcwilink_download_fw(struct nfcwilink *drv)
|
||||
{
|
||||
unsigned char file_name[BTS_FILE_NAME_MAX_SIZE];
|
||||
const struct firmware *fw;
|
||||
__u16 action_type, action_len;
|
||||
__u8 *ptr;
|
||||
int len, rc;
|
||||
|
||||
set_bit(NFCWILINK_FW_DOWNLOAD, &drv->flags);
|
||||
|
||||
rc = nfcwilink_get_bts_file_name(drv, file_name);
|
||||
if (rc)
|
||||
goto exit;
|
||||
|
||||
rc = request_firmware(&fw, file_name, &drv->pdev->dev);
|
||||
if (rc) {
|
||||
nfc_err(&drv->pdev->dev, "request_firmware failed %d\n", rc);
|
||||
|
||||
/* if the file is not found, don't exit with failure */
|
||||
if (rc == -ENOENT)
|
||||
rc = 0;
|
||||
|
||||
goto exit;
|
||||
}
|
||||
|
||||
len = fw->size;
|
||||
ptr = (__u8 *)fw->data;
|
||||
|
||||
if ((len == 0) || (ptr == NULL)) {
|
||||
dev_dbg(&drv->pdev->dev,
|
||||
"request_firmware returned size %d\n", len);
|
||||
goto release_fw;
|
||||
}
|
||||
|
||||
if (__le32_to_cpu(((struct bts_file_hdr *)ptr)->magic) !=
|
||||
BTS_FILE_HDR_MAGIC) {
|
||||
nfc_err(&drv->pdev->dev, "wrong bts magic number\n");
|
||||
rc = -EINVAL;
|
||||
goto release_fw;
|
||||
}
|
||||
|
||||
/* remove the BTS header */
|
||||
len -= sizeof(struct bts_file_hdr);
|
||||
ptr += sizeof(struct bts_file_hdr);
|
||||
|
||||
while (len > 0) {
|
||||
action_type =
|
||||
__le16_to_cpu(((struct bts_file_action *)ptr)->type);
|
||||
action_len =
|
||||
__le16_to_cpu(((struct bts_file_action *)ptr)->len);
|
||||
|
||||
dev_dbg(&drv->pdev->dev, "bts_file_action type %d, len %d\n",
|
||||
action_type, action_len);
|
||||
|
||||
switch (action_type) {
|
||||
case BTS_FILE_ACTION_TYPE_SEND_CMD:
|
||||
rc = nfcwilink_send_bts_cmd(drv,
|
||||
((struct bts_file_action *)ptr)->data,
|
||||
action_len);
|
||||
if (rc)
|
||||
goto release_fw;
|
||||
break;
|
||||
}
|
||||
|
||||
/* advance to the next action */
|
||||
len -= (sizeof(struct bts_file_action) + action_len);
|
||||
ptr += (sizeof(struct bts_file_action) + action_len);
|
||||
}
|
||||
|
||||
release_fw:
|
||||
release_firmware(fw);
|
||||
|
||||
exit:
|
||||
clear_bit(NFCWILINK_FW_DOWNLOAD, &drv->flags);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Called by ST when registration is complete */
|
||||
static void nfcwilink_register_complete(void *priv_data, int data)
|
||||
{
|
||||
struct nfcwilink *drv = priv_data;
|
||||
|
||||
/* store ST registration status */
|
||||
drv->st_register_cb_status = data;
|
||||
|
||||
/* complete the wait in nfc_st_open() */
|
||||
complete(&drv->completed);
|
||||
}
|
||||
|
||||
/* Called by ST when receive data is available */
|
||||
static long nfcwilink_receive(void *priv_data, struct sk_buff *skb)
|
||||
{
|
||||
struct nfcwilink *drv = priv_data;
|
||||
int rc;
|
||||
|
||||
if (!skb)
|
||||
return -EFAULT;
|
||||
|
||||
if (!drv) {
|
||||
kfree_skb(skb);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
dev_dbg(&drv->pdev->dev, "receive entry, len %d\n", skb->len);
|
||||
|
||||
/* strip the ST header
|
||||
(apart for the chnl byte, which is not received in the hdr) */
|
||||
skb_pull(skb, (NFCWILINK_HDR_LEN-1));
|
||||
|
||||
if (test_bit(NFCWILINK_FW_DOWNLOAD, &drv->flags)) {
|
||||
nfcwilink_fw_download_receive(drv, skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Forward skb to NCI core layer */
|
||||
rc = nci_recv_frame(drv->ndev, skb);
|
||||
if (rc < 0) {
|
||||
nfc_err(&drv->pdev->dev, "nci_recv_frame failed %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* protocol structure registered with ST */
|
||||
static struct st_proto_s nfcwilink_proto = {
|
||||
.chnl_id = NFCWILINK_CHNL,
|
||||
.max_frame_size = NFCWILINK_MAX_FRAME_SIZE,
|
||||
.hdr_len = (NFCWILINK_HDR_LEN-1), /* not including chnl byte */
|
||||
.offset_len_in_hdr = NFCWILINK_OFFSET_LEN_IN_HDR,
|
||||
.len_size = NFCWILINK_LEN_SIZE,
|
||||
.reserve = 0,
|
||||
.recv = nfcwilink_receive,
|
||||
.reg_complete_cb = nfcwilink_register_complete,
|
||||
.write = NULL,
|
||||
};
|
||||
|
||||
static int nfcwilink_open(struct nci_dev *ndev)
|
||||
{
|
||||
struct nfcwilink *drv = nci_get_drvdata(ndev);
|
||||
unsigned long comp_ret;
|
||||
int rc;
|
||||
|
||||
if (test_and_set_bit(NFCWILINK_RUNNING, &drv->flags)) {
|
||||
rc = -EBUSY;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
nfcwilink_proto.priv_data = drv;
|
||||
|
||||
init_completion(&drv->completed);
|
||||
drv->st_register_cb_status = -EINPROGRESS;
|
||||
|
||||
rc = st_register(&nfcwilink_proto);
|
||||
if (rc < 0) {
|
||||
if (rc == -EINPROGRESS) {
|
||||
comp_ret = wait_for_completion_timeout(
|
||||
&drv->completed,
|
||||
msecs_to_jiffies(NFCWILINK_REGISTER_TIMEOUT));
|
||||
|
||||
dev_dbg(&drv->pdev->dev,
|
||||
"wait_for_completion_timeout returned %ld\n",
|
||||
comp_ret);
|
||||
|
||||
if (comp_ret == 0) {
|
||||
/* timeout */
|
||||
rc = -ETIMEDOUT;
|
||||
goto clear_exit;
|
||||
} else if (drv->st_register_cb_status != 0) {
|
||||
rc = drv->st_register_cb_status;
|
||||
nfc_err(&drv->pdev->dev,
|
||||
"st_register_cb failed %d\n", rc);
|
||||
goto clear_exit;
|
||||
}
|
||||
} else {
|
||||
nfc_err(&drv->pdev->dev, "st_register failed %d\n", rc);
|
||||
goto clear_exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* st_register MUST fill the write callback */
|
||||
BUG_ON(nfcwilink_proto.write == NULL);
|
||||
drv->st_write = nfcwilink_proto.write;
|
||||
|
||||
if (nfcwilink_download_fw(drv)) {
|
||||
nfc_err(&drv->pdev->dev, "nfcwilink_download_fw failed %d\n",
|
||||
rc);
|
||||
/* open should succeed, even if the FW download failed */
|
||||
}
|
||||
|
||||
goto exit;
|
||||
|
||||
clear_exit:
|
||||
clear_bit(NFCWILINK_RUNNING, &drv->flags);
|
||||
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int nfcwilink_close(struct nci_dev *ndev)
|
||||
{
|
||||
struct nfcwilink *drv = nci_get_drvdata(ndev);
|
||||
int rc;
|
||||
|
||||
if (!test_and_clear_bit(NFCWILINK_RUNNING, &drv->flags))
|
||||
return 0;
|
||||
|
||||
rc = st_unregister(&nfcwilink_proto);
|
||||
if (rc)
|
||||
nfc_err(&drv->pdev->dev, "st_unregister failed %d\n", rc);
|
||||
|
||||
drv->st_write = NULL;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int nfcwilink_send(struct nci_dev *ndev, struct sk_buff *skb)
|
||||
{
|
||||
struct nfcwilink *drv = nci_get_drvdata(ndev);
|
||||
struct nfcwilink_hdr hdr = {NFCWILINK_CHNL, NFCWILINK_OPCODE, 0x0000};
|
||||
long len;
|
||||
|
||||
dev_dbg(&drv->pdev->dev, "send entry, len %d\n", skb->len);
|
||||
|
||||
if (!test_bit(NFCWILINK_RUNNING, &drv->flags)) {
|
||||
kfree_skb(skb);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* add the ST hdr to the start of the buffer */
|
||||
hdr.len = cpu_to_le16(skb->len);
|
||||
memcpy(skb_push(skb, NFCWILINK_HDR_LEN), &hdr, NFCWILINK_HDR_LEN);
|
||||
|
||||
/* Insert skb to shared transport layer's transmit queue.
|
||||
* Freeing skb memory is taken care in shared transport layer,
|
||||
* so don't free skb memory here.
|
||||
*/
|
||||
len = drv->st_write(skb);
|
||||
if (len < 0) {
|
||||
kfree_skb(skb);
|
||||
nfc_err(&drv->pdev->dev, "st_write failed %ld\n", len);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nci_ops nfcwilink_ops = {
|
||||
.open = nfcwilink_open,
|
||||
.close = nfcwilink_close,
|
||||
.send = nfcwilink_send,
|
||||
};
|
||||
|
||||
static int nfcwilink_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct nfcwilink *drv;
|
||||
int rc;
|
||||
__u32 protocols;
|
||||
|
||||
drv = devm_kzalloc(&pdev->dev, sizeof(struct nfcwilink), GFP_KERNEL);
|
||||
if (!drv) {
|
||||
rc = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
drv->pdev = pdev;
|
||||
|
||||
protocols = NFC_PROTO_JEWEL_MASK
|
||||
| NFC_PROTO_MIFARE_MASK | NFC_PROTO_FELICA_MASK
|
||||
| NFC_PROTO_ISO14443_MASK
|
||||
| NFC_PROTO_ISO14443_B_MASK
|
||||
| NFC_PROTO_NFC_DEP_MASK;
|
||||
|
||||
drv->ndev = nci_allocate_device(&nfcwilink_ops,
|
||||
protocols,
|
||||
NFCWILINK_HDR_LEN,
|
||||
0);
|
||||
if (!drv->ndev) {
|
||||
nfc_err(&pdev->dev, "nci_allocate_device failed\n");
|
||||
rc = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
nci_set_parent_dev(drv->ndev, &pdev->dev);
|
||||
nci_set_drvdata(drv->ndev, drv);
|
||||
|
||||
rc = nci_register_device(drv->ndev);
|
||||
if (rc < 0) {
|
||||
nfc_err(&pdev->dev, "nci_register_device failed %d\n", rc);
|
||||
goto free_dev_exit;
|
||||
}
|
||||
|
||||
dev_set_drvdata(&pdev->dev, drv);
|
||||
|
||||
goto exit;
|
||||
|
||||
free_dev_exit:
|
||||
nci_free_device(drv->ndev);
|
||||
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int nfcwilink_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct nfcwilink *drv = dev_get_drvdata(&pdev->dev);
|
||||
struct nci_dev *ndev;
|
||||
|
||||
if (!drv)
|
||||
return -EFAULT;
|
||||
|
||||
ndev = drv->ndev;
|
||||
|
||||
nci_unregister_device(ndev);
|
||||
nci_free_device(ndev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver nfcwilink_driver = {
|
||||
.probe = nfcwilink_probe,
|
||||
.remove = nfcwilink_remove,
|
||||
.driver = {
|
||||
.name = "nfcwilink",
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(nfcwilink_driver);
|
||||
|
||||
/* ------ Module Info ------ */
|
||||
|
||||
MODULE_AUTHOR("Ilan Elias <ilane@ti.com>");
|
||||
MODULE_DESCRIPTION("NFC Driver for TI Shared Transport");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -24,7 +24,7 @@
|
|||
#include <linux/completion.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/nfc.h>
|
||||
#include <linux/unaligned/access_ok.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "nxp-nci.h"
|
||||
|
||||
|
|
|
@ -29,14 +29,13 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/nfc.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/platform_data/nxp-nci.h>
|
||||
#include <linux/unaligned/access_ok.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <net/nfc/nfc.h>
|
||||
|
||||
|
@ -86,7 +85,7 @@ static int nxp_nci_i2c_write(void *phy_id, struct sk_buff *skb)
|
|||
r = i2c_master_send(client, skb->data, skb->len);
|
||||
if (r < 0) {
|
||||
/* Retry, chip was in standby */
|
||||
usleep_range(110000, 120000);
|
||||
msleep(110);
|
||||
r = i2c_master_send(client, skb->data, skb->len);
|
||||
}
|
||||
|
||||
|
@ -127,7 +126,7 @@ static int nxp_nci_i2c_fw_read(struct nxp_nci_i2c_phy *phy,
|
|||
goto fw_read_exit;
|
||||
}
|
||||
|
||||
frame_len = (get_unaligned_be16(&header) & NXP_NCI_FW_FRAME_LEN_MASK) +
|
||||
frame_len = (be16_to_cpu(header) & NXP_NCI_FW_FRAME_LEN_MASK) +
|
||||
NXP_NCI_FW_CRC_LEN;
|
||||
|
||||
*skb = alloc_skb(NXP_NCI_FW_HDR_LEN + frame_len, GFP_KERNEL);
|
||||
|
|
|
@ -51,7 +51,7 @@ static int pn533_i2c_send_ack(struct pn533 *dev, gfp_t flags)
|
|||
{
|
||||
struct pn533_i2c_phy *phy = dev->phy;
|
||||
struct i2c_client *client = phy->i2c_dev;
|
||||
u8 ack[6] = {0x00, 0x00, 0xff, 0x00, 0xff, 0x00};
|
||||
static const u8 ack[6] = {0x00, 0x00, 0xff, 0x00, 0xff, 0x00};
|
||||
/* spec 6.2.1.3: Preamble, SoPC (2), ACK Code (2), Postamble */
|
||||
int rc;
|
||||
|
||||
|
@ -206,14 +206,6 @@ static int pn533_i2c_probe(struct i2c_client *client,
|
|||
phy->i2c_dev = client;
|
||||
i2c_set_clientdata(client, phy);
|
||||
|
||||
r = request_threaded_irq(client->irq, NULL, pn533_i2c_irq_thread_fn,
|
||||
IRQF_TRIGGER_FALLING |
|
||||
IRQF_SHARED | IRQF_ONESHOT,
|
||||
PN533_I2C_DRIVER_NAME, phy);
|
||||
|
||||
if (r < 0)
|
||||
nfc_err(&client->dev, "Unable to register IRQ handler\n");
|
||||
|
||||
priv = pn533_register_device(PN533_DEVICE_PN532,
|
||||
PN533_NO_TYPE_B_PROTOCOLS,
|
||||
PN533_PROTO_REQ_ACK_RESP,
|
||||
|
@ -223,16 +215,32 @@ static int pn533_i2c_probe(struct i2c_client *client,
|
|||
|
||||
if (IS_ERR(priv)) {
|
||||
r = PTR_ERR(priv);
|
||||
goto err_register;
|
||||
return r;
|
||||
}
|
||||
|
||||
phy->priv = priv;
|
||||
|
||||
r = request_threaded_irq(client->irq, NULL, pn533_i2c_irq_thread_fn,
|
||||
IRQF_TRIGGER_FALLING |
|
||||
IRQF_SHARED | IRQF_ONESHOT,
|
||||
PN533_I2C_DRIVER_NAME, phy);
|
||||
if (r < 0) {
|
||||
nfc_err(&client->dev, "Unable to register IRQ handler\n");
|
||||
goto irq_rqst_err;
|
||||
}
|
||||
|
||||
r = pn533_finalize_setup(priv);
|
||||
if (r)
|
||||
goto fn_setup_err;
|
||||
|
||||
return 0;
|
||||
|
||||
err_register:
|
||||
fn_setup_err:
|
||||
free_irq(client->irq, phy);
|
||||
|
||||
irq_rqst_err:
|
||||
pn533_unregister_device(phy->priv);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -242,10 +250,10 @@ static int pn533_i2c_remove(struct i2c_client *client)
|
|||
|
||||
dev_dbg(&client->dev, "%s\n", __func__);
|
||||
|
||||
pn533_unregister_device(phy->priv);
|
||||
|
||||
free_irq(client->irq, phy);
|
||||
|
||||
pn533_unregister_device(phy->priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -383,14 +383,18 @@ static void pn533_build_cmd_frame(struct pn533 *dev, u8 cmd_code,
|
|||
static int pn533_send_async_complete(struct pn533 *dev)
|
||||
{
|
||||
struct pn533_cmd *cmd = dev->cmd;
|
||||
int status = cmd->status;
|
||||
struct sk_buff *resp;
|
||||
int status, rc = 0;
|
||||
|
||||
struct sk_buff *req = cmd->req;
|
||||
struct sk_buff *resp = cmd->resp;
|
||||
if (!cmd) {
|
||||
dev_dbg(dev->dev, "%s: cmd not set\n", __func__);
|
||||
goto done;
|
||||
}
|
||||
|
||||
int rc;
|
||||
dev_kfree_skb(cmd->req);
|
||||
|
||||
dev_kfree_skb(req);
|
||||
status = cmd->status;
|
||||
resp = cmd->resp;
|
||||
|
||||
if (status < 0) {
|
||||
rc = cmd->complete_cb(dev, cmd->complete_cb_context,
|
||||
|
@ -399,8 +403,14 @@ static int pn533_send_async_complete(struct pn533 *dev)
|
|||
goto done;
|
||||
}
|
||||
|
||||
/* when no response is set we got interrupted */
|
||||
if (!resp)
|
||||
resp = ERR_PTR(-EINTR);
|
||||
|
||||
if (!IS_ERR(resp)) {
|
||||
skb_pull(resp, dev->ops->rx_header_len);
|
||||
skb_trim(resp, resp->len - dev->ops->rx_tail_len);
|
||||
}
|
||||
|
||||
rc = cmd->complete_cb(dev, cmd->complete_cb_context, resp);
|
||||
|
||||
|
@ -434,12 +444,14 @@ static int __pn533_send_async(struct pn533 *dev, u8 cmd_code,
|
|||
mutex_lock(&dev->cmd_lock);
|
||||
|
||||
if (!dev->cmd_pending) {
|
||||
dev->cmd = cmd;
|
||||
rc = dev->phy_ops->send_frame(dev, req);
|
||||
if (rc)
|
||||
if (rc) {
|
||||
dev->cmd = NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
dev->cmd_pending = 1;
|
||||
dev->cmd = cmd;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
|
@ -511,11 +523,12 @@ static int pn533_send_cmd_direct_async(struct pn533 *dev, u8 cmd_code,
|
|||
|
||||
pn533_build_cmd_frame(dev, cmd_code, req);
|
||||
|
||||
rc = dev->phy_ops->send_frame(dev, req);
|
||||
if (rc < 0)
|
||||
kfree(cmd);
|
||||
else
|
||||
dev->cmd = cmd;
|
||||
rc = dev->phy_ops->send_frame(dev, req);
|
||||
if (rc < 0) {
|
||||
dev->cmd = NULL;
|
||||
kfree(cmd);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@ -550,14 +563,15 @@ static void pn533_wq_cmd(struct work_struct *work)
|
|||
|
||||
mutex_unlock(&dev->cmd_lock);
|
||||
|
||||
dev->cmd = cmd;
|
||||
rc = dev->phy_ops->send_frame(dev, cmd->req);
|
||||
if (rc < 0) {
|
||||
dev->cmd = NULL;
|
||||
dev_kfree_skb(cmd->req);
|
||||
kfree(cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
dev->cmd = cmd;
|
||||
}
|
||||
|
||||
struct pn533_sync_cmd_response {
|
||||
|
@ -2556,6 +2570,31 @@ static int pn533_setup(struct pn533 *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int pn533_finalize_setup(struct pn533 *dev)
|
||||
{
|
||||
|
||||
struct pn533_fw_version fw_ver;
|
||||
int rc;
|
||||
|
||||
memset(&fw_ver, 0, sizeof(fw_ver));
|
||||
|
||||
rc = pn533_get_firmware_version(dev, &fw_ver);
|
||||
if (rc) {
|
||||
nfc_err(dev->dev, "Unable to get FW version\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
nfc_info(dev->dev, "NXP PN5%02X firmware ver %d.%d now attached\n",
|
||||
fw_ver.ic, fw_ver.ver, fw_ver.rev);
|
||||
|
||||
rc = pn533_setup(dev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pn533_finalize_setup);
|
||||
|
||||
struct pn533 *pn533_register_device(u32 device_type,
|
||||
u32 protocols,
|
||||
enum pn533_protocol_type protocol_type,
|
||||
|
@ -2565,7 +2604,6 @@ struct pn533 *pn533_register_device(u32 device_type,
|
|||
struct device *dev,
|
||||
struct device *parent)
|
||||
{
|
||||
struct pn533_fw_version fw_ver;
|
||||
struct pn533 *priv;
|
||||
int rc = -ENOMEM;
|
||||
|
||||
|
@ -2608,15 +2646,6 @@ struct pn533 *pn533_register_device(u32 device_type,
|
|||
|
||||
INIT_LIST_HEAD(&priv->cmd_queue);
|
||||
|
||||
memset(&fw_ver, 0, sizeof(fw_ver));
|
||||
rc = pn533_get_firmware_version(priv, &fw_ver);
|
||||
if (rc < 0)
|
||||
goto destroy_wq;
|
||||
|
||||
nfc_info(dev, "NXP PN5%02X firmware ver %d.%d now attached\n",
|
||||
fw_ver.ic, fw_ver.ver, fw_ver.rev);
|
||||
|
||||
|
||||
priv->nfc_dev = nfc_allocate_device(&pn533_nfc_ops, protocols,
|
||||
priv->ops->tx_header_len +
|
||||
PN533_CMD_DATAEXCH_HEAD_LEN,
|
||||
|
@ -2633,15 +2662,8 @@ struct pn533 *pn533_register_device(u32 device_type,
|
|||
if (rc)
|
||||
goto free_nfc_dev;
|
||||
|
||||
rc = pn533_setup(priv);
|
||||
if (rc)
|
||||
goto unregister_nfc_dev;
|
||||
|
||||
return priv;
|
||||
|
||||
unregister_nfc_dev:
|
||||
nfc_unregister_device(priv->nfc_dev);
|
||||
|
||||
free_nfc_dev:
|
||||
nfc_free_device(priv->nfc_dev);
|
||||
|
||||
|
|
|
@ -231,6 +231,7 @@ struct pn533 *pn533_register_device(u32 device_type,
|
|||
struct device *dev,
|
||||
struct device *parent);
|
||||
|
||||
int pn533_finalize_setup(struct pn533 *dev);
|
||||
void pn533_unregister_device(struct pn533 *priv);
|
||||
void pn533_recv_frame(struct pn533 *dev, struct sk_buff *skb, int status);
|
||||
|
||||
|
|
|
@ -148,11 +148,11 @@ static int pn533_submit_urb_for_ack(struct pn533_usb_phy *phy, gfp_t flags)
|
|||
static int pn533_usb_send_ack(struct pn533 *dev, gfp_t flags)
|
||||
{
|
||||
struct pn533_usb_phy *phy = dev->phy;
|
||||
u8 ack[6] = {0x00, 0x00, 0xff, 0x00, 0xff, 0x00};
|
||||
static const u8 ack[6] = {0x00, 0x00, 0xff, 0x00, 0xff, 0x00};
|
||||
/* spec 7.1.1.3: Preamble, SoPC (2), ACK Code (2), Postamble */
|
||||
int rc;
|
||||
|
||||
phy->out_urb->transfer_buffer = ack;
|
||||
phy->out_urb->transfer_buffer = (u8 *)ack;
|
||||
phy->out_urb->transfer_buffer_length = sizeof(ack);
|
||||
rc = usb_submit_urb(phy->out_urb, flags);
|
||||
|
||||
|
@ -543,6 +543,10 @@ static int pn533_usb_probe(struct usb_interface *interface,
|
|||
|
||||
phy->priv = priv;
|
||||
|
||||
rc = pn533_finalize_setup(priv);
|
||||
if (rc)
|
||||
goto error;
|
||||
|
||||
usb_set_intfdata(interface, phy);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -21,17 +21,13 @@
|
|||
#include <linux/crc-ccitt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/nfc.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/platform_data/pn544.h>
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <net/nfc/hci.h>
|
||||
|
@ -165,8 +161,9 @@ struct pn544_i2c_phy {
|
|||
struct i2c_client *i2c_dev;
|
||||
struct nfc_hci_dev *hdev;
|
||||
|
||||
unsigned int gpio_en;
|
||||
unsigned int gpio_fw;
|
||||
struct gpio_desc *gpiod_en;
|
||||
struct gpio_desc *gpiod_fw;
|
||||
|
||||
unsigned int en_polarity;
|
||||
|
||||
u8 hw_variant;
|
||||
|
@ -208,19 +205,18 @@ static void pn544_hci_i2c_platform_init(struct pn544_i2c_phy *phy)
|
|||
nfc_info(&phy->i2c_dev->dev, "Detecting nfc_en polarity\n");
|
||||
|
||||
/* Disable fw download */
|
||||
gpio_set_value_cansleep(phy->gpio_fw, 0);
|
||||
gpiod_set_value_cansleep(phy->gpiod_fw, 0);
|
||||
|
||||
for (polarity = 0; polarity < 2; polarity++) {
|
||||
phy->en_polarity = polarity;
|
||||
retry = 3;
|
||||
while (retry--) {
|
||||
/* power off */
|
||||
gpio_set_value_cansleep(phy->gpio_en,
|
||||
!phy->en_polarity);
|
||||
gpiod_set_value_cansleep(phy->gpiod_en, !phy->en_polarity);
|
||||
usleep_range(10000, 15000);
|
||||
|
||||
/* power on */
|
||||
gpio_set_value_cansleep(phy->gpio_en, phy->en_polarity);
|
||||
gpiod_set_value_cansleep(phy->gpiod_en, phy->en_polarity);
|
||||
usleep_range(10000, 15000);
|
||||
|
||||
/* send reset */
|
||||
|
@ -239,14 +235,13 @@ static void pn544_hci_i2c_platform_init(struct pn544_i2c_phy *phy)
|
|||
"Could not detect nfc_en polarity, fallback to active high\n");
|
||||
|
||||
out:
|
||||
gpio_set_value_cansleep(phy->gpio_en, !phy->en_polarity);
|
||||
gpiod_set_value_cansleep(phy->gpiod_en, !phy->en_polarity);
|
||||
}
|
||||
|
||||
static void pn544_hci_i2c_enable_mode(struct pn544_i2c_phy *phy, int run_mode)
|
||||
{
|
||||
gpio_set_value_cansleep(phy->gpio_fw,
|
||||
run_mode == PN544_FW_MODE ? 1 : 0);
|
||||
gpio_set_value_cansleep(phy->gpio_en, phy->en_polarity);
|
||||
gpiod_set_value_cansleep(phy->gpiod_fw, run_mode == PN544_FW_MODE ? 1 : 0);
|
||||
gpiod_set_value_cansleep(phy->gpiod_en, phy->en_polarity);
|
||||
usleep_range(10000, 15000);
|
||||
|
||||
phy->run_mode = run_mode;
|
||||
|
@ -269,14 +264,14 @@ static void pn544_hci_i2c_disable(void *phy_id)
|
|||
{
|
||||
struct pn544_i2c_phy *phy = phy_id;
|
||||
|
||||
gpio_set_value_cansleep(phy->gpio_fw, 0);
|
||||
gpio_set_value_cansleep(phy->gpio_en, !phy->en_polarity);
|
||||
gpiod_set_value_cansleep(phy->gpiod_fw, 0);
|
||||
gpiod_set_value_cansleep(phy->gpiod_en, !phy->en_polarity);
|
||||
usleep_range(10000, 15000);
|
||||
|
||||
gpio_set_value_cansleep(phy->gpio_en, phy->en_polarity);
|
||||
gpiod_set_value_cansleep(phy->gpiod_en, phy->en_polarity);
|
||||
usleep_range(10000, 15000);
|
||||
|
||||
gpio_set_value_cansleep(phy->gpio_en, !phy->en_polarity);
|
||||
gpiod_set_value_cansleep(phy->gpiod_en, !phy->en_polarity);
|
||||
usleep_range(10000, 15000);
|
||||
|
||||
phy->powered = 0;
|
||||
|
@ -874,106 +869,20 @@ exit_state_wait_secure_write_answer:
|
|||
}
|
||||
}
|
||||
|
||||
static int pn544_hci_i2c_acpi_request_resources(struct i2c_client *client)
|
||||
{
|
||||
struct pn544_i2c_phy *phy = i2c_get_clientdata(client);
|
||||
struct gpio_desc *gpiod_en, *gpiod_fw;
|
||||
struct device *dev = &client->dev;
|
||||
static const struct acpi_gpio_params enable_gpios = { 1, 0, false };
|
||||
static const struct acpi_gpio_params firmware_gpios = { 2, 0, false };
|
||||
|
||||
/* Get EN GPIO from ACPI */
|
||||
gpiod_en = devm_gpiod_get_index(dev, PN544_GPIO_NAME_EN, 1,
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(gpiod_en)) {
|
||||
nfc_err(dev, "Unable to get EN GPIO\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
phy->gpio_en = desc_to_gpio(gpiod_en);
|
||||
|
||||
/* Get FW GPIO from ACPI */
|
||||
gpiod_fw = devm_gpiod_get_index(dev, PN544_GPIO_NAME_FW, 2,
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(gpiod_fw)) {
|
||||
nfc_err(dev, "Unable to get FW GPIO\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
phy->gpio_fw = desc_to_gpio(gpiod_fw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pn544_hci_i2c_of_request_resources(struct i2c_client *client)
|
||||
{
|
||||
struct pn544_i2c_phy *phy = i2c_get_clientdata(client);
|
||||
struct device_node *pp;
|
||||
int ret;
|
||||
|
||||
pp = client->dev.of_node;
|
||||
if (!pp) {
|
||||
ret = -ENODEV;
|
||||
goto err_dt;
|
||||
}
|
||||
|
||||
/* Obtention of EN GPIO from device tree */
|
||||
ret = of_get_named_gpio(pp, "enable-gpios", 0);
|
||||
if (ret < 0) {
|
||||
if (ret != -EPROBE_DEFER)
|
||||
nfc_err(&client->dev,
|
||||
"Failed to get EN gpio, error: %d\n", ret);
|
||||
goto err_dt;
|
||||
}
|
||||
phy->gpio_en = ret;
|
||||
|
||||
/* Configuration of EN GPIO */
|
||||
ret = gpio_request(phy->gpio_en, PN544_GPIO_NAME_EN);
|
||||
if (ret) {
|
||||
nfc_err(&client->dev, "Fail EN pin\n");
|
||||
goto err_dt;
|
||||
}
|
||||
ret = gpio_direction_output(phy->gpio_en, 0);
|
||||
if (ret) {
|
||||
nfc_err(&client->dev, "Fail EN pin direction\n");
|
||||
goto err_gpio_en;
|
||||
}
|
||||
|
||||
/* Obtention of FW GPIO from device tree */
|
||||
ret = of_get_named_gpio(pp, "firmware-gpios", 0);
|
||||
if (ret < 0) {
|
||||
if (ret != -EPROBE_DEFER)
|
||||
nfc_err(&client->dev,
|
||||
"Failed to get FW gpio, error: %d\n", ret);
|
||||
goto err_gpio_en;
|
||||
}
|
||||
phy->gpio_fw = ret;
|
||||
|
||||
/* Configuration of FW GPIO */
|
||||
ret = gpio_request(phy->gpio_fw, PN544_GPIO_NAME_FW);
|
||||
if (ret) {
|
||||
nfc_err(&client->dev, "Fail FW pin\n");
|
||||
goto err_gpio_en;
|
||||
}
|
||||
ret = gpio_direction_output(phy->gpio_fw, 0);
|
||||
if (ret) {
|
||||
nfc_err(&client->dev, "Fail FW pin direction\n");
|
||||
goto err_gpio_fw;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_gpio_fw:
|
||||
gpio_free(phy->gpio_fw);
|
||||
err_gpio_en:
|
||||
gpio_free(phy->gpio_en);
|
||||
err_dt:
|
||||
return ret;
|
||||
}
|
||||
static const struct acpi_gpio_mapping acpi_pn544_gpios[] = {
|
||||
{ "enable-gpios", &enable_gpios, 1 },
|
||||
{ "firmware-gpios", &firmware_gpios, 1 },
|
||||
{ },
|
||||
};
|
||||
|
||||
static int pn544_hci_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct pn544_i2c_phy *phy;
|
||||
struct pn544_nfc_platform_data *pdata;
|
||||
int r = 0;
|
||||
|
||||
dev_dbg(&client->dev, "%s\n", __func__);
|
||||
|
@ -995,53 +904,33 @@ static int pn544_hci_i2c_probe(struct i2c_client *client,
|
|||
phy->i2c_dev = client;
|
||||
i2c_set_clientdata(client, phy);
|
||||
|
||||
pdata = client->dev.platform_data;
|
||||
r = acpi_dev_add_driver_gpios(ACPI_COMPANION(dev), acpi_pn544_gpios);
|
||||
if (r)
|
||||
dev_dbg(dev, "Unable to add GPIO mapping table\n");
|
||||
|
||||
/* No platform data, using device tree. */
|
||||
if (!pdata && client->dev.of_node) {
|
||||
r = pn544_hci_i2c_of_request_resources(client);
|
||||
if (r) {
|
||||
nfc_err(&client->dev, "No DT data\n");
|
||||
return r;
|
||||
}
|
||||
/* Using platform data. */
|
||||
} else if (pdata) {
|
||||
|
||||
if (pdata->request_resources == NULL) {
|
||||
nfc_err(&client->dev, "request_resources() missing\n");
|
||||
return -EINVAL;
|
||||
/* Get EN GPIO */
|
||||
phy->gpiod_en = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(phy->gpiod_en)) {
|
||||
nfc_err(dev, "Unable to get EN GPIO\n");
|
||||
return PTR_ERR(phy->gpiod_en);
|
||||
}
|
||||
|
||||
r = pdata->request_resources(client);
|
||||
if (r) {
|
||||
nfc_err(&client->dev,
|
||||
"Cannot get platform resources\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
phy->gpio_en = pdata->get_gpio(NFC_GPIO_ENABLE);
|
||||
phy->gpio_fw = pdata->get_gpio(NFC_GPIO_FW_RESET);
|
||||
/* Using ACPI */
|
||||
} else if (ACPI_HANDLE(&client->dev)) {
|
||||
r = pn544_hci_i2c_acpi_request_resources(client);
|
||||
if (r) {
|
||||
nfc_err(&client->dev,
|
||||
"Cannot get ACPI data\n");
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
nfc_err(&client->dev, "No platform data\n");
|
||||
return -EINVAL;
|
||||
/* Get FW GPIO */
|
||||
phy->gpiod_fw = devm_gpiod_get(dev, "firmware", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(phy->gpiod_fw)) {
|
||||
nfc_err(dev, "Unable to get FW GPIO\n");
|
||||
return PTR_ERR(phy->gpiod_fw);
|
||||
}
|
||||
|
||||
pn544_hci_i2c_platform_init(phy);
|
||||
|
||||
r = request_threaded_irq(client->irq, NULL, pn544_hci_i2c_irq_thread_fn,
|
||||
r = devm_request_threaded_irq(&client->dev, client->irq, NULL,
|
||||
pn544_hci_i2c_irq_thread_fn,
|
||||
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
||||
PN544_HCI_I2C_DRIVER_NAME, phy);
|
||||
if (r < 0) {
|
||||
nfc_err(&client->dev, "Unable to register IRQ handler\n");
|
||||
goto err_rti;
|
||||
return r;
|
||||
}
|
||||
|
||||
r = pn544_hci_probe(phy, &i2c_phy_ops, LLC_SHDLC_NAME,
|
||||
|
@ -1049,28 +938,14 @@ static int pn544_hci_i2c_probe(struct i2c_client *client,
|
|||
PN544_HCI_I2C_LLC_MAX_PAYLOAD,
|
||||
pn544_hci_i2c_fw_download, &phy->hdev);
|
||||
if (r < 0)
|
||||
goto err_hci;
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
|
||||
err_hci:
|
||||
free_irq(client->irq, phy);
|
||||
|
||||
err_rti:
|
||||
if (!pdata) {
|
||||
gpio_free(phy->gpio_en);
|
||||
gpio_free(phy->gpio_fw);
|
||||
} else if (pdata->free_resources) {
|
||||
pdata->free_resources();
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int pn544_hci_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct pn544_i2c_phy *phy = i2c_get_clientdata(client);
|
||||
struct pn544_nfc_platform_data *pdata = client->dev.platform_data;
|
||||
|
||||
dev_dbg(&client->dev, "%s\n", __func__);
|
||||
|
||||
|
@ -1083,17 +958,7 @@ static int pn544_hci_i2c_remove(struct i2c_client *client)
|
|||
if (phy->powered)
|
||||
pn544_hci_i2c_disable(phy);
|
||||
|
||||
free_irq(client->irq, phy);
|
||||
|
||||
/* No platform data, GPIOs have been requested by this driver */
|
||||
if (!pdata) {
|
||||
gpio_free(phy->gpio_en);
|
||||
gpio_free(phy->gpio_fw);
|
||||
/* Using platform data */
|
||||
} else if (pdata->free_resources) {
|
||||
pdata->free_resources();
|
||||
}
|
||||
|
||||
acpi_dev_remove_driver_gpios(ACPI_COMPANION(&client->dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,8 @@
|
|||
#define VERSION "0.1"
|
||||
|
||||
#define SONY_VENDOR_ID 0x054c
|
||||
#define RCS380_PRODUCT_ID 0x06c1
|
||||
#define RCS380S_PRODUCT_ID 0x06c1
|
||||
#define RCS380P_PRODUCT_ID 0x06c3
|
||||
|
||||
#define PORT100_PROTOCOLS (NFC_PROTO_JEWEL_MASK | \
|
||||
NFC_PROTO_MIFARE_MASK | \
|
||||
|
@ -725,11 +726,19 @@ static int port100_submit_urb_for_ack(struct port100 *dev, gfp_t flags)
|
|||
|
||||
static int port100_send_ack(struct port100 *dev)
|
||||
{
|
||||
int rc;
|
||||
int rc = 0;
|
||||
|
||||
mutex_lock(&dev->out_urb_lock);
|
||||
|
||||
init_completion(&dev->cmd_cancel_done);
|
||||
/*
|
||||
* If prior cancel is in-flight (dev->cmd_cancel == true), we
|
||||
* can skip to send cancel. Then this will wait the prior
|
||||
* cancel, or merged into the next cancel rarely if next
|
||||
* cancel was started before waiting done. In any case, this
|
||||
* will be waked up soon or later.
|
||||
*/
|
||||
if (!dev->cmd_cancel) {
|
||||
reinit_completion(&dev->cmd_cancel_done);
|
||||
|
||||
usb_kill_urb(dev->out_urb);
|
||||
|
||||
|
@ -737,11 +746,13 @@ static int port100_send_ack(struct port100 *dev)
|
|||
dev->out_urb->transfer_buffer_length = sizeof(ack_frame);
|
||||
rc = usb_submit_urb(dev->out_urb, GFP_KERNEL);
|
||||
|
||||
/* Set the cmd_cancel flag only if the URB has been successfully
|
||||
* submitted. It will be reset by the out URB completion callback
|
||||
* port100_send_complete().
|
||||
/*
|
||||
* Set the cmd_cancel flag only if the URB has been
|
||||
* successfully submitted. It will be reset by the out
|
||||
* URB completion callback port100_send_complete().
|
||||
*/
|
||||
dev->cmd_cancel = !rc;
|
||||
}
|
||||
|
||||
mutex_unlock(&dev->out_urb_lock);
|
||||
|
||||
|
@ -928,8 +939,8 @@ static void port100_send_complete(struct urb *urb)
|
|||
struct port100 *dev = urb->context;
|
||||
|
||||
if (dev->cmd_cancel) {
|
||||
complete_all(&dev->cmd_cancel_done);
|
||||
dev->cmd_cancel = false;
|
||||
complete(&dev->cmd_cancel_done);
|
||||
}
|
||||
|
||||
switch (urb->status) {
|
||||
|
@ -1477,7 +1488,8 @@ static struct nfc_digital_ops port100_digital_ops = {
|
|||
};
|
||||
|
||||
static const struct usb_device_id port100_table[] = {
|
||||
{ USB_DEVICE(SONY_VENDOR_ID, RCS380_PRODUCT_ID), },
|
||||
{ USB_DEVICE(SONY_VENDOR_ID, RCS380S_PRODUCT_ID), },
|
||||
{ USB_DEVICE(SONY_VENDOR_ID, RCS380P_PRODUCT_ID), },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, port100_table);
|
||||
|
@ -1538,11 +1550,13 @@ static int port100_probe(struct usb_interface *interface,
|
|||
usb_fill_bulk_urb(dev->out_urb, dev->udev,
|
||||
usb_sndbulkpipe(dev->udev, out_endpoint),
|
||||
NULL, 0, port100_send_complete, dev);
|
||||
dev->out_urb->transfer_flags = URB_ZERO_PACKET;
|
||||
|
||||
dev->skb_headroom = PORT100_FRAME_HEADER_LEN +
|
||||
PORT100_COMM_RF_HEAD_MAX_LEN;
|
||||
dev->skb_tailroom = PORT100_FRAME_TAIL_LEN;
|
||||
|
||||
init_completion(&dev->cmd_cancel_done);
|
||||
INIT_WORK(&dev->cmd_complete_work, port100_wq_cmd_complete);
|
||||
|
||||
/* The first thing to do with the Port-100 is to set the command type
|
||||
|
|
|
@ -959,10 +959,8 @@ int st21nfca_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops,
|
|||
unsigned long quirks = 0;
|
||||
|
||||
info = kzalloc(sizeof(struct st21nfca_hci_info), GFP_KERNEL);
|
||||
if (!info) {
|
||||
r = -ENOMEM;
|
||||
goto err_alloc_hdev;
|
||||
}
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
info->phy_ops = phy_ops;
|
||||
info->phy_id = phy_id;
|
||||
|
@ -978,8 +976,10 @@ int st21nfca_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops,
|
|||
* persistent info to discriminate 2 identical chips
|
||||
*/
|
||||
dev_num = find_first_zero_bit(dev_mask, ST21NFCA_NUM_DEVICES);
|
||||
if (dev_num >= ST21NFCA_NUM_DEVICES)
|
||||
return -ENODEV;
|
||||
if (dev_num >= ST21NFCA_NUM_DEVICES) {
|
||||
r = -ENODEV;
|
||||
goto err_alloc_hdev;
|
||||
}
|
||||
|
||||
set_bit(dev_num, dev_mask);
|
||||
|
||||
|
|
|
@ -20,17 +20,15 @@
|
|||
#include <linux/crc-ccitt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/nfc.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/platform_data/st21nfca.h>
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <net/nfc/hci.h>
|
||||
|
@ -60,6 +58,7 @@
|
|||
#define IS_START_OF_FRAME(buf) (buf[0] == ST21NFCA_SOF_EOF && \
|
||||
buf[1] == 0)
|
||||
|
||||
#define ST21NFCA_HCI_DRIVER_NAME "st21nfca_hci"
|
||||
#define ST21NFCA_HCI_I2C_DRIVER_NAME "st21nfca_hci_i2c"
|
||||
|
||||
#define ST21NFCA_GPIO_NAME_EN "enable"
|
||||
|
@ -68,9 +67,7 @@ struct st21nfca_i2c_phy {
|
|||
struct i2c_client *i2c_dev;
|
||||
struct nfc_hci_dev *hdev;
|
||||
|
||||
unsigned int gpio_ena;
|
||||
unsigned int irq_polarity;
|
||||
|
||||
struct gpio_desc *gpiod_ena;
|
||||
struct st21nfca_se_status se_status;
|
||||
|
||||
struct sk_buff *pending_skb;
|
||||
|
@ -151,7 +148,7 @@ static int st21nfca_hci_i2c_enable(void *phy_id)
|
|||
{
|
||||
struct st21nfca_i2c_phy *phy = phy_id;
|
||||
|
||||
gpio_set_value(phy->gpio_ena, 1);
|
||||
gpiod_set_value(phy->gpiod_ena, 1);
|
||||
phy->powered = 1;
|
||||
phy->run_mode = ST21NFCA_HCI_MODE;
|
||||
|
||||
|
@ -164,7 +161,7 @@ static void st21nfca_hci_i2c_disable(void *phy_id)
|
|||
{
|
||||
struct st21nfca_i2c_phy *phy = phy_id;
|
||||
|
||||
gpio_set_value(phy->gpio_ena, 0);
|
||||
gpiod_set_value(phy->gpiod_ena, 0);
|
||||
|
||||
phy->powered = 0;
|
||||
}
|
||||
|
@ -507,33 +504,14 @@ static struct nfc_phy_ops i2c_phy_ops = {
|
|||
static int st21nfca_hci_i2c_acpi_request_resources(struct i2c_client *client)
|
||||
{
|
||||
struct st21nfca_i2c_phy *phy = i2c_get_clientdata(client);
|
||||
struct gpio_desc *gpiod_ena;
|
||||
struct device *dev = &client->dev;
|
||||
u8 tmp;
|
||||
|
||||
/* Get EN GPIO from ACPI */
|
||||
gpiod_ena = devm_gpiod_get_index(dev, ST21NFCA_GPIO_NAME_EN, 1,
|
||||
phy->gpiod_ena = devm_gpiod_get_index(dev, ST21NFCA_GPIO_NAME_EN, 1,
|
||||
GPIOD_OUT_LOW);
|
||||
if (!IS_ERR(gpiod_ena)) {
|
||||
if (IS_ERR(phy->gpiod_ena)) {
|
||||
nfc_err(dev, "Unable to get ENABLE GPIO\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
phy->gpio_ena = desc_to_gpio(gpiod_ena);
|
||||
|
||||
phy->irq_polarity = irq_get_trigger_type(client->irq);
|
||||
|
||||
phy->se_status.is_ese_present = false;
|
||||
phy->se_status.is_uicc_present = false;
|
||||
|
||||
if (device_property_present(dev, "ese-present")) {
|
||||
device_property_read_u8(dev, "ese-present", &tmp);
|
||||
phy->se_status.is_ese_present = tmp;
|
||||
}
|
||||
|
||||
if (device_property_present(dev, "uicc-present")) {
|
||||
device_property_read_u8(dev, "uicc-present", &tmp);
|
||||
phy->se_status.is_uicc_present = tmp;
|
||||
return PTR_ERR(phy->gpiod_ena);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -542,70 +520,16 @@ static int st21nfca_hci_i2c_acpi_request_resources(struct i2c_client *client)
|
|||
static int st21nfca_hci_i2c_of_request_resources(struct i2c_client *client)
|
||||
{
|
||||
struct st21nfca_i2c_phy *phy = i2c_get_clientdata(client);
|
||||
struct device_node *pp;
|
||||
int gpio;
|
||||
int r;
|
||||
|
||||
pp = client->dev.of_node;
|
||||
if (!pp)
|
||||
return -ENODEV;
|
||||
struct device *dev = &client->dev;
|
||||
|
||||
/* Get GPIO from device tree */
|
||||
gpio = of_get_named_gpio(pp, "enable-gpios", 0);
|
||||
if (gpio < 0) {
|
||||
nfc_err(&client->dev, "Failed to retrieve enable-gpios from device tree\n");
|
||||
return gpio;
|
||||
phy->gpiod_ena = devm_gpiod_get_index(dev, ST21NFCA_GPIO_NAME_EN, 0,
|
||||
GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(phy->gpiod_ena)) {
|
||||
nfc_err(dev, "Failed to request enable pin\n");
|
||||
return PTR_ERR(phy->gpiod_ena);
|
||||
}
|
||||
|
||||
/* GPIO request and configuration */
|
||||
r = devm_gpio_request_one(&client->dev, gpio, GPIOF_OUT_INIT_HIGH,
|
||||
ST21NFCA_GPIO_NAME_EN);
|
||||
if (r) {
|
||||
nfc_err(&client->dev, "Failed to request enable pin\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
phy->gpio_ena = gpio;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int st21nfca_hci_i2c_request_resources(struct i2c_client *client)
|
||||
{
|
||||
struct st21nfca_nfc_platform_data *pdata;
|
||||
struct st21nfca_i2c_phy *phy = i2c_get_clientdata(client);
|
||||
int r;
|
||||
|
||||
pdata = client->dev.platform_data;
|
||||
if (pdata == NULL) {
|
||||
nfc_err(&client->dev, "No platform data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* store for later use */
|
||||
phy->gpio_ena = pdata->gpio_ena;
|
||||
phy->irq_polarity = pdata->irq_polarity;
|
||||
|
||||
if (phy->gpio_ena > 0) {
|
||||
r = devm_gpio_request_one(&client->dev, phy->gpio_ena,
|
||||
GPIOF_OUT_INIT_HIGH,
|
||||
ST21NFCA_GPIO_NAME_EN);
|
||||
if (r) {
|
||||
pr_err("%s : ena gpio_request failed\n", __FILE__);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
phy->se_status.is_ese_present = pdata->is_ese_present;
|
||||
phy->se_status.is_uicc_present = pdata->is_uicc_present;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -613,7 +537,6 @@ static int st21nfca_hci_i2c_probe(struct i2c_client *client,
|
|||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct st21nfca_i2c_phy *phy;
|
||||
struct st21nfca_nfc_platform_data *pdata;
|
||||
int r;
|
||||
|
||||
dev_dbg(&client->dev, "%s\n", __func__);
|
||||
|
@ -639,19 +562,12 @@ static int st21nfca_hci_i2c_probe(struct i2c_client *client,
|
|||
mutex_init(&phy->phy_lock);
|
||||
i2c_set_clientdata(client, phy);
|
||||
|
||||
pdata = client->dev.platform_data;
|
||||
if (!pdata && client->dev.of_node) {
|
||||
if (client->dev.of_node) {
|
||||
r = st21nfca_hci_i2c_of_request_resources(client);
|
||||
if (r) {
|
||||
nfc_err(&client->dev, "No platform data\n");
|
||||
return r;
|
||||
}
|
||||
} else if (pdata) {
|
||||
r = st21nfca_hci_i2c_request_resources(client);
|
||||
if (r) {
|
||||
nfc_err(&client->dev, "Cannot get platform resources\n");
|
||||
return r;
|
||||
}
|
||||
} else if (ACPI_HANDLE(&client->dev)) {
|
||||
r = st21nfca_hci_i2c_acpi_request_resources(client);
|
||||
if (r) {
|
||||
|
@ -663,6 +579,11 @@ static int st21nfca_hci_i2c_probe(struct i2c_client *client,
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
phy->se_status.is_ese_present =
|
||||
device_property_read_bool(&client->dev, "ese-present");
|
||||
phy->se_status.is_uicc_present =
|
||||
device_property_read_bool(&client->dev, "uicc-present");
|
||||
|
||||
r = st21nfca_hci_platform_init(phy);
|
||||
if (r < 0) {
|
||||
nfc_err(&client->dev, "Unable to reboot st21nfca\n");
|
||||
|
@ -671,7 +592,7 @@ static int st21nfca_hci_i2c_probe(struct i2c_client *client,
|
|||
|
||||
r = devm_request_threaded_irq(&client->dev, client->irq, NULL,
|
||||
st21nfca_hci_irq_thread_fn,
|
||||
phy->irq_polarity | IRQF_ONESHOT,
|
||||
IRQF_ONESHOT,
|
||||
ST21NFCA_HCI_DRIVER_NAME, phy);
|
||||
if (r < 0) {
|
||||
nfc_err(&client->dev, "Unable to register IRQ handler\n");
|
||||
|
|
|
@ -124,6 +124,9 @@
|
|||
NFC_PROTO_ISO15693_MASK | NFC_PROTO_NFC_DEP_MASK)
|
||||
|
||||
#define TRF7970A_AUTOSUSPEND_DELAY 30000 /* 30 seconds */
|
||||
#define TRF7970A_13MHZ_CLOCK_FREQUENCY 13560000
|
||||
#define TRF7970A_27MHZ_CLOCK_FREQUENCY 27120000
|
||||
|
||||
|
||||
#define TRF7970A_RX_SKB_ALLOC_SIZE 256
|
||||
|
||||
|
@ -441,6 +444,7 @@ struct trf7970a {
|
|||
u8 iso_ctrl_tech;
|
||||
u8 modulator_sys_clk_ctrl;
|
||||
u8 special_fcn_reg1;
|
||||
u8 io_ctrl;
|
||||
unsigned int guard_time;
|
||||
int technology;
|
||||
int framing;
|
||||
|
@ -1048,6 +1052,11 @@ static int trf7970a_init(struct trf7970a *trf)
|
|||
if (ret)
|
||||
goto err_out;
|
||||
|
||||
ret = trf7970a_write(trf, TRF7970A_REG_IO_CTRL,
|
||||
trf->io_ctrl | TRF7970A_REG_IO_CTRL_VRS(0x1));
|
||||
if (ret)
|
||||
goto err_out;
|
||||
|
||||
ret = trf7970a_write(trf, TRF7970A_NFC_TARGET_LEVEL, 0);
|
||||
if (ret)
|
||||
goto err_out;
|
||||
|
@ -1056,12 +1065,11 @@ static int trf7970a_init(struct trf7970a *trf)
|
|||
|
||||
trf->chip_status_ctrl &= ~TRF7970A_CHIP_STATUS_RF_ON;
|
||||
|
||||
ret = trf7970a_write(trf, TRF7970A_MODULATOR_SYS_CLK_CTRL, 0);
|
||||
ret = trf7970a_write(trf, TRF7970A_MODULATOR_SYS_CLK_CTRL,
|
||||
trf->modulator_sys_clk_ctrl);
|
||||
if (ret)
|
||||
goto err_out;
|
||||
|
||||
trf->modulator_sys_clk_ctrl = 0;
|
||||
|
||||
ret = trf7970a_write(trf, TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS,
|
||||
TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLH_96 |
|
||||
TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_32);
|
||||
|
@ -1181,27 +1189,37 @@ static int trf7970a_in_config_rf_tech(struct trf7970a *trf, int tech)
|
|||
switch (tech) {
|
||||
case NFC_DIGITAL_RF_TECH_106A:
|
||||
trf->iso_ctrl_tech = TRF7970A_ISO_CTRL_14443A_106;
|
||||
trf->modulator_sys_clk_ctrl = TRF7970A_MODULATOR_DEPTH_OOK;
|
||||
trf->modulator_sys_clk_ctrl =
|
||||
(trf->modulator_sys_clk_ctrl & 0xf8) |
|
||||
TRF7970A_MODULATOR_DEPTH_OOK;
|
||||
trf->guard_time = TRF7970A_GUARD_TIME_NFCA;
|
||||
break;
|
||||
case NFC_DIGITAL_RF_TECH_106B:
|
||||
trf->iso_ctrl_tech = TRF7970A_ISO_CTRL_14443B_106;
|
||||
trf->modulator_sys_clk_ctrl = TRF7970A_MODULATOR_DEPTH_ASK10;
|
||||
trf->modulator_sys_clk_ctrl =
|
||||
(trf->modulator_sys_clk_ctrl & 0xf8) |
|
||||
TRF7970A_MODULATOR_DEPTH_ASK10;
|
||||
trf->guard_time = TRF7970A_GUARD_TIME_NFCB;
|
||||
break;
|
||||
case NFC_DIGITAL_RF_TECH_212F:
|
||||
trf->iso_ctrl_tech = TRF7970A_ISO_CTRL_FELICA_212;
|
||||
trf->modulator_sys_clk_ctrl = TRF7970A_MODULATOR_DEPTH_ASK10;
|
||||
trf->modulator_sys_clk_ctrl =
|
||||
(trf->modulator_sys_clk_ctrl & 0xf8) |
|
||||
TRF7970A_MODULATOR_DEPTH_ASK10;
|
||||
trf->guard_time = TRF7970A_GUARD_TIME_NFCF;
|
||||
break;
|
||||
case NFC_DIGITAL_RF_TECH_424F:
|
||||
trf->iso_ctrl_tech = TRF7970A_ISO_CTRL_FELICA_424;
|
||||
trf->modulator_sys_clk_ctrl = TRF7970A_MODULATOR_DEPTH_ASK10;
|
||||
trf->modulator_sys_clk_ctrl =
|
||||
(trf->modulator_sys_clk_ctrl & 0xf8) |
|
||||
TRF7970A_MODULATOR_DEPTH_ASK10;
|
||||
trf->guard_time = TRF7970A_GUARD_TIME_NFCF;
|
||||
break;
|
||||
case NFC_DIGITAL_RF_TECH_ISO15693:
|
||||
trf->iso_ctrl_tech = TRF7970A_ISO_CTRL_15693_SGL_1OF4_2648;
|
||||
trf->modulator_sys_clk_ctrl = TRF7970A_MODULATOR_DEPTH_OOK;
|
||||
trf->modulator_sys_clk_ctrl =
|
||||
(trf->modulator_sys_clk_ctrl & 0xf8) |
|
||||
TRF7970A_MODULATOR_DEPTH_OOK;
|
||||
trf->guard_time = TRF7970A_GUARD_TIME_15693;
|
||||
break;
|
||||
default:
|
||||
|
@ -1571,17 +1589,23 @@ static int trf7970a_tg_config_rf_tech(struct trf7970a *trf, int tech)
|
|||
trf->iso_ctrl_tech = TRF7970A_ISO_CTRL_NFC_NFC_CE_MODE |
|
||||
TRF7970A_ISO_CTRL_NFC_CE |
|
||||
TRF7970A_ISO_CTRL_NFC_CE_14443A;
|
||||
trf->modulator_sys_clk_ctrl = TRF7970A_MODULATOR_DEPTH_OOK;
|
||||
trf->modulator_sys_clk_ctrl =
|
||||
(trf->modulator_sys_clk_ctrl & 0xf8) |
|
||||
TRF7970A_MODULATOR_DEPTH_OOK;
|
||||
break;
|
||||
case NFC_DIGITAL_RF_TECH_212F:
|
||||
trf->iso_ctrl_tech = TRF7970A_ISO_CTRL_NFC_NFC_CE_MODE |
|
||||
TRF7970A_ISO_CTRL_NFC_NFCF_212;
|
||||
trf->modulator_sys_clk_ctrl = TRF7970A_MODULATOR_DEPTH_ASK10;
|
||||
trf->modulator_sys_clk_ctrl =
|
||||
(trf->modulator_sys_clk_ctrl & 0xf8) |
|
||||
TRF7970A_MODULATOR_DEPTH_ASK10;
|
||||
break;
|
||||
case NFC_DIGITAL_RF_TECH_424F:
|
||||
trf->iso_ctrl_tech = TRF7970A_ISO_CTRL_NFC_NFC_CE_MODE |
|
||||
TRF7970A_ISO_CTRL_NFC_NFCF_424;
|
||||
trf->modulator_sys_clk_ctrl = TRF7970A_MODULATOR_DEPTH_ASK10;
|
||||
trf->modulator_sys_clk_ctrl =
|
||||
(trf->modulator_sys_clk_ctrl & 0xf8) |
|
||||
TRF7970A_MODULATOR_DEPTH_ASK10;
|
||||
break;
|
||||
default:
|
||||
dev_dbg(trf->dev, "Unsupported rf technology: %d\n", tech);
|
||||
|
@ -1749,7 +1773,7 @@ static int _trf7970a_tg_listen(struct nfc_digital_dev *ddev, u16 timeout,
|
|||
goto out_err;
|
||||
|
||||
ret = trf7970a_write(trf, TRF7970A_REG_IO_CTRL,
|
||||
TRF7970A_REG_IO_CTRL_VRS(0x1));
|
||||
trf->io_ctrl | TRF7970A_REG_IO_CTRL_VRS(0x1));
|
||||
if (ret)
|
||||
goto out_err;
|
||||
|
||||
|
@ -1885,9 +1909,11 @@ static int trf7970a_power_up(struct trf7970a *trf)
|
|||
usleep_range(5000, 6000);
|
||||
|
||||
if (!(trf->quirks & TRF7970A_QUIRK_EN2_MUST_STAY_LOW)) {
|
||||
if (gpio_is_valid(trf->en2_gpio)) {
|
||||
gpio_set_value(trf->en2_gpio, 1);
|
||||
usleep_range(1000, 2000);
|
||||
}
|
||||
}
|
||||
|
||||
gpio_set_value(trf->en_gpio, 1);
|
||||
|
||||
|
@ -1914,6 +1940,7 @@ static int trf7970a_power_down(struct trf7970a *trf)
|
|||
}
|
||||
|
||||
gpio_set_value(trf->en_gpio, 0);
|
||||
if (gpio_is_valid(trf->en2_gpio))
|
||||
gpio_set_value(trf->en2_gpio, 0);
|
||||
|
||||
ret = regulator_disable(trf->regulator);
|
||||
|
@ -1987,6 +2014,7 @@ static int trf7970a_probe(struct spi_device *spi)
|
|||
struct device_node *np = spi->dev.of_node;
|
||||
struct trf7970a *trf;
|
||||
int uvolts, autosuspend_delay, ret;
|
||||
u32 clk_freq = TRF7970A_13MHZ_CLOCK_FREQUENCY;
|
||||
|
||||
if (!np) {
|
||||
dev_err(&spi->dev, "No Device Tree entry\n");
|
||||
|
@ -2032,16 +2060,24 @@ static int trf7970a_probe(struct spi_device *spi)
|
|||
|
||||
trf->en2_gpio = of_get_named_gpio(np, "ti,enable-gpios", 1);
|
||||
if (!gpio_is_valid(trf->en2_gpio)) {
|
||||
dev_err(trf->dev, "No EN2 GPIO property\n");
|
||||
return trf->en2_gpio;
|
||||
}
|
||||
|
||||
dev_info(trf->dev, "No EN2 GPIO property\n");
|
||||
} else {
|
||||
ret = devm_gpio_request_one(trf->dev, trf->en2_gpio,
|
||||
GPIOF_DIR_OUT | GPIOF_INIT_LOW, "trf7970a EN2");
|
||||
if (ret) {
|
||||
dev_err(trf->dev, "Can't request EN2 GPIO: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
of_property_read_u32(np, "clock-frequency", &clk_freq);
|
||||
if ((clk_freq != TRF7970A_27MHZ_CLOCK_FREQUENCY) ||
|
||||
(clk_freq != TRF7970A_13MHZ_CLOCK_FREQUENCY)) {
|
||||
dev_err(trf->dev,
|
||||
"clock-frequency (%u Hz) unsupported\n",
|
||||
clk_freq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (of_property_read_bool(np, "en2-rf-quirk"))
|
||||
trf->quirks |= TRF7970A_QUIRK_EN2_MUST_STAY_LOW;
|
||||
|
@ -2077,6 +2113,24 @@ static int trf7970a_probe(struct spi_device *spi)
|
|||
if (uvolts > 4000000)
|
||||
trf->chip_status_ctrl = TRF7970A_CHIP_STATUS_VRS5_3;
|
||||
|
||||
trf->regulator = devm_regulator_get(&spi->dev, "vdd-io");
|
||||
if (IS_ERR(trf->regulator)) {
|
||||
ret = PTR_ERR(trf->regulator);
|
||||
dev_err(trf->dev, "Can't get VDD_IO regulator: %d\n", ret);
|
||||
goto err_destroy_lock;
|
||||
}
|
||||
|
||||
ret = regulator_enable(trf->regulator);
|
||||
if (ret) {
|
||||
dev_err(trf->dev, "Can't enable VDD_IO: %d\n", ret);
|
||||
goto err_destroy_lock;
|
||||
}
|
||||
|
||||
if (regulator_get_voltage(trf->regulator) == 1800000) {
|
||||
trf->io_ctrl = TRF7970A_REG_IO_CTRL_IO_LOW;
|
||||
dev_dbg(trf->dev, "trf7970a config vdd_io to 1.8V\n");
|
||||
}
|
||||
|
||||
trf->ddev = nfc_digital_allocate_device(&trf7970a_nfc_ops,
|
||||
TRF7970A_SUPPORTED_PROTOCOLS,
|
||||
NFC_DIGITAL_DRV_CAPS_IN_CRC |
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
* Driver include for the PN544 NFC chip.
|
||||
*
|
||||
* Copyright (C) Nokia Corporation
|
||||
*
|
||||
* Author: Jari Vanhala <ext-jari.vanhala@nokia.com>
|
||||
* Contact: Matti Aaltoenn <matti.j.aaltonen@nokia.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 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 _PN544_H_
|
||||
#define _PN544_H_
|
||||
|
||||
#include <linux/i2c.h>
|
||||
|
||||
enum {
|
||||
NFC_GPIO_ENABLE,
|
||||
NFC_GPIO_FW_RESET,
|
||||
NFC_GPIO_IRQ
|
||||
};
|
||||
|
||||
/* board config */
|
||||
struct pn544_nfc_platform_data {
|
||||
int (*request_resources) (struct i2c_client *client);
|
||||
void (*free_resources) (void);
|
||||
void (*enable) (int fw);
|
||||
int (*test) (void);
|
||||
void (*disable) (void);
|
||||
int (*get_gpio)(int type);
|
||||
};
|
||||
|
||||
#endif /* _PN544_H_ */
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
* Driver include for the ST21NFCA NFC chip.
|
||||
*
|
||||
* Copyright (C) 2014 STMicroelectronics SAS. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _ST21NFCA_HCI_H_
|
||||
#define _ST21NFCA_HCI_H_
|
||||
|
||||
#include <linux/i2c.h>
|
||||
|
||||
#define ST21NFCA_HCI_DRIVER_NAME "st21nfca_hci"
|
||||
|
||||
struct st21nfca_nfc_platform_data {
|
||||
unsigned int gpio_ena;
|
||||
unsigned int irq_polarity;
|
||||
bool is_ese_present;
|
||||
bool is_uicc_present;
|
||||
};
|
||||
|
||||
#endif /* _ST21NFCA_HCI_H_ */
|
|
@ -27,6 +27,7 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#define nfc_dbg(dev, fmt, ...) dev_dbg((dev), "NFC: " fmt, ##__VA_ARGS__)
|
||||
#define nfc_info(dev, fmt, ...) dev_info((dev), "NFC: " fmt, ##__VA_ARGS__)
|
||||
#define nfc_err(dev, fmt, ...) dev_err((dev), "NFC: " fmt, ##__VA_ARGS__)
|
||||
|
||||
|
|
|
@ -304,6 +304,17 @@ free_msg:
|
|||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
static int nfc_genl_setup_device_added(struct nfc_dev *dev, struct sk_buff *msg)
|
||||
{
|
||||
if (nla_put_string(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev)) ||
|
||||
nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) ||
|
||||
nla_put_u32(msg, NFC_ATTR_PROTOCOLS, dev->supported_protocols) ||
|
||||
nla_put_u8(msg, NFC_ATTR_DEVICE_POWERED, dev->dev_up) ||
|
||||
nla_put_u8(msg, NFC_ATTR_RF_MODE, dev->rf_mode))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nfc_genl_device_added(struct nfc_dev *dev)
|
||||
{
|
||||
struct sk_buff *msg;
|
||||
|
@ -318,10 +329,7 @@ int nfc_genl_device_added(struct nfc_dev *dev)
|
|||
if (!hdr)
|
||||
goto free_msg;
|
||||
|
||||
if (nla_put_string(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev)) ||
|
||||
nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) ||
|
||||
nla_put_u32(msg, NFC_ATTR_PROTOCOLS, dev->supported_protocols) ||
|
||||
nla_put_u8(msg, NFC_ATTR_DEVICE_POWERED, dev->dev_up))
|
||||
if (nfc_genl_setup_device_added(dev, msg))
|
||||
goto nla_put_failure;
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
|
@ -597,11 +605,7 @@ static int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev,
|
|||
if (cb)
|
||||
genl_dump_check_consistent(cb, hdr, &nfc_genl_family);
|
||||
|
||||
if (nla_put_string(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev)) ||
|
||||
nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) ||
|
||||
nla_put_u32(msg, NFC_ATTR_PROTOCOLS, dev->supported_protocols) ||
|
||||
nla_put_u8(msg, NFC_ATTR_DEVICE_POWERED, dev->dev_up) ||
|
||||
nla_put_u8(msg, NFC_ATTR_RF_MODE, dev->rf_mode))
|
||||
if (nfc_genl_setup_device_added(dev, msg))
|
||||
goto nla_put_failure;
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
|
@ -919,7 +923,7 @@ static int nfc_genl_activate_target(struct sk_buff *skb, struct genl_info *info)
|
|||
rc = nfc_activate_target(dev, target_idx, protocol);
|
||||
|
||||
nfc_put_device(dev);
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int nfc_genl_dep_link_up(struct sk_buff *skb, struct genl_info *info)
|
||||
|
|
Загрузка…
Ссылка в новой задаче