xref: /kernel/linux/linux-6.6/drivers/nfc/nxp-nci/i2c.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * I2C link layer for the NXP NCI driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2014  NXP Semiconductors  All rights reserved.
662306a36Sopenharmony_ci * Copyright (C) 2012-2015  Intel Corporation. All rights reserved.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Authors: Clément Perrochaud <clement.perrochaud@nxp.com>
962306a36Sopenharmony_ci * Authors: Oleg Zhurakivskyy <oleg.zhurakivskyy@intel.com>
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * Derived from PN544 device driver:
1262306a36Sopenharmony_ci * Copyright (C) 2012  Intel Corporation. All rights reserved.
1362306a36Sopenharmony_ci */
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <linux/acpi.h>
1662306a36Sopenharmony_ci#include <linux/delay.h>
1762306a36Sopenharmony_ci#include <linux/i2c.h>
1862306a36Sopenharmony_ci#include <linux/interrupt.h>
1962306a36Sopenharmony_ci#include <linux/module.h>
2062306a36Sopenharmony_ci#include <linux/nfc.h>
2162306a36Sopenharmony_ci#include <linux/gpio/consumer.h>
2262306a36Sopenharmony_ci#include <asm/unaligned.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include <net/nfc/nfc.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#include "nxp-nci.h"
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define NXP_NCI_I2C_DRIVER_NAME	"nxp-nci_i2c"
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define NXP_NCI_I2C_MAX_PAYLOAD	32
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistruct nxp_nci_i2c_phy {
3362306a36Sopenharmony_ci	struct i2c_client *i2c_dev;
3462306a36Sopenharmony_ci	struct nci_dev *ndev;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	struct gpio_desc *gpiod_en;
3762306a36Sopenharmony_ci	struct gpio_desc *gpiod_fw;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	int hard_fault; /*
4062306a36Sopenharmony_ci			 * < 0 if hardware error occurred (e.g. i2c err)
4162306a36Sopenharmony_ci			 * and prevents normal operation.
4262306a36Sopenharmony_ci			 */
4362306a36Sopenharmony_ci};
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic int nxp_nci_i2c_set_mode(void *phy_id,
4662306a36Sopenharmony_ci				    enum nxp_nci_mode mode)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	struct nxp_nci_i2c_phy *phy = (struct nxp_nci_i2c_phy *) phy_id;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	gpiod_set_value(phy->gpiod_fw, (mode == NXP_NCI_MODE_FW) ? 1 : 0);
5162306a36Sopenharmony_ci	gpiod_set_value(phy->gpiod_en, (mode != NXP_NCI_MODE_COLD) ? 1 : 0);
5262306a36Sopenharmony_ci	usleep_range(10000, 15000);
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	if (mode == NXP_NCI_MODE_COLD)
5562306a36Sopenharmony_ci		phy->hard_fault = 0;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	return 0;
5862306a36Sopenharmony_ci}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic int nxp_nci_i2c_write(void *phy_id, struct sk_buff *skb)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	int r;
6362306a36Sopenharmony_ci	struct nxp_nci_i2c_phy *phy = phy_id;
6462306a36Sopenharmony_ci	struct i2c_client *client = phy->i2c_dev;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	if (phy->hard_fault != 0)
6762306a36Sopenharmony_ci		return phy->hard_fault;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	r = i2c_master_send(client, skb->data, skb->len);
7062306a36Sopenharmony_ci	if (r < 0) {
7162306a36Sopenharmony_ci		/* Retry, chip was in standby */
7262306a36Sopenharmony_ci		msleep(110);
7362306a36Sopenharmony_ci		r = i2c_master_send(client, skb->data, skb->len);
7462306a36Sopenharmony_ci	}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	if (r < 0) {
7762306a36Sopenharmony_ci		nfc_err(&client->dev, "Error %d on I2C send\n", r);
7862306a36Sopenharmony_ci	} else if (r != skb->len) {
7962306a36Sopenharmony_ci		nfc_err(&client->dev,
8062306a36Sopenharmony_ci			"Invalid length sent: %u (expected %u)\n",
8162306a36Sopenharmony_ci			r, skb->len);
8262306a36Sopenharmony_ci		r = -EREMOTEIO;
8362306a36Sopenharmony_ci	} else {
8462306a36Sopenharmony_ci		/* Success but return 0 and not number of bytes */
8562306a36Sopenharmony_ci		r = 0;
8662306a36Sopenharmony_ci	}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	return r;
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistatic const struct nxp_nci_phy_ops i2c_phy_ops = {
9262306a36Sopenharmony_ci	.set_mode = nxp_nci_i2c_set_mode,
9362306a36Sopenharmony_ci	.write = nxp_nci_i2c_write,
9462306a36Sopenharmony_ci};
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic int nxp_nci_i2c_fw_read(struct nxp_nci_i2c_phy *phy,
9762306a36Sopenharmony_ci			       struct sk_buff **skb)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	struct i2c_client *client = phy->i2c_dev;
10062306a36Sopenharmony_ci	size_t frame_len;
10162306a36Sopenharmony_ci	__be16 header;
10262306a36Sopenharmony_ci	int r;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	r = i2c_master_recv(client, (u8 *) &header, NXP_NCI_FW_HDR_LEN);
10562306a36Sopenharmony_ci	if (r < 0) {
10662306a36Sopenharmony_ci		goto fw_read_exit;
10762306a36Sopenharmony_ci	} else if (r != NXP_NCI_FW_HDR_LEN) {
10862306a36Sopenharmony_ci		nfc_err(&client->dev, "Incorrect header length: %u\n", r);
10962306a36Sopenharmony_ci		r = -EBADMSG;
11062306a36Sopenharmony_ci		goto fw_read_exit;
11162306a36Sopenharmony_ci	}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	frame_len = (be16_to_cpu(header) & NXP_NCI_FW_FRAME_LEN_MASK) +
11462306a36Sopenharmony_ci		    NXP_NCI_FW_CRC_LEN;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	*skb = alloc_skb(NXP_NCI_FW_HDR_LEN + frame_len, GFP_KERNEL);
11762306a36Sopenharmony_ci	if (*skb == NULL) {
11862306a36Sopenharmony_ci		r = -ENOMEM;
11962306a36Sopenharmony_ci		goto fw_read_exit;
12062306a36Sopenharmony_ci	}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	skb_put_data(*skb, &header, NXP_NCI_FW_HDR_LEN);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	r = i2c_master_recv(client, skb_put(*skb, frame_len), frame_len);
12562306a36Sopenharmony_ci	if (r < 0) {
12662306a36Sopenharmony_ci		goto fw_read_exit_free_skb;
12762306a36Sopenharmony_ci	} else if (r != frame_len) {
12862306a36Sopenharmony_ci		nfc_err(&client->dev,
12962306a36Sopenharmony_ci			"Invalid frame length: %u (expected %zu)\n",
13062306a36Sopenharmony_ci			r, frame_len);
13162306a36Sopenharmony_ci		r = -EBADMSG;
13262306a36Sopenharmony_ci		goto fw_read_exit_free_skb;
13362306a36Sopenharmony_ci	}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	return 0;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cifw_read_exit_free_skb:
13862306a36Sopenharmony_ci	kfree_skb(*skb);
13962306a36Sopenharmony_cifw_read_exit:
14062306a36Sopenharmony_ci	return r;
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic int nxp_nci_i2c_nci_read(struct nxp_nci_i2c_phy *phy,
14462306a36Sopenharmony_ci				struct sk_buff **skb)
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	struct nci_ctrl_hdr header; /* May actually be a data header */
14762306a36Sopenharmony_ci	struct i2c_client *client = phy->i2c_dev;
14862306a36Sopenharmony_ci	int r;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	r = i2c_master_recv(client, (u8 *) &header, NCI_CTRL_HDR_SIZE);
15162306a36Sopenharmony_ci	if (r < 0) {
15262306a36Sopenharmony_ci		goto nci_read_exit;
15362306a36Sopenharmony_ci	} else if (r != NCI_CTRL_HDR_SIZE) {
15462306a36Sopenharmony_ci		nfc_err(&client->dev, "Incorrect header length: %u\n", r);
15562306a36Sopenharmony_ci		r = -EBADMSG;
15662306a36Sopenharmony_ci		goto nci_read_exit;
15762306a36Sopenharmony_ci	}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	*skb = alloc_skb(NCI_CTRL_HDR_SIZE + header.plen, GFP_KERNEL);
16062306a36Sopenharmony_ci	if (*skb == NULL) {
16162306a36Sopenharmony_ci		r = -ENOMEM;
16262306a36Sopenharmony_ci		goto nci_read_exit;
16362306a36Sopenharmony_ci	}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	skb_put_data(*skb, (void *)&header, NCI_CTRL_HDR_SIZE);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	if (!header.plen)
16862306a36Sopenharmony_ci		return 0;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	r = i2c_master_recv(client, skb_put(*skb, header.plen), header.plen);
17162306a36Sopenharmony_ci	if (r < 0) {
17262306a36Sopenharmony_ci		goto nci_read_exit_free_skb;
17362306a36Sopenharmony_ci	} else if (r != header.plen) {
17462306a36Sopenharmony_ci		nfc_err(&client->dev,
17562306a36Sopenharmony_ci			"Invalid frame payload length: %u (expected %u)\n",
17662306a36Sopenharmony_ci			r, header.plen);
17762306a36Sopenharmony_ci		r = -EBADMSG;
17862306a36Sopenharmony_ci		goto nci_read_exit_free_skb;
17962306a36Sopenharmony_ci	}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	return 0;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cinci_read_exit_free_skb:
18462306a36Sopenharmony_ci	kfree_skb(*skb);
18562306a36Sopenharmony_cinci_read_exit:
18662306a36Sopenharmony_ci	return r;
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistatic irqreturn_t nxp_nci_i2c_irq_thread_fn(int irq, void *phy_id)
19062306a36Sopenharmony_ci{
19162306a36Sopenharmony_ci	struct nxp_nci_i2c_phy *phy = phy_id;
19262306a36Sopenharmony_ci	struct i2c_client *client;
19362306a36Sopenharmony_ci	struct nxp_nci_info *info;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	struct sk_buff *skb = NULL;
19662306a36Sopenharmony_ci	int r = 0;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	if (!phy || !phy->ndev)
19962306a36Sopenharmony_ci		goto exit_irq_none;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	client = phy->i2c_dev;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	if (!client || irq != client->irq)
20462306a36Sopenharmony_ci		goto exit_irq_none;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	info = nci_get_drvdata(phy->ndev);
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	if (!info)
20962306a36Sopenharmony_ci		goto exit_irq_none;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	mutex_lock(&info->info_lock);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	if (phy->hard_fault != 0)
21462306a36Sopenharmony_ci		goto exit_irq_handled;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	switch (info->mode) {
21762306a36Sopenharmony_ci	case NXP_NCI_MODE_NCI:
21862306a36Sopenharmony_ci		r = nxp_nci_i2c_nci_read(phy, &skb);
21962306a36Sopenharmony_ci		break;
22062306a36Sopenharmony_ci	case NXP_NCI_MODE_FW:
22162306a36Sopenharmony_ci		r = nxp_nci_i2c_fw_read(phy, &skb);
22262306a36Sopenharmony_ci		break;
22362306a36Sopenharmony_ci	case NXP_NCI_MODE_COLD:
22462306a36Sopenharmony_ci		r = -EREMOTEIO;
22562306a36Sopenharmony_ci		break;
22662306a36Sopenharmony_ci	}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	if (r == -EREMOTEIO) {
22962306a36Sopenharmony_ci		phy->hard_fault = r;
23062306a36Sopenharmony_ci		if (info->mode == NXP_NCI_MODE_FW)
23162306a36Sopenharmony_ci			nxp_nci_fw_recv_frame(phy->ndev, NULL);
23262306a36Sopenharmony_ci	}
23362306a36Sopenharmony_ci	if (r < 0) {
23462306a36Sopenharmony_ci		nfc_err(&client->dev, "Read failed with error %d\n", r);
23562306a36Sopenharmony_ci		goto exit_irq_handled;
23662306a36Sopenharmony_ci	}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	switch (info->mode) {
23962306a36Sopenharmony_ci	case NXP_NCI_MODE_NCI:
24062306a36Sopenharmony_ci		nci_recv_frame(phy->ndev, skb);
24162306a36Sopenharmony_ci		break;
24262306a36Sopenharmony_ci	case NXP_NCI_MODE_FW:
24362306a36Sopenharmony_ci		nxp_nci_fw_recv_frame(phy->ndev, skb);
24462306a36Sopenharmony_ci		break;
24562306a36Sopenharmony_ci	case NXP_NCI_MODE_COLD:
24662306a36Sopenharmony_ci		break;
24762306a36Sopenharmony_ci	}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ciexit_irq_handled:
25062306a36Sopenharmony_ci	mutex_unlock(&info->info_lock);
25162306a36Sopenharmony_ci	return IRQ_HANDLED;
25262306a36Sopenharmony_ciexit_irq_none:
25362306a36Sopenharmony_ci	WARN_ON_ONCE(1);
25462306a36Sopenharmony_ci	return IRQ_NONE;
25562306a36Sopenharmony_ci}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_cistatic const struct acpi_gpio_params firmware_gpios = { 1, 0, false };
25862306a36Sopenharmony_cistatic const struct acpi_gpio_params enable_gpios = { 2, 0, false };
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_cistatic const struct acpi_gpio_mapping acpi_nxp_nci_gpios[] = {
26162306a36Sopenharmony_ci	{ "enable-gpios", &enable_gpios, 1 },
26262306a36Sopenharmony_ci	{ "firmware-gpios", &firmware_gpios, 1 },
26362306a36Sopenharmony_ci	{ }
26462306a36Sopenharmony_ci};
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_cistatic int nxp_nci_i2c_probe(struct i2c_client *client)
26762306a36Sopenharmony_ci{
26862306a36Sopenharmony_ci	struct device *dev = &client->dev;
26962306a36Sopenharmony_ci	struct nxp_nci_i2c_phy *phy;
27062306a36Sopenharmony_ci	int r;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
27362306a36Sopenharmony_ci		nfc_err(&client->dev, "Need I2C_FUNC_I2C\n");
27462306a36Sopenharmony_ci		return -ENODEV;
27562306a36Sopenharmony_ci	}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	phy = devm_kzalloc(&client->dev, sizeof(struct nxp_nci_i2c_phy),
27862306a36Sopenharmony_ci			   GFP_KERNEL);
27962306a36Sopenharmony_ci	if (!phy)
28062306a36Sopenharmony_ci		return -ENOMEM;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	phy->i2c_dev = client;
28362306a36Sopenharmony_ci	i2c_set_clientdata(client, phy);
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	r = devm_acpi_dev_add_driver_gpios(dev, acpi_nxp_nci_gpios);
28662306a36Sopenharmony_ci	if (r)
28762306a36Sopenharmony_ci		dev_dbg(dev, "Unable to add GPIO mapping table\n");
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	phy->gpiod_en = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
29062306a36Sopenharmony_ci	if (IS_ERR(phy->gpiod_en)) {
29162306a36Sopenharmony_ci		nfc_err(dev, "Failed to get EN gpio\n");
29262306a36Sopenharmony_ci		return PTR_ERR(phy->gpiod_en);
29362306a36Sopenharmony_ci	}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	phy->gpiod_fw = devm_gpiod_get_optional(dev, "firmware", GPIOD_OUT_LOW);
29662306a36Sopenharmony_ci	if (IS_ERR(phy->gpiod_fw)) {
29762306a36Sopenharmony_ci		nfc_err(dev, "Failed to get FW gpio\n");
29862306a36Sopenharmony_ci		return PTR_ERR(phy->gpiod_fw);
29962306a36Sopenharmony_ci	}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	r = nxp_nci_probe(phy, &client->dev, &i2c_phy_ops,
30262306a36Sopenharmony_ci			  NXP_NCI_I2C_MAX_PAYLOAD, &phy->ndev);
30362306a36Sopenharmony_ci	if (r < 0)
30462306a36Sopenharmony_ci		return r;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	r = request_threaded_irq(client->irq, NULL,
30762306a36Sopenharmony_ci				 nxp_nci_i2c_irq_thread_fn,
30862306a36Sopenharmony_ci				 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
30962306a36Sopenharmony_ci				 NXP_NCI_I2C_DRIVER_NAME, phy);
31062306a36Sopenharmony_ci	if (r < 0)
31162306a36Sopenharmony_ci		nfc_err(&client->dev, "Unable to register IRQ handler\n");
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	return r;
31462306a36Sopenharmony_ci}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_cistatic void nxp_nci_i2c_remove(struct i2c_client *client)
31762306a36Sopenharmony_ci{
31862306a36Sopenharmony_ci	struct nxp_nci_i2c_phy *phy = i2c_get_clientdata(client);
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	nxp_nci_remove(phy->ndev);
32162306a36Sopenharmony_ci	free_irq(client->irq, phy);
32262306a36Sopenharmony_ci}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_cistatic const struct i2c_device_id nxp_nci_i2c_id_table[] = {
32562306a36Sopenharmony_ci	{"nxp-nci_i2c", 0},
32662306a36Sopenharmony_ci	{}
32762306a36Sopenharmony_ci};
32862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, nxp_nci_i2c_id_table);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_cistatic const struct of_device_id of_nxp_nci_i2c_match[] = {
33162306a36Sopenharmony_ci	{ .compatible = "nxp,nxp-nci-i2c", },
33262306a36Sopenharmony_ci	{}
33362306a36Sopenharmony_ci};
33462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, of_nxp_nci_i2c_match);
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci#ifdef CONFIG_ACPI
33762306a36Sopenharmony_cistatic const struct acpi_device_id acpi_id[] = {
33862306a36Sopenharmony_ci	{ "NXP1001" },
33962306a36Sopenharmony_ci	{ "NXP1002" },
34062306a36Sopenharmony_ci	{ "NXP7471" },
34162306a36Sopenharmony_ci	{ }
34262306a36Sopenharmony_ci};
34362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, acpi_id);
34462306a36Sopenharmony_ci#endif
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_cistatic struct i2c_driver nxp_nci_i2c_driver = {
34762306a36Sopenharmony_ci	.driver = {
34862306a36Sopenharmony_ci		   .name = NXP_NCI_I2C_DRIVER_NAME,
34962306a36Sopenharmony_ci		   .acpi_match_table = ACPI_PTR(acpi_id),
35062306a36Sopenharmony_ci		   .of_match_table = of_nxp_nci_i2c_match,
35162306a36Sopenharmony_ci		  },
35262306a36Sopenharmony_ci	.probe = nxp_nci_i2c_probe,
35362306a36Sopenharmony_ci	.id_table = nxp_nci_i2c_id_table,
35462306a36Sopenharmony_ci	.remove = nxp_nci_i2c_remove,
35562306a36Sopenharmony_ci};
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_cimodule_i2c_driver(nxp_nci_i2c_driver);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ciMODULE_LICENSE("GPL");
36062306a36Sopenharmony_ciMODULE_DESCRIPTION("I2C driver for NXP NCI NFC controllers");
36162306a36Sopenharmony_ciMODULE_AUTHOR("Clément Perrochaud <clement.perrochaud@nxp.com>");
36262306a36Sopenharmony_ciMODULE_AUTHOR("Oleg Zhurakivskyy <oleg.zhurakivskyy@intel.com>");
363