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

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

Merge "NFC: Add support for ese cold reset"

parents 3a9eb4f4 dea45e3d
Loading
Loading
Loading
Loading
+172 −27
Original line number Diff line number Diff line
@@ -41,21 +41,9 @@ 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
#define MAX_IRQ_WAIT_TIME		(90)	//in ms

struct nqx_dev {
	wait_queue_head_t	read_wq;
	wait_queue_head_t	cold_reset_read_wq;
	struct	mutex		read_mutex;
	struct	mutex		dev_ref_mutex;
	struct	i2c_client	*client;
@@ -72,10 +60,14 @@ struct nqx_dev {
	unsigned int		ese_gpio;
	/* NFC VEN pin state powered by Nfc */
	bool			nfc_ven_enabled;
	/* NFC state reflected from MW */
	bool			nfc_enabled;
	/* NFC_IRQ state */
	bool			irq_enabled;
	/* NFC_IRQ wake-up state */
	bool			irq_wake_up;
	bool			cold_reset_rsp_pending;
	uint8_t			cold_reset_status;
	spinlock_t		irq_enabled_lock;
	unsigned int		count_irq;
	/* NFC_IRQ Count */
@@ -97,6 +89,9 @@ static int nfcc_reboot(struct notifier_block *notifier, unsigned long val,
static int nqx_clock_select(struct nqx_dev *nqx_dev);
/*clock disable function*/
static int nqx_clock_deselect(struct nqx_dev *nqx_dev);
static int nqx_standby_write(struct nqx_dev *nqx_dev,
				const unsigned char *buf, size_t len);

static struct notifier_block nfcc_notifier = {
	.notifier_call	= nfcc_reboot,
	.next			= NULL,
@@ -159,6 +154,92 @@ 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 int send_cold_reset_cmd(struct nqx_dev *nqx_dev)
{
	int ret;
	char *cold_reset_cmd = NULL;

	if (gpio_get_value(nqx_dev->firm_gpio)) {
		dev_err(&nqx_dev->client->dev, "FW download in-progress\n");
		return -EBUSY;
	}
	if (!gpio_get_value(nqx_dev->en_gpio)) {
		dev_err(&nqx_dev->client->dev, "VEN LOW - NFCC powered off\n");
		return -ENODEV;
	}
	cold_reset_cmd = kzalloc(COLD_RESET_CMD_LEN, GFP_DMA | GFP_KERNEL);
	if (!cold_reset_cmd)
		return -ENOMEM;

	cold_reset_cmd[0] = COLD_RESET_CMD_GID;
	cold_reset_cmd[1] = COLD_RESET_OID;
	cold_reset_cmd[2] = COLD_RESET_CMD_PAYLOAD_LEN;

	ret = nqx_standby_write(nqx_dev, cold_reset_cmd, COLD_RESET_CMD_LEN);
	if (ret < 0) {
		dev_err(&nqx_dev->client->dev,
			"%s: write failed after max retry\n", __func__);
	}
	kfree(cold_reset_cmd);
	return ret;
}

static void read_cold_reset_rsp(struct nqx_dev *nqx_dev, bool isNfcEnabled,
				char *header)
{
	int ret = -1;
	char *cold_reset_rsp = NULL;

	cold_reset_rsp = kzalloc(COLD_RESET_RSP_LEN, GFP_DMA | GFP_KERNEL);
	if (!cold_reset_rsp)
		return;

	/*
	 * read header also if NFC is disabled
	 * for enable case, will be taken care by nfc_read thread
	 */
	if (!isNfcEnabled) {
		ret = i2c_master_recv(nqx_dev->client, cold_reset_rsp,
					NCI_HEADER_LEN);
		if (ret != NCI_HEADER_LEN) {
			dev_err(&nqx_dev->client->dev,
				"%s: failure to read cold reset rsp header\n",
				__func__);
			goto error;
		}
	} else {
		memcpy(cold_reset_rsp, header, NCI_HEADER_LEN);
	}

	if ((NCI_HEADER_LEN + cold_reset_rsp[2]) > COLD_RESET_RSP_LEN) {
		dev_err(&nqx_dev->client->dev,
			"%s: - invalid response for cold_reset\n", __func__);
		ret = -EINVAL;
		goto error;
	}
	ret = i2c_master_recv(nqx_dev->client, &cold_reset_rsp[NCI_PAYLOAD_IDX],
				cold_reset_rsp[2]);
	if (ret != cold_reset_rsp[2]) {
		dev_err(&nqx_dev->client->dev,
			"%s: failure to read cold reset rsp status\n",
			__func__);
		goto error;
	}
	nqx_dev->cold_reset_status = cold_reset_rsp[NCI_PAYLOAD_IDX];
error:
	kfree(cold_reset_rsp);
}

static ssize_t nfc_read(struct file *filp, char __user *buf,
					size_t count, loff_t *offset)
{
@@ -232,6 +313,24 @@ static ssize_t nfc_read(struct file *filp, char __user *buf,
		ret = -EIO;
		goto err;
	}
	/* check if it's response of cold reset command
	 * NFC HAL process shouldn't receive this data as
	 * command was sent by eSE HAL
	 */
	if (nqx_dev->cold_reset_rsp_pending
		&& (tmp[0] == COLD_RESET_RSP_GID)
		&& (tmp[1] == COLD_RESET_OID)) {
		read_cold_reset_rsp(nqx_dev, true, tmp);
		nqx_dev->cold_reset_rsp_pending = false;
		wake_up_interruptible(&nqx_dev->cold_reset_read_wq);
		mutex_unlock(&nqx_dev->read_mutex);
		/*
		 * NFC process doesn't know about cold reset command
		 * being sent as it was initiated by eSE process
		 * we shouldn't return any data to NFC process
		 */
		return 0;
	}
#ifdef NFC_KERNEL_BU
		dev_dbg(&nqx_dev->client->dev, "%s : NfcNciRx %x %x %x\n",
			__func__, tmp[0], tmp[1], tmp[2]);
@@ -326,17 +425,19 @@ static int nqx_standby_write(struct nqx_dev *nqx_dev,
	return ret;
}


/*
 * Power management of the SN100 eSE
 * eSE and NFCC both are powered using VEN gpio in SN100,
 * VEN HIGH - eSE and NFCC both are powered on
 * VEN LOW - eSE and NFCC both are power down
 */

static int sn100_ese_pwr(struct nqx_dev *nqx_dev, unsigned long arg)
{
	int r = -1;

	if (arg == 0) {
	if (arg == ESE_POWER_ON) {
		/**
		 * Let's store the NFC VEN pin state
		 * will check stored value in case of eSE power off request,
@@ -355,7 +456,7 @@ static int sn100_ese_pwr(struct nqx_dev *nqx_dev, unsigned long arg)
			dev_dbg(&nqx_dev->client->dev, "en_gpio already HIGH\n");
		}
		r = 0;
	} else if (arg == 1) {
	} else if (arg == ESE_POWER_OFF) {
		if (!nqx_dev->nfc_ven_enabled) {
			dev_dbg(&nqx_dev->client->dev, "NFC not enabled, disabling en_gpio\n");
			gpio_set_value(nqx_dev->en_gpio, 0);
@@ -365,7 +466,40 @@ static int sn100_ese_pwr(struct nqx_dev *nqx_dev, unsigned long arg)
			dev_dbg(&nqx_dev->client->dev, "keep en_gpio high as NFC is enabled\n");
		}
		r = 0;
	} else if (arg == 3) {
	} else if (arg == ESE_COLD_RESET) {
		// set default value for status as failure
		nqx_dev->cold_reset_status = EIO;

		r = send_cold_reset_cmd(nqx_dev);
		if (r <= 0) {
			dev_err(&nqx_dev->client->dev,
				"failed to send cold reset command\n");
			return nqx_dev->cold_reset_status;
		}
		nqx_dev->cold_reset_rsp_pending = true;
		// check if NFC is enabled
		if (nqx_dev->nfc_enabled) {
			/*
			 * nfc_read thread will initiate cold reset response
			 * and it will signal for data available
			 */
			wait_event_interruptible(nqx_dev->cold_reset_read_wq,
				!nqx_dev->cold_reset_rsp_pending);
		} else {
			/*
			 * Read data as NFC thread is not active
			 */
			r = is_data_available_for_read(nqx_dev);
			if (r <= 0) {
				nqx_disable_irq(nqx_dev);
				nqx_dev->cold_reset_rsp_pending = false;
				return nqx_dev->cold_reset_status;
			}
			read_cold_reset_rsp(nqx_dev, false, NULL);
			nqx_dev->cold_reset_rsp_pending = false;
		}
		r = nqx_dev->cold_reset_status;
	} else if (arg == ESE_POWER_STATE) {
		// eSE power state
		r = gpio_get_value(nqx_dev->en_gpio);
	}
@@ -556,7 +690,7 @@ int nfc_ioctl_power_states(struct file *filp, unsigned long arg)
	int r = 0;
	struct nqx_dev *nqx_dev = filp->private_data;

	if (arg == 0) {
	if (arg == NFC_POWER_OFF) {
		/*
		 * We are attempting a hardware reset so let us disable
		 * interrupts to avoid spurious notifications to upper
@@ -590,7 +724,7 @@ int nfc_ioctl_power_states(struct file *filp, unsigned long arg)
				dev_err(&nqx_dev->client->dev, "unable to disable clock\n");
		}
		nqx_dev->nfc_ven_enabled = false;
	} else if (arg == 1) {
	} else if (arg == NFC_POWER_ON) {
		nqx_enable_irq(nqx_dev);
		dev_dbg(&nqx_dev->client->dev,
			"gpio_set_value enable: %s: info: %p\n",
@@ -607,7 +741,7 @@ int nfc_ioctl_power_states(struct file *filp, unsigned long arg)
				dev_err(&nqx_dev->client->dev, "unable to enable clock\n");
		}
		nqx_dev->nfc_ven_enabled = true;
	} else if (arg == 2) {
	} else if (arg == NFC_FW_DWL_VEN_TOGGLE) {
		/*
		 * We are switching to Dowload Mode, toggle the enable pin
		 * in order to set the NFCC in the new mode
@@ -629,7 +763,7 @@ int nfc_ioctl_power_states(struct file *filp, unsigned long arg)
		usleep_range(10000, 10100);
		gpio_set_value(nqx_dev->en_gpio, 1);
		usleep_range(10000, 10100);
	} else if (arg == 4) {
	} else if (arg == NFC_FW_DWL_HIGH) {
		/*
		 * Setting firmware download gpio to HIGH for SN100U
		 * before FW download start
@@ -641,7 +775,7 @@ int nfc_ioctl_power_states(struct file *filp, unsigned long arg)
		} else
			dev_err(&nqx_dev->client->dev,
				"firm_gpio is invalid\n");
	} else if (arg == 6) {
	} else if (arg == NFC_FW_DWL_LOW) {
		/*
		 * Setting firmware download gpio to LOW for SN100U
		 * FW download finished
@@ -654,6 +788,16 @@ int nfc_ioctl_power_states(struct file *filp, unsigned long arg)
			dev_err(&nqx_dev->client->dev,
				"firm_gpio is invalid\n");
		}
	} else if (arg == NFC_ENABLE) {
		/*
		 * Setting flag true when NFC is enabled
		 */
		nqx_dev->nfc_enabled = true;
	} else if (arg == NFC_DISABLE) {
		/*
		 * Setting flag false when NFC is disabled
		 */
		nqx_dev->nfc_enabled = false;
	} else {
		r = -ENOIOCTLCMD;
	}
@@ -897,9 +1041,8 @@ 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_timeout(nqx_dev->read_wq,
		!nqx_dev->irq_enabled, msecs_to_jiffies(MAX_IRQ_WAIT_TIME));

	ret = is_data_available_for_read(nqx_dev);
	if (ret <= 0) {
		nqx_disable_irq(nqx_dev);
		goto err_nfcc_hw_check;
@@ -915,9 +1058,8 @@ static int nfcc_hw_check(struct i2c_client *client, struct nqx_dev *nqx_dev)
			goto reset_enable_gpio;
		goto err_nfcc_hw_check;
	}
	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));

	ret = is_data_available_for_read(nqx_dev);
	if (ret <= 0) {
		nqx_disable_irq(nqx_dev);
		goto err_nfcc_hw_check;
@@ -1280,6 +1422,7 @@ static int nqx_probe(struct i2c_client *client,

	/* init mutex and queues */
	init_waitqueue_head(&nqx_dev->read_wq);
	init_waitqueue_head(&nqx_dev->cold_reset_read_wq);
	mutex_init(&nqx_dev->read_mutex);
	mutex_init(&nqx_dev->dev_ref_mutex);
	spin_lock_init(&nqx_dev->irq_enabled_lock);
@@ -1362,6 +1505,8 @@ static int nqx_probe(struct i2c_client *client,
	device_set_wakeup_capable(&client->dev, true);
	i2c_set_clientdata(client, nqx_dev);
	nqx_dev->irq_wake_up = false;
	nqx_dev->cold_reset_rsp_pending = false;
	nqx_dev->nfc_enabled = false;

	dev_err(&client->dev,
	"%s: probing NFCC NQxxx exited successfully\n",
+53 −0
Original line number Diff line number Diff line
@@ -24,12 +24,65 @@
#define SET_EMULATOR_TEST_POINT		_IOW(0xE9, 0x05, unsigned int)
#define NFCC_INITIAL_CORE_RESET_NTF	_IOW(0xE9, 0x10, unsigned int)

#define DEV_COUNT			1
#define DEVICE_NAME			"nq-nci"
#define CLASS_NAME			"nqx"
#define MAX_BUFFER_SIZE			(320)
#define WAKEUP_SRC_TIMEOUT		(2000)
#define NCI_HEADER_LEN			3
#define NCI_PAYLOAD_IDX			3
#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
#define MAX_IRQ_WAIT_TIME		(90)	//in ms
#define COLD_RESET_CMD_LEN		3
#define COLD_RESET_RSP_LEN		4
#define COLD_RESET_CMD_GID		0x2F
#define COLD_RESET_CMD_PAYLOAD_LEN	0x00
#define COLD_RESET_RSP_GID		0x4F
#define COLD_RESET_OID			0x1E

#define NFC_RX_BUFFER_CNT_START		(0x0)
#define PAYLOAD_HEADER_LENGTH		(0x3)
#define PAYLOAD_LENGTH_MAX		(256)
#define BYTE				(0x8)
#define NCI_IDENTIFIER			(0x10)

enum ese_ioctl_request {
	/* eSE POWER ON */
	ESE_POWER_ON = 0,
	/* eSE POWER OFF */
	ESE_POWER_OFF,
	/* eSE COLD RESET */
	ESE_COLD_RESET,
	/* eSE POWER STATE */
	ESE_POWER_STATE
};

enum nfcc_ioctl_request {
	/* NFC disable request with VEN LOW */
	NFC_POWER_OFF = 0,
	/* NFC enable request with VEN Toggle */
	NFC_POWER_ON,
	/* firmware download request with VEN Toggle */
	NFC_FW_DWL_VEN_TOGGLE,
	/* ISO reset request */
	NFC_ISO_RESET,
	/* request for firmware download gpio HIGH */
	NFC_FW_DWL_HIGH,
	/* hard reset request */
	NFC_HARD_RESET,
	/* request for firmware download gpio LOW */
	NFC_FW_DWL_LOW,
	/* NFC enable without VEN gpio modification */
	NFC_ENABLE,
	/* NFC disable without VEN gpio modification */
	NFC_DISABLE
};

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