aboutsummaryrefslogtreecommitdiff
path: root/drivers/core
diff options
context:
space:
mode:
authorJean-Jacques Hiblot <jjhiblot@ti.com>2020-09-24 10:04:16 +0530
committerTom Rini <trini@konsulko.com>2020-09-30 11:55:23 -0400
commit1c4db59d9bf711e7f8902eaa145959429d659679 (patch)
treea7a3bc07988a5af2dfdeeb1f95f498c8ca64e0ef /drivers/core
parentd8babb9598ce237ffb1feccb576c66a21c52e5f7 (diff)
downloadu-boot-1c4db59d9bf711e7f8902eaa145959429d659679.zip
u-boot-1c4db59d9bf711e7f8902eaa145959429d659679.tar.gz
u-boot-1c4db59d9bf711e7f8902eaa145959429d659679.tar.bz2
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.c83
1 files changed, 83 insertions, 0 deletions
diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c
index a3da0cf..c2bed88 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, &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);
+}