diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/nfc/trf7970a.c | 132 |
1 files changed, 96 insertions, 36 deletions
diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c index cda854b98cf3..84a9c3f78621 100644 --- a/drivers/nfc/trf7970a.c +++ b/drivers/nfc/trf7970a.c @@ -332,6 +332,7 @@ (ISO15693_REQ_FLAG_SUB_CARRIER | ISO15693_REQ_FLAG_DATA_RATE) enum trf7970a_state { + TRF7970A_ST_PWR_OFF, TRF7970A_ST_RF_OFF, TRF7970A_ST_IDLE, TRF7970A_ST_IDLE_RX_BLOCKED, @@ -877,6 +878,12 @@ static int trf7970a_switch_rf_on(struct trf7970a *trf) pm_runtime_get_sync(trf->dev); + if (trf->state != TRF7970A_ST_RF_OFF) { /* Power on, RF off */ + dev_err(trf->dev, "%s - Incorrect state: %d\n", __func__, + trf->state); + return -EINVAL; + } + ret = trf7970a_init(trf); if (ret) { dev_err(trf->dev, "%s - Can't initialize: %d\n", __func__, ret); @@ -899,6 +906,7 @@ static int trf7970a_switch_rf(struct nfc_digital_dev *ddev, bool on) if (on) { switch (trf->state) { + case TRF7970A_ST_PWR_OFF: case TRF7970A_ST_RF_OFF: ret = trf7970a_switch_rf_on(trf); break; @@ -913,6 +921,7 @@ static int trf7970a_switch_rf(struct nfc_digital_dev *ddev, bool on) } } else { switch (trf->state) { + case TRF7970A_ST_PWR_OFF: case TRF7970A_ST_RF_OFF: break; default: @@ -1045,7 +1054,8 @@ static int trf7970a_in_configure_hw(struct nfc_digital_dev *ddev, int type, mutex_lock(&trf->lock); - if (trf->state == TRF7970A_ST_RF_OFF) { + if ((trf->state == TRF7970A_ST_PWR_OFF) || + (trf->state == TRF7970A_ST_RF_OFF)) { ret = trf7970a_switch_rf_on(trf); if (ret) goto err_unlock; @@ -1316,6 +1326,65 @@ static struct nfc_digital_ops trf7970a_nfc_ops = { .abort_cmd = trf7970a_abort_cmd, }; +static int trf7970a_power_up(struct trf7970a *trf) +{ + int ret; + + dev_dbg(trf->dev, "Powering up - state: %d\n", trf->state); + + if (trf->state != TRF7970A_ST_PWR_OFF) + return 0; + + ret = regulator_enable(trf->regulator); + if (ret) { + dev_err(trf->dev, "%s - Can't enable VIN: %d\n", __func__, ret); + return ret; + } + + usleep_range(5000, 6000); + + if (!(trf->quirks & TRF7970A_QUIRK_EN2_MUST_STAY_LOW)) { + gpio_set_value(trf->en2_gpio, 1); + usleep_range(1000, 2000); + } + + gpio_set_value(trf->en_gpio, 1); + + usleep_range(20000, 21000); + + trf->state = TRF7970A_ST_RF_OFF; + + return 0; +} + +static int trf7970a_power_down(struct trf7970a *trf) +{ + int ret; + + dev_dbg(trf->dev, "Powering down - state: %d\n", trf->state); + + if (trf->state == TRF7970A_ST_PWR_OFF) + return 0; + + if (trf->state != TRF7970A_ST_RF_OFF) { + dev_dbg(trf->dev, "Can't power down - not RF_OFF state (%d)\n", + trf->state); + return -EBUSY; + } + + gpio_set_value(trf->en_gpio, 0); + gpio_set_value(trf->en2_gpio, 0); + + ret = regulator_disable(trf->regulator); + if (ret) + dev_err(trf->dev, "%s - Can't disable VIN: %d\n", __func__, + ret); + + trf->state = TRF7970A_ST_PWR_OFF; + + return ret; +} + static int trf7970a_get_autosuspend_delay(struct device_node *np) { int autosuspend_delay, ret; @@ -1348,7 +1417,7 @@ static int trf7970a_probe(struct spi_device *spi) if (!trf) return -ENOMEM; - trf->state = TRF7970A_ST_RF_OFF; + trf->state = TRF7970A_ST_PWR_OFF; trf->dev = &spi->dev; trf->spi = spi; @@ -1442,19 +1511,29 @@ static int trf7970a_probe(struct spi_device *spi) pm_runtime_set_autosuspend_delay(trf->dev, autosuspend_delay); pm_runtime_use_autosuspend(trf->dev); + + ret = trf7970a_power_up(trf); + if (ret) + goto err_free_ddev; + + pm_runtime_set_active(trf->dev); pm_runtime_enable(trf->dev); + pm_runtime_mark_last_busy(trf->dev); ret = nfc_digital_register_device(trf->ddev); if (ret) { dev_err(trf->dev, "Can't register NFC digital device: %d\n", ret); - goto err_free_ddev; + goto err_power_down; } return 0; -err_free_ddev: +err_power_down: pm_runtime_disable(trf->dev); + pm_runtime_set_suspended(trf->dev); + trf7970a_power_down(trf); +err_free_ddev: nfc_digital_free_device(trf->ddev); err_disable_regulator: regulator_disable(trf->regulator); @@ -1478,15 +1557,18 @@ static int trf7970a_remove(struct spi_device *spi) /* FALLTHROUGH */ case TRF7970A_ST_IDLE: case TRF7970A_ST_IDLE_RX_BLOCKED: - pm_runtime_put_sync(trf->dev); + trf7970a_switch_rf_off(trf); break; default: break; } - mutex_unlock(&trf->lock); - pm_runtime_disable(trf->dev); + pm_runtime_set_suspended(trf->dev); + + trf7970a_power_down(trf); + + mutex_unlock(&trf->lock); nfc_digital_unregister_device(trf->ddev); nfc_digital_free_device(trf->ddev); @@ -1507,18 +1589,11 @@ static int trf7970a_pm_runtime_suspend(struct device *dev) dev_dbg(dev, "Runtime suspend\n"); - if (trf->state != TRF7970A_ST_RF_OFF) { - dev_dbg(dev, "Can't suspend - not in OFF state (%d)\n", - trf->state); - return -EBUSY; - } + mutex_lock(&trf->lock); - gpio_set_value(trf->en_gpio, 0); - gpio_set_value(trf->en2_gpio, 0); + ret = trf7970a_power_down(trf); - ret = regulator_disable(trf->regulator); - if (ret) - dev_err(dev, "%s - Can't disable VIN: %d\n", __func__, ret); + mutex_unlock(&trf->lock); return ret; } @@ -1531,26 +1606,11 @@ static int trf7970a_pm_runtime_resume(struct device *dev) dev_dbg(dev, "Runtime resume\n"); - ret = regulator_enable(trf->regulator); - if (ret) { - dev_err(dev, "%s - Can't enable VIN: %d\n", __func__, ret); - return ret; - } - - usleep_range(5000, 6000); - - if (!(trf->quirks & TRF7970A_QUIRK_EN2_MUST_STAY_LOW)) { - gpio_set_value(trf->en2_gpio, 1); - usleep_range(1000, 2000); - } - - gpio_set_value(trf->en_gpio, 1); - - usleep_range(20000, 21000); + ret = trf7970a_power_up(trf); + if (!ret) + pm_runtime_mark_last_busy(dev); - pm_runtime_mark_last_busy(dev); - - return 0; + return ret; } #endif |