diff options
Diffstat (limited to 'drivers/nfc/trf7970a.c')
| -rw-r--r-- | drivers/nfc/trf7970a.c | 139 |
1 files changed, 105 insertions, 34 deletions
diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c index 29ca9c328df2..d17c701c7888 100644 --- a/drivers/nfc/trf7970a.c +++ b/drivers/nfc/trf7970a.c @@ -272,12 +272,18 @@ #define TRF7970A_MODULATOR_EN_OOK BIT(6) #define TRF7970A_MODULATOR_27MHZ BIT(7) +#define TRF7970A_RX_GAIN_REDUCTION_MAX_DB 15 +#define TRF7970A_RX_GAIN_REDUCTION_DB_PER_LSB 5 #define TRF7970A_RX_SPECIAL_SETTINGS_NO_LIM BIT(0) #define TRF7970A_RX_SPECIAL_SETTINGS_AGCR BIT(1) -#define TRF7970A_RX_SPECIAL_SETTINGS_GD_0DB (0x0 << 2) -#define TRF7970A_RX_SPECIAL_SETTINGS_GD_5DB (0x1 << 2) -#define TRF7970A_RX_SPECIAL_SETTINGS_GD_10DB (0x2 << 2) -#define TRF7970A_RX_SPECIAL_SETTINGS_GD_15DB (0x3 << 2) +#define TRF7970A_RX_SPECIAL_SETTINGS_GD_SHIFT 2 +#define TRF7970A_RX_SPECIAL_SETTINGS_GD_MAX (0x3) +#define TRF7970A_RX_SPECIAL_SETTINGS_GD_MASK (TRF7970A_RX_SPECIAL_SETTINGS_GD_MAX << \ + TRF7970A_RX_SPECIAL_SETTINGS_GD_SHIFT) +#define TRF7970A_RX_SPECIAL_SETTINGS_GD_0DB (0x0 << TRF7970A_RX_SPECIAL_SETTINGS_GD_SHIFT) +#define TRF7970A_RX_SPECIAL_SETTINGS_GD_5DB (0x1 << TRF7970A_RX_SPECIAL_SETTINGS_GD_SHIFT) +#define TRF7970A_RX_SPECIAL_SETTINGS_GD_10DB (0x2 << TRF7970A_RX_SPECIAL_SETTINGS_GD_SHIFT) +#define TRF7970A_RX_SPECIAL_SETTINGS_GD_15DB (0x3 << TRF7970A_RX_SPECIAL_SETTINGS_GD_SHIFT) #define TRF7970A_RX_SPECIAL_SETTINGS_HBT BIT(4) #define TRF7970A_RX_SPECIAL_SETTINGS_M848 BIT(5) #define TRF7970A_RX_SPECIAL_SETTINGS_C424 BIT(6) @@ -424,7 +430,8 @@ struct trf7970a { enum trf7970a_state state; struct device *dev; struct spi_device *spi; - struct regulator *regulator; + struct regulator *vin_regulator; + struct regulator *vddio_regulator; struct nfc_digital_dev *ddev; u32 quirks; bool is_initiator; @@ -451,6 +458,8 @@ struct trf7970a { unsigned int timeout; bool ignore_timeout; struct delayed_work timeout_work; + u8 rx_gain_reduction; + bool custom_rx_gain_reduction; }; static int trf7970a_cmd(struct trf7970a *trf, u8 opcode) @@ -550,6 +559,41 @@ static int trf7970a_read_irqstatus(struct trf7970a *trf, u8 *status) return ret; } +static int trf7970a_update_rx_gain_reduction(struct trf7970a *trf) +{ + int ret = 0; + u8 reg; + + if (!trf->custom_rx_gain_reduction) + return 0; + + ret = trf7970a_read(trf, TRF7970A_RX_SPECIAL_SETTINGS, ®); + if (ret) + return ret; + reg &= ~(TRF7970A_RX_SPECIAL_SETTINGS_GD_MASK); + reg |= trf->rx_gain_reduction; + + ret = trf7970a_write(trf, TRF7970A_RX_SPECIAL_SETTINGS, reg); + + return ret; +} + +static int trf7970a_update_iso_ctrl_register(struct trf7970a *trf, u8 iso_ctrl) +{ + int ret; + + ret = trf7970a_write(trf, TRF7970A_ISO_CTRL, iso_ctrl); + if (ret) + return ret; + /* + * Every time the ISO_CTRL register is written, the RX special setting register is reset by + * the chip. When a custom gain reguduction is required, it should be rewritten now. + */ + ret = trf7970a_update_rx_gain_reduction(trf); + + return ret; +} + static int trf7970a_read_target_proto(struct trf7970a *trf, u8 *target_proto) { int ret; @@ -929,8 +973,7 @@ static irqreturn_t trf7970a_irq(int irq, void *dev_id) } if (iso_ctrl != trf->iso_ctrl) { - ret = trf7970a_write(trf, TRF7970A_ISO_CTRL, - iso_ctrl); + ret = trf7970a_update_iso_ctrl_register(trf, iso_ctrl); if (ret) goto err_unlock_exit; @@ -1034,6 +1077,11 @@ static int trf7970a_init(struct trf7970a *trf) if (ret) goto err_out; + /* Set the gain reduction after soft init */ + ret = trf7970a_update_rx_gain_reduction(trf); + if (ret) + goto err_out; + ret = trf7970a_cmd(trf, TRF7970A_CMD_IDLE); if (ret) goto err_out; @@ -1308,7 +1356,7 @@ static int trf7970a_in_config_framing(struct trf7970a *trf, int framing) } if (iso_ctrl != trf->iso_ctrl) { - ret = trf7970a_write(trf, TRF7970A_ISO_CTRL, iso_ctrl); + ret = trf7970a_update_iso_ctrl_register(trf, iso_ctrl); if (ret) return ret; @@ -1440,7 +1488,7 @@ static int trf7970a_per_cmd_config(struct trf7970a *trf, } if (iso_ctrl != trf->iso_ctrl) { - ret = trf7970a_write(trf, TRF7970A_ISO_CTRL, iso_ctrl); + ret = trf7970a_update_iso_ctrl_register(trf, iso_ctrl); if (ret) return ret; @@ -1604,8 +1652,7 @@ static int trf7970a_tg_config_rf_tech(struct trf7970a *trf, int tech) */ if ((trf->framing == NFC_DIGITAL_FRAMING_NFC_DEP_ACTIVATED) && (trf->iso_ctrl_tech != trf->iso_ctrl)) { - ret = trf7970a_write(trf, TRF7970A_ISO_CTRL, - trf->iso_ctrl_tech); + ret = trf7970a_update_iso_ctrl_register(trf, trf->iso_ctrl_tech); trf->iso_ctrl = trf->iso_ctrl_tech; } @@ -1653,7 +1700,7 @@ static int trf7970a_tg_config_framing(struct trf7970a *trf, int framing) trf->framing = framing; if (iso_ctrl != trf->iso_ctrl) { - ret = trf7970a_write(trf, TRF7970A_ISO_CTRL, iso_ctrl); + ret = trf7970a_update_iso_ctrl_register(trf, iso_ctrl); if (ret) return ret; @@ -1754,6 +1801,10 @@ static int _trf7970a_tg_listen(struct nfc_digital_dev *ddev, u16 timeout, if (ret) goto out_err; + ret = trf7970a_update_rx_gain_reduction(trf); + if (ret) + goto out_err; + ret = trf7970a_write(trf, TRF7970A_REG_IO_CTRL, trf->io_ctrl | TRF7970A_REG_IO_CTRL_VRS(0x1)); if (ret) @@ -1883,7 +1934,7 @@ static int trf7970a_power_up(struct trf7970a *trf) if (trf->state != TRF7970A_ST_PWR_OFF) return 0; - ret = regulator_enable(trf->regulator); + ret = regulator_enable(trf->vin_regulator); if (ret) { dev_err(trf->dev, "%s - Can't enable VIN: %d\n", __func__, ret); return ret; @@ -1926,7 +1977,7 @@ static int trf7970a_power_down(struct trf7970a *trf) if (trf->en2_gpiod && !(trf->quirks & TRF7970A_QUIRK_EN2_MUST_STAY_LOW)) gpiod_set_value_cansleep(trf->en2_gpiod, 0); - ret = regulator_disable(trf->regulator); + ret = regulator_disable(trf->vin_regulator); if (ret) dev_err(trf->dev, "%s - Can't disable VIN: %d\n", __func__, ret); @@ -1944,6 +1995,10 @@ static int trf7970a_startup(struct trf7970a *trf) if (ret) return ret; + ret = trf7970a_update_rx_gain_reduction(trf); + if (ret) + return ret; + pm_runtime_set_active(trf->dev); pm_runtime_enable(trf->dev); pm_runtime_mark_last_busy(trf->dev); @@ -1992,6 +2047,7 @@ static int trf7970a_probe(struct spi_device *spi) struct trf7970a *trf; int uvolts, autosuspend_delay, ret; u32 clk_freq = TRF7970A_13MHZ_CLOCK_FREQUENCY; + u32 rx_gain_reduction_db; if (!np) { dev_err(&spi->dev, "No Device Tree entry\n"); @@ -2053,6 +2109,20 @@ static int trf7970a_probe(struct spi_device *spi) trf->modulator_sys_clk_ctrl = 0; } + if (of_property_read_u32(np, "ti,rx-gain-reduction-db", &rx_gain_reduction_db) == 0) { + if (rx_gain_reduction_db > TRF7970A_RX_GAIN_REDUCTION_MAX_DB) { + dev_warn(trf->dev, "RX Gain reduction too high. Ignored\n"); + } else if ((rx_gain_reduction_db % TRF7970A_RX_GAIN_REDUCTION_DB_PER_LSB)) { + dev_warn(trf->dev, "RX Gain must be set in 5 dB increments. Ignored\n"); + } else { + dev_dbg(trf->dev, "RX gain set to -%udB\n", rx_gain_reduction_db); + trf->rx_gain_reduction = ((rx_gain_reduction_db / + TRF7970A_RX_GAIN_REDUCTION_DB_PER_LSB) << + TRF7970A_RX_SPECIAL_SETTINGS_GD_SHIFT); + trf->custom_rx_gain_reduction = true; + } + } + ret = devm_request_threaded_irq(trf->dev, spi->irq, NULL, trf7970a_irq, IRQF_TRIGGER_RISING | IRQF_ONESHOT, @@ -2065,37 +2135,37 @@ static int trf7970a_probe(struct spi_device *spi) mutex_init(&trf->lock); INIT_DELAYED_WORK(&trf->timeout_work, trf7970a_timeout_work_handler); - trf->regulator = devm_regulator_get(&spi->dev, "vin"); - if (IS_ERR(trf->regulator)) { - ret = PTR_ERR(trf->regulator); + trf->vin_regulator = devm_regulator_get(&spi->dev, "vin"); + if (IS_ERR(trf->vin_regulator)) { + ret = PTR_ERR(trf->vin_regulator); dev_err(trf->dev, "Can't get VIN regulator: %d\n", ret); goto err_destroy_lock; } - ret = regulator_enable(trf->regulator); + ret = regulator_enable(trf->vin_regulator); if (ret) { dev_err(trf->dev, "Can't enable VIN: %d\n", ret); goto err_destroy_lock; } - uvolts = regulator_get_voltage(trf->regulator); + uvolts = regulator_get_voltage(trf->vin_regulator); if (uvolts > 4000000) trf->chip_status_ctrl = TRF7970A_CHIP_STATUS_VRS5_3; - trf->regulator = devm_regulator_get(&spi->dev, "vdd-io"); - if (IS_ERR(trf->regulator)) { - ret = PTR_ERR(trf->regulator); + trf->vddio_regulator = devm_regulator_get(&spi->dev, "vdd-io"); + if (IS_ERR(trf->vddio_regulator)) { + ret = PTR_ERR(trf->vddio_regulator); dev_err(trf->dev, "Can't get VDD_IO regulator: %d\n", ret); - goto err_destroy_lock; + goto err_disable_vin_regulator; } - ret = regulator_enable(trf->regulator); + ret = regulator_enable(trf->vddio_regulator); if (ret) { dev_err(trf->dev, "Can't enable VDD_IO: %d\n", ret); - goto err_destroy_lock; + goto err_disable_vin_regulator; } - if (regulator_get_voltage(trf->regulator) == 1800000) { + if (regulator_get_voltage(trf->vddio_regulator) == 1800000) { trf->io_ctrl = TRF7970A_REG_IO_CTRL_IO_LOW; dev_dbg(trf->dev, "trf7970a config vdd_io to 1.8V\n"); } @@ -2108,7 +2178,7 @@ static int trf7970a_probe(struct spi_device *spi) if (!trf->ddev) { dev_err(trf->dev, "Can't allocate NFC digital device\n"); ret = -ENOMEM; - goto err_disable_regulator; + goto err_disable_vddio_regulator; } nfc_digital_set_parent_dev(trf->ddev, trf->dev); @@ -2137,14 +2207,16 @@ err_shutdown: trf7970a_shutdown(trf); err_free_ddev: nfc_digital_free_device(trf->ddev); -err_disable_regulator: - regulator_disable(trf->regulator); +err_disable_vddio_regulator: + regulator_disable(trf->vddio_regulator); +err_disable_vin_regulator: + regulator_disable(trf->vin_regulator); err_destroy_lock: mutex_destroy(&trf->lock); return ret; } -static int trf7970a_remove(struct spi_device *spi) +static void trf7970a_remove(struct spi_device *spi) { struct trf7970a *trf = spi_get_drvdata(spi); @@ -2157,11 +2229,10 @@ static int trf7970a_remove(struct spi_device *spi) nfc_digital_unregister_device(trf->ddev); nfc_digital_free_device(trf->ddev); - regulator_disable(trf->regulator); + regulator_disable(trf->vddio_regulator); + regulator_disable(trf->vin_regulator); mutex_destroy(&trf->lock); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -2231,7 +2302,7 @@ static const struct dev_pm_ops trf7970a_pm_ops = { trf7970a_pm_runtime_resume, NULL) }; -static const struct of_device_id trf7970a_of_match[] = { +static const struct of_device_id trf7970a_of_match[] __maybe_unused = { {.compatible = "ti,trf7970a",}, {}, }; |
