162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Driver for NXP PN532 NFC Chip - UART transport layer 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2018 Lemonage Software GmbH 662306a36Sopenharmony_ci * Author: Lars Pöschel <poeschel@lemonage.de> 762306a36Sopenharmony_ci * All rights reserved. 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/device.h> 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/nfc.h> 1462306a36Sopenharmony_ci#include <linux/netdevice.h> 1562306a36Sopenharmony_ci#include <linux/of.h> 1662306a36Sopenharmony_ci#include <linux/serdev.h> 1762306a36Sopenharmony_ci#include "pn533.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#define PN532_UART_SKB_BUFF_LEN (PN533_CMD_DATAEXCH_DATA_MAXLEN * 2) 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cienum send_wakeup { 2262306a36Sopenharmony_ci PN532_SEND_NO_WAKEUP = 0, 2362306a36Sopenharmony_ci PN532_SEND_WAKEUP, 2462306a36Sopenharmony_ci PN532_SEND_LAST_WAKEUP, 2562306a36Sopenharmony_ci}; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistruct pn532_uart_phy { 2962306a36Sopenharmony_ci struct serdev_device *serdev; 3062306a36Sopenharmony_ci struct sk_buff *recv_skb; 3162306a36Sopenharmony_ci struct pn533 *priv; 3262306a36Sopenharmony_ci /* 3362306a36Sopenharmony_ci * send_wakeup variable is used to control if we need to send a wakeup 3462306a36Sopenharmony_ci * request to the pn532 chip prior to our actual command. There is a 3562306a36Sopenharmony_ci * little propability of a race condition. We decided to not mutex the 3662306a36Sopenharmony_ci * variable as the worst that could happen is, that we send a wakeup 3762306a36Sopenharmony_ci * to the chip that is already awake. This does not hurt. It is a 3862306a36Sopenharmony_ci * no-op to the chip. 3962306a36Sopenharmony_ci */ 4062306a36Sopenharmony_ci enum send_wakeup send_wakeup; 4162306a36Sopenharmony_ci struct timer_list cmd_timeout; 4262306a36Sopenharmony_ci struct sk_buff *cur_out_buf; 4362306a36Sopenharmony_ci}; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic int pn532_uart_send_frame(struct pn533 *dev, 4662306a36Sopenharmony_ci struct sk_buff *out) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci /* wakeup sequence and dummy bytes for waiting time */ 4962306a36Sopenharmony_ci static const u8 wakeup[] = { 5062306a36Sopenharmony_ci 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 5162306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 5262306a36Sopenharmony_ci struct pn532_uart_phy *pn532 = dev->phy; 5362306a36Sopenharmony_ci int err; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci print_hex_dump_debug("PN532_uart TX: ", DUMP_PREFIX_NONE, 16, 1, 5662306a36Sopenharmony_ci out->data, out->len, false); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci pn532->cur_out_buf = out; 5962306a36Sopenharmony_ci if (pn532->send_wakeup) { 6062306a36Sopenharmony_ci err = serdev_device_write(pn532->serdev, 6162306a36Sopenharmony_ci wakeup, sizeof(wakeup), 6262306a36Sopenharmony_ci MAX_SCHEDULE_TIMEOUT); 6362306a36Sopenharmony_ci if (err < 0) 6462306a36Sopenharmony_ci return err; 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci if (pn532->send_wakeup == PN532_SEND_LAST_WAKEUP) 6862306a36Sopenharmony_ci pn532->send_wakeup = PN532_SEND_NO_WAKEUP; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci err = serdev_device_write(pn532->serdev, out->data, out->len, 7162306a36Sopenharmony_ci MAX_SCHEDULE_TIMEOUT); 7262306a36Sopenharmony_ci if (err < 0) 7362306a36Sopenharmony_ci return err; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci mod_timer(&pn532->cmd_timeout, HZ / 40 + jiffies); 7662306a36Sopenharmony_ci return 0; 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic int pn532_uart_send_ack(struct pn533 *dev, gfp_t flags) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci /* spec 7.1.1.3: Preamble, SoPC (2), ACK Code (2), Postamble */ 8262306a36Sopenharmony_ci static const u8 ack[PN533_STD_FRAME_ACK_SIZE] = { 8362306a36Sopenharmony_ci 0x00, 0x00, 0xff, 0x00, 0xff, 0x00}; 8462306a36Sopenharmony_ci struct pn532_uart_phy *pn532 = dev->phy; 8562306a36Sopenharmony_ci int err; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci err = serdev_device_write(pn532->serdev, ack, sizeof(ack), 8862306a36Sopenharmony_ci MAX_SCHEDULE_TIMEOUT); 8962306a36Sopenharmony_ci if (err < 0) 9062306a36Sopenharmony_ci return err; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci return 0; 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic void pn532_uart_abort_cmd(struct pn533 *dev, gfp_t flags) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci /* An ack will cancel the last issued command */ 9862306a36Sopenharmony_ci pn532_uart_send_ack(dev, flags); 9962306a36Sopenharmony_ci /* schedule cmd_complete_work to finish current command execution */ 10062306a36Sopenharmony_ci pn533_recv_frame(dev, NULL, -ENOENT); 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic int pn532_dev_up(struct pn533 *dev) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci struct pn532_uart_phy *pn532 = dev->phy; 10662306a36Sopenharmony_ci int ret = 0; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci ret = serdev_device_open(pn532->serdev); 10962306a36Sopenharmony_ci if (ret) 11062306a36Sopenharmony_ci return ret; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci pn532->send_wakeup = PN532_SEND_LAST_WAKEUP; 11362306a36Sopenharmony_ci return ret; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic int pn532_dev_down(struct pn533 *dev) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci struct pn532_uart_phy *pn532 = dev->phy; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci serdev_device_close(pn532->serdev); 12162306a36Sopenharmony_ci pn532->send_wakeup = PN532_SEND_WAKEUP; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci return 0; 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic const struct pn533_phy_ops uart_phy_ops = { 12762306a36Sopenharmony_ci .send_frame = pn532_uart_send_frame, 12862306a36Sopenharmony_ci .send_ack = pn532_uart_send_ack, 12962306a36Sopenharmony_ci .abort_cmd = pn532_uart_abort_cmd, 13062306a36Sopenharmony_ci .dev_up = pn532_dev_up, 13162306a36Sopenharmony_ci .dev_down = pn532_dev_down, 13262306a36Sopenharmony_ci}; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic void pn532_cmd_timeout(struct timer_list *t) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci struct pn532_uart_phy *dev = from_timer(dev, t, cmd_timeout); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci pn532_uart_send_frame(dev->priv, dev->cur_out_buf); 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci/* 14262306a36Sopenharmony_ci * scans the buffer if it contains a pn532 frame. It is not checked if the 14362306a36Sopenharmony_ci * frame is really valid. This is later done with pn533_rx_frame_is_valid. 14462306a36Sopenharmony_ci * This is useful for malformed or errornous transmitted frames. Adjusts the 14562306a36Sopenharmony_ci * bufferposition where the frame starts, since pn533_recv_frame expects a 14662306a36Sopenharmony_ci * well formed frame. 14762306a36Sopenharmony_ci */ 14862306a36Sopenharmony_cistatic int pn532_uart_rx_is_frame(struct sk_buff *skb) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci struct pn533_std_frame *std; 15162306a36Sopenharmony_ci struct pn533_ext_frame *ext; 15262306a36Sopenharmony_ci u16 frame_len; 15362306a36Sopenharmony_ci int i; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci for (i = 0; i + PN533_STD_FRAME_ACK_SIZE <= skb->len; i++) { 15662306a36Sopenharmony_ci std = (struct pn533_std_frame *)&skb->data[i]; 15762306a36Sopenharmony_ci /* search start code */ 15862306a36Sopenharmony_ci if (std->start_frame != cpu_to_be16(PN533_STD_FRAME_SOF)) 15962306a36Sopenharmony_ci continue; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci /* frame type */ 16262306a36Sopenharmony_ci switch (std->datalen) { 16362306a36Sopenharmony_ci case PN533_FRAME_DATALEN_ACK: 16462306a36Sopenharmony_ci if (std->datalen_checksum == 0xff) { 16562306a36Sopenharmony_ci skb_pull(skb, i); 16662306a36Sopenharmony_ci return 1; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci break; 17062306a36Sopenharmony_ci case PN533_FRAME_DATALEN_ERROR: 17162306a36Sopenharmony_ci if ((std->datalen_checksum == 0xff) && 17262306a36Sopenharmony_ci (skb->len >= 17362306a36Sopenharmony_ci PN533_STD_ERROR_FRAME_SIZE)) { 17462306a36Sopenharmony_ci skb_pull(skb, i); 17562306a36Sopenharmony_ci return 1; 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci break; 17962306a36Sopenharmony_ci case PN533_FRAME_DATALEN_EXTENDED: 18062306a36Sopenharmony_ci ext = (struct pn533_ext_frame *)&skb->data[i]; 18162306a36Sopenharmony_ci frame_len = be16_to_cpu(ext->datalen); 18262306a36Sopenharmony_ci if (skb->len >= frame_len + 18362306a36Sopenharmony_ci sizeof(struct pn533_ext_frame) + 18462306a36Sopenharmony_ci 2 /* CKS + Postamble */) { 18562306a36Sopenharmony_ci skb_pull(skb, i); 18662306a36Sopenharmony_ci return 1; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci break; 19062306a36Sopenharmony_ci default: /* normal information frame */ 19162306a36Sopenharmony_ci frame_len = std->datalen; 19262306a36Sopenharmony_ci if (skb->len >= frame_len + 19362306a36Sopenharmony_ci sizeof(struct pn533_std_frame) + 19462306a36Sopenharmony_ci 2 /* CKS + Postamble */) { 19562306a36Sopenharmony_ci skb_pull(skb, i); 19662306a36Sopenharmony_ci return 1; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci break; 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci return 0; 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic int pn532_receive_buf(struct serdev_device *serdev, 20762306a36Sopenharmony_ci const unsigned char *data, size_t count) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci struct pn532_uart_phy *dev = serdev_device_get_drvdata(serdev); 21062306a36Sopenharmony_ci size_t i; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci del_timer(&dev->cmd_timeout); 21362306a36Sopenharmony_ci for (i = 0; i < count; i++) { 21462306a36Sopenharmony_ci skb_put_u8(dev->recv_skb, *data++); 21562306a36Sopenharmony_ci if (!pn532_uart_rx_is_frame(dev->recv_skb)) 21662306a36Sopenharmony_ci continue; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci pn533_recv_frame(dev->priv, dev->recv_skb, 0); 21962306a36Sopenharmony_ci dev->recv_skb = alloc_skb(PN532_UART_SKB_BUFF_LEN, GFP_KERNEL); 22062306a36Sopenharmony_ci if (!dev->recv_skb) 22162306a36Sopenharmony_ci return 0; 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci return i; 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic const struct serdev_device_ops pn532_serdev_ops = { 22862306a36Sopenharmony_ci .receive_buf = pn532_receive_buf, 22962306a36Sopenharmony_ci .write_wakeup = serdev_device_write_wakeup, 23062306a36Sopenharmony_ci}; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic const struct of_device_id pn532_uart_of_match[] = { 23362306a36Sopenharmony_ci { .compatible = "nxp,pn532", }, 23462306a36Sopenharmony_ci {}, 23562306a36Sopenharmony_ci}; 23662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, pn532_uart_of_match); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cistatic int pn532_uart_probe(struct serdev_device *serdev) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci struct pn532_uart_phy *pn532; 24162306a36Sopenharmony_ci struct pn533 *priv; 24262306a36Sopenharmony_ci int err; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci err = -ENOMEM; 24562306a36Sopenharmony_ci pn532 = kzalloc(sizeof(*pn532), GFP_KERNEL); 24662306a36Sopenharmony_ci if (!pn532) 24762306a36Sopenharmony_ci goto err_exit; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci pn532->recv_skb = alloc_skb(PN532_UART_SKB_BUFF_LEN, GFP_KERNEL); 25062306a36Sopenharmony_ci if (!pn532->recv_skb) 25162306a36Sopenharmony_ci goto err_free; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci pn532->serdev = serdev; 25462306a36Sopenharmony_ci serdev_device_set_drvdata(serdev, pn532); 25562306a36Sopenharmony_ci serdev_device_set_client_ops(serdev, &pn532_serdev_ops); 25662306a36Sopenharmony_ci err = serdev_device_open(serdev); 25762306a36Sopenharmony_ci if (err) { 25862306a36Sopenharmony_ci dev_err(&serdev->dev, "Unable to open device\n"); 25962306a36Sopenharmony_ci goto err_skb; 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci err = serdev_device_set_baudrate(serdev, 115200); 26362306a36Sopenharmony_ci if (err != 115200) { 26462306a36Sopenharmony_ci err = -EINVAL; 26562306a36Sopenharmony_ci goto err_serdev; 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci serdev_device_set_flow_control(serdev, false); 26962306a36Sopenharmony_ci pn532->send_wakeup = PN532_SEND_WAKEUP; 27062306a36Sopenharmony_ci timer_setup(&pn532->cmd_timeout, pn532_cmd_timeout, 0); 27162306a36Sopenharmony_ci priv = pn53x_common_init(PN533_DEVICE_PN532_AUTOPOLL, 27262306a36Sopenharmony_ci PN533_PROTO_REQ_ACK_RESP, 27362306a36Sopenharmony_ci pn532, &uart_phy_ops, NULL, 27462306a36Sopenharmony_ci &pn532->serdev->dev); 27562306a36Sopenharmony_ci if (IS_ERR(priv)) { 27662306a36Sopenharmony_ci err = PTR_ERR(priv); 27762306a36Sopenharmony_ci goto err_serdev; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci pn532->priv = priv; 28162306a36Sopenharmony_ci err = pn533_finalize_setup(pn532->priv); 28262306a36Sopenharmony_ci if (err) 28362306a36Sopenharmony_ci goto err_clean; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci serdev_device_close(serdev); 28662306a36Sopenharmony_ci err = pn53x_register_nfc(priv, PN533_NO_TYPE_B_PROTOCOLS, &serdev->dev); 28762306a36Sopenharmony_ci if (err) { 28862306a36Sopenharmony_ci pn53x_common_clean(pn532->priv); 28962306a36Sopenharmony_ci goto err_skb; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci return err; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cierr_clean: 29562306a36Sopenharmony_ci pn53x_common_clean(pn532->priv); 29662306a36Sopenharmony_cierr_serdev: 29762306a36Sopenharmony_ci serdev_device_close(serdev); 29862306a36Sopenharmony_cierr_skb: 29962306a36Sopenharmony_ci kfree_skb(pn532->recv_skb); 30062306a36Sopenharmony_cierr_free: 30162306a36Sopenharmony_ci kfree(pn532); 30262306a36Sopenharmony_cierr_exit: 30362306a36Sopenharmony_ci return err; 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cistatic void pn532_uart_remove(struct serdev_device *serdev) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci struct pn532_uart_phy *pn532 = serdev_device_get_drvdata(serdev); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci pn53x_unregister_nfc(pn532->priv); 31162306a36Sopenharmony_ci serdev_device_close(serdev); 31262306a36Sopenharmony_ci pn53x_common_clean(pn532->priv); 31362306a36Sopenharmony_ci timer_shutdown_sync(&pn532->cmd_timeout); 31462306a36Sopenharmony_ci kfree_skb(pn532->recv_skb); 31562306a36Sopenharmony_ci kfree(pn532); 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_cistatic struct serdev_device_driver pn532_uart_driver = { 31962306a36Sopenharmony_ci .probe = pn532_uart_probe, 32062306a36Sopenharmony_ci .remove = pn532_uart_remove, 32162306a36Sopenharmony_ci .driver = { 32262306a36Sopenharmony_ci .name = "pn532_uart", 32362306a36Sopenharmony_ci .of_match_table = pn532_uart_of_match, 32462306a36Sopenharmony_ci }, 32562306a36Sopenharmony_ci}; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cimodule_serdev_device_driver(pn532_uart_driver); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ciMODULE_AUTHOR("Lars Pöschel <poeschel@lemonage.de>"); 33062306a36Sopenharmony_ciMODULE_DESCRIPTION("PN532 UART driver"); 33162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 332