Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 732bcfd4 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "NFC: Add support for core init command"

parents b3f77586 a1dbc26f
Loading
Loading
Loading
Loading
+156 −51
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
#ifdef CONFIG_COMPAT
#include <linux/compat.h>
#endif
#include <linux/jiffies.h>

struct nqx_platform_data {
	unsigned int irq_gpio;
@@ -47,18 +48,6 @@ static const struct of_device_id msm_match_table[] = {

MODULE_DEVICE_TABLE(of, msm_match_table);

#define DEV_COUNT	1
#define DEVICE_NAME	"nq-nci"
#define CLASS_NAME	"nqx"
#define MAX_BUFFER_SIZE			(320)
#define WAKEUP_SRC_TIMEOUT		(2000)
#define MAX_RETRY_COUNT			3
#define NCI_RESET_CMD_LEN		4
#define NCI_RESET_RSP_LEN		4
#define NCI_RESET_NTF_LEN		13
#define NCI_GET_VERSION_CMD_LEN		8
#define NCI_GET_VERSION_RSP_LEN		12

struct nqx_dev {
	wait_queue_head_t	read_wq;
	struct	mutex		read_mutex;
@@ -164,6 +153,16 @@ static irqreturn_t nqx_dev_irq_handler(int irq, void *dev_id)
	return IRQ_HANDLED;
}

static int is_data_available_for_read(struct nqx_dev *nqx_dev)
{
	int ret;

	nqx_enable_irq(nqx_dev);
	ret = wait_event_interruptible_timeout(nqx_dev->read_wq,
		!nqx_dev->irq_enabled, msecs_to_jiffies(MAX_IRQ_WAIT_TIME));
	return ret;
}

static ssize_t nfc_read(struct file *filp, char __user *buf,
					size_t count, loff_t *offset)
{
@@ -793,17 +792,143 @@ static const struct file_operations nfc_dev_fops = {
#endif
};

/*
 * function: get_nfcc_hw_info()
 *
 * @client:                     pointer to i2c_client
 * @nqx_dev:                    pointer to nqx_dev structure
 * @nci_reset_rsp_payload_len:  payload length of NCI reset cmd
 *
 * Retrieves NFCC HW information based on the type of NFC chip
 * used on the device. Depending on the nci_reset_rsp_payload_len
 * value, core INIT command will be sent.
 *
 * NFC HW               NCI version     Send Core INIT cmd
 * NQ3xx or old         1.0             Yes
 * NQ4xx                2.0             No
 * Sn1x0x               2.0             No
 *
 * Return:      error codes in case of any failure,
 *              number of bytes read otherwise
 */
static int get_nfcc_hw_info(struct i2c_client *client,
		struct nqx_dev *nqx_dev, char nci_reset_rsp_payload_len)
{
	int ret = 0;

	char *nci_init_cmd = NULL;
	char *nci_init_rsp = NULL;
	char *nci_reset_ntf = NULL;
	char *nfcc_hw_info = NULL;
	unsigned char nfcc_hw_info_len = 0;

	nci_init_cmd = kzalloc(NCI_INIT_CMD_LEN + 1, GFP_DMA | GFP_KERNEL);
	if (!nci_init_cmd) {
		ret = -ENOMEM;
		goto err_nfcc_hw_info;
	}

	nci_init_rsp = kzalloc(NCI_INIT_RSP_LEN + 1,  GFP_DMA | GFP_KERNEL);
	if (!nci_init_rsp) {
		ret = -ENOMEM;
		goto err_nfcc_hw_info;
	}

	nci_reset_ntf = kzalloc(NCI_RESET_NTF_LEN + 1,  GFP_DMA | GFP_KERNEL);
	if (!nci_reset_ntf) {
		ret = -ENOMEM;
		goto err_nfcc_hw_info;
	}

	if (nci_reset_rsp_payload_len == NCI_1_0_RESET_RSP_PAYLOAD_LEN) {
		/*
		 * Chipset is NQ330 or older.
		 * Send core INIT command to get HW info.
		 */
		nci_init_cmd[0] = 0x20;
		nci_init_cmd[1] = 0x01;
		nci_init_cmd[2] = 0x00;
		ret = nqx_standby_write(nqx_dev, nci_init_cmd,
					NCI_INIT_CMD_LEN);
		if (ret < 0) {
			dev_err(&client->dev,
			"%s: - i2c_master_send failed for Core INIT\n",
					__func__);
			goto err_nfcc_hw_info;
		}

		ret = is_data_available_for_read(nqx_dev);
		if (ret <= 0) {
			nqx_disable_irq(nqx_dev);
			goto err_nfcc_hw_info;
		}

		/* Read Response of INIT command */
		ret = i2c_master_recv(client, nci_init_rsp, NCI_INIT_RSP_LEN);
		if (ret < 0) {
			dev_err(&client->dev,
			"%s: - i2c_master_recv get INIT rsp Error\n",
					__func__);
			goto err_nfcc_hw_info;
		}
		nfcc_hw_info = nci_init_rsp;
	} else {
		/*
		 * Chipset is NQ4xx or later.
		 * Retrieve NTF data from wait queue.
		 */
		ret = is_data_available_for_read(nqx_dev);
		if (ret <= 0) {
			nqx_disable_irq(nqx_dev);
			goto err_nfcc_hw_info;
		}

		/* Read Notification of RESET command */
		ret = i2c_master_recv(client, nci_reset_ntf, NCI_RESET_NTF_LEN);
		if (ret < 0) {
			dev_err(&client->dev,
			"%s: - i2c_master_recv get RESET ntf Error\n",
					__func__);
			goto err_nfcc_hw_info;
		}
		nfcc_hw_info = nci_reset_ntf;
	}

	/* Save NFCC HW info */
	nfcc_hw_info_len =
		NCI_HEADER_LEN + nfcc_hw_info[NCI_PAYLOAD_LENGTH_INDEX];
	if (nfcc_hw_info_len > PAYLOAD_HEADER_LENGTH) {
		nqx_dev->nqx_info.info.chip_type =
			nfcc_hw_info[nfcc_hw_info_len -
					NFCC_HW_CHIP_ID_OFFSET];
		nqx_dev->nqx_info.info.rom_version =
			nfcc_hw_info[nfcc_hw_info_len -
					NFCC_HW_ROM_VER_OFFSET];
		nqx_dev->nqx_info.info.fw_major =
			nfcc_hw_info[nfcc_hw_info_len -
					NFCC_HW_MAJOR_NO_OFFSET];
		nqx_dev->nqx_info.info.fw_minor =
			nfcc_hw_info[nfcc_hw_info_len -
					NFCC_HW_MINOR_NO_OFFSET];
	}

err_nfcc_hw_info:

	kfree(nci_reset_ntf);
	kfree(nci_init_rsp);
	kfree(nci_init_cmd);

	return ret;
}

/* Check for availability of NQ_ NFC controller hardware */
static int nfcc_hw_check(struct i2c_client *client, struct nqx_dev *nqx_dev)
{
	int ret = 0;

	int gpio_retry_count = 0;
	unsigned char reset_ntf_len = 0;
	unsigned int enable_gpio = nqx_dev->en_gpio;
	char *nci_reset_cmd = NULL;
	char *nci_reset_rsp = NULL;
	char *nci_reset_ntf = NULL;
	char *nci_get_version_cmd = NULL;
	char *nci_get_version_rsp = NULL;

@@ -819,12 +944,6 @@ static int nfcc_hw_check(struct i2c_client *client, struct nqx_dev *nqx_dev)
		goto done;
	}

	nci_reset_ntf = kzalloc(NCI_RESET_NTF_LEN + 1,  GFP_DMA | GFP_KERNEL);
	if (!nci_reset_ntf) {
		ret = -ENOMEM;
		goto done;
	}

	nci_get_version_cmd = kzalloc(NCI_GET_VERSION_CMD_LEN + 1,
					GFP_DMA | GFP_KERNEL);
	if (!nci_get_version_cmd) {
@@ -839,7 +958,6 @@ static int nfcc_hw_check(struct i2c_client *client, struct nqx_dev *nqx_dev)
		goto done;
	}

reset_enable_gpio:
	/* making sure that the NFCC starts in a clean state. */
	gpio_set_value(enable_gpio, 1);/* HPD : Enable*/
	/* hardware dependent delay */
@@ -909,49 +1027,37 @@ static int nfcc_hw_check(struct i2c_client *client, struct nqx_dev *nqx_dev)
		}
		goto err_nfcc_reset_failed;
	}
	nqx_enable_irq(nqx_dev);
	ret = wait_event_interruptible(nqx_dev->read_wq, !nqx_dev->irq_enabled);
	if (ret < 0) {
	ret = is_data_available_for_read(nqx_dev);
	if (ret <= 0) {
		nqx_disable_irq(nqx_dev);
		goto err_nfcc_hw_check;
	}

	/* Read Response of RESET command */
	ret = i2c_master_recv(client, nci_reset_rsp, NCI_RESET_RSP_LEN);
	if (ret < 0) {
	/* Read Header of RESET command */
	ret = i2c_master_recv(client, nci_reset_rsp, NCI_HEADER_LEN);
	if (ret != NCI_HEADER_LEN) {
		dev_err(&client->dev,
		"%s: - i2c_master_recv Error\n", __func__);
		gpio_retry_count = gpio_retry_count + 1;
		if (gpio_retry_count < MAX_RETRY_COUNT)
			goto reset_enable_gpio;
		"%s: - i2c_master_recv get RESET rsp header Error\n", __func__);
		goto err_nfcc_hw_check;
	}
	nqx_enable_irq(nqx_dev);
	ret = wait_event_interruptible(nqx_dev->read_wq, !nqx_dev->irq_enabled);
	if (ret < 0) {
		nqx_disable_irq(nqx_dev);

	ret = i2c_master_recv(client, &nci_reset_rsp[NCI_PAYLOAD_START_INDEX],
				nci_reset_rsp[NCI_PAYLOAD_LENGTH_INDEX]);
	if (ret != nci_reset_rsp[NCI_PAYLOAD_LENGTH_INDEX]) {
		dev_err(&client->dev,
		"%s: - i2c_master_recv get RESET rsp data Error\n", __func__);
		goto err_nfcc_hw_check;
	}

	/* Read Notification of RESET command */
	ret = i2c_master_recv(client, nci_reset_ntf, NCI_RESET_NTF_LEN);
	/* Retrieve NFCC HW info */
	ret = get_nfcc_hw_info(client, nqx_dev,
			nci_reset_rsp[NCI_PAYLOAD_LENGTH_INDEX]);
	if (ret < 0) {
		dev_err(&client->dev,
		"%s: - i2c_master_recv Error\n", __func__);
			"%s: - Error in getting NFCC HW info\n", __func__);
		goto err_nfcc_hw_check;
	}

	reset_ntf_len = 2 + nci_reset_ntf[2]; /*payload + len*/
	if (reset_ntf_len > PAYLOAD_HEADER_LENGTH) {
		nqx_dev->nqx_info.info.chip_type =
				nci_reset_ntf[reset_ntf_len - 3];
		nqx_dev->nqx_info.info.rom_version =
				nci_reset_ntf[reset_ntf_len - 2];
		nqx_dev->nqx_info.info.fw_major =
				nci_reset_ntf[reset_ntf_len - 1];
		nqx_dev->nqx_info.info.fw_minor =
				nci_reset_ntf[reset_ntf_len];
	}
	dev_dbg(&client->dev,
		"%s: - nq - reset cmd answer : NfcNciRx %x %x %x\n",
		__func__, nci_reset_rsp[0],
@@ -1000,7 +1106,6 @@ static int nfcc_hw_check(struct i2c_client *client, struct nqx_dev *nqx_dev)

done:
	kfree(nci_reset_rsp);
	kfree(nci_reset_ntf);
	kfree(nci_reset_cmd);
	kfree(nci_get_version_cmd);
	kfree(nci_get_version_rsp);
+23 −0
Original line number Diff line number Diff line
@@ -37,6 +37,29 @@
#define BYTE				(0x8)
#define NCI_IDENTIFIER			(0x10)

#define DEV_COUNT	1
#define DEVICE_NAME	"nq-nci"
#define CLASS_NAME	"nqx"
#define MAX_BUFFER_SIZE			(320)
#define WAKEUP_SRC_TIMEOUT		(2000)
#define MAX_RETRY_COUNT			3
#define NCI_RESET_CMD_LEN		4
#define NCI_RESET_RSP_LEN		6
#define NCI_RESET_NTF_LEN		13
#define NCI_INIT_CMD_LEN		3
#define NCI_INIT_RSP_LEN		28
#define NCI_GET_VERSION_CMD_LEN		8
#define NCI_GET_VERSION_RSP_LEN		12
#define NCI_HEADER_LEN			3
#define NCI_1_0_RESET_RSP_PAYLOAD_LEN	3
#define NCI_PAYLOAD_START_INDEX		3
#define NCI_PAYLOAD_LENGTH_INDEX	(NCI_PAYLOAD_START_INDEX - 1)
#define MAX_IRQ_WAIT_TIME		(90) /* in ms */
#define NFCC_HW_CHIP_ID_OFFSET		4
#define NFCC_HW_ROM_VER_OFFSET		3
#define NFCC_HW_MAJOR_NO_OFFSET		2
#define NFCC_HW_MINOR_NO_OFFSET		1

enum nfcc_initial_core_reset_ntf {
	TIMEDOUT_INITIAL_CORE_RESET_NTF = 0, /* 0*/
	ARRIVED_INITIAL_CORE_RESET_NTF, /* 1 */