NFC: Add support for core init command

NFC driver currently have support for
targtes with NQ4xx and later NFC HW.
Targets having NQ3xx or older HW do not
support NCI 2.0 specifications.

Add support to probe device node on
targets with NQ3xx or older NFC HW.

Change-Id: I179a536cf68dea72f125f730d55fdb6d559fbe2c
Signed-off-by: Bhuvan Varshney <bvarshne@codeaurora.org>
Signed-off-by: Asha Magadi Venkateshamurthy <amagad@codeaurora.org>
This commit is contained in:
Asha Magadi Venkateshamurthy 2020-10-01 09:37:21 +05:30
parent 6b11034977
commit 020bfa88c1
2 changed files with 161 additions and 43 deletions

View File

@ -1050,17 +1050,145 @@ 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_dbg(&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_dbg(&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_dbg(&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;
@ -1075,13 +1203,6 @@ static int nfcc_hw_check(struct i2c_client *client, struct nqx_dev *nqx_dev)
ret = -ENOMEM;
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) {
@ -1096,7 +1217,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 */
@ -1173,42 +1293,32 @@ reset_enable_gpio:
goto err_nfcc_hw_check;
}
/* Read Response of RESET command */
ret = i2c_master_recv(client, nci_reset_rsp, NCI_RESET_RSP_LEN);
/* Read Header of RESET command */
ret = i2c_master_recv(client, nci_reset_rsp, NCI_HEADER_LEN);
if (ret != NCI_HEADER_LEN) {
dev_dbg(&client->dev,
"%s: - i2c_master_recv get RESET rsp header Error\n", __func__);
goto err_nfcc_hw_check;
}
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_dbg(&client->dev,
"%s: - i2c_master_recv get RESET rsp data Error\n", __func__);
goto err_nfcc_hw_check;
}
/* 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__);
gpio_retry_count = gpio_retry_count + 1;
if (gpio_retry_count < MAX_RETRY_COUNT)
goto reset_enable_gpio;
dev_dbg(&client->dev,
"%s: - Error in getting NFCC HW info\n", __func__);
goto err_nfcc_hw_check;
}
ret = is_data_available_for_read(nqx_dev);
if (ret <= 0) {
nqx_disable_irq(nqx_dev);
goto err_nfcc_hw_check;
}
/* 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 Error\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],
@ -1257,7 +1367,6 @@ err_nfcc_hw_check:
done:
kfree(nci_reset_rsp);
kfree(nci_reset_ntf);
kfree(nci_reset_cmd);
kfree(nci_get_version_cmd);
kfree(nci_get_version_rsp);

View File

@ -40,8 +40,17 @@
#define NCI_RESET_CMD_LEN 4
#define NCI_RESET_RSP_LEN 4
#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_1_0_RESET_RSP_PAYLOAD_LEN 3
#define NCI_PAYLOAD_START_INDEX 3
#define NCI_PAYLOAD_LENGTH_INDEX (NCI_PAYLOAD_START_INDEX - 1)
#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
#define MAX_IRQ_WAIT_TIME (90) //in ms
#define COLD_RESET_CMD_LEN 3
#define COLD_RESET_RSP_LEN 4