Hi Pratyush, On Wed, 27 May 2020 at 06:52, Pratyush Yadav <[email protected]> wrote: > > From: Jean-Jacques Hiblot <[email protected]> > > 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 <[email protected]> > Reviewed-by: Simon Glass <[email protected]> > Signed-off-by: Pratyush Yadav <[email protected]> > --- > drivers/core/regmap.c | 78 ++++++++++++++++++++++++++++++ > include/regmap.h | 108 ++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 186 insertions(+) >
Reviewed-by: Simon Glass <[email protected]> Please see below > diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c > index 4792067f24..cbc01b689a 100644 > --- a/drivers/core/regmap.c > +++ b/drivers/core/regmap.c > @@ -18,6 +18,15 @@ > #include <linux/ioport.h> > #include <linux/compat.h> > #include <linux/err.h> > +#include <linux/bitops.h> > + > +struct regmap_field { Needs comments as I'm not sure what this is for > + struct regmap *regmap; > + unsigned int mask; > + /* lsb */ > + unsigned int shift; > + unsigned int reg; > +}; > > DECLARE_GLOBAL_DATA_PTR; > > @@ -545,3 +554,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); > +} > diff --git a/include/regmap.h b/include/regmap.h > index 007e6f4b6f..190ea44f6a 100644 > --- a/include/regmap.h > +++ b/include/regmap.h > @@ -314,6 +314,43 @@ int regmap_raw_read_range(struct regmap *map, uint > range_num, uint offset, > regmap_read_poll_timeout_test(map, addr, val, cond, sleep_us, \ > timeout_ms, 0) \ > > +/** > + * regmap_field_read_poll_timeout - Poll until a condition is met or a > timeout > + * occurs > + * > + * @field: Regmap field to read from > + * @val: Unsigned integer variable to read the value into > + * @cond: Break condition (usually involving @val) > + * @sleep_us: Maximum time to sleep between reads in us (0 tight-loops). > + * @timeout_ms: Timeout in ms, 0 means never timeout > + * > + * Returns 0 on success and -ETIMEDOUT upon a timeout or the > regmap_field_read > + * error return value in case of a error read. In the two former cases, > + * the last read value at @addr is stored in @val. > + * > + * This is modelled after the regmap_read_poll_timeout macros in linux but > + * with millisecond timeout. > + */ > +#define regmap_field_read_poll_timeout(field, val, cond, sleep_us, > timeout_ms) \ > +({ \ > + unsigned long __start = get_timer(0); \ > + int __ret; \ > + for (;;) { \ > + __ret = regmap_field_read((field), &(val)); \ > + if (__ret) \ > + break; \ > + if (cond) \ > + break; \ > + if ((timeout_ms) && get_timer(__start) > (timeout_ms)) { \ > + __ret = regmap_field_read((field), &(val)); \ > + break; \ > + } \ > + if ((sleep_us)) \ > + udelay((sleep_us)); \ > + } \ > + __ret ?: ((cond) ? 0 : -ETIMEDOUT); \ > +}) > + > /** > * regmap_update_bits() - Perform a read/modify/write using a mask > * > @@ -409,4 +446,75 @@ void *regmap_get_range(struct regmap *map, unsigned int > range_num); > */ > int regmap_uninit(struct regmap *map); > > +/** > + * struct reg_field - Description of an register field > + * > + * @reg: Offset of the register within the regmap bank > + * @lsb: lsb of the register field. > + * @msb: msb of the register field. > + * @id_size: port size if it has some ports > + * @id_offset: address offset for each ports Those last two don't seem to be present. > + */ > +struct reg_field { > + unsigned int reg; > + unsigned int lsb; > + unsigned int msb; > +}; > + > +struct regmap_field; > + > +#define REG_FIELD(_reg, _lsb, _msb) { \ comment and perhaps an example of how to use it > + .reg = _reg, \ > + .lsb = _lsb, \ > + .msb = _msb, \ > + } > + > +/** > + * devm_regmap_field_alloc() - Allocate and initialise a register field. > + * > + * @dev: Device that will be interacted with > + * @regmap: regmap bank in which this register field is located. > + * @reg_field: Register field with in the bank. > + * > + * The return value will be an ERR_PTR() on error or a valid pointer > + * to a struct regmap_field. The regmap_field will be automatically freed > + * by the device management code. > + */ > +struct regmap_field *devm_regmap_field_alloc(struct udevice *dev, > + struct regmap *regmap, > + struct reg_field reg_field); > +/** > + * devm_regmap_field_free() - Free a register field allocated using > + * devm_regmap_field_alloc. > + * > + * @dev: Device that will be interacted with > + * @field: regmap field which should be freed. > + * > + * Free register field allocated using devm_regmap_field_alloc(). Usually > + * drivers need not call this function, as the memory allocated via devm > + * will be freed as per device-driver life-cyle. > + */ > +void devm_regmap_field_free(struct udevice *dev, struct regmap_field *field); > + > +/** > + * regmap_field_write() - Write a value to a regmap field > + * > + * @field: Regmap field to write to > + * @val: Data to write to the regmap at the specified offset > + * > + * Return: 0 if OK, -ve on error > + */ > +int regmap_field_write(struct regmap_field *field, unsigned int val); > + > +/** > + * regmap_read() - Read a 32-bit value from a regmap > + * > + * @field: Regmap field to write to > + * @valp: Pointer to the buffer to receive the data read from the regmap > + * field > + * > + * Return: 0 if OK, -ve on error > + */ > +int regmap_field_read(struct regmap_field *field, unsigned int *val); > + > #endif > -- > 2.26.2 > Regards, Simon

