[PATCH 7/8] regmap: Add support for regmap fields

Pratyush Yadav p.yadav at ti.com
Fri Jun 5 21:03:01 CEST 2020


Hi Simon,

On 31/05/20 08:08AM, Simon Glass wrote:
> Hi Pratyush,
> 
> On Wed, 27 May 2020 at 06:52, Pratyush Yadav <p.yadav at ti.com> wrote:
> >
> > From: Jean-Jacques Hiblot <jjhiblot at ti.com>
> >
> > 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 at ti.com>
> > Reviewed-by: Simon Glass <sjg at chromium.org>
> > Signed-off-by: Pratyush Yadav <p.yadav at ti.com>
> > ---
> >  drivers/core/regmap.c |  78 ++++++++++++++++++++++++++++++
> >  include/regmap.h      | 108 ++++++++++++++++++++++++++++++++++++++++++
> >  2 files changed, 186 insertions(+)
> >
> 
> Reviewed-by: Simon Glass <sjg at chromium.org>
> 
> 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

Heh, I'm that sure either. I went digging in the Linux source, and the 
only commit that touches this is the one that added regmap fields and it 
doesn't mention why we have both "regmap_field" and "reg_field".

Looking at the patch, I gather that regmap_field and reg_field look at 
the field in two different ways. reg_field is how a driver would look at 
a regmap field: which register this field belongs to, and what are its 
LSB and MSB? Datasheets usually tell you this information directly.

regmap_field looks at it from a lower level view: what register this 
feild belongs to, and how do I need to shift and mask the data I read 
from the bus? This is closer to how to actually read/write the field. 
The fact that regmap_field's definition is private to regmap.c also 
points in this direction.

The conversion from reg_field to regmap_field is done in 
regmap_field_init().

As to why have these two representations of the same thing, I can't say 
with certainty. My guess is that it makes the internal regmap code 
cleaner and slightly faster because you don't have to calculate the 
shift and mask every time.
 
> > +       struct regmap *regmap;
> > +       unsigned int mask;
> > +       /* lsb */
> > +       unsigned int shift;
> > +       unsigned int reg;
> > +};
> >
> >  DECLARE_GLOBAL_DATA_PTR;
> >
[..]
> > 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.

Good catch! Will drop them.
 
> > + */
> > +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

Ok.
 
> > +                               .reg = _reg,    \
> > +                               .lsb = _lsb,    \
> > +                               .msb = _msb,    \
> > +                               }
> > +

-- 
Regards,
Pratyush Yadav
Texas Instruments India


More information about the U-Boot mailing list