From: Sascha Hauer <s.hauer@pengutronix.de>
To: "open list:BAREBOX" <barebox@lists.infradead.org>
Subject: [PATCH v2 04/15] regmap: add regfield support
Date: Fri, 27 Sep 2024 12:37:37 +0200 [thread overview]
Message-ID: <20240927-vop2-v2-4-dc8dcfc651d5@pengutronix.de> (raw)
In-Reply-To: <20240927-vop2-v2-0-dc8dcfc651d5@pengutronix.de>
Add regfield support to get comfortable access to register fields in a
regmap. The functions are taken directly from Linux-6.10.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/base/regmap/internal.h | 11 ++++
drivers/base/regmap/regmap.c | 131 +++++++++++++++++++++++++++++++++++++++++
include/linux/regmap.h | 39 ++++++++++++
3 files changed, 181 insertions(+)
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index ac3f0d3c0f..6f6a34edc7 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -41,6 +41,17 @@ struct regmap {
unsigned int val);
};
+struct regmap_field {
+ struct regmap *regmap;
+ unsigned int mask;
+ /* lsb */
+ unsigned int shift;
+ unsigned int reg;
+
+ unsigned int id_size;
+ unsigned int id_offset;
+};
+
enum regmap_endian regmap_get_val_endian(struct device *dev,
const struct regmap_bus *bus,
const struct regmap_config *config);
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 7ad527954c..1f10424a42 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -242,6 +242,30 @@ int regmap_write_bits(struct regmap *map, unsigned int reg,
return regmap_write(map, reg, tmp);
}
+/**
+ * regmap_field_read(): Read a value to a single register field
+ *
+ * @field: Register field to read from
+ * @val: Pointer to store read value
+ *
+ * A value of zero will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+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;
+}
+
/**
* regmap_bulk_read(): Read data from the device
*
@@ -377,6 +401,67 @@ static int regmap_round_val_bytes(struct regmap *map)
return map->format.val_bytes ?: 1;
}
+/**
+ * regmap_update_bits_base() - Perform a read/modify/write cycle on a register
+ *
+ * @map: Register map to update
+ * @reg: Register to update
+ * @mask: Bitmask to change
+ * @val: New value for bitmask
+ * @change: Boolean indicating if a write was done
+ * @async: Boolean indicating asynchronously
+ * @force: Boolean indicating use force update
+ *
+ * Perform a read/modify/write cycle on a register map with change, async, force
+ * options.
+ *
+ * If async is true:
+ *
+ * With most buses the read must be done synchronously so this is most useful
+ * for devices with a cache which do not need to interact with the hardware to
+ * determine the current register value.
+ *
+ * Returns zero for success, a negative number on error.
+ */
+int regmap_update_bits_base(struct regmap *map, unsigned int reg,
+ unsigned int mask, unsigned int val,
+ bool *change, bool async, bool force)
+{
+ int ret;
+
+ ret = regmap_update_bits(map, reg, mask, val);
+
+ return ret;
+}
+
+/**
+ * regmap_field_update_bits_base() - Perform a read/modify/write cycle a
+ * register field.
+ *
+ * @field: Register field to write to
+ * @mask: Bitmask to change
+ * @val: Value to be written
+ * @change: Boolean indicating if a write was done
+ * @async: Boolean indicating asynchronously
+ * @force: Boolean indicating use force update
+ *
+ * Perform a read/modify/write cycle on the register field with change,
+ * async, force option.
+ *
+ * A value of zero will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+int regmap_field_update_bits_base(struct regmap_field *field,
+ unsigned int mask, unsigned int val,
+ bool *change, bool async, bool force)
+{
+ mask = (mask << field->shift) & field->mask;
+
+ return regmap_update_bits_base(field->regmap, field->reg,
+ mask, val << field->shift,
+ change, async, force);
+}
+
static ssize_t regmap_cdev_read(struct cdev *cdev, void *buf, size_t count, loff_t offset,
unsigned long flags)
{
@@ -442,6 +527,52 @@ size_t regmap_size_bytes(struct regmap *map)
return regmap_round_val_bytes(map) * regmap_count_registers(map);
}
+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);
+
+ WARN_ONCE(rm_field->mask == 0, "invalid empty mask defined\n");
+
+ rm_field->id_size = reg_field.id_size;
+ rm_field->id_offset = reg_field.id_offset;
+}
+
+/**
+ * regmap_field_bulk_alloc() - Allocate and initialise a bulk register field.
+ *
+ * @regmap: regmap bank in which this register field is located.
+ * @rm_field: regmap register fields within the bank.
+ * @reg_field: Register fields within the bank.
+ * @num_fields: Number of register fields.
+ *
+ * The return value will be an -ENOMEM on error or zero for success.
+ * Newly allocated regmap_fields should be freed by calling
+ * regmap_field_bulk_free()
+ */
+int regmap_field_bulk_alloc(struct regmap *regmap,
+ struct regmap_field **rm_field,
+ const struct reg_field *reg_field,
+ int num_fields)
+{
+ struct regmap_field *rf;
+ int i;
+
+ rf = kcalloc(num_fields, sizeof(*rf), GFP_KERNEL);
+ if (!rf)
+ return -ENOMEM;
+
+ for (i = 0; i < num_fields; i++) {
+ regmap_field_init(&rf[i], regmap, reg_field[i]);
+ rm_field[i] = &rf[i];
+ }
+
+ return 0;
+}
+
/*
* regmap_register_cdev - register a devfs file for a regmap
*
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 3ba0f852f6..e38b4f2dc8 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -212,6 +212,45 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
#define regmap_bulk_write regmap_bulk_write
int regmap_bulk_write(struct regmap *map, unsigned int reg,
const void *val, size_t val_count);
+
+struct regmap_field;
+
+struct reg_field {
+ unsigned int reg;
+ unsigned int lsb;
+ unsigned int msb;
+ unsigned int id_size;
+ unsigned int id_offset;
+};
+
+#define REG_FIELD(_reg, _lsb, _msb) { \
+ .reg = _reg, \
+ .lsb = _lsb, \
+ .msb = _msb, \
+ }
+
+int regmap_field_bulk_alloc(struct regmap *regmap,
+ struct regmap_field **rm_field,
+ const struct reg_field *reg_field,
+ int num_fields);
+
+int regmap_field_read(struct regmap_field *field, unsigned int *val);
+
+int regmap_update_bits_base(struct regmap *map, unsigned int reg,
+ unsigned int mask, unsigned int val,
+ bool *change, bool async, bool force);
+
+int regmap_field_update_bits_base(struct regmap_field *field,
+ 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);
+}
+
#endif
int regmap_get_val_bytes(struct regmap *map);
--
2.39.5
next prev parent reply other threads:[~2024-09-27 10:43 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-09-27 10:37 [PATCH v2 00/15] video: Add Rockchip VOP2 support Sascha Hauer
2024-09-27 10:37 ` [PATCH v2 01/15] clk: rockchip: rk3568: Fix HDMI clocks Sascha Hauer
2024-09-27 10:37 ` [PATCH v2 02/15] video: add videomode helpers Sascha Hauer
2024-09-27 10:37 ` [PATCH v2 03/15] media-bus-format: update from kernel Sascha Hauer
2024-09-27 10:37 ` Sascha Hauer [this message]
2024-09-27 10:37 ` [PATCH v2 05/15] video: add include/video/drm/drm_connector.h Sascha Hauer
2024-09-27 10:37 ` [PATCH v2 06/15] fb: add fb_rect functions Sascha Hauer
2024-09-27 10:37 ` [PATCH v2 07/15] video: Add Sitronix st7789v panel driver Sascha Hauer
2024-09-27 10:37 ` [PATCH v2 08/15] video: add dw-hdmi driver Sascha Hauer
2024-09-27 10:37 ` [PATCH v2 09/15] video: i.MX ipuv3: switch to upstream hdmi driver Sascha Hauer
2024-09-27 10:37 ` [PATCH v2 10/15] fb: Accept overlay framebuffers without modes Sascha Hauer
2024-09-27 10:37 ` [PATCH v2 11/15] fb: print more information on devinfo Sascha Hauer
2024-09-27 10:37 ` [PATCH v2 12/15] fbconsole: Adjust fbconsole names for overlays Sascha Hauer
2024-09-27 10:37 ` [PATCH v2 13/15] ARM: ARM64: implement dma_alloc_writecombine() Sascha Hauer
2024-09-27 10:37 ` [PATCH v2 14/15] vpl: make vpl deep probe aware Sascha Hauer
2024-09-27 10:37 ` [PATCH v2 15/15] video: Rockchip: Add VOP2 driver Sascha Hauer
2024-09-30 6:35 ` Ahmad Fatoum
2024-10-01 6:35 ` Sascha Hauer
2024-10-01 6:32 ` [PATCH v2 00/15] video: Add Rockchip VOP2 support Sascha Hauer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240927-vop2-v2-4-dc8dcfc651d5@pengutronix.de \
--to=s.hauer@pengutronix.de \
--cc=barebox@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox