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 (8407B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * I2C link layer for the NXP NCI driver
      4 *
      5 * Copyright (C) 2014  NXP Semiconductors  All rights reserved.
      6 * Copyright (C) 2012-2015  Intel Corporation. All rights reserved.
      7 *
      8 * Authors: Clément Perrochaud <clement.perrochaud@nxp.com>
      9 * Authors: Oleg Zhurakivskyy <oleg.zhurakivskyy@intel.com>
     10 *
     11 * Derived from PN544 device driver:
     12 * Copyright (C) 2012  Intel Corporation. All rights reserved.
     13 */
     14
     15#include <linux/acpi.h>
     16#include <linux/delay.h>
     17#include <linux/i2c.h>
     18#include <linux/interrupt.h>
     19#include <linux/module.h>
     20#include <linux/nfc.h>
     21#include <linux/gpio/consumer.h>
     22#include <asm/unaligned.h>
     23
     24#include <net/nfc/nfc.h>
     25
     26#include "nxp-nci.h"
     27
     28#define NXP_NCI_I2C_DRIVER_NAME	"nxp-nci_i2c"
     29
     30#define NXP_NCI_I2C_MAX_PAYLOAD	32
     31
     32struct nxp_nci_i2c_phy {
     33	struct i2c_client *i2c_dev;
     34	struct nci_dev *ndev;
     35
     36	struct gpio_desc *gpiod_en;
     37	struct gpio_desc *gpiod_fw;
     38
     39	int hard_fault; /*
     40			 * < 0 if hardware error occurred (e.g. i2c err)
     41			 * and prevents normal operation.
     42			 */
     43};
     44
     45static int nxp_nci_i2c_set_mode(void *phy_id,
     46				    enum nxp_nci_mode mode)
     47{
     48	struct nxp_nci_i2c_phy *phy = (struct nxp_nci_i2c_phy *) phy_id;
     49
     50	gpiod_set_value(phy->gpiod_fw, (mode == NXP_NCI_MODE_FW) ? 1 : 0);
     51	gpiod_set_value(phy->gpiod_en, (mode != NXP_NCI_MODE_COLD) ? 1 : 0);
     52	usleep_range(10000, 15000);
     53
     54	if (mode == NXP_NCI_MODE_COLD)
     55		phy->hard_fault = 0;
     56
     57	return 0;
     58}
     59
     60static int nxp_nci_i2c_write(void *phy_id, struct sk_buff *skb)
     61{
     62	int r;
     63	struct nxp_nci_i2c_phy *phy = phy_id;
     64	struct i2c_client *client = phy->i2c_dev;
     65
     66	if (phy->hard_fault != 0)
     67		return phy->hard_fault;
     68
     69	r = i2c_master_send(client, skb->data, skb->len);
     70	if (r < 0) {
     71		/* Retry, chip was in standby */
     72		msleep(110);
     73		r = i2c_master_send(client, skb->data, skb->len);
     74	}
     75
     76	if (r < 0) {
     77		nfc_err(&client->dev, "Error %d on I2C send\n", r);
     78	} else if (r != skb->len) {
     79		nfc_err(&client->dev,
     80			"Invalid length sent: %u (expected %u)\n",
     81			r, skb->len);
     82		r = -EREMOTEIO;
     83	} else {
     84		/* Success but return 0 and not number of bytes */
     85		r = 0;
     86	}
     87
     88	return r;
     89}
     90
     91static const struct nxp_nci_phy_ops i2c_phy_ops = {
     92	.set_mode = nxp_nci_i2c_set_mode,
     93	.write = nxp_nci_i2c_write,
     94};
     95
     96static int nxp_nci_i2c_fw_read(struct nxp_nci_i2c_phy *phy,
     97			       struct sk_buff **skb)
     98{
     99	struct i2c_client *client = phy->i2c_dev;
    100	u16 header;
    101	size_t frame_len;
    102	int r;
    103
    104	r = i2c_master_recv(client, (u8 *) &header, NXP_NCI_FW_HDR_LEN);
    105	if (r < 0) {
    106		goto fw_read_exit;
    107	} else if (r != NXP_NCI_FW_HDR_LEN) {
    108		nfc_err(&client->dev, "Incorrect header length: %u\n", r);
    109		r = -EBADMSG;
    110		goto fw_read_exit;
    111	}
    112
    113	frame_len = (be16_to_cpu(header) & NXP_NCI_FW_FRAME_LEN_MASK) +
    114		    NXP_NCI_FW_CRC_LEN;
    115
    116	*skb = alloc_skb(NXP_NCI_FW_HDR_LEN + frame_len, GFP_KERNEL);
    117	if (*skb == NULL) {
    118		r = -ENOMEM;
    119		goto fw_read_exit;
    120	}
    121
    122	skb_put_data(*skb, &header, NXP_NCI_FW_HDR_LEN);
    123
    124	r = i2c_master_recv(client, skb_put(*skb, frame_len), frame_len);
    125	if (r < 0) {
    126		goto fw_read_exit_free_skb;
    127	} else if (r != frame_len) {
    128		nfc_err(&client->dev,
    129			"Invalid frame length: %u (expected %zu)\n",
    130			r, frame_len);
    131		r = -EBADMSG;
    132		goto fw_read_exit_free_skb;
    133	}
    134
    135	return 0;
    136
    137fw_read_exit_free_skb:
    138	kfree_skb(*skb);
    139fw_read_exit:
    140	return r;
    141}
    142
    143static int nxp_nci_i2c_nci_read(struct nxp_nci_i2c_phy *phy,
    144				struct sk_buff **skb)
    145{
    146	struct nci_ctrl_hdr header; /* May actually be a data header */
    147	struct i2c_client *client = phy->i2c_dev;
    148	int r;
    149
    150	r = i2c_master_recv(client, (u8 *) &header, NCI_CTRL_HDR_SIZE);
    151	if (r < 0) {
    152		goto nci_read_exit;
    153	} else if (r != NCI_CTRL_HDR_SIZE) {
    154		nfc_err(&client->dev, "Incorrect header length: %u\n", r);
    155		r = -EBADMSG;
    156		goto nci_read_exit;
    157	}
    158
    159	*skb = alloc_skb(NCI_CTRL_HDR_SIZE + header.plen, GFP_KERNEL);
    160	if (*skb == NULL) {
    161		r = -ENOMEM;
    162		goto nci_read_exit;
    163	}
    164
    165	skb_put_data(*skb, (void *)&header, NCI_CTRL_HDR_SIZE);
    166
    167	if (!header.plen)
    168		return 0;
    169
    170	r = i2c_master_recv(client, skb_put(*skb, header.plen), header.plen);
    171	if (r < 0) {
    172		goto nci_read_exit_free_skb;
    173	} else if (r != header.plen) {
    174		nfc_err(&client->dev,
    175			"Invalid frame payload length: %u (expected %u)\n",
    176			r, header.plen);
    177		r = -EBADMSG;
    178		goto nci_read_exit_free_skb;
    179	}
    180
    181	return 0;
    182
    183nci_read_exit_free_skb:
    184	kfree_skb(*skb);
    185nci_read_exit:
    186	return r;
    187}
    188
    189static irqreturn_t nxp_nci_i2c_irq_thread_fn(int irq, void *phy_id)
    190{
    191	struct nxp_nci_i2c_phy *phy = phy_id;
    192	struct i2c_client *client;
    193	struct nxp_nci_info *info;
    194
    195	struct sk_buff *skb = NULL;
    196	int r = 0;
    197
    198	if (!phy || !phy->ndev)
    199		goto exit_irq_none;
    200
    201	client = phy->i2c_dev;
    202
    203	if (!client || irq != client->irq)
    204		goto exit_irq_none;
    205
    206	info = nci_get_drvdata(phy->ndev);
    207
    208	if (!info)
    209		goto exit_irq_none;
    210
    211	mutex_lock(&info->info_lock);
    212
    213	if (phy->hard_fault != 0)
    214		goto exit_irq_handled;
    215
    216	switch (info->mode) {
    217	case NXP_NCI_MODE_NCI:
    218		r = nxp_nci_i2c_nci_read(phy, &skb);
    219		break;
    220	case NXP_NCI_MODE_FW:
    221		r = nxp_nci_i2c_fw_read(phy, &skb);
    222		break;
    223	case NXP_NCI_MODE_COLD:
    224		r = -EREMOTEIO;
    225		break;
    226	}
    227
    228	if (r == -EREMOTEIO) {
    229		phy->hard_fault = r;
    230		if (info->mode == NXP_NCI_MODE_FW)
    231			nxp_nci_fw_recv_frame(phy->ndev, NULL);
    232	}
    233	if (r < 0) {
    234		nfc_err(&client->dev, "Read failed with error %d\n", r);
    235		goto exit_irq_handled;
    236	}
    237
    238	switch (info->mode) {
    239	case NXP_NCI_MODE_NCI:
    240		nci_recv_frame(phy->ndev, skb);
    241		break;
    242	case NXP_NCI_MODE_FW:
    243		nxp_nci_fw_recv_frame(phy->ndev, skb);
    244		break;
    245	case NXP_NCI_MODE_COLD:
    246		break;
    247	}
    248
    249exit_irq_handled:
    250	mutex_unlock(&info->info_lock);
    251	return IRQ_HANDLED;
    252exit_irq_none:
    253	WARN_ON_ONCE(1);
    254	return IRQ_NONE;
    255}
    256
    257static const struct acpi_gpio_params firmware_gpios = { 1, 0, false };
    258static const struct acpi_gpio_params enable_gpios = { 2, 0, false };
    259
    260static const struct acpi_gpio_mapping acpi_nxp_nci_gpios[] = {
    261	{ "enable-gpios", &enable_gpios, 1 },
    262	{ "firmware-gpios", &firmware_gpios, 1 },
    263	{ }
    264};
    265
    266static int nxp_nci_i2c_probe(struct i2c_client *client,
    267			    const struct i2c_device_id *id)
    268{
    269	struct device *dev = &client->dev;
    270	struct nxp_nci_i2c_phy *phy;
    271	int r;
    272
    273	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
    274		nfc_err(&client->dev, "Need I2C_FUNC_I2C\n");
    275		return -ENODEV;
    276	}
    277
    278	phy = devm_kzalloc(&client->dev, sizeof(struct nxp_nci_i2c_phy),
    279			   GFP_KERNEL);
    280	if (!phy)
    281		return -ENOMEM;
    282
    283	phy->i2c_dev = client;
    284	i2c_set_clientdata(client, phy);
    285
    286	r = devm_acpi_dev_add_driver_gpios(dev, acpi_nxp_nci_gpios);
    287	if (r)
    288		dev_dbg(dev, "Unable to add GPIO mapping table\n");
    289
    290	phy->gpiod_en = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
    291	if (IS_ERR(phy->gpiod_en)) {
    292		nfc_err(dev, "Failed to get EN gpio\n");
    293		return PTR_ERR(phy->gpiod_en);
    294	}
    295
    296	phy->gpiod_fw = devm_gpiod_get_optional(dev, "firmware", GPIOD_OUT_LOW);
    297	if (IS_ERR(phy->gpiod_fw)) {
    298		nfc_err(dev, "Failed to get FW gpio\n");
    299		return PTR_ERR(phy->gpiod_fw);
    300	}
    301
    302	r = nxp_nci_probe(phy, &client->dev, &i2c_phy_ops,
    303			  NXP_NCI_I2C_MAX_PAYLOAD, &phy->ndev);
    304	if (r < 0)
    305		return r;
    306
    307	r = request_threaded_irq(client->irq, NULL,
    308				 nxp_nci_i2c_irq_thread_fn,
    309				 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
    310				 NXP_NCI_I2C_DRIVER_NAME, phy);
    311	if (r < 0)
    312		nfc_err(&client->dev, "Unable to register IRQ handler\n");
    313
    314	return r;
    315}
    316
    317static int nxp_nci_i2c_remove(struct i2c_client *client)
    318{
    319	struct nxp_nci_i2c_phy *phy = i2c_get_clientdata(client);
    320
    321	nxp_nci_remove(phy->ndev);
    322	free_irq(client->irq, phy);
    323
    324	return 0;
    325}
    326
    327static const struct i2c_device_id nxp_nci_i2c_id_table[] = {
    328	{"nxp-nci_i2c", 0},
    329	{}
    330};
    331MODULE_DEVICE_TABLE(i2c, nxp_nci_i2c_id_table);
    332
    333static const struct of_device_id of_nxp_nci_i2c_match[] = {
    334	{ .compatible = "nxp,nxp-nci-i2c", },
    335	{}
    336};
    337MODULE_DEVICE_TABLE(of, of_nxp_nci_i2c_match);
    338
    339#ifdef CONFIG_ACPI
    340static const struct acpi_device_id acpi_id[] = {
    341	{ "NXP1001" },
    342	{ "NXP7471" },
    343	{ }
    344};
    345MODULE_DEVICE_TABLE(acpi, acpi_id);
    346#endif
    347
    348static struct i2c_driver nxp_nci_i2c_driver = {
    349	.driver = {
    350		   .name = NXP_NCI_I2C_DRIVER_NAME,
    351		   .acpi_match_table = ACPI_PTR(acpi_id),
    352		   .of_match_table = of_nxp_nci_i2c_match,
    353		  },
    354	.probe = nxp_nci_i2c_probe,
    355	.id_table = nxp_nci_i2c_id_table,
    356	.remove = nxp_nci_i2c_remove,
    357};
    358
    359module_i2c_driver(nxp_nci_i2c_driver);
    360
    361MODULE_LICENSE("GPL");
    362MODULE_DESCRIPTION("I2C driver for NXP NCI NFC controllers");
    363MODULE_AUTHOR("Clément Perrochaud <clement.perrochaud@nxp.com>");
    364MODULE_AUTHOR("Oleg Zhurakivskyy <oleg.zhurakivskyy@intel.com>");