Merge "NFC: Inform CLF whenever eSE is powered off"

This commit is contained in:
Linux Build Service Account 2016-12-13 12:17:54 -08:00 committed by Gerrit - the friendly Code Review server
commit d3fdecd206
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