Commit 74923441 authored by David S. Miller's avatar David S. Miller

Merge branch 'nfc-pn533-add-uart-phy-driver'

Lars Poeschel says:

====================
nfc: pn533: add uart phy driver

The purpose of this patch series is to add a uart phy driver to the
pn533 nfc driver.
It first changes the dt strings and docs. The dt compatible strings
need to change, because I would add "pn532-uart" to the already
existing "pn533-i2c" one. These two are now unified into just
"pn532". Then the neccessary changes to the pn533 core driver are
made. Then the uart phy is added.
As the pn532 chip supports a autopoll, I wanted to use this instead
of the software poll loop in the pn533 core driver. It is added and
activated by the last to patches.
The way to add the autopoll later in seperate patches is chosen, to
show, that the uart phy driver can also work with the software poll
loop, if someone needs that for some reason.
In v11 of this patchseries I address a byte ordering issue reported
by kbuild test robot in patch 5/7.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 9014fc31 e4a5dc18
* NXP Semiconductors PN532 NFC Controller * NXP Semiconductors PN532 NFC Controller
Required properties: Required properties:
- compatible: Should be "nxp,pn532-i2c" or "nxp,pn533-i2c". - compatible: Should be
- "nxp,pn532" Place a node with this inside the devicetree node of the bus
where the NFC chip is connected to.
Currently the kernel has phy bindings for uart and i2c.
- "nxp,pn532-i2c" (DEPRECATED) only works for the i2c binding.
- "nxp,pn533-i2c" (DEPRECATED) only works for the i2c binding.
Required properties if connected on i2c:
- clock-frequency: I²C work frequency. - clock-frequency: I²C work frequency.
- reg: address on the bus - reg: for the I²C bus address. This is fixed at 0x24 for the PN532.
- interrupts: GPIO interrupt to which the chip is connected - interrupts: GPIO interrupt to which the chip is connected
Optional SoC Specific Properties: Optional SoC Specific Properties:
...@@ -15,9 +22,9 @@ Example (for ARM-based BeagleBone with PN532 on I2C2): ...@@ -15,9 +22,9 @@ Example (for ARM-based BeagleBone with PN532 on I2C2):
&i2c2 { &i2c2 {
pn532: pn532@24 { pn532: nfc@24 {
compatible = "nxp,pn532-i2c"; compatible = "nxp,pn532";
reg = <0x24>; reg = <0x24>;
clock-frequency = <400000>; clock-frequency = <400000>;
...@@ -27,3 +34,13 @@ Example (for ARM-based BeagleBone with PN532 on I2C2): ...@@ -27,3 +34,13 @@ Example (for ARM-based BeagleBone with PN532 on I2C2):
}; };
}; };
Example (for PN532 connected via uart):
uart4: serial@49042000 {
compatible = "ti,omap3-uart";
pn532: nfc {
compatible = "nxp,pn532";
};
};
...@@ -26,3 +26,14 @@ config NFC_PN533_I2C ...@@ -26,3 +26,14 @@ config NFC_PN533_I2C
If you choose to build a module, it'll be called pn533_i2c. If you choose to build a module, it'll be called pn533_i2c.
Say N if unsure. Say N if unsure.
config NFC_PN532_UART
tristate "NFC PN532 device support (UART)"
depends on SERIAL_DEV_BUS
select NFC_PN533
---help---
This module adds support for the NXP pn532 UART interface.
Select this if your platform is using the UART bus.
If you choose to build a module, it'll be called pn532_uart.
Say N if unsure.
...@@ -4,7 +4,9 @@ ...@@ -4,7 +4,9 @@
# #
pn533_usb-objs = usb.o pn533_usb-objs = usb.o
pn533_i2c-objs = i2c.o pn533_i2c-objs = i2c.o
pn532_uart-objs = uart.o
obj-$(CONFIG_NFC_PN533) += pn533.o obj-$(CONFIG_NFC_PN533) += pn533.o
obj-$(CONFIG_NFC_PN533_USB) += pn533_usb.o obj-$(CONFIG_NFC_PN533_USB) += pn533_usb.o
obj-$(CONFIG_NFC_PN533_I2C) += pn533_i2c.o obj-$(CONFIG_NFC_PN533_I2C) += pn533_i2c.o
obj-$(CONFIG_NFC_PN532_UART) += pn532_uart.o
...@@ -193,12 +193,10 @@ static int pn533_i2c_probe(struct i2c_client *client, ...@@ -193,12 +193,10 @@ static int pn533_i2c_probe(struct i2c_client *client,
phy->i2c_dev = client; phy->i2c_dev = client;
i2c_set_clientdata(client, phy); i2c_set_clientdata(client, phy);
priv = pn533_register_device(PN533_DEVICE_PN532, priv = pn53x_common_init(PN533_DEVICE_PN532,
PN533_NO_TYPE_B_PROTOCOLS, PN533_PROTO_REQ_ACK_RESP,
PN533_PROTO_REQ_ACK_RESP, phy, &i2c_phy_ops, NULL,
phy, &i2c_phy_ops, NULL, &phy->i2c_dev->dev);
&phy->i2c_dev->dev,
&client->dev);
if (IS_ERR(priv)) { if (IS_ERR(priv)) {
r = PTR_ERR(priv); r = PTR_ERR(priv);
...@@ -206,6 +204,9 @@ static int pn533_i2c_probe(struct i2c_client *client, ...@@ -206,6 +204,9 @@ static int pn533_i2c_probe(struct i2c_client *client,
} }
phy->priv = priv; phy->priv = priv;
r = pn532_i2c_nfc_alloc(priv, PN533_NO_TYPE_B_PROTOCOLS, &client->dev);
if (r)
goto nfc_alloc_err;
r = request_threaded_irq(client->irq, NULL, pn533_i2c_irq_thread_fn, r = request_threaded_irq(client->irq, NULL, pn533_i2c_irq_thread_fn,
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_FALLING |
...@@ -220,13 +221,20 @@ static int pn533_i2c_probe(struct i2c_client *client, ...@@ -220,13 +221,20 @@ static int pn533_i2c_probe(struct i2c_client *client,
if (r) if (r)
goto fn_setup_err; goto fn_setup_err;
return 0; r = nfc_register_device(priv->nfc_dev);
if (r)
goto fn_setup_err;
return r;
fn_setup_err: fn_setup_err:
free_irq(client->irq, phy); free_irq(client->irq, phy);
irq_rqst_err: irq_rqst_err:
pn533_unregister_device(phy->priv); nfc_free_device(priv->nfc_dev);
nfc_alloc_err:
pn53x_common_clean(phy->priv);
return r; return r;
} }
...@@ -239,12 +247,18 @@ static int pn533_i2c_remove(struct i2c_client *client) ...@@ -239,12 +247,18 @@ static int pn533_i2c_remove(struct i2c_client *client)
free_irq(client->irq, phy); free_irq(client->irq, phy);
pn533_unregister_device(phy->priv); pn53x_unregister_nfc(phy->priv);
pn53x_common_clean(phy->priv);
return 0; return 0;
} }
static const struct of_device_id of_pn533_i2c_match[] = { static const struct of_device_id of_pn533_i2c_match[] = {
{ .compatible = "nxp,pn532", },
/*
* NOTE: The use of the compatibles with the trailing "...-i2c" is
* deprecated and will be removed.
*/
{ .compatible = "nxp,pn533-i2c", }, { .compatible = "nxp,pn533-i2c", },
{ .compatible = "nxp,pn532-i2c", }, { .compatible = "nxp,pn532-i2c", },
{}, {},
......
This diff is collapsed.
...@@ -6,10 +6,11 @@ ...@@ -6,10 +6,11 @@
* Copyright (C) 2012-2013 Tieto Poland * Copyright (C) 2012-2013 Tieto Poland
*/ */
#define PN533_DEVICE_STD 0x1 #define PN533_DEVICE_STD 0x1
#define PN533_DEVICE_PASORI 0x2 #define PN533_DEVICE_PASORI 0x2
#define PN533_DEVICE_ACR122U 0x3 #define PN533_DEVICE_ACR122U 0x3
#define PN533_DEVICE_PN532 0x4 #define PN533_DEVICE_PN532 0x4
#define PN533_DEVICE_PN532_AUTOPOLL 0x5
#define PN533_ALL_PROTOCOLS (NFC_PROTO_JEWEL_MASK | NFC_PROTO_MIFARE_MASK |\ #define PN533_ALL_PROTOCOLS (NFC_PROTO_JEWEL_MASK | NFC_PROTO_MIFARE_MASK |\
NFC_PROTO_FELICA_MASK | NFC_PROTO_ISO14443_MASK |\ NFC_PROTO_FELICA_MASK | NFC_PROTO_ISO14443_MASK |\
...@@ -43,6 +44,11 @@ ...@@ -43,6 +44,11 @@
/* Preamble (1), SoPC (2), ACK Code (2), Postamble (1) */ /* Preamble (1), SoPC (2), ACK Code (2), Postamble (1) */
#define PN533_STD_FRAME_ACK_SIZE 6 #define PN533_STD_FRAME_ACK_SIZE 6
/*
* Preamble (1), SoPC (2), Packet Length (1), Packet Length Checksum (1),
* Specific Application Level Error Code (1) , Postamble (1)
*/
#define PN533_STD_ERROR_FRAME_SIZE 8
#define PN533_STD_FRAME_CHECKSUM(f) (f->data[f->datalen]) #define PN533_STD_FRAME_CHECKSUM(f) (f->data[f->datalen])
#define PN533_STD_FRAME_POSTAMBLE(f) (f->data[f->datalen + 1]) #define PN533_STD_FRAME_POSTAMBLE(f) (f->data[f->datalen + 1])
/* Half start code (3), LEN (4) should be 0xffff for extended frame */ /* Half start code (3), LEN (4) should be 0xffff for extended frame */
...@@ -70,6 +76,7 @@ ...@@ -70,6 +76,7 @@
#define PN533_CMD_IN_ATR 0x50 #define PN533_CMD_IN_ATR 0x50
#define PN533_CMD_IN_RELEASE 0x52 #define PN533_CMD_IN_RELEASE 0x52
#define PN533_CMD_IN_JUMP_FOR_DEP 0x56 #define PN533_CMD_IN_JUMP_FOR_DEP 0x56
#define PN533_CMD_IN_AUTOPOLL 0x60
#define PN533_CMD_TG_INIT_AS_TARGET 0x8c #define PN533_CMD_TG_INIT_AS_TARGET 0x8c
#define PN533_CMD_TG_GET_DATA 0x86 #define PN533_CMD_TG_GET_DATA 0x86
...@@ -84,6 +91,9 @@ ...@@ -84,6 +91,9 @@
#define PN533_CMD_MI_MASK 0x40 #define PN533_CMD_MI_MASK 0x40
#define PN533_CMD_RET_SUCCESS 0x00 #define PN533_CMD_RET_SUCCESS 0x00
#define PN533_FRAME_DATALEN_ACK 0x00
#define PN533_FRAME_DATALEN_ERROR 0x01
#define PN533_FRAME_DATALEN_EXTENDED 0xFF
enum pn533_protocol_type { enum pn533_protocol_type {
PN533_PROTO_REQ_ACK_RESP = 0, PN533_PROTO_REQ_ACK_RESP = 0,
...@@ -207,21 +217,33 @@ struct pn533_phy_ops { ...@@ -207,21 +217,33 @@ struct pn533_phy_ops {
struct sk_buff *out); struct sk_buff *out);
int (*send_ack)(struct pn533 *dev, gfp_t flags); int (*send_ack)(struct pn533 *dev, gfp_t flags);
void (*abort_cmd)(struct pn533 *priv, gfp_t flags); void (*abort_cmd)(struct pn533 *priv, gfp_t flags);
/*
* dev_up and dev_down are optional.
* They are used to inform the phy layer that the nfc chip
* is going to be really used very soon. The phy layer can then
* bring up it's interface to the chip and have it suspended for power
* saving reasons otherwise.
*/
void (*dev_up)(struct pn533 *priv);
void (*dev_down)(struct pn533 *priv);
}; };
struct pn533 *pn533_register_device(u32 device_type, struct pn533 *pn53x_common_init(u32 device_type,
u32 protocols,
enum pn533_protocol_type protocol_type, enum pn533_protocol_type protocol_type,
void *phy, void *phy,
struct pn533_phy_ops *phy_ops, struct pn533_phy_ops *phy_ops,
struct pn533_frame_ops *fops, struct pn533_frame_ops *fops,
struct device *dev, struct device *dev);
struct device *parent);
int pn533_finalize_setup(struct pn533 *dev); int pn533_finalize_setup(struct pn533 *dev);
void pn533_unregister_device(struct pn533 *priv); void pn53x_common_clean(struct pn533 *priv);
void pn533_recv_frame(struct pn533 *dev, struct sk_buff *skb, int status); void pn533_recv_frame(struct pn533 *dev, struct sk_buff *skb, int status);
int pn532_i2c_nfc_alloc(struct pn533 *priv, u32 protocols,
struct device *parent);
int pn53x_register_nfc(struct pn533 *priv, u32 protocols,
struct device *parent);
void pn53x_unregister_nfc(struct pn533 *priv);
bool pn533_rx_frame_is_cmd_response(struct pn533 *dev, void *frame); bool pn533_rx_frame_is_cmd_response(struct pn533 *dev, void *frame);
bool pn533_rx_frame_is_ack(void *_frame); bool pn533_rx_frame_is_ack(void *_frame);
// SPDX-License-Identifier: GPL-2.0+
/*
* Driver for NXP PN532 NFC Chip - UART transport layer
*
* Copyright (C) 2018 Lemonage Software GmbH
* Author: Lars Pöschel <poeschel@lemonage.de>
* All rights reserved.
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/nfc.h>
#include <linux/netdevice.h>
#include <linux/of.h>
#include <linux/serdev.h>
#include "pn533.h"
#define PN532_UART_SKB_BUFF_LEN (PN533_CMD_DATAEXCH_DATA_MAXLEN * 2)
enum send_wakeup {
PN532_SEND_NO_WAKEUP = 0,
PN532_SEND_WAKEUP,
PN532_SEND_LAST_WAKEUP,
};
struct pn532_uart_phy {
struct serdev_device *serdev;
struct sk_buff *recv_skb;
struct pn533 *priv;
/*
* send_wakeup variable is used to control if we need to send a wakeup
* request to the pn532 chip prior to our actual command. There is a
* little propability of a race condition. We decided to not mutex the
* variable as the worst that could happen is, that we send a wakeup
* to the chip that is already awake. This does not hurt. It is a
* no-op to the chip.
*/
enum send_wakeup send_wakeup;
struct timer_list cmd_timeout;
struct sk_buff *cur_out_buf;
};
static int pn532_uart_send_frame(struct pn533 *dev,
struct sk_buff *out)
{
/* wakeup sequence and dummy bytes for waiting time */
static const u8 wakeup[] = {
0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
struct pn532_uart_phy *pn532 = dev->phy;
int err;
print_hex_dump_debug("PN532_uart TX: ", DUMP_PREFIX_NONE, 16, 1,
out->data, out->len, false);
pn532->cur_out_buf = out;
if (pn532->send_wakeup) {
err = serdev_device_write(pn532->serdev,
wakeup, sizeof(wakeup),
MAX_SCHEDULE_TIMEOUT);
if (err < 0)
return err;
}
if (pn532->send_wakeup == PN532_SEND_LAST_WAKEUP)
pn532->send_wakeup = PN532_SEND_NO_WAKEUP;
err = serdev_device_write(pn532->serdev, out->data, out->len,
MAX_SCHEDULE_TIMEOUT);
if (err < 0)
return err;
mod_timer(&pn532->cmd_timeout, HZ / 40 + jiffies);
return 0;
}
static int pn532_uart_send_ack(struct pn533 *dev, gfp_t flags)
{
/* spec 7.1.1.3: Preamble, SoPC (2), ACK Code (2), Postamble */
static const u8 ack[PN533_STD_FRAME_ACK_SIZE] = {
0x00, 0x00, 0xff, 0x00, 0xff, 0x00};
struct pn532_uart_phy *pn532 = dev->phy;
int err;
err = serdev_device_write(pn532->serdev, ack, sizeof(ack),
MAX_SCHEDULE_TIMEOUT);
if (err < 0)
return err;
return 0;
}
static void pn532_uart_abort_cmd(struct pn533 *dev, gfp_t flags)
{
/* An ack will cancel the last issued command */
pn532_uart_send_ack(dev, flags);
/* schedule cmd_complete_work to finish current command execution */
pn533_recv_frame(dev, NULL, -ENOENT);
}
static void pn532_dev_up(struct pn533 *dev)
{
struct pn532_uart_phy *pn532 = dev->phy;
serdev_device_open(pn532->serdev);
pn532->send_wakeup = PN532_SEND_LAST_WAKEUP;
}
static void pn532_dev_down(struct pn533 *dev)
{
struct pn532_uart_phy *pn532 = dev->phy;
serdev_device_close(pn532->serdev);
pn532->send_wakeup = PN532_SEND_WAKEUP;
}
static struct pn533_phy_ops uart_phy_ops = {
.send_frame = pn532_uart_send_frame,
.send_ack = pn532_uart_send_ack,
.abort_cmd = pn532_uart_abort_cmd,
.dev_up = pn532_dev_up,
.dev_down = pn532_dev_down,
};
static void pn532_cmd_timeout(struct timer_list *t)
{
struct pn532_uart_phy *dev = from_timer(dev, t, cmd_timeout);
pn532_uart_send_frame(dev->priv, dev->cur_out_buf);
}
/*
* scans the buffer if it contains a pn532 frame. It is not checked if the
* frame is really valid. This is later done with pn533_rx_frame_is_valid.
* This is useful for malformed or errornous transmitted frames. Adjusts the
* bufferposition where the frame starts, since pn533_recv_frame expects a
* well formed frame.
*/
static int pn532_uart_rx_is_frame(struct sk_buff *skb)
{
struct pn533_std_frame *std;
struct pn533_ext_frame *ext;
u16 frame_len;
int i;
for (i = 0; i + PN533_STD_FRAME_ACK_SIZE <= skb->len; i++) {
std = (struct pn533_std_frame *)&skb->data[i];
/* search start code */
if (std->start_frame != cpu_to_be16(PN533_STD_FRAME_SOF))
continue;
/* frame type */
switch (std->datalen) {
case PN533_FRAME_DATALEN_ACK:
if (std->datalen_checksum == 0xff) {
skb_pull(skb, i);
return 1;
}
break;
case PN533_FRAME_DATALEN_ERROR:
if ((std->datalen_checksum == 0xff) &&
(skb->len >=
PN533_STD_ERROR_FRAME_SIZE)) {
skb_pull(skb, i);
return 1;
}
break;
case PN533_FRAME_DATALEN_EXTENDED:
ext = (struct pn533_ext_frame *)&skb->data[i];
frame_len = be16_to_cpu(ext->datalen);
if (skb->len >= frame_len +
sizeof(struct pn533_ext_frame) +
2 /* CKS + Postamble */) {
skb_pull(skb, i);
return 1;
}
break;
default: /* normal information frame */
frame_len = std->datalen;
if (skb->len >= frame_len +
sizeof(struct pn533_std_frame) +
2 /* CKS + Postamble */) {
skb_pull(skb, i);
return 1;
}
break;
}
}
return 0;
}
static int pn532_receive_buf(struct serdev_device *serdev,
const unsigned char *data, size_t count)
{
struct pn532_uart_phy *dev = serdev_device_get_drvdata(serdev);
size_t i;
del_timer(&dev->cmd_timeout);
for (i = 0; i < count; i++) {
skb_put_u8(dev->recv_skb, *data++);
if (!pn532_uart_rx_is_frame(dev->recv_skb))
continue;
pn533_recv_frame(dev->priv, dev->recv_skb, 0);
dev->recv_skb = alloc_skb(PN532_UART_SKB_BUFF_LEN, GFP_KERNEL);
if (!dev->recv_skb)
return 0;
}
return i;
}
static struct serdev_device_ops pn532_serdev_ops = {
.receive_buf = pn532_receive_buf,
.write_wakeup = serdev_device_write_wakeup,
};
static const struct of_device_id pn532_uart_of_match[] = {
{ .compatible = "nxp,pn532", },
{},
};
MODULE_DEVICE_TABLE(of, pn532_uart_of_match);
static int pn532_uart_probe(struct serdev_device *serdev)
{
struct pn532_uart_phy *pn532;
struct pn533 *priv;
int err;
err = -ENOMEM;
pn532 = kzalloc(sizeof(*pn532), GFP_KERNEL);
if (!pn532)
goto err_exit;
pn532->recv_skb = alloc_skb(PN532_UART_SKB_BUFF_LEN, GFP_KERNEL);
if (!pn532->recv_skb)
goto err_free;
pn532->serdev = serdev;
serdev_device_set_drvdata(serdev, pn532);
serdev_device_set_client_ops(serdev, &pn532_serdev_ops);
err = serdev_device_open(serdev);
if (err) {
dev_err(&serdev->dev, "Unable to open device\n");
goto err_skb;
}
err = serdev_device_set_baudrate(serdev, 115200);
if (err != 115200) {
err = -EINVAL;
goto err_serdev;
}
serdev_device_set_flow_control(serdev, false);
pn532->send_wakeup = PN532_SEND_WAKEUP;
timer_setup(&pn532->cmd_timeout, pn532_cmd_timeout, 0);
priv = pn53x_common_init(PN533_DEVICE_PN532_AUTOPOLL,
PN533_PROTO_REQ_ACK_RESP,
pn532, &uart_phy_ops, NULL,
&pn532->serdev->dev);
if (IS_ERR(priv)) {
err = PTR_ERR(priv);
goto err_serdev;
}
pn532->priv = priv;
err = pn533_finalize_setup(pn532->priv);
if (err)
goto err_clean;
serdev_device_close(serdev);
err = pn53x_register_nfc(priv, PN533_NO_TYPE_B_PROTOCOLS, &serdev->dev);
if (err) {
pn53x_common_clean(pn532->priv);
goto err_skb;
}
return err;
err_clean:
pn53x_common_clean(pn532->priv);
err_serdev:
serdev_device_close(serdev);
err_skb:
kfree_skb(pn532->recv_skb);
err_free:
kfree(pn532);
err_exit:
return err;
}
static void pn532_uart_remove(struct serdev_device *serdev)
{
struct pn532_uart_phy *pn532 = serdev_device_get_drvdata(serdev);
pn53x_unregister_nfc(pn532->priv);
serdev_device_close(serdev);
pn53x_common_clean(pn532->priv);
kfree_skb(pn532->recv_skb);
kfree(pn532);
}
static struct serdev_device_driver pn532_uart_driver = {
.probe = pn532_uart_probe,
.remove = pn532_uart_remove,
.driver = {
.name = "pn532_uart",
.of_match_table = of_match_ptr(pn532_uart_of_match),
},
};
module_serdev_device_driver(pn532_uart_driver);
MODULE_AUTHOR("Lars Pöschel <poeschel@lemonage.de>");
MODULE_DESCRIPTION("PN532 UART driver");
MODULE_LICENSE("GPL");
...@@ -534,9 +534,9 @@ static int pn533_usb_probe(struct usb_interface *interface, ...@@ -534,9 +534,9 @@ static int pn533_usb_probe(struct usb_interface *interface,
goto error; goto error;
} }
priv = pn533_register_device(id->driver_info, protocols, protocol_type, priv = pn53x_common_init(id->driver_info, protocol_type,
phy, &usb_phy_ops, fops, phy, &usb_phy_ops, fops,
&phy->udev->dev, &interface->dev); &phy->udev->dev);
if (IS_ERR(priv)) { if (IS_ERR(priv)) {
rc = PTR_ERR(priv); rc = PTR_ERR(priv);
...@@ -547,14 +547,17 @@ static int pn533_usb_probe(struct usb_interface *interface, ...@@ -547,14 +547,17 @@ static int pn533_usb_probe(struct usb_interface *interface,
rc = pn533_finalize_setup(priv); rc = pn533_finalize_setup(priv);
if (rc) if (rc)
goto err_deregister; goto err_clean;
usb_set_intfdata(interface, phy); usb_set_intfdata(interface, phy);
rc = pn53x_register_nfc(priv, protocols, &interface->dev);
if (rc)
goto err_clean;
return 0; return 0;
err_deregister: err_clean:
pn533_unregister_device(phy->priv); pn53x_common_clean(priv);
error: error:
usb_kill_urb(phy->in_urb); usb_kill_urb(phy->in_urb);
usb_kill_urb(phy->out_urb); usb_kill_urb(phy->out_urb);
...@@ -577,7 +580,8 @@ static void pn533_usb_disconnect(struct usb_interface *interface) ...@@ -577,7 +580,8 @@ static void pn533_usb_disconnect(struct usb_interface *interface)
if (!phy) if (!phy)
return; return;
pn533_unregister_device(phy->priv); pn53x_unregister_nfc(phy->priv);
pn53x_common_clean(phy->priv);
usb_set_intfdata(interface, NULL); usb_set_intfdata(interface, NULL);
......
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