diff options
Diffstat (limited to 'drivers/nfc')
-rw-r--r-- | drivers/nfc/nfcmrvl/Kconfig | 2 | ||||
-rw-r--r-- | drivers/nfc/nfcmrvl/i2c.c | 1 | ||||
-rw-r--r-- | drivers/nfc/pn533/Kconfig | 11 | ||||
-rw-r--r-- | drivers/nfc/pn533/Makefile | 2 | ||||
-rw-r--r-- | drivers/nfc/pn533/i2c.c | 32 | ||||
-rw-r--r-- | drivers/nfc/pn533/pn533.c | 287 | ||||
-rw-r--r-- | drivers/nfc/pn533/pn533.h | 40 | ||||
-rw-r--r-- | drivers/nfc/pn533/uart.c | 330 | ||||
-rw-r--r-- | drivers/nfc/pn533/usb.c | 16 | ||||
-rw-r--r-- | drivers/nfc/s3fwrn5/i2c.c | 1 |
10 files changed, 659 insertions, 63 deletions
diff --git a/drivers/nfc/nfcmrvl/Kconfig b/drivers/nfc/nfcmrvl/Kconfig index 06f34fb4e0b0..ded0d03c0015 100644 --- a/drivers/nfc/nfcmrvl/Kconfig +++ b/drivers/nfc/nfcmrvl/Kconfig @@ -15,7 +15,7 @@ config NFC_MRVL_USB Marvell NFC-over-USB driver. This driver provides support for Marvell NFC-over-USB devices: - 8897. + 8897. Say Y here to compile support for Marvell NFC-over-USB driver into the kernel or say M to compile it as module. diff --git a/drivers/nfc/nfcmrvl/i2c.c b/drivers/nfc/nfcmrvl/i2c.c index 0f22379887ca..18cd96284b77 100644 --- a/drivers/nfc/nfcmrvl/i2c.c +++ b/drivers/nfc/nfcmrvl/i2c.c @@ -278,7 +278,6 @@ static struct i2c_driver nfcmrvl_i2c_driver = { .remove = nfcmrvl_i2c_remove, .driver = { .name = "nfcmrvl_i2c", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(of_nfcmrvl_i2c_match), }, }; diff --git a/drivers/nfc/pn533/Kconfig b/drivers/nfc/pn533/Kconfig index f6d6b345ba0d..7fe1bbe26568 100644 --- a/drivers/nfc/pn533/Kconfig +++ b/drivers/nfc/pn533/Kconfig @@ -26,3 +26,14 @@ config NFC_PN533_I2C If you choose to build a module, it'll be called pn533_i2c. 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. diff --git a/drivers/nfc/pn533/Makefile b/drivers/nfc/pn533/Makefile index 43c25b4f9466..b9648337576f 100644 --- a/drivers/nfc/pn533/Makefile +++ b/drivers/nfc/pn533/Makefile @@ -4,7 +4,9 @@ # pn533_usb-objs = usb.o pn533_i2c-objs = i2c.o +pn532_uart-objs = uart.o obj-$(CONFIG_NFC_PN533) += pn533.o obj-$(CONFIG_NFC_PN533_USB) += pn533_usb.o obj-$(CONFIG_NFC_PN533_I2C) += pn533_i2c.o +obj-$(CONFIG_NFC_PN532_UART) += pn532_uart.o diff --git a/drivers/nfc/pn533/i2c.c b/drivers/nfc/pn533/i2c.c index 1832cd921ea7..7507176cca0a 100644 --- a/drivers/nfc/pn533/i2c.c +++ b/drivers/nfc/pn533/i2c.c @@ -193,12 +193,10 @@ static int pn533_i2c_probe(struct i2c_client *client, phy->i2c_dev = client; i2c_set_clientdata(client, phy); - priv = pn533_register_device(PN533_DEVICE_PN532, - PN533_NO_TYPE_B_PROTOCOLS, - PN533_PROTO_REQ_ACK_RESP, - phy, &i2c_phy_ops, NULL, - &phy->i2c_dev->dev, - &client->dev); + priv = pn53x_common_init(PN533_DEVICE_PN532, + PN533_PROTO_REQ_ACK_RESP, + phy, &i2c_phy_ops, NULL, + &phy->i2c_dev->dev); if (IS_ERR(priv)) { r = PTR_ERR(priv); @@ -206,6 +204,9 @@ static int pn533_i2c_probe(struct i2c_client *client, } 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, IRQF_TRIGGER_FALLING | @@ -220,13 +221,20 @@ static int pn533_i2c_probe(struct i2c_client *client, if (r) goto fn_setup_err; - return 0; + r = nfc_register_device(priv->nfc_dev); + if (r) + goto fn_setup_err; + + return r; fn_setup_err: free_irq(client->irq, phy); irq_rqst_err: - pn533_unregister_device(phy->priv); + nfc_free_device(priv->nfc_dev); + +nfc_alloc_err: + pn53x_common_clean(phy->priv); return r; } @@ -239,12 +247,18 @@ static int pn533_i2c_remove(struct i2c_client *client) free_irq(client->irq, phy); - pn533_unregister_device(phy->priv); + pn53x_unregister_nfc(phy->priv); + pn53x_common_clean(phy->priv); return 0; } 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,pn532-i2c", }, {}, diff --git a/drivers/nfc/pn533/pn533.c b/drivers/nfc/pn533/pn533.c index a172a32aa9d9..346e084387f7 100644 --- a/drivers/nfc/pn533/pn533.c +++ b/drivers/nfc/pn533/pn533.c @@ -185,6 +185,32 @@ struct pn533_cmd_jump_dep_response { u8 gt[]; } __packed; +struct pn532_autopoll_resp { + u8 type; + u8 ln; + u8 tg; + u8 tgdata[]; +}; + +/* PN532_CMD_IN_AUTOPOLL */ +#define PN532_AUTOPOLL_POLLNR_INFINITE 0xff +#define PN532_AUTOPOLL_PERIOD 0x03 /* in units of 150 ms */ + +#define PN532_AUTOPOLL_TYPE_GENERIC_106 0x00 +#define PN532_AUTOPOLL_TYPE_GENERIC_212 0x01 +#define PN532_AUTOPOLL_TYPE_GENERIC_424 0x02 +#define PN532_AUTOPOLL_TYPE_JEWEL 0x04 +#define PN532_AUTOPOLL_TYPE_MIFARE 0x10 +#define PN532_AUTOPOLL_TYPE_FELICA212 0x11 +#define PN532_AUTOPOLL_TYPE_FELICA424 0x12 +#define PN532_AUTOPOLL_TYPE_ISOA 0x20 +#define PN532_AUTOPOLL_TYPE_ISOB 0x23 +#define PN532_AUTOPOLL_TYPE_DEP_PASSIVE_106 0x40 +#define PN532_AUTOPOLL_TYPE_DEP_PASSIVE_212 0x41 +#define PN532_AUTOPOLL_TYPE_DEP_PASSIVE_424 0x42 +#define PN532_AUTOPOLL_TYPE_DEP_ACTIVE_106 0x80 +#define PN532_AUTOPOLL_TYPE_DEP_ACTIVE_212 0x81 +#define PN532_AUTOPOLL_TYPE_DEP_ACTIVE_424 0x82 /* PN533_TG_INIT_AS_TARGET */ #define PN533_INIT_TARGET_PASSIVE 0x1 @@ -1389,6 +1415,101 @@ static int pn533_poll_dep(struct nfc_dev *nfc_dev) return rc; } +static int pn533_autopoll_complete(struct pn533 *dev, void *arg, + struct sk_buff *resp) +{ + struct pn532_autopoll_resp *apr; + struct nfc_target nfc_tgt; + u8 nbtg; + int rc; + + if (IS_ERR(resp)) { + rc = PTR_ERR(resp); + + nfc_err(dev->dev, "%s autopoll complete error %d\n", + __func__, rc); + + if (rc == -ENOENT) { + if (dev->poll_mod_count != 0) + return rc; + goto stop_poll; + } else if (rc < 0) { + nfc_err(dev->dev, + "Error %d when running autopoll\n", rc); + goto stop_poll; + } + } + + nbtg = resp->data[0]; + if ((nbtg > 2) || (nbtg <= 0)) + return -EAGAIN; + + apr = (struct pn532_autopoll_resp *)&resp->data[1]; + while (nbtg--) { + memset(&nfc_tgt, 0, sizeof(struct nfc_target)); + switch (apr->type) { + case PN532_AUTOPOLL_TYPE_ISOA: + dev_dbg(dev->dev, "ISOA\n"); + rc = pn533_target_found_type_a(&nfc_tgt, apr->tgdata, + apr->ln - 1); + break; + case PN532_AUTOPOLL_TYPE_FELICA212: + case PN532_AUTOPOLL_TYPE_FELICA424: + dev_dbg(dev->dev, "FELICA\n"); + rc = pn533_target_found_felica(&nfc_tgt, apr->tgdata, + apr->ln - 1); + break; + case PN532_AUTOPOLL_TYPE_JEWEL: + dev_dbg(dev->dev, "JEWEL\n"); + rc = pn533_target_found_jewel(&nfc_tgt, apr->tgdata, + apr->ln - 1); + break; + case PN532_AUTOPOLL_TYPE_ISOB: + dev_dbg(dev->dev, "ISOB\n"); + rc = pn533_target_found_type_b(&nfc_tgt, apr->tgdata, + apr->ln - 1); + break; + case PN532_AUTOPOLL_TYPE_MIFARE: + dev_dbg(dev->dev, "Mifare\n"); + rc = pn533_target_found_type_a(&nfc_tgt, apr->tgdata, + apr->ln - 1); + break; + default: + nfc_err(dev->dev, + "Unknown current poll modulation\n"); + rc = -EPROTO; + } + + if (rc) + goto done; + + if (!(nfc_tgt.supported_protocols & dev->poll_protocols)) { + nfc_err(dev->dev, + "The Tg found doesn't have the desired protocol\n"); + rc = -EAGAIN; + goto done; + } + + dev->tgt_available_prots = nfc_tgt.supported_protocols; + apr = (struct pn532_autopoll_resp *) + (apr->tgdata + (apr->ln - 1)); + } + + pn533_poll_reset_mod_list(dev); + nfc_targets_found(dev->nfc_dev, &nfc_tgt, 1); + +done: + dev_kfree_skb(resp); + return rc; + +stop_poll: + nfc_err(dev->dev, "autopoll operation has been stopped\n"); + + pn533_poll_reset_mod_list(dev); + dev->poll_protocols = 0; + return rc; +} + static int pn533_poll_complete(struct pn533 *dev, void *arg, struct sk_buff *resp) { @@ -1532,6 +1653,7 @@ static int pn533_start_poll(struct nfc_dev *nfc_dev, { struct pn533 *dev = nfc_get_drvdata(nfc_dev); struct pn533_poll_modulations *cur_mod; + struct sk_buff *skb; u8 rand_mod; int rc; @@ -1557,9 +1679,73 @@ static int pn533_start_poll(struct nfc_dev *nfc_dev, tm_protocols = 0; } - pn533_poll_create_mod_list(dev, im_protocols, tm_protocols); dev->poll_protocols = im_protocols; dev->listen_protocols = tm_protocols; + if (dev->device_type == PN533_DEVICE_PN532_AUTOPOLL) { + skb = pn533_alloc_skb(dev, 4 + 6); + if (!skb) + return -ENOMEM; + + *((u8 *)skb_put(skb, sizeof(u8))) = + PN532_AUTOPOLL_POLLNR_INFINITE; + *((u8 *)skb_put(skb, sizeof(u8))) = PN532_AUTOPOLL_PERIOD; + + if ((im_protocols & NFC_PROTO_MIFARE_MASK) && + (im_protocols & NFC_PROTO_ISO14443_MASK) && + (im_protocols & NFC_PROTO_NFC_DEP_MASK)) + *((u8 *)skb_put(skb, sizeof(u8))) = + PN532_AUTOPOLL_TYPE_GENERIC_106; + else { + if (im_protocols & NFC_PROTO_MIFARE_MASK) + *((u8 *)skb_put(skb, sizeof(u8))) = + PN532_AUTOPOLL_TYPE_MIFARE; + + if (im_protocols & NFC_PROTO_ISO14443_MASK) + *((u8 *)skb_put(skb, sizeof(u8))) = + PN532_AUTOPOLL_TYPE_ISOA; + + if (im_protocols & NFC_PROTO_NFC_DEP_MASK) { + *((u8 *)skb_put(skb, sizeof(u8))) = + PN532_AUTOPOLL_TYPE_DEP_PASSIVE_106; + *((u8 *)skb_put(skb, sizeof(u8))) = + PN532_AUTOPOLL_TYPE_DEP_PASSIVE_212; + *((u8 *)skb_put(skb, sizeof(u8))) = + PN532_AUTOPOLL_TYPE_DEP_PASSIVE_424; + } + } + + if (im_protocols & NFC_PROTO_FELICA_MASK || + im_protocols & NFC_PROTO_NFC_DEP_MASK) { + *((u8 *)skb_put(skb, sizeof(u8))) = + PN532_AUTOPOLL_TYPE_FELICA212; + *((u8 *)skb_put(skb, sizeof(u8))) = + PN532_AUTOPOLL_TYPE_FELICA424; + } + + if (im_protocols & NFC_PROTO_JEWEL_MASK) + *((u8 *)skb_put(skb, sizeof(u8))) = + PN532_AUTOPOLL_TYPE_JEWEL; + + if (im_protocols & NFC_PROTO_ISO14443_B_MASK) + *((u8 *)skb_put(skb, sizeof(u8))) = + PN532_AUTOPOLL_TYPE_ISOB; + + if (tm_protocols) + *((u8 *)skb_put(skb, sizeof(u8))) = + PN532_AUTOPOLL_TYPE_DEP_ACTIVE_106; + + rc = pn533_send_cmd_async(dev, PN533_CMD_IN_AUTOPOLL, skb, + pn533_autopoll_complete, NULL); + + if (rc < 0) + dev_kfree_skb(skb); + else + dev->poll_mod_count++; + + return rc; + } + + pn533_poll_create_mod_list(dev, im_protocols, tm_protocols); /* Do not always start polling from the same modulation */ get_random_bytes(&rand_mod, sizeof(rand_mod)); @@ -2457,9 +2643,17 @@ static int pn532_sam_configuration(struct nfc_dev *nfc_dev) static int pn533_dev_up(struct nfc_dev *nfc_dev) { struct pn533 *dev = nfc_get_drvdata(nfc_dev); + int rc; + + if (dev->phy_ops->dev_up) { + rc = dev->phy_ops->dev_up(dev); + if (rc) + return rc; + } - if (dev->device_type == PN533_DEVICE_PN532) { - int rc = pn532_sam_configuration(nfc_dev); + if ((dev->device_type == PN533_DEVICE_PN532) || + (dev->device_type == PN533_DEVICE_PN532_AUTOPOLL)) { + rc = pn532_sam_configuration(nfc_dev); if (rc) return rc; @@ -2470,7 +2664,14 @@ static int pn533_dev_up(struct nfc_dev *nfc_dev) static int pn533_dev_down(struct nfc_dev *nfc_dev) { - return pn533_rf_field(nfc_dev, 0); + struct pn533 *dev = nfc_get_drvdata(nfc_dev); + int ret; + + ret = pn533_rf_field(nfc_dev, 0); + if (dev->phy_ops->dev_down && !ret) + ret = dev->phy_ops->dev_down(dev); + + return ret; } static struct nfc_ops pn533_nfc_ops = { @@ -2498,6 +2699,7 @@ static int pn533_setup(struct pn533 *dev) case PN533_DEVICE_PASORI: case PN533_DEVICE_ACR122U: case PN533_DEVICE_PN532: + case PN533_DEVICE_PN532_AUTOPOLL: max_retries.mx_rty_atr = 0x2; max_retries.mx_rty_psl = 0x1; max_retries.mx_rty_passive_act = @@ -2534,6 +2736,7 @@ static int pn533_setup(struct pn533 *dev) switch (dev->device_type) { case PN533_DEVICE_STD: case PN533_DEVICE_PN532: + case PN533_DEVICE_PN532_AUTOPOLL: break; case PN533_DEVICE_PASORI: @@ -2580,14 +2783,12 @@ int pn533_finalize_setup(struct pn533 *dev) } EXPORT_SYMBOL_GPL(pn533_finalize_setup); -struct pn533 *pn533_register_device(u32 device_type, - u32 protocols, +struct pn533 *pn53x_common_init(u32 device_type, enum pn533_protocol_type protocol_type, void *phy, struct pn533_phy_ops *phy_ops, struct pn533_frame_ops *fops, - struct device *dev, - struct device *parent) + struct device *dev) { struct pn533 *priv; int rc = -ENOMEM; @@ -2628,43 +2829,18 @@ struct pn533 *pn533_register_device(u32 device_type, skb_queue_head_init(&priv->fragment_skb); INIT_LIST_HEAD(&priv->cmd_queue); - - priv->nfc_dev = nfc_allocate_device(&pn533_nfc_ops, protocols, - priv->ops->tx_header_len + - PN533_CMD_DATAEXCH_HEAD_LEN, - priv->ops->tx_tail_len); - if (!priv->nfc_dev) { - rc = -ENOMEM; - goto destroy_wq; - } - - nfc_set_parent_dev(priv->nfc_dev, parent); - nfc_set_drvdata(priv->nfc_dev, priv); - - rc = nfc_register_device(priv->nfc_dev); - if (rc) - goto free_nfc_dev; - return priv; -free_nfc_dev: - nfc_free_device(priv->nfc_dev); - -destroy_wq: - destroy_workqueue(priv->wq); error: kfree(priv); return ERR_PTR(rc); } -EXPORT_SYMBOL_GPL(pn533_register_device); +EXPORT_SYMBOL_GPL(pn53x_common_init); -void pn533_unregister_device(struct pn533 *priv) +void pn53x_common_clean(struct pn533 *priv) { struct pn533_cmd *cmd, *n; - nfc_unregister_device(priv->nfc_dev); - nfc_free_device(priv->nfc_dev); - flush_delayed_work(&priv->poll_work); destroy_workqueue(priv->wq); @@ -2679,8 +2855,47 @@ void pn533_unregister_device(struct pn533 *priv) kfree(priv); } -EXPORT_SYMBOL_GPL(pn533_unregister_device); +EXPORT_SYMBOL_GPL(pn53x_common_clean); + +int pn532_i2c_nfc_alloc(struct pn533 *priv, u32 protocols, + struct device *parent) +{ + priv->nfc_dev = nfc_allocate_device(&pn533_nfc_ops, protocols, + priv->ops->tx_header_len + + PN533_CMD_DATAEXCH_HEAD_LEN, + priv->ops->tx_tail_len); + if (!priv->nfc_dev) + return -ENOMEM; + + nfc_set_parent_dev(priv->nfc_dev, parent); + nfc_set_drvdata(priv->nfc_dev, priv); + return 0; +} +EXPORT_SYMBOL_GPL(pn532_i2c_nfc_alloc); +int pn53x_register_nfc(struct pn533 *priv, u32 protocols, + struct device *parent) +{ + int rc; + + rc = pn532_i2c_nfc_alloc(priv, protocols, parent); + if (rc) + return rc; + + rc = nfc_register_device(priv->nfc_dev); + if (rc) + nfc_free_device(priv->nfc_dev); + + return rc; +} +EXPORT_SYMBOL_GPL(pn53x_register_nfc); + +void pn53x_unregister_nfc(struct pn533 *priv) +{ + nfc_unregister_device(priv->nfc_dev); + nfc_free_device(priv->nfc_dev); +} +EXPORT_SYMBOL_GPL(pn53x_unregister_nfc); MODULE_AUTHOR("Lauro Ramos Venancio <lauro.venancio@openbossa.org>"); MODULE_AUTHOR("Aloisio Almeida Jr <aloisio.almeida@openbossa.org>"); diff --git a/drivers/nfc/pn533/pn533.h b/drivers/nfc/pn533/pn533.h index 8bf9d6ece0f5..5f94f38a2a08 100644 --- a/drivers/nfc/pn533/pn533.h +++ b/drivers/nfc/pn533/pn533.h @@ -6,10 +6,11 @@ * Copyright (C) 2012-2013 Tieto Poland */ -#define PN533_DEVICE_STD 0x1 -#define PN533_DEVICE_PASORI 0x2 -#define PN533_DEVICE_ACR122U 0x3 -#define PN533_DEVICE_PN532 0x4 +#define PN533_DEVICE_STD 0x1 +#define PN533_DEVICE_PASORI 0x2 +#define PN533_DEVICE_ACR122U 0x3 +#define PN533_DEVICE_PN532 0x4 +#define PN533_DEVICE_PN532_AUTOPOLL 0x5 #define PN533_ALL_PROTOCOLS (NFC_PROTO_JEWEL_MASK | NFC_PROTO_MIFARE_MASK |\ NFC_PROTO_FELICA_MASK | NFC_PROTO_ISO14443_MASK |\ @@ -43,6 +44,11 @@ /* Preamble (1), SoPC (2), ACK Code (2), Postamble (1) */ #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_POSTAMBLE(f) (f->data[f->datalen + 1]) /* Half start code (3), LEN (4) should be 0xffff for extended frame */ @@ -70,6 +76,7 @@ #define PN533_CMD_IN_ATR 0x50 #define PN533_CMD_IN_RELEASE 0x52 #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_GET_DATA 0x86 @@ -84,6 +91,9 @@ #define PN533_CMD_MI_MASK 0x40 #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 { PN533_PROTO_REQ_ACK_RESP = 0, @@ -207,21 +217,33 @@ struct pn533_phy_ops { struct sk_buff *out); int (*send_ack)(struct pn533 *dev, 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. + */ + int (*dev_up)(struct pn533 *priv); + int (*dev_down)(struct pn533 *priv); }; -struct pn533 *pn533_register_device(u32 device_type, - u32 protocols, +struct pn533 *pn53x_common_init(u32 device_type, enum pn533_protocol_type protocol_type, void *phy, struct pn533_phy_ops *phy_ops, struct pn533_frame_ops *fops, - struct device *dev, - struct device *parent); + struct device *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); +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_ack(void *_frame); diff --git a/drivers/nfc/pn533/uart.c b/drivers/nfc/pn533/uart.c new file mode 100644 index 000000000000..a0665d8ea85b --- /dev/null +++ b/drivers/nfc/pn533/uart.c @@ -0,0 +1,330 @@ +// 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 int pn532_dev_up(struct pn533 *dev) +{ + struct pn532_uart_phy *pn532 = dev->phy; + int ret = 0; + + ret = serdev_device_open(pn532->serdev); + if (ret) + return ret; + + pn532->send_wakeup = PN532_SEND_LAST_WAKEUP; + return ret; +} + +static int pn532_dev_down(struct pn533 *dev) +{ + struct pn532_uart_phy *pn532 = dev->phy; + + serdev_device_close(pn532->serdev); + pn532->send_wakeup = PN532_SEND_WAKEUP; + + return 0; +} + +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"); diff --git a/drivers/nfc/pn533/usb.c b/drivers/nfc/pn533/usb.c index e897e4d768ef..4590fbf82dc2 100644 --- a/drivers/nfc/pn533/usb.c +++ b/drivers/nfc/pn533/usb.c @@ -534,9 +534,9 @@ static int pn533_usb_probe(struct usb_interface *interface, 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->udev->dev, &interface->dev); + &phy->udev->dev); if (IS_ERR(priv)) { rc = PTR_ERR(priv); @@ -547,14 +547,17 @@ static int pn533_usb_probe(struct usb_interface *interface, rc = pn533_finalize_setup(priv); if (rc) - goto err_deregister; + goto err_clean; usb_set_intfdata(interface, phy); + rc = pn53x_register_nfc(priv, protocols, &interface->dev); + if (rc) + goto err_clean; return 0; -err_deregister: - pn533_unregister_device(phy->priv); +err_clean: + pn53x_common_clean(priv); error: usb_kill_urb(phy->in_urb); usb_kill_urb(phy->out_urb); @@ -577,7 +580,8 @@ static void pn533_usb_disconnect(struct usb_interface *interface) if (!phy) return; - pn533_unregister_device(phy->priv); + pn53x_unregister_nfc(phy->priv); + pn53x_common_clean(phy->priv); usb_set_intfdata(interface, NULL); diff --git a/drivers/nfc/s3fwrn5/i2c.c b/drivers/nfc/s3fwrn5/i2c.c index e4f7fa00862d..b4eb926d220a 100644 --- a/drivers/nfc/s3fwrn5/i2c.c +++ b/drivers/nfc/s3fwrn5/i2c.c @@ -279,7 +279,6 @@ MODULE_DEVICE_TABLE(of, of_s3fwrn5_i2c_match); static struct i2c_driver s3fwrn5_i2c_driver = { .driver = { - .owner = THIS_MODULE, .name = S3FWRN5_I2C_DRIVER_NAME, .of_match_table = of_match_ptr(of_s3fwrn5_i2c_match), }, |