Merge "NFC: Inform CLF whenever eSE is powered off"
This commit is contained in:
commit
d3fdecd206
2 changed files with 112 additions and 27 deletions
|
@ -47,6 +47,7 @@ MODULE_DEVICE_TABLE(of, msm_match_table);
|
||||||
|
|
||||||
#define MAX_BUFFER_SIZE (320)
|
#define MAX_BUFFER_SIZE (320)
|
||||||
#define WAKEUP_SRC_TIMEOUT (2000)
|
#define WAKEUP_SRC_TIMEOUT (2000)
|
||||||
|
#define MAX_RETRY_COUNT 3
|
||||||
|
|
||||||
struct nqx_dev {
|
struct nqx_dev {
|
||||||
wait_queue_head_t read_wq;
|
wait_queue_head_t read_wq;
|
||||||
|
@ -264,6 +265,35 @@ out:
|
||||||
return ret;
|
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
|
* Power management of the eSE
|
||||||
* NFC & eSE ON : NFC_EN high and eSE_pwr_req high.
|
* 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)
|
static int nqx_ese_pwr(struct nqx_dev *nqx_dev, unsigned long int arg)
|
||||||
{
|
{
|
||||||
int r = -1;
|
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) {
|
if (arg == 0) {
|
||||||
/*
|
/*
|
||||||
* We want to power on the eSE and to do so we need the
|
* 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
|
* 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 (gpio_get_value(nqx_dev->ese_gpio)) {
|
||||||
if (!nqx_dev->nfc_ven_enabled) {
|
dev_dbg(&nqx_dev->client->dev, "ese_gpio is already high\n");
|
||||||
gpio_set_value(nqx_dev->en_gpio, 1);
|
r = 0;
|
||||||
/* hardware dependent delay */
|
} else {
|
||||||
usleep_range(1000, 1100);
|
/**
|
||||||
}
|
* Let's store the NFC_EN pin state
|
||||||
if (gpio_is_valid(nqx_dev->ese_gpio)) {
|
* 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)) {
|
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;
|
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) {
|
} else if (arg == 1) {
|
||||||
if (gpio_is_valid(nqx_dev->ese_gpio)) {
|
if (nqx_dev->nfc_ven_enabled &&
|
||||||
gpio_set_value(nqx_dev->ese_gpio, 0);
|
((nqx_dev->nqx_info.info.chip_type == NFCC_NQ_220) ||
|
||||||
if (!gpio_get_value(nqx_dev->ese_gpio)) {
|
(nqx_dev->nqx_info.info.chip_type == NFCC_PN66T))) {
|
||||||
dev_dbg(&nqx_dev->client->dev, "ese_gpio is disabled\n");
|
/**
|
||||||
r = 0;
|
* 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) {
|
if (!nqx_dev->nfc_ven_enabled) {
|
||||||
/* hardware dependent delay */
|
/* hardware dependent delay */
|
||||||
usleep_range(1000, 1100);
|
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);
|
gpio_set_value(nqx_dev->en_gpio, 0);
|
||||||
}
|
}
|
||||||
} else if (arg == 3) {
|
} else if (arg == 3) {
|
||||||
if (!nqx_dev->nfc_ven_enabled)
|
r = gpio_get_value(nqx_dev->ese_gpio);
|
||||||
r = 0;
|
|
||||||
else {
|
|
||||||
if (gpio_is_valid(nqx_dev->ese_gpio))
|
|
||||||
r = gpio_get_value(nqx_dev->ese_gpio);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -624,6 +705,10 @@ static int nfcc_hw_check(struct i2c_client *client, struct nqx_dev *nqx_dev)
|
||||||
dev_dbg(&client->dev,
|
dev_dbg(&client->dev,
|
||||||
"%s: ## NFCC == NQ330 ##\n", __func__);
|
"%s: ## NFCC == NQ330 ##\n", __func__);
|
||||||
break;
|
break;
|
||||||
|
case NFCC_PN66T:
|
||||||
|
dev_dbg(&client->dev,
|
||||||
|
"%s: ## NFCC == PN66T ##\n", __func__);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
dev_err(&client->dev,
|
dev_err(&client->dev,
|
||||||
"%s: - NFCC HW not Supported\n", __func__);
|
"%s: - NFCC HW not Supported\n", __func__);
|
||||||
|
|
|
@ -48,7 +48,7 @@ enum nfcc_chip_variant {
|
||||||
NFCC_NQ_220 = 0x58, /**< NFCC NQ220 */
|
NFCC_NQ_220 = 0x58, /**< NFCC NQ220 */
|
||||||
NFCC_NQ_310 = 0x40, /**< NFCC NQ310 */
|
NFCC_NQ_310 = 0x40, /**< NFCC NQ310 */
|
||||||
NFCC_NQ_330 = 0x51, /**< NFCC NQ330 */
|
NFCC_NQ_330 = 0x51, /**< NFCC NQ330 */
|
||||||
|
NFCC_PN66T = 0x18, /**< NFCC PN66T */
|
||||||
NFCC_NOT_SUPPORTED = 0xFF /**< NFCC is not supported */
|
NFCC_NOT_SUPPORTED = 0xFF /**< NFCC is not supported */
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Reference in a new issue