2021-05-31 09:35:14 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2021-05-24 02:39:09 +05:30
/*
2015-06-11 14:00:20 +02:00
* Marvell NFC - over - UART driver
*
* Copyright ( C ) 2015 , Marvell International Ltd .
*/
# include <linux/module.h>
# include <linux/delay.h>
# include <linux/of_gpio.h>
# include <net/nfc/nci.h>
# include <net/nfc/nci_core.h>
# include "nfcmrvl.h"
static unsigned int hci_muxed ;
static unsigned int flow_control ;
static unsigned int break_control ;
2019-08-05 12:00:55 +02:00
static int reset_n_io = - EINVAL ;
2015-06-11 14:00:20 +02:00
/*
2021-05-31 09:35:15 +02:00
* NFCMRVL NCI OPS
*/
2015-06-11 14:00:20 +02:00
static int nfcmrvl_uart_nci_open ( struct nfcmrvl_private * priv )
{
return 0 ;
}
static int nfcmrvl_uart_nci_close ( struct nfcmrvl_private * priv )
{
return 0 ;
}
static int nfcmrvl_uart_nci_send ( struct nfcmrvl_private * priv ,
struct sk_buff * skb )
{
struct nci_uart * nu = priv - > drv_data ;
return nu - > ops . send ( nu , skb ) ;
}
2015-10-26 10:27:39 +01:00
static void nfcmrvl_uart_nci_update_config ( struct nfcmrvl_private * priv ,
const void * param )
{
struct nci_uart * nu = priv - > drv_data ;
const struct nfcmrvl_fw_uart_config * config = param ;
nci_uart_set_config ( nu , le32_to_cpu ( config - > baudrate ) ,
config - > flow_control ) ;
}
2021-07-29 12:42:41 +02:00
static const struct nfcmrvl_if_ops uart_ops = {
2015-06-11 14:00:20 +02:00
. nci_open = nfcmrvl_uart_nci_open ,
. nci_close = nfcmrvl_uart_nci_close ,
. nci_send = nfcmrvl_uart_nci_send ,
2015-10-26 10:27:39 +01:00
. nci_update_config = nfcmrvl_uart_nci_update_config
2015-06-11 14:00:20 +02:00
} ;
static int nfcmrvl_uart_parse_dt ( struct device_node * node ,
struct nfcmrvl_platform_data * pdata )
{
struct device_node * matched_node ;
int ret ;
2018-08-27 10:21:52 +02:00
matched_node = of_get_compatible_child ( node , " marvell,nfc-uart " ) ;
2015-10-26 10:27:45 +01:00
if ( ! matched_node ) {
2018-08-27 10:21:52 +02:00
matched_node = of_get_compatible_child ( node , " mrvl,nfc-uart " ) ;
2015-10-26 10:27:45 +01:00
if ( ! matched_node )
return - ENODEV ;
}
2015-06-11 14:00:20 +02:00
ret = nfcmrvl_parse_dt ( matched_node , pdata ) ;
if ( ret < 0 ) {
pr_err ( " Failed to get generic entries \n " ) ;
2017-03-30 12:15:40 +02:00
of_node_put ( matched_node ) ;
2015-06-11 14:00:20 +02:00
return ret ;
}
if ( of_find_property ( matched_node , " flow-control " , NULL ) )
pdata - > flow_control = 1 ;
else
pdata - > flow_control = 0 ;
if ( of_find_property ( matched_node , " break-control " , NULL ) )
pdata - > break_control = 1 ;
else
pdata - > break_control = 0 ;
2017-03-30 12:15:40 +02:00
of_node_put ( matched_node ) ;
2015-06-11 14:00:20 +02:00
return 0 ;
}
/*
2021-05-31 09:35:15 +02:00
* NCI UART OPS
*/
2015-06-11 14:00:20 +02:00
static int nfcmrvl_nci_uart_open ( struct nci_uart * nu )
{
struct nfcmrvl_private * priv ;
struct nfcmrvl_platform_data config ;
2021-07-29 12:40:21 +02:00
const struct nfcmrvl_platform_data * pdata = NULL ;
2017-03-30 12:15:36 +02:00
struct device * dev = nu - > tty - > dev ;
2015-06-11 14:00:20 +02:00
/*
* Platform data cannot be used here since usually it is already used
* by low level serial driver . We can try to retrieve serial device
* and check if DT entries were added .
*/
2017-03-30 12:15:36 +02:00
if ( dev & & dev - > parent & & dev - > parent - > of_node )
if ( nfcmrvl_uart_parse_dt ( dev - > parent - > of_node , & config ) = = 0 )
2015-06-11 14:00:20 +02:00
pdata = & config ;
if ( ! pdata ) {
pr_info ( " No platform data / DT -> fallback to module params \n " ) ;
config . hci_muxed = hci_muxed ;
config . reset_n_io = reset_n_io ;
config . flow_control = flow_control ;
config . break_control = break_control ;
pdata = & config ;
}
2015-10-26 10:27:40 +01:00
priv = nfcmrvl_nci_register_dev ( NFCMRVL_PHY_UART , nu , & uart_ops ,
2017-03-30 12:15:36 +02:00
dev , pdata ) ;
2015-06-11 14:00:20 +02:00
if ( IS_ERR ( priv ) )
return PTR_ERR ( priv ) ;
2015-10-26 10:27:39 +01:00
priv - > support_fw_dnld = true ;
2015-06-11 14:00:20 +02:00
nu - > drv_data = priv ;
nu - > ndev = priv - > ndev ;
return 0 ;
}
static void nfcmrvl_nci_uart_close ( struct nci_uart * nu )
{
nfcmrvl_nci_unregister_dev ( ( struct nfcmrvl_private * ) nu - > drv_data ) ;
}
static int nfcmrvl_nci_uart_recv ( struct nci_uart * nu , struct sk_buff * skb )
{
return nfcmrvl_nci_recv_frame ( ( struct nfcmrvl_private * ) nu - > drv_data ,
skb ) ;
}
static void nfcmrvl_nci_uart_tx_start ( struct nci_uart * nu )
{
struct nfcmrvl_private * priv = ( struct nfcmrvl_private * ) nu - > drv_data ;
2015-11-03 19:19:32 +01:00
if ( priv - > ndev - > nfc_dev - > fw_download_in_progress )
return ;
2015-06-11 14:00:20 +02:00
/* Remove BREAK to wake up the NFCC */
if ( priv - > config . break_control & & nu - > tty - > ops - > break_ctl ) {
nu - > tty - > ops - > break_ctl ( nu - > tty , 0 ) ;
usleep_range ( 3000 , 5000 ) ;
}
}
static void nfcmrvl_nci_uart_tx_done ( struct nci_uart * nu )
{
struct nfcmrvl_private * priv = ( struct nfcmrvl_private * ) nu - > drv_data ;
2015-11-03 19:19:32 +01:00
if ( priv - > ndev - > nfc_dev - > fw_download_in_progress )
return ;
2015-06-11 14:00:20 +02:00
/*
2021-05-31 09:35:15 +02:00
* To ensure that if the NFCC goes in DEEP SLEEP sate we can wake him
* up . we set BREAK . Once we will be ready to send again we will remove
* it .
*/
2015-11-03 19:19:33 +01:00
if ( priv - > config . break_control & & nu - > tty - > ops - > break_ctl ) {
2015-06-11 14:00:20 +02:00
nu - > tty - > ops - > break_ctl ( nu - > tty , - 1 ) ;
2015-11-03 19:19:33 +01:00
usleep_range ( 1000 , 3000 ) ;
}
2015-06-11 14:00:20 +02:00
}
static struct nci_uart nfcmrvl_nci_uart = {
. owner = THIS_MODULE ,
. name = " nfcmrvl_uart " ,
. driver = NCI_UART_DRIVER_MARVELL ,
. ops = {
. open = nfcmrvl_nci_uart_open ,
. close = nfcmrvl_nci_uart_close ,
. recv = nfcmrvl_nci_uart_recv ,
. tx_start = nfcmrvl_nci_uart_tx_start ,
. tx_done = nfcmrvl_nci_uart_tx_done ,
}
} ;
2021-05-31 09:38:56 +02:00
module_driver ( nfcmrvl_nci_uart , nci_uart_register , nci_uart_unregister ) ;
2015-06-11 14:00:20 +02:00
MODULE_AUTHOR ( " Marvell International Ltd. " ) ;
MODULE_DESCRIPTION ( " Marvell NFC-over-UART " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
module_param ( flow_control , uint , 0 ) ;
MODULE_PARM_DESC ( flow_control , " Tell if UART needs flow control at init. " ) ;
module_param ( break_control , uint , 0 ) ;
MODULE_PARM_DESC ( break_control , " Tell if UART driver must drive break signal. " ) ;
module_param ( hci_muxed , uint , 0 ) ;
MODULE_PARM_DESC ( hci_muxed , " Tell if transport is muxed in HCI one. " ) ;
2019-08-05 12:00:55 +02:00
module_param ( reset_n_io , int , 0 ) ;
2015-06-11 14:00:20 +02:00
MODULE_PARM_DESC ( reset_n_io , " GPIO that is wired to RESET_N signal. " ) ;