diff options
author | Jean-Jacques Hiblot <jjhiblot@ti.com> | 2020-09-24 10:04:16 +0530 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2020-09-30 11:55:23 -0400 |
commit | 1c4db59d9bf711e7f8902eaa145959429d659679 (patch) | |
tree | a7a3bc07988a5af2dfdeeb1f95f498c8ca64e0ef /drivers/core | |
parent | d8babb9598ce237ffb1feccb576c66a21c52e5f7 (diff) | |
download | u-boot-1c4db59d9bf711e7f8902eaa145959429d659679.tar.gz |
regmap: Add support for regmap fields
A regmap field is an abstraction available in Linux. It provides to access
bitfields in a regmap without having to worry about shifts and masks.
Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
Diffstat (limited to 'drivers/core')
-rw-r--r-- | drivers/core/regmap.c | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c index a3da0cf7c3..c2bed88eac 100644 --- a/drivers/core/regmap.c +++ b/drivers/core/regmap.c @@ -18,6 +18,20 @@ #include <linux/ioport.h> #include <linux/compat.h> #include <linux/err.h> +#include <linux/bitops.h> + +/* + * Internal representation of a regmap field. Instead of storing the MSB and + * LSB, store the shift and mask. This makes the code a bit cleaner and faster + * because the shift and mask don't have to be calculated every time. + */ +struct regmap_field { + struct regmap *regmap; + unsigned int mask; + /* lsb */ + unsigned int shift; + unsigned int reg; +}; DECLARE_GLOBAL_DATA_PTR; @@ -547,3 +561,72 @@ int regmap_update_bits(struct regmap *map, uint offset, uint mask, uint val) return regmap_write(map, offset, reg | (val & mask)); } + +int regmap_field_read(struct regmap_field *field, unsigned int *val) +{ + int ret; + unsigned int reg_val; + + ret = regmap_read(field->regmap, field->reg, ®_val); + if (ret != 0) + return ret; + + reg_val &= field->mask; + reg_val >>= field->shift; + *val = reg_val; + + return ret; +} + +int regmap_field_write(struct regmap_field *field, unsigned int val) +{ + return regmap_update_bits(field->regmap, field->reg, field->mask, + val << field->shift); +} + +static void regmap_field_init(struct regmap_field *rm_field, + struct regmap *regmap, + struct reg_field reg_field) +{ + rm_field->regmap = regmap; + rm_field->reg = reg_field.reg; + rm_field->shift = reg_field.lsb; + rm_field->mask = GENMASK(reg_field.msb, reg_field.lsb); +} + +struct regmap_field *devm_regmap_field_alloc(struct udevice *dev, + struct regmap *regmap, + struct reg_field reg_field) +{ + struct regmap_field *rm_field = devm_kzalloc(dev, sizeof(*rm_field), + GFP_KERNEL); + if (!rm_field) + return ERR_PTR(-ENOMEM); + + regmap_field_init(rm_field, regmap, reg_field); + + return rm_field; +} + +void devm_regmap_field_free(struct udevice *dev, struct regmap_field *field) +{ + devm_kfree(dev, field); +} + +struct regmap_field *regmap_field_alloc(struct regmap *regmap, + struct reg_field reg_field) +{ + struct regmap_field *rm_field = kzalloc(sizeof(*rm_field), GFP_KERNEL); + + if (!rm_field) + return ERR_PTR(-ENOMEM); + + regmap_field_init(rm_field, regmap, reg_field); + + return rm_field; +} + +void regmap_field_free(struct regmap_field *field) +{ + kfree(field); +} |