2019-10-29 17:47:14 +03:00
// 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 ) ;
}
2019-11-13 16:50:22 +03:00
static int pn532_dev_up ( struct pn533 * dev )
2019-10-29 17:47:14 +03:00
{
struct pn532_uart_phy * pn532 = dev - > phy ;
2019-11-13 16:50:22 +03:00
int ret = 0 ;
ret = serdev_device_open ( pn532 - > serdev ) ;
if ( ret )
return ret ;
2019-10-29 17:47:14 +03:00
pn532 - > send_wakeup = PN532_SEND_LAST_WAKEUP ;
2019-11-13 16:50:22 +03:00
return ret ;
2019-10-29 17:47:14 +03:00
}
2019-11-13 16:50:22 +03:00
static int pn532_dev_down ( struct pn533 * dev )
2019-10-29 17:47:14 +03:00
{
struct pn532_uart_phy * pn532 = dev - > phy ;
serdev_device_close ( pn532 - > serdev ) ;
pn532 - > send_wakeup = PN532_SEND_WAKEUP ;
2019-11-13 16:50:22 +03:00
return 0 ;
2019-10-29 17:47:14 +03:00
}
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 ) ;
2019-10-29 17:48:02 +03:00
priv = pn53x_common_init ( PN533_DEVICE_PN532_AUTOPOLL ,
2019-10-29 17:47:14 +03:00
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 " ) ;