2014-01-07 00:58:19 +04:00
/*
* Marvell NFC driver : major functions
*
2015-10-26 12:27:37 +03:00
* Copyright ( C ) 2014 - 2015 Marvell International Ltd .
2014-01-07 00:58:19 +04:00
*
* This software file ( the " File " ) is distributed by Marvell International
* Ltd . under the terms of the GNU General Public License Version 2 , June 1991
* ( the " License " ) . You may use , redistribute and / or modify this File in
* accordance with the terms and conditions of the License , a copy of which
* is available on the worldwide web at
* http : //www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* THE FILE IS DISTRIBUTED AS - IS , WITHOUT WARRANTY OF ANY KIND , AND THE
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
* ARE EXPRESSLY DISCLAIMED . The License provides additional details about
* this warranty disclaimer .
*/
# include <linux/module.h>
2015-06-11 12:25:46 +03:00
# include <linux/gpio.h>
# include <linux/delay.h>
2015-06-11 15:00:19 +03:00
# include <linux/of_gpio.h>
2014-01-07 00:58:19 +04:00
# include <linux/nfc.h>
# include <net/nfc/nci.h>
# include <net/nfc/nci_core.h>
# include "nfcmrvl.h"
static int nfcmrvl_nci_open ( struct nci_dev * ndev )
{
struct nfcmrvl_private * priv = nci_get_drvdata ( ndev ) ;
int err ;
if ( test_and_set_bit ( NFCMRVL_NCI_RUNNING , & priv - > flags ) )
return 0 ;
2015-10-26 12:27:41 +03:00
/* Reset possible fault of previous session */
clear_bit ( NFCMRVL_PHY_ERROR , & priv - > flags ) ;
2014-01-07 00:58:19 +04:00
err = priv - > if_ops - > nci_open ( priv ) ;
if ( err )
clear_bit ( NFCMRVL_NCI_RUNNING , & priv - > flags ) ;
return err ;
}
static int nfcmrvl_nci_close ( struct nci_dev * ndev )
{
struct nfcmrvl_private * priv = nci_get_drvdata ( ndev ) ;
if ( ! test_and_clear_bit ( NFCMRVL_NCI_RUNNING , & priv - > flags ) )
return 0 ;
priv - > if_ops - > nci_close ( priv ) ;
return 0 ;
}
static int nfcmrvl_nci_send ( struct nci_dev * ndev , struct sk_buff * skb )
{
struct nfcmrvl_private * priv = nci_get_drvdata ( ndev ) ;
nfc_info ( priv - > dev , " send entry, len %d \n " , skb - > len ) ;
skb - > dev = ( void * ) ndev ;
2015-06-11 15:00:19 +03:00
if ( priv - > config . hci_muxed ) {
2015-06-11 12:25:43 +03:00
unsigned char * hdr ;
unsigned char len = skb - > len ;
networking: make skb_push & __skb_push return void pointers
It seems like a historic accident that these return unsigned char *,
and in many places that means casts are required, more often than not.
Make these functions return void * and remove all the casts across
the tree, adding a (u8 *) cast only where the unsigned char pointer
was used directly, all done with the following spatch:
@@
expression SKB, LEN;
typedef u8;
identifier fn = { skb_push, __skb_push, skb_push_rcsum };
@@
- *(fn(SKB, LEN))
+ *(u8 *)fn(SKB, LEN)
@@
expression E, SKB, LEN;
identifier fn = { skb_push, __skb_push, skb_push_rcsum };
type T;
@@
- E = ((T *)(fn(SKB, LEN)))
+ E = fn(SKB, LEN)
@@
expression SKB, LEN;
identifier fn = { skb_push, __skb_push, skb_push_rcsum };
@@
- fn(SKB, LEN)[0]
+ *(u8 *)fn(SKB, LEN)
Note that the last part there converts from push(...)[0] to the
more idiomatic *(u8 *)push(...).
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-06-16 15:29:23 +03:00
hdr = skb_push ( skb , NFCMRVL_HCI_EVENT_HEADER_SIZE ) ;
2015-06-11 12:25:43 +03:00
hdr [ 0 ] = NFCMRVL_HCI_COMMAND_CODE ;
hdr [ 1 ] = NFCMRVL_HCI_OGF ;
hdr [ 2 ] = NFCMRVL_HCI_OCF ;
hdr [ 3 ] = len ;
}
2014-01-07 00:58:19 +04:00
return priv - > if_ops - > nci_send ( priv , skb ) ;
}
2014-01-07 00:58:20 +04:00
static int nfcmrvl_nci_setup ( struct nci_dev * ndev )
{
2015-06-12 16:35:54 +03:00
__u8 val = 1 ;
nci_set_config ( ndev , NFCMRVL_PB_BAIL_OUT , 1 , & val ) ;
2014-01-07 00:58:20 +04:00
return 0 ;
}
2015-10-26 12:27:39 +03:00
static int nfcmrvl_nci_fw_download ( struct nci_dev * ndev ,
const char * firmware_name )
{
return nfcmrvl_fw_dnld_start ( ndev , firmware_name ) ;
}
2014-01-07 00:58:19 +04:00
static struct nci_ops nfcmrvl_nci_ops = {
. open = nfcmrvl_nci_open ,
. close = nfcmrvl_nci_close ,
. send = nfcmrvl_nci_send ,
2014-01-07 00:58:20 +04:00
. setup = nfcmrvl_nci_setup ,
2015-10-26 12:27:39 +03:00
. fw_download = nfcmrvl_nci_fw_download ,
2014-01-07 00:58:19 +04:00
} ;
2015-10-26 12:27:40 +03:00
struct nfcmrvl_private * nfcmrvl_nci_register_dev ( enum nfcmrvl_phy phy ,
void * drv_data ,
2015-06-11 15:00:19 +03:00
struct nfcmrvl_if_ops * ops ,
struct device * dev ,
struct nfcmrvl_platform_data * pdata )
2014-01-07 00:58:19 +04:00
{
struct nfcmrvl_private * priv ;
int rc ;
2015-10-26 12:27:40 +03:00
int headroom ;
int tailroom ;
2014-01-07 00:58:19 +04:00
u32 protocols ;
priv = kzalloc ( sizeof ( * priv ) , GFP_KERNEL ) ;
if ( ! priv )
return ERR_PTR ( - ENOMEM ) ;
priv - > drv_data = drv_data ;
priv - > if_ops = ops ;
priv - > dev = dev ;
2015-10-26 12:27:40 +03:00
priv - > phy = phy ;
2015-06-11 12:25:46 +03:00
2015-06-11 15:00:19 +03:00
memcpy ( & priv - > config , pdata , sizeof ( * pdata ) ) ;
if ( priv - > config . reset_n_io ) {
2015-06-11 12:25:46 +03:00
rc = devm_gpio_request_one ( dev ,
2015-06-11 15:00:19 +03:00
priv - > config . reset_n_io ,
2015-06-11 12:25:46 +03:00
GPIOF_OUT_INIT_LOW ,
" nfcmrvl_reset_n " ) ;
if ( rc < 0 )
nfc_err ( dev , " failed to request reset_n io \n " ) ;
}
2015-06-11 12:25:43 +03:00
2015-10-26 12:27:44 +03:00
if ( phy = = NFCMRVL_PHY_SPI ) {
headroom = NCI_SPI_HDR_LEN ;
tailroom = 1 ;
} else
headroom = tailroom = 0 ;
2015-10-26 12:27:40 +03:00
2015-06-11 15:00:19 +03:00
if ( priv - > config . hci_muxed )
2015-10-26 12:27:40 +03:00
headroom + = NFCMRVL_HCI_EVENT_HEADER_SIZE ;
2014-01-07 00:58:19 +04:00
protocols = NFC_PROTO_JEWEL_MASK
2015-06-11 15:00:19 +03:00
| NFC_PROTO_MIFARE_MASK
| NFC_PROTO_FELICA_MASK
2014-01-07 00:58:19 +04:00
| NFC_PROTO_ISO14443_MASK
| NFC_PROTO_ISO14443_B_MASK
2015-06-12 16:35:52 +03:00
| NFC_PROTO_ISO15693_MASK
2014-01-07 00:58:19 +04:00
| NFC_PROTO_NFC_DEP_MASK ;
2015-06-11 12:25:43 +03:00
priv - > ndev = nci_allocate_device ( & nfcmrvl_nci_ops , protocols ,
2015-10-26 12:27:40 +03:00
headroom , tailroom ) ;
2014-01-07 00:58:19 +04:00
if ( ! priv - > ndev ) {
2015-04-07 10:17:00 +03:00
nfc_err ( dev , " nci_allocate_device failed \n " ) ;
2014-01-08 22:52:27 +04:00
rc = - ENOMEM ;
goto error ;
2014-01-07 00:58:19 +04:00
}
nci_set_drvdata ( priv - > ndev , priv ) ;
rc = nci_register_device ( priv - > ndev ) ;
if ( rc ) {
2015-04-07 10:17:00 +03:00
nfc_err ( dev , " nci_register_device failed %d \n " , rc ) ;
2015-10-26 12:27:39 +03:00
goto error_free_dev ;
}
/* Ensure that controller is powered off */
nfcmrvl_chip_halt ( priv ) ;
rc = nfcmrvl_fw_dnld_init ( priv ) ;
if ( rc ) {
nfc_err ( dev , " failed to initialize FW download %d \n " , rc ) ;
goto error_free_dev ;
2014-01-07 00:58:19 +04:00
}
nfc_info ( dev , " registered with nci successfully \n " ) ;
return priv ;
2014-01-08 22:52:27 +04:00
2015-10-26 12:27:39 +03:00
error_free_dev :
nci_free_device ( priv - > ndev ) ;
2014-01-08 22:52:27 +04:00
error :
kfree ( priv ) ;
return ERR_PTR ( rc ) ;
2014-01-07 00:58:19 +04:00
}
EXPORT_SYMBOL_GPL ( nfcmrvl_nci_register_dev ) ;
void nfcmrvl_nci_unregister_dev ( struct nfcmrvl_private * priv )
{
struct nci_dev * ndev = priv - > ndev ;
2015-10-26 12:27:39 +03:00
if ( priv - > ndev - > nfc_dev - > fw_download_in_progress )
nfcmrvl_fw_dnld_abort ( priv ) ;
nfcmrvl_fw_dnld_deinit ( priv ) ;
2015-11-03 21:19:34 +03:00
if ( priv - > config . reset_n_io )
devm_gpio_free ( priv - > dev , priv - > config . reset_n_io ) ;
2014-01-07 00:58:19 +04:00
nci_unregister_device ( ndev ) ;
nci_free_device ( ndev ) ;
kfree ( priv ) ;
}
EXPORT_SYMBOL_GPL ( nfcmrvl_nci_unregister_dev ) ;
2015-06-11 12:25:44 +03:00
int nfcmrvl_nci_recv_frame ( struct nfcmrvl_private * priv , struct sk_buff * skb )
2014-01-07 00:58:19 +04:00
{
2015-06-11 15:00:19 +03:00
if ( priv - > config . hci_muxed ) {
2015-06-11 12:25:43 +03:00
if ( skb - > data [ 0 ] = = NFCMRVL_HCI_EVENT_CODE & &
skb - > data [ 1 ] = = NFCMRVL_HCI_NFC_EVENT_CODE ) {
/* Data packet, let's extract NCI payload */
skb_pull ( skb , NFCMRVL_HCI_EVENT_HEADER_SIZE ) ;
} else {
/* Skip this packet */
kfree_skb ( skb ) ;
return 0 ;
}
}
2015-10-26 12:27:39 +03:00
if ( priv - > ndev - > nfc_dev - > fw_download_in_progress ) {
nfcmrvl_fw_dnld_recv_frame ( priv , skb ) ;
return 0 ;
}
2015-06-11 12:25:44 +03:00
if ( test_bit ( NFCMRVL_NCI_RUNNING , & priv - > flags ) )
nci_recv_frame ( priv - > ndev , skb ) ;
else {
/* Drop this packet since nobody wants it */
kfree_skb ( skb ) ;
return 0 ;
}
2014-01-07 00:58:19 +04:00
2015-06-11 12:25:44 +03:00
return 0 ;
2014-01-07 00:58:19 +04:00
}
EXPORT_SYMBOL_GPL ( nfcmrvl_nci_recv_frame ) ;
2015-06-11 12:25:46 +03:00
void nfcmrvl_chip_reset ( struct nfcmrvl_private * priv )
{
2015-10-26 12:27:41 +03:00
/* Reset possible fault of previous session */
clear_bit ( NFCMRVL_PHY_ERROR , & priv - > flags ) ;
2015-06-11 12:25:46 +03:00
2015-06-11 15:00:19 +03:00
if ( priv - > config . reset_n_io ) {
2015-06-11 12:25:46 +03:00
nfc_info ( priv - > dev , " reset the chip \n " ) ;
2015-06-11 15:00:19 +03:00
gpio_set_value ( priv - > config . reset_n_io , 0 ) ;
2015-06-11 12:25:46 +03:00
usleep_range ( 5000 , 10000 ) ;
2015-06-11 15:00:19 +03:00
gpio_set_value ( priv - > config . reset_n_io , 1 ) ;
2015-06-11 12:25:46 +03:00
} else
nfc_info ( priv - > dev , " no reset available on this interface \n " ) ;
}
2015-10-26 12:27:39 +03:00
void nfcmrvl_chip_halt ( struct nfcmrvl_private * priv )
{
if ( priv - > config . reset_n_io )
gpio_set_value ( priv - > config . reset_n_io , 0 ) ;
}
2015-06-11 15:00:19 +03:00
int nfcmrvl_parse_dt ( struct device_node * node ,
struct nfcmrvl_platform_data * pdata )
{
int reset_n_io ;
reset_n_io = of_get_named_gpio ( node , " reset-n-io " , 0 ) ;
if ( reset_n_io < 0 ) {
pr_info ( " no reset-n-io config \n " ) ;
reset_n_io = 0 ;
} else if ( ! gpio_is_valid ( reset_n_io ) ) {
pr_err ( " invalid reset-n-io GPIO \n " ) ;
return reset_n_io ;
}
pdata - > reset_n_io = reset_n_io ;
if ( of_find_property ( node , " hci-muxed " , NULL ) )
pdata - > hci_muxed = 1 ;
else
pdata - > hci_muxed = 0 ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( nfcmrvl_parse_dt ) ;
2014-01-07 00:58:19 +04:00
MODULE_AUTHOR ( " Marvell International Ltd. " ) ;
2015-10-26 12:27:37 +03:00
MODULE_DESCRIPTION ( " Marvell NFC driver " ) ;
2014-01-07 00:58:19 +04:00
MODULE_LICENSE ( " GPL v2 " ) ;