Messages in this thread Patch in this message | | | From | Krzysztof Kozlowski <> | Subject | [PATCH] regmap: support regmap_field_write() on non-readable fields | Date | Tue, 19 Jul 2022 14:14:46 +0200 |
| |
Current implementation of regmap_field_write() performs an update of register (read+write), therefore it ignores regmap read-restrictions and is not suitable for write-only registers (e.g. interrupt clearing).
Extend regmap_field_write() and regmap_field_force_write() to check if register is readable and only then perform an update. In the other case, it is expected that mask of field covers entire register thus a full write is allowed.
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
---
Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> Cc: Charles Keepax <ckeepax@opensource.cirrus.com> Cc: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Cc: Bjorn Andersson <bjorn.andersson@linaro.org> --- drivers/base/regmap/regmap.c | 50 ++++++++++++++++++++++++++++++++++++ include/linux/regmap.h | 15 ++--------- 2 files changed, 52 insertions(+), 13 deletions(-)
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 0caa5690c560..4d18a34f7b2c 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -2192,6 +2192,56 @@ int regmap_noinc_write(struct regmap *map, unsigned int reg, } EXPORT_SYMBOL_GPL(regmap_noinc_write); +static int _regmap_field_write_or_update(struct regmap_field *field, + unsigned int val, bool *change, + bool async, bool force) +{ + unsigned int mask = (~0 << field->shift) & field->mask; + unsigned int map_val_mask, map_val_mask_h; + int ret; + + if (regmap_readable(field->regmap, field->reg)) + return regmap_update_bits_base(field->regmap, field->reg, + mask, val << field->shift, + change, async, force); + + map_val_mask_h = field->regmap->format.val_bytes * 8 - 1; + map_val_mask = GENMASK(map_val_mask_h, 0); + + /* Writes of parts of register are not allowed for sanity */ + if (field->shift) + return -EINVAL; + + /* Mask of field must cover entire register */ + if (field->mask != map_val_mask) + return -EINVAL; + + if (change) + *change = false; + + if (async) + ret = regmap_write(field->regmap, field->reg, val); + else + ret = regmap_write_async(field->regmap, field->reg, val); + + if (ret == 0 && change) + *change = true; + + return ret; +} + +int regmap_field_write(struct regmap_field *field, unsigned int val) +{ + return _regmap_field_write_or_update(field, val, NULL, false, false); +} +EXPORT_SYMBOL_GPL(regmap_field_write); + +int regmap_field_force_write(struct regmap_field *field, unsigned int val) +{ + return _regmap_field_write_or_update(field, val, NULL, false, true); +} +EXPORT_SYMBOL_GPL(regmap_field_force_write); + /** * regmap_field_update_bits_base() - Perform a read/modify/write cycle a * register field. diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 7cf2157134ac..08507e764dfa 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -1307,6 +1307,8 @@ void devm_regmap_field_bulk_free(struct device *dev, struct regmap_field *field); int regmap_field_read(struct regmap_field *field, unsigned int *val); +int regmap_field_write(struct regmap_field *field, unsigned int val); +int regmap_field_force_write(struct regmap_field *field, unsigned int val); int regmap_field_update_bits_base(struct regmap_field *field, unsigned int mask, unsigned int val, bool *change, bool async, bool force); @@ -1316,19 +1318,6 @@ int regmap_fields_update_bits_base(struct regmap_field *field, unsigned int id, unsigned int mask, unsigned int val, bool *change, bool async, bool force); -static inline int regmap_field_write(struct regmap_field *field, - unsigned int val) -{ - return regmap_field_update_bits_base(field, ~0, val, - NULL, false, false); -} - -static inline int regmap_field_force_write(struct regmap_field *field, - unsigned int val) -{ - return regmap_field_update_bits_base(field, ~0, val, NULL, false, true); -} - static inline int regmap_field_update_bits(struct regmap_field *field, unsigned int mask, unsigned int val) { -- 2.34.1
| |