2014-05-26 00:35:38 +04:00
/*
* I2C Link Layer for ST21NFCB NCI based Driver
* Copyright ( C ) 2014 STMicroelectronics SAS . All rights reserved .
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms and conditions of the GNU General Public License ,
* version 2 , as published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
*/
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
# include <linux/module.h>
# include <linux/i2c.h>
# include <linux/gpio.h>
# include <linux/of_irq.h>
# include <linux/of_gpio.h>
# include <linux/interrupt.h>
# include <linux/delay.h>
# include <linux/nfc.h>
# include <linux/platform_data/st21nfcb.h>
# include "ndlc.h"
# define DRIVER_DESC "NCI NFC driver for ST21NFCB"
/* ndlc header */
# define ST21NFCB_FRAME_HEADROOM 1
# define ST21NFCB_FRAME_TAILROOM 0
# define ST21NFCB_NCI_I2C_MIN_SIZE 4 /* PCB(1) + NCI Packet header(3) */
# define ST21NFCB_NCI_I2C_MAX_SIZE 250 /* req 4.2.1 */
# define ST21NFCB_NCI_I2C_DRIVER_NAME "st21nfcb_nci_i2c"
static struct i2c_device_id st21nfcb_nci_i2c_id_table [ ] = {
{ ST21NFCB_NCI_DRIVER_NAME , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , st21nfcb_nci_i2c_id_table ) ;
struct st21nfcb_i2c_phy {
struct i2c_client * i2c_dev ;
struct llt_ndlc * ndlc ;
unsigned int gpio_irq ;
unsigned int gpio_reset ;
unsigned int irq_polarity ;
int powered ;
} ;
# define I2C_DUMP_SKB(info, skb) \
do { \
pr_debug ( " %s: \n " , info ) ; \
print_hex_dump ( KERN_DEBUG , " i2c: " , DUMP_PREFIX_OFFSET , \
16 , 1 , ( skb ) - > data , ( skb ) - > len , 0 ) ; \
} while ( 0 )
static int st21nfcb_nci_i2c_enable ( void * phy_id )
{
struct st21nfcb_i2c_phy * phy = phy_id ;
gpio_set_value ( phy - > gpio_reset , 0 ) ;
usleep_range ( 10000 , 15000 ) ;
gpio_set_value ( phy - > gpio_reset , 1 ) ;
phy - > powered = 1 ;
usleep_range ( 80000 , 85000 ) ;
return 0 ;
}
static void st21nfcb_nci_i2c_disable ( void * phy_id )
{
struct st21nfcb_i2c_phy * phy = phy_id ;
pr_info ( " \n " ) ;
phy - > powered = 0 ;
/* reset chip in order to flush clf */
gpio_set_value ( phy - > gpio_reset , 0 ) ;
usleep_range ( 10000 , 15000 ) ;
gpio_set_value ( phy - > gpio_reset , 1 ) ;
}
static void st21nfcb_nci_remove_header ( struct sk_buff * skb )
{
skb_pull ( skb , ST21NFCB_FRAME_HEADROOM ) ;
}
/*
* Writing a frame must not return the number of written bytes .
* It must return either zero for success , or < 0 for error .
* In addition , it must not alter the skb
*/
static int st21nfcb_nci_i2c_write ( void * phy_id , struct sk_buff * skb )
{
int r = - 1 ;
struct st21nfcb_i2c_phy * phy = phy_id ;
struct i2c_client * client = phy - > i2c_dev ;
I2C_DUMP_SKB ( " st21nfcb_nci_i2c_write " , skb ) ;
2014-09-13 12:28:47 +04:00
if ( phy - > ndlc - > hard_fault ! = 0 )
return phy - > ndlc - > hard_fault ;
2014-05-26 00:35:38 +04:00
r = i2c_master_send ( client , skb - > data , skb - > len ) ;
if ( r = = - EREMOTEIO ) { /* Retry, chip was in standby */
usleep_range ( 1000 , 4000 ) ;
r = i2c_master_send ( client , skb - > data , skb - > len ) ;
}
if ( r > = 0 ) {
if ( r ! = skb - > len )
r = - EREMOTEIO ;
else
r = 0 ;
}
st21nfcb_nci_remove_header ( skb ) ;
return r ;
}
/*
* Reads an ndlc frame and returns it in a newly allocated sk_buff .
* returns :
* frame size : if received frame is complete ( find ST21NFCB_SOF_EOF at
* end of read )
* - EAGAIN : if received frame is incomplete ( not find ST21NFCB_SOF_EOF
* at end of read )
* - EREMOTEIO : i2c read error ( fatal )
* - EBADMSG : frame was incorrect and discarded
* ( value returned from st21nfcb_nci_i2c_repack )
* - EIO : if no ST21NFCB_SOF_EOF is found after reaching
* the read length end sequence
*/
static int st21nfcb_nci_i2c_read ( struct st21nfcb_i2c_phy * phy ,
struct sk_buff * * skb )
{
int r ;
u8 len ;
u8 buf [ ST21NFCB_NCI_I2C_MAX_SIZE ] ;
struct i2c_client * client = phy - > i2c_dev ;
2014-05-26 00:46:58 +04:00
r = i2c_master_recv ( client , buf , ST21NFCB_NCI_I2C_MIN_SIZE ) ;
2014-05-26 00:35:38 +04:00
if ( r = = - EREMOTEIO ) { /* Retry, chip was in standby */
usleep_range ( 1000 , 4000 ) ;
2014-05-26 00:46:58 +04:00
r = i2c_master_recv ( client , buf , ST21NFCB_NCI_I2C_MIN_SIZE ) ;
2014-09-04 01:30:26 +04:00
}
2014-09-13 12:28:51 +04:00
if ( r ! = ST21NFCB_NCI_I2C_MIN_SIZE )
2014-05-26 00:35:38 +04:00
return - EREMOTEIO ;
len = be16_to_cpu ( * ( __be16 * ) ( buf + 2 ) ) ;
if ( len > ST21NFCB_NCI_I2C_MAX_SIZE ) {
nfc_err ( & client - > dev , " invalid frame len \n " ) ;
return - EBADMSG ;
}
2014-05-26 00:46:58 +04:00
* skb = alloc_skb ( ST21NFCB_NCI_I2C_MIN_SIZE + len , GFP_KERNEL ) ;
2014-05-26 00:35:38 +04:00
if ( * skb = = NULL )
return - ENOMEM ;
2014-05-26 00:46:58 +04:00
skb_reserve ( * skb , ST21NFCB_NCI_I2C_MIN_SIZE ) ;
skb_put ( * skb , ST21NFCB_NCI_I2C_MIN_SIZE ) ;
memcpy ( ( * skb ) - > data , buf , ST21NFCB_NCI_I2C_MIN_SIZE ) ;
2014-05-26 00:35:38 +04:00
if ( ! len )
return 0 ;
r = i2c_master_recv ( client , buf , len ) ;
if ( r ! = len ) {
kfree_skb ( * skb ) ;
return - EREMOTEIO ;
}
skb_put ( * skb , len ) ;
2014-05-26 00:46:58 +04:00
memcpy ( ( * skb ) - > data + ST21NFCB_NCI_I2C_MIN_SIZE , buf , len ) ;
2014-05-26 00:35:38 +04:00
I2C_DUMP_SKB ( " i2c frame read " , * skb ) ;
return 0 ;
}
/*
* Reads an ndlc frame from the chip .
*
* On ST21NFCB , IRQ goes in idle state when read starts .
*/
static irqreturn_t st21nfcb_nci_irq_thread_fn ( int irq , void * phy_id )
{
struct st21nfcb_i2c_phy * phy = phy_id ;
struct i2c_client * client ;
struct sk_buff * skb = NULL ;
int r ;
if ( ! phy | | irq ! = phy - > i2c_dev - > irq ) {
WARN_ON_ONCE ( 1 ) ;
return IRQ_NONE ;
}
client = phy - > i2c_dev ;
dev_dbg ( & client - > dev , " IRQ \n " ) ;
2014-09-13 12:28:47 +04:00
if ( phy - > ndlc - > hard_fault )
2014-05-26 00:35:38 +04:00
return IRQ_HANDLED ;
if ( ! phy - > powered ) {
st21nfcb_nci_i2c_disable ( phy ) ;
return IRQ_HANDLED ;
}
r = st21nfcb_nci_i2c_read ( phy , & skb ) ;
2014-09-13 12:28:47 +04:00
if ( r = = - EREMOTEIO | | r = = - ENOMEM | | r = = - EBADMSG )
2014-05-26 00:35:38 +04:00
return IRQ_HANDLED ;
ndlc_recv ( phy - > ndlc , skb ) ;
return IRQ_HANDLED ;
}
static struct nfc_phy_ops i2c_phy_ops = {
. write = st21nfcb_nci_i2c_write ,
. enable = st21nfcb_nci_i2c_enable ,
. disable = st21nfcb_nci_i2c_disable ,
} ;
# ifdef CONFIG_OF
static int st21nfcb_nci_i2c_of_request_resources ( struct i2c_client * client )
{
struct st21nfcb_i2c_phy * phy = i2c_get_clientdata ( client ) ;
struct device_node * pp ;
int gpio ;
int r ;
pp = client - > dev . of_node ;
if ( ! pp )
return - ENODEV ;
/* Get GPIO from device tree */
gpio = of_get_named_gpio ( pp , " reset-gpios " , 0 ) ;
if ( gpio < 0 ) {
nfc_err ( & client - > dev ,
" Failed to retrieve reset-gpios from device tree \n " ) ;
return gpio ;
}
/* GPIO request and configuration */
2014-07-28 20:11:33 +04:00
r = devm_gpio_request_one ( & client - > dev , gpio ,
GPIOF_OUT_INIT_HIGH , " clf_reset " ) ;
2014-05-26 00:35:38 +04:00
if ( r ) {
nfc_err ( & client - > dev , " Failed to request reset pin \n " ) ;
return - ENODEV ;
}
phy - > gpio_reset = gpio ;
/* IRQ */
r = irq_of_parse_and_map ( pp , 0 ) ;
if ( r < 0 ) {
2014-07-28 20:11:35 +04:00
nfc_err ( & client - > dev , " Unable to get irq, error: %d \n " , r ) ;
2014-05-26 00:35:38 +04:00
return r ;
}
phy - > irq_polarity = irq_get_trigger_type ( r ) ;
client - > irq = r ;
return 0 ;
}
# else
static int st21nfcb_nci_i2c_of_request_resources ( struct i2c_client * client )
{
return - ENODEV ;
}
# endif
static int st21nfcb_nci_i2c_request_resources ( struct i2c_client * client )
{
struct st21nfcb_nfc_platform_data * pdata ;
struct st21nfcb_i2c_phy * phy = i2c_get_clientdata ( client ) ;
int r ;
int irq ;
pdata = client - > dev . platform_data ;
if ( pdata = = NULL ) {
nfc_err ( & client - > dev , " No platform data \n " ) ;
return - EINVAL ;
}
/* store for later use */
phy - > gpio_irq = pdata - > gpio_irq ;
phy - > gpio_reset = pdata - > gpio_reset ;
phy - > irq_polarity = pdata - > irq_polarity ;
2014-07-28 20:11:33 +04:00
r = devm_gpio_request_one ( & client - > dev , phy - > gpio_irq ,
GPIOF_IN , " clf_irq " ) ;
2014-05-26 00:35:38 +04:00
if ( r ) {
pr_err ( " %s : gpio_request failed \n " , __FILE__ ) ;
return - ENODEV ;
}
2014-07-28 20:11:33 +04:00
r = devm_gpio_request_one ( & client - > dev ,
phy - > gpio_reset , GPIOF_OUT_INIT_HIGH , " clf_reset " ) ;
2014-05-26 00:35:38 +04:00
if ( r ) {
pr_err ( " %s : reset gpio_request failed \n " , __FILE__ ) ;
return - ENODEV ;
}
/* IRQ */
irq = gpio_to_irq ( phy - > gpio_irq ) ;
if ( irq < 0 ) {
nfc_err ( & client - > dev ,
" Unable to get irq number for GPIO %d error %d \n " ,
phy - > gpio_irq , r ) ;
return - ENODEV ;
}
client - > irq = irq ;
return 0 ;
}
static int st21nfcb_nci_i2c_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
{
struct st21nfcb_i2c_phy * phy ;
struct st21nfcb_nfc_platform_data * pdata ;
int r ;
dev_dbg ( & client - > dev , " %s \n " , __func__ ) ;
dev_dbg ( & client - > dev , " IRQ: %d \n " , client - > irq ) ;
if ( ! i2c_check_functionality ( client - > adapter , I2C_FUNC_I2C ) ) {
nfc_err ( & client - > dev , " Need I2C_FUNC_I2C \n " ) ;
return - ENODEV ;
}
phy = devm_kzalloc ( & client - > dev , sizeof ( struct st21nfcb_i2c_phy ) ,
GFP_KERNEL ) ;
if ( ! phy ) {
nfc_err ( & client - > dev ,
" Cannot allocate memory for st21nfcb i2c phy. \n " ) ;
return - ENOMEM ;
}
phy - > i2c_dev = client ;
i2c_set_clientdata ( client , phy ) ;
pdata = client - > dev . platform_data ;
if ( ! pdata & & client - > dev . of_node ) {
r = st21nfcb_nci_i2c_of_request_resources ( client ) ;
if ( r ) {
nfc_err ( & client - > dev , " No platform data \n " ) ;
return r ;
}
} else if ( pdata ) {
r = st21nfcb_nci_i2c_request_resources ( client ) ;
if ( r ) {
nfc_err ( & client - > dev ,
" Cannot get platform resources \n " ) ;
return r ;
}
} else {
nfc_err ( & client - > dev ,
" st21nfcb platform resources not available \n " ) ;
return - ENODEV ;
}
r = devm_request_threaded_irq ( & client - > dev , client - > irq , NULL ,
st21nfcb_nci_irq_thread_fn ,
phy - > irq_polarity | IRQF_ONESHOT ,
ST21NFCB_NCI_DRIVER_NAME , phy ) ;
if ( r < 0 ) {
nfc_err ( & client - > dev , " Unable to register IRQ handler \n " ) ;
return r ;
}
return ndlc_probe ( phy , & i2c_phy_ops , & client - > dev ,
ST21NFCB_FRAME_HEADROOM , ST21NFCB_FRAME_TAILROOM ,
& phy - > ndlc ) ;
}
static int st21nfcb_nci_i2c_remove ( struct i2c_client * client )
{
struct st21nfcb_i2c_phy * phy = i2c_get_clientdata ( client ) ;
dev_dbg ( & client - > dev , " %s \n " , __func__ ) ;
ndlc_remove ( phy - > ndlc ) ;
if ( phy - > powered )
st21nfcb_nci_i2c_disable ( phy ) ;
return 0 ;
}
static const struct of_device_id of_st21nfcb_i2c_match [ ] = {
{ . compatible = " st,st21nfcb_i2c " , } ,
{ }
} ;
static struct i2c_driver st21nfcb_nci_i2c_driver = {
. driver = {
. owner = THIS_MODULE ,
. name = ST21NFCB_NCI_I2C_DRIVER_NAME ,
. of_match_table = of_match_ptr ( of_st21nfcb_i2c_match ) ,
} ,
. probe = st21nfcb_nci_i2c_probe ,
. id_table = st21nfcb_nci_i2c_id_table ,
. remove = st21nfcb_nci_i2c_remove ,
} ;
module_i2c_driver ( st21nfcb_nci_i2c_driver ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;