Source
x
/**
* Marvell NFC-over-I2C driver: I2C interface related functions
*
* Copyright (C) 2015, Marvell International Ltd.
*
* 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.
**/
struct nfcmrvl_i2c_drv_data {
unsigned long flags;
struct device *dev;
struct i2c_client *i2c;
struct nfcmrvl_private *priv;
};
static int nfcmrvl_i2c_read(struct nfcmrvl_i2c_drv_data *drv_data,
struct sk_buff **skb)
{
int ret;
struct nci_ctrl_hdr nci_hdr;
/* Read NCI header to know the payload size */
ret = i2c_master_recv(drv_data->i2c, (u8 *)&nci_hdr, NCI_CTRL_HDR_SIZE);
if (ret != NCI_CTRL_HDR_SIZE) {
nfc_err(&drv_data->i2c->dev, "cannot read NCI header\n");
return -EBADMSG;
}
if (nci_hdr.plen > NCI_MAX_PAYLOAD_SIZE) {
nfc_err(&drv_data->i2c->dev, "invalid packet payload size\n");
return -EBADMSG;
}
*skb = nci_skb_alloc(drv_data->priv->ndev,
nci_hdr.plen + NCI_CTRL_HDR_SIZE, GFP_KERNEL);
if (!*skb)
return -ENOMEM;
/* Copy NCI header into the SKB */
skb_put_data(*skb, &nci_hdr, NCI_CTRL_HDR_SIZE);
if (nci_hdr.plen) {
/* Read the NCI payload */
ret = i2c_master_recv(drv_data->i2c,
skb_put(*skb, nci_hdr.plen),
nci_hdr.plen);
if (ret != nci_hdr.plen) {
nfc_err(&drv_data->i2c->dev,
"Invalid frame payload length: %u (expected %u)\n",
ret, nci_hdr.plen);
kfree_skb(*skb);
return -EBADMSG;
}
}
return 0;
}
static irqreturn_t nfcmrvl_i2c_int_irq_thread_fn(int irq, void *drv_data_ptr)
{
struct nfcmrvl_i2c_drv_data *drv_data = drv_data_ptr;
struct sk_buff *skb = NULL;
int ret;
if (!drv_data->priv)
return IRQ_HANDLED;
if (test_bit(NFCMRVL_PHY_ERROR, &drv_data->priv->flags))