NFC: Inform CLF whenever eSE is powered off

When the eSE is powered off, the “system” needs to give
8ms to the capacitor connected on the SVDD line to discharge.

We should inform the FW we just powered off the eSE.

Change-Id: I864fd8f75ded6ab8c42ea36bcdadcdbe924e927d
Signed-off-by: Gaurav Singhal <gsinghal@codeaurora.org>
This commit is contained in:
Gaurav Singhal 2016-11-28 17:23:58 +05:30 committed by Rohit Rangwani
parent 368fecd7df
commit 41b99b48c5
2 changed files with 112 additions and 27 deletions

View file

@ -47,6 +47,7 @@ MODULE_DEVICE_TABLE(of, msm_match_table);
#define MAX_BUFFER_SIZE (320)
#define WAKEUP_SRC_TIMEOUT (2000)
#define MAX_RETRY_COUNT 3
struct nqx_dev {
wait_queue_head_t read_wq;
@ -264,6 +265,35 @@ out:
return ret;
}
/**
* nqx_standby_write()
* @buf: pointer to data buffer
* @len: # of bytes need to transfer
*
* write data buffer over I2C and retry
* if NFCC is in stand by mode
*
* Return: # of bytes written or -ve value in case of error
*/
static int nqx_standby_write(struct nqx_dev *nqx_dev,
const unsigned char *buf, size_t len)
{
int ret = -EINVAL;
int retry_cnt;
for (retry_cnt = 1; retry_cnt <= MAX_RETRY_COUNT; retry_cnt++) {
ret = i2c_master_send(nqx_dev->client, buf, len);
if (ret < 0) {
dev_err(&nqx_dev->client->dev,
"%s: write failed, Maybe in Standby Mode - Retry(%d)\n",
__func__, retry_cnt);
usleep_range(1000, 1100);
} else if (ret == len)
break;
}
return ret;
}
/*
* Power management of the eSE
* NFC & eSE ON : NFC_EN high and eSE_pwr_req high.
@ -273,39 +303,95 @@ out:
static int nqx_ese_pwr(struct nqx_dev *nqx_dev, unsigned long int arg)
{
int r = -1;
const unsigned char svdd_off_cmd_warn[] = {0x2F, 0x31, 0x01, 0x01};
const unsigned char svdd_off_cmd_done[] = {0x2F, 0x31, 0x01, 0x00};
if (!gpio_is_valid(nqx_dev->ese_gpio)) {
dev_err(&nqx_dev->client->dev,
"%s: ese_gpio is not valid\n", __func__);
return -EINVAL;
}
/* Let's store the NFC_EN pin state */
if (arg == 0) {
/*
* We want to power on the eSE and to do so we need the
* eSE_pwr_req pin and the NFC_EN pin to be high
*/
nqx_dev->nfc_ven_enabled = gpio_get_value(nqx_dev->en_gpio);
if (!nqx_dev->nfc_ven_enabled) {
gpio_set_value(nqx_dev->en_gpio, 1);
/* hardware dependent delay */
usleep_range(1000, 1100);
}
if (gpio_is_valid(nqx_dev->ese_gpio)) {
if (gpio_get_value(nqx_dev->ese_gpio)) {
dev_dbg(&nqx_dev->client->dev, "ese_gpio is already high\n");
r = 0;
} else {
/**
* Let's store the NFC_EN pin state
* only if the eSE is not yet on
*/
nqx_dev->nfc_ven_enabled =
gpio_get_value(nqx_dev->en_gpio);
if (!nqx_dev->nfc_ven_enabled) {
gpio_set_value(nqx_dev->en_gpio, 1);
/* hardware dependent delay */
usleep_range(1000, 1100);
}
gpio_set_value(nqx_dev->ese_gpio, 1);
if (gpio_get_value(nqx_dev->ese_gpio)) {
dev_dbg(&nqx_dev->client->dev, "ese_gpio is already high\n");
dev_dbg(&nqx_dev->client->dev, "ese_gpio is enabled\n");
r = 0;
} else {
gpio_set_value(nqx_dev->ese_gpio, 1);
if (gpio_get_value(nqx_dev->ese_gpio)) {
dev_dbg(&nqx_dev->client->dev, "ese_gpio is enabled\n");
r = 0;
}
}
}
} else if (arg == 1) {
if (gpio_is_valid(nqx_dev->ese_gpio)) {
gpio_set_value(nqx_dev->ese_gpio, 0);
if (!gpio_get_value(nqx_dev->ese_gpio)) {
dev_dbg(&nqx_dev->client->dev, "ese_gpio is disabled\n");
r = 0;
if (nqx_dev->nfc_ven_enabled &&
((nqx_dev->nqx_info.info.chip_type == NFCC_NQ_220) ||
(nqx_dev->nqx_info.info.chip_type == NFCC_PN66T))) {
/**
* Let's inform the CLF we're
* powering off the eSE
*/
r = nqx_standby_write(nqx_dev, svdd_off_cmd_warn,
sizeof(svdd_off_cmd_warn));
if (r < 0) {
dev_err(&nqx_dev->client->dev,
"%s: write failed after max retry\n",
__func__);
return -ENXIO;
}
dev_dbg(&nqx_dev->client->dev,
"%s: svdd_off_cmd_warn sent\n", __func__);
/* let's power down the eSE */
gpio_set_value(nqx_dev->ese_gpio, 0);
dev_dbg(&nqx_dev->client->dev,
"%s: nqx_dev->ese_gpio set to 0\n", __func__);
/**
* Time needed for the SVDD capacitor
* to get discharged
*/
usleep_range(8000, 8100);
/* Let's inform the CLF the eSE is now off */
r = nqx_standby_write(nqx_dev, svdd_off_cmd_done,
sizeof(svdd_off_cmd_done));
if (r < 0) {
dev_err(&nqx_dev->client->dev,
"%s: write failed after max retry\n",
__func__);
return -ENXIO;
}
dev_dbg(&nqx_dev->client->dev,
"%s: svdd_off_cmd_done sent\n", __func__);
} else {
/**
* In case the NFC is off,
* there's no need to send the i2c commands
*/
gpio_set_value(nqx_dev->ese_gpio, 0);
}
if (!gpio_get_value(nqx_dev->ese_gpio)) {
dev_dbg(&nqx_dev->client->dev, "ese_gpio is disabled\n");
r = 0;
}
if (!nqx_dev->nfc_ven_enabled) {
/* hardware dependent delay */
usleep_range(1000, 1100);
@ -313,12 +399,7 @@ static int nqx_ese_pwr(struct nqx_dev *nqx_dev, unsigned long int arg)
gpio_set_value(nqx_dev->en_gpio, 0);
}
} else if (arg == 3) {
if (!nqx_dev->nfc_ven_enabled)
r = 0;
else {
if (gpio_is_valid(nqx_dev->ese_gpio))
r = gpio_get_value(nqx_dev->ese_gpio);
}
r = gpio_get_value(nqx_dev->ese_gpio);
}
return r;
}
@ -624,6 +705,10 @@ static int nfcc_hw_check(struct i2c_client *client, struct nqx_dev *nqx_dev)
dev_dbg(&client->dev,
"%s: ## NFCC == NQ330 ##\n", __func__);
break;
case NFCC_PN66T:
dev_dbg(&client->dev,
"%s: ## NFCC == PN66T ##\n", __func__);
break;
default:
dev_err(&client->dev,
"%s: - NFCC HW not Supported\n", __func__);

View file

@ -48,7 +48,7 @@ enum nfcc_chip_variant {
NFCC_NQ_220 = 0x58, /**< NFCC NQ220 */
NFCC_NQ_310 = 0x40, /**< NFCC NQ310 */
NFCC_NQ_330 = 0x51, /**< NFCC NQ330 */
NFCC_PN66T = 0x18, /**< NFCC PN66T */
NFCC_NOT_SUPPORTED = 0xFF /**< NFCC is not supported */
};
#endif