The TPS65214 PMIC variant has a LOCK_REG register that prevents writes to nearly all registers.
Implement custom regmap operations that automatically unlock before writes and re-lock afterwards for TPS65214, while leaving other chip variants unaffected.
The implementation follows the regmap-i2c design pattern.
Cc: stable@vger.kernel.org Fixes: 7947219ab1a2d ("mfd: tps65219: Add support for TI TPS65214 PMIC") Signed-off-by: Kory Maincent (TI.com) kory.maincent@bootlin.com ---
Changes in v2: - Setup a custom regmap_bus only for the TPS65214 instead of checking the chip_id every time reg_write is called. --- drivers/mfd/tps65219.c | 51 +++++++++++++++++++++++++++++++++++++++++++- include/linux/mfd/tps65219.h | 2 ++ 2 files changed, 52 insertions(+), 1 deletion(-)
diff --git a/drivers/mfd/tps65219.c b/drivers/mfd/tps65219.c index 65a952555218d..7e916a9ce2335 100644 --- a/drivers/mfd/tps65219.c +++ b/drivers/mfd/tps65219.c @@ -473,6 +473,50 @@ static const struct tps65219_chip_data chip_info_table[] = { }, };
+static int tps65214_reg_write(void *context, unsigned int reg, unsigned int val) +{ + struct i2c_client *i2c = context; + struct tps65219 *tps; + int ret; + + if (val > 0xff || reg > 0xff) + return -EINVAL; + + tps = i2c_get_clientdata(i2c); + ret = i2c_smbus_write_byte_data(i2c, TPS65214_REG_LOCK, + TPS65214_LOCK_ACCESS_CMD); + if (ret) + return ret; + + ret = i2c_smbus_write_byte_data(i2c, reg, val); + if (ret) + return ret; + + return i2c_smbus_write_byte_data(i2c, TPS65214_REG_LOCK, 0); +} + +static int tps65214_reg_read(void *context, unsigned int reg, unsigned int *val) +{ + struct i2c_client *i2c = context; + int ret; + + if (reg > 0xff) + return -EINVAL; + + ret = i2c_smbus_read_byte_data(i2c, reg); + if (ret < 0) + return ret; + + *val = ret; + + return 0; +} + +static const struct regmap_bus tps65214_regmap_bus = { + .reg_write = tps65214_reg_write, + .reg_read = tps65214_reg_read, +}; + static int tps65219_probe(struct i2c_client *client) { struct tps65219 *tps; @@ -491,7 +535,12 @@ static int tps65219_probe(struct i2c_client *client) chip_id = (uintptr_t)i2c_get_match_data(client); pmic = &chip_info_table[chip_id];
- tps->regmap = devm_regmap_init_i2c(client, &tps65219_regmap_config); + if (chip_id == TPS65214) + tps->regmap = devm_regmap_init(&client->dev, + &tps65214_regmap_bus, client, + &tps65219_regmap_config); + else + tps->regmap = devm_regmap_init_i2c(client, &tps65219_regmap_config); if (IS_ERR(tps->regmap)) { ret = PTR_ERR(tps->regmap); dev_err(tps->dev, "Failed to allocate register map: %d\n", ret); diff --git a/include/linux/mfd/tps65219.h b/include/linux/mfd/tps65219.h index 55234e771ba73..198ee319dd1db 100644 --- a/include/linux/mfd/tps65219.h +++ b/include/linux/mfd/tps65219.h @@ -149,6 +149,8 @@ enum pmic_id { #define TPS65215_ENABLE_LDO2_EN_MASK BIT(5) #define TPS65214_ENABLE_LDO1_EN_MASK BIT(5) #define TPS65219_ENABLE_LDO4_EN_MASK BIT(6) +/* Register Lock */ +#define TPS65214_LOCK_ACCESS_CMD 0x5a /* power ON-OFF sequence slot */ #define TPS65219_BUCKS_LDOS_SEQUENCE_OFF_SLOT_MASK GENMASK(3, 0) #define TPS65219_BUCKS_LDOS_SEQUENCE_ON_SLOT_MASK GENMASK(7, 4)