cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

i2c.c (6224B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Marvell NFC-over-I2C driver: I2C interface related functions
      4 *
      5 * Copyright (C) 2015, Marvell International Ltd.
      6 */
      7
      8#include <linux/module.h>
      9#include <linux/interrupt.h>
     10#include <linux/i2c.h>
     11#include <linux/nfc.h>
     12#include <linux/delay.h>
     13#include <linux/of_irq.h>
     14#include <net/nfc/nci.h>
     15#include <net/nfc/nci_core.h>
     16#include "nfcmrvl.h"
     17
     18struct nfcmrvl_i2c_drv_data {
     19	unsigned long flags;
     20	struct device *dev;
     21	struct i2c_client *i2c;
     22	struct nfcmrvl_private *priv;
     23};
     24
     25static int nfcmrvl_i2c_read(struct nfcmrvl_i2c_drv_data *drv_data,
     26			    struct sk_buff **skb)
     27{
     28	int ret;
     29	struct nci_ctrl_hdr nci_hdr;
     30
     31	/* Read NCI header to know the payload size */
     32	ret = i2c_master_recv(drv_data->i2c, (u8 *)&nci_hdr, NCI_CTRL_HDR_SIZE);
     33	if (ret != NCI_CTRL_HDR_SIZE) {
     34		nfc_err(&drv_data->i2c->dev, "cannot read NCI header\n");
     35		return -EBADMSG;
     36	}
     37
     38	*skb = nci_skb_alloc(drv_data->priv->ndev,
     39			     nci_hdr.plen + NCI_CTRL_HDR_SIZE, GFP_KERNEL);
     40	if (!*skb)
     41		return -ENOMEM;
     42
     43	/* Copy NCI header into the SKB */
     44	skb_put_data(*skb, &nci_hdr, NCI_CTRL_HDR_SIZE);
     45
     46	if (nci_hdr.plen) {
     47		/* Read the NCI payload */
     48		ret = i2c_master_recv(drv_data->i2c,
     49				      skb_put(*skb, nci_hdr.plen),
     50				      nci_hdr.plen);
     51
     52		if (ret != nci_hdr.plen) {
     53			nfc_err(&drv_data->i2c->dev,
     54				"Invalid frame payload length: %u (expected %u)\n",
     55				ret, nci_hdr.plen);
     56			kfree_skb(*skb);
     57			return -EBADMSG;
     58		}
     59	}
     60
     61	return 0;
     62}
     63
     64static irqreturn_t nfcmrvl_i2c_int_irq_thread_fn(int irq, void *drv_data_ptr)
     65{
     66	struct nfcmrvl_i2c_drv_data *drv_data = drv_data_ptr;
     67	struct sk_buff *skb = NULL;
     68	int ret;
     69
     70	if (!drv_data->priv)
     71		return IRQ_HANDLED;
     72
     73	if (test_bit(NFCMRVL_PHY_ERROR, &drv_data->priv->flags))
     74		return IRQ_HANDLED;
     75
     76	ret = nfcmrvl_i2c_read(drv_data, &skb);
     77
     78	switch (ret) {
     79	case -EREMOTEIO:
     80		set_bit(NFCMRVL_PHY_ERROR, &drv_data->priv->flags);
     81		break;
     82	case -ENOMEM:
     83	case -EBADMSG:
     84		nfc_err(&drv_data->i2c->dev, "read failed %d\n", ret);
     85		break;
     86	default:
     87		if (nfcmrvl_nci_recv_frame(drv_data->priv, skb) < 0)
     88			nfc_err(&drv_data->i2c->dev, "corrupted RX packet\n");
     89		break;
     90	}
     91	return IRQ_HANDLED;
     92}
     93
     94static int nfcmrvl_i2c_nci_open(struct nfcmrvl_private *priv)
     95{
     96	struct nfcmrvl_i2c_drv_data *drv_data = priv->drv_data;
     97
     98	if (!drv_data)
     99		return -ENODEV;
    100
    101	return 0;
    102}
    103
    104static int nfcmrvl_i2c_nci_close(struct nfcmrvl_private *priv)
    105{
    106	return 0;
    107}
    108
    109static int nfcmrvl_i2c_nci_send(struct nfcmrvl_private *priv,
    110				struct sk_buff *skb)
    111{
    112	struct nfcmrvl_i2c_drv_data *drv_data = priv->drv_data;
    113	int ret;
    114
    115	if (test_bit(NFCMRVL_PHY_ERROR, &priv->flags))
    116		return -EREMOTEIO;
    117
    118	ret = i2c_master_send(drv_data->i2c, skb->data, skb->len);
    119
    120	/* Retry if chip was in standby */
    121	if (ret == -EREMOTEIO) {
    122		nfc_info(drv_data->dev, "chip may sleep, retry\n");
    123		usleep_range(6000, 10000);
    124		ret = i2c_master_send(drv_data->i2c, skb->data, skb->len);
    125	}
    126
    127	if (ret >= 0) {
    128		if (ret != skb->len) {
    129			nfc_err(drv_data->dev,
    130				"Invalid length sent: %u (expected %u)\n",
    131				ret, skb->len);
    132			ret = -EREMOTEIO;
    133		} else
    134			ret = 0;
    135		kfree_skb(skb);
    136	}
    137
    138	return ret;
    139}
    140
    141static void nfcmrvl_i2c_nci_update_config(struct nfcmrvl_private *priv,
    142					  const void *param)
    143{
    144}
    145
    146static const struct nfcmrvl_if_ops i2c_ops = {
    147	.nci_open = nfcmrvl_i2c_nci_open,
    148	.nci_close = nfcmrvl_i2c_nci_close,
    149	.nci_send = nfcmrvl_i2c_nci_send,
    150	.nci_update_config = nfcmrvl_i2c_nci_update_config,
    151};
    152
    153static int nfcmrvl_i2c_parse_dt(struct device_node *node,
    154				struct nfcmrvl_platform_data *pdata)
    155{
    156	int ret;
    157
    158	ret = nfcmrvl_parse_dt(node, pdata);
    159	if (ret < 0) {
    160		pr_err("Failed to get generic entries\n");
    161		return ret;
    162	}
    163
    164	if (of_find_property(node, "i2c-int-falling", NULL))
    165		pdata->irq_polarity = IRQF_TRIGGER_FALLING;
    166	else
    167		pdata->irq_polarity = IRQF_TRIGGER_RISING;
    168
    169	ret = irq_of_parse_and_map(node, 0);
    170	if (!ret) {
    171		pr_err("Unable to get irq\n");
    172		return -EINVAL;
    173	}
    174	pdata->irq = ret;
    175
    176	return 0;
    177}
    178
    179static int nfcmrvl_i2c_probe(struct i2c_client *client,
    180			     const struct i2c_device_id *id)
    181{
    182	const struct nfcmrvl_platform_data *pdata;
    183	struct nfcmrvl_i2c_drv_data *drv_data;
    184	struct nfcmrvl_platform_data config;
    185	int ret;
    186
    187	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
    188		nfc_err(&client->dev, "Need I2C_FUNC_I2C\n");
    189		return -ENODEV;
    190	}
    191
    192	drv_data = devm_kzalloc(&client->dev, sizeof(*drv_data), GFP_KERNEL);
    193	if (!drv_data)
    194		return -ENOMEM;
    195
    196	drv_data->i2c = client;
    197	drv_data->dev = &client->dev;
    198	drv_data->priv = NULL;
    199
    200	i2c_set_clientdata(client, drv_data);
    201
    202	pdata = client->dev.platform_data;
    203
    204	if (!pdata && client->dev.of_node)
    205		if (nfcmrvl_i2c_parse_dt(client->dev.of_node, &config) == 0)
    206			pdata = &config;
    207
    208	if (!pdata)
    209		return -EINVAL;
    210
    211	/* Request the read IRQ */
    212	ret = devm_request_threaded_irq(&drv_data->i2c->dev, pdata->irq,
    213					NULL, nfcmrvl_i2c_int_irq_thread_fn,
    214					pdata->irq_polarity | IRQF_ONESHOT,
    215					"nfcmrvl_i2c_int", drv_data);
    216	if (ret < 0) {
    217		nfc_err(&drv_data->i2c->dev,
    218			"Unable to register IRQ handler\n");
    219		return ret;
    220	}
    221
    222	drv_data->priv = nfcmrvl_nci_register_dev(NFCMRVL_PHY_I2C,
    223						  drv_data, &i2c_ops,
    224						  &drv_data->i2c->dev, pdata);
    225
    226	if (IS_ERR(drv_data->priv))
    227		return PTR_ERR(drv_data->priv);
    228
    229	drv_data->priv->support_fw_dnld = true;
    230
    231	return 0;
    232}
    233
    234static int nfcmrvl_i2c_remove(struct i2c_client *client)
    235{
    236	struct nfcmrvl_i2c_drv_data *drv_data = i2c_get_clientdata(client);
    237
    238	nfcmrvl_nci_unregister_dev(drv_data->priv);
    239
    240	return 0;
    241}
    242
    243
    244static const struct of_device_id of_nfcmrvl_i2c_match[] __maybe_unused = {
    245	{ .compatible = "marvell,nfc-i2c", },
    246	{},
    247};
    248MODULE_DEVICE_TABLE(of, of_nfcmrvl_i2c_match);
    249
    250static const struct i2c_device_id nfcmrvl_i2c_id_table[] = {
    251	{ "nfcmrvl_i2c", 0 },
    252	{}
    253};
    254MODULE_DEVICE_TABLE(i2c, nfcmrvl_i2c_id_table);
    255
    256static struct i2c_driver nfcmrvl_i2c_driver = {
    257	.probe = nfcmrvl_i2c_probe,
    258	.id_table = nfcmrvl_i2c_id_table,
    259	.remove = nfcmrvl_i2c_remove,
    260	.driver = {
    261		.name		= "nfcmrvl_i2c",
    262		.of_match_table	= of_match_ptr(of_nfcmrvl_i2c_match),
    263	},
    264};
    265
    266module_i2c_driver(nfcmrvl_i2c_driver);
    267
    268MODULE_AUTHOR("Marvell International Ltd.");
    269MODULE_DESCRIPTION("Marvell NFC-over-I2C driver");
    270MODULE_LICENSE("GPL v2");