diff mbox series

[U-Boot,v2,2/4] regmap: Allow providing read/write callbacks through struct regmap_config

Message ID 20191105114700.24989-3-jjhiblot@ti.com
State Changes Requested
Delegated to: Tom Rini
Headers show
Series regmap: Add a managed API, custom read/write callbacks and support for regmap fields | expand

Commit Message

Jean-Jacques Hiblot Nov. 5, 2019, 11:46 a.m. UTC
Some linux drivers provide their own read/write functions to access data
from/of the regmap. Adding support for it.

Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>

---

Changes in v2:
- Only use custom accessors if {,SPL,TPL}_REGMAP_ACCESSORS is enabled

 drivers/core/Kconfig  | 25 +++++++++++++++++++++++++
 drivers/core/regmap.c | 22 ++++++++++++++++++++--
 include/regmap.h      | 28 +++++++++++++++++++++++++---
 3 files changed, 70 insertions(+), 5 deletions(-)

Comments

Simon Glass Dec. 10, 2019, 3:18 p.m. UTC | #1
Hi Jean-Jacques,

On Tue, 5 Nov 2019 at 04:47, Jean-Jacques Hiblot <jjhiblot@ti.com> wrote:
>
> Some linux drivers provide their own read/write functions to access data
> from/of the regmap. Adding support for it.
>
> Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
>
> ---
>
> Changes in v2:
> - Only use custom accessors if {,SPL,TPL}_REGMAP_ACCESSORS is enabled
>
>  drivers/core/Kconfig  | 25 +++++++++++++++++++++++++
>  drivers/core/regmap.c | 22 ++++++++++++++++++++--
>  include/regmap.h      | 28 +++++++++++++++++++++++++---
>  3 files changed, 70 insertions(+), 5 deletions(-)

Coming back to the discussion on driver model....

How do you specify the fields? I would expect that this would be done
in the driver tree? Perhaps in a subnode of the device?

Just to state what I see as the advantages of using a separate device
for access:

- Remove the #ifdef in the regmap struct
- Easy to specify the behaviour in a device-tree node
- Easy to extend as the child device can do what it likes with respect to access

Disadvantage is that it takes a bit more space.

Regards,
Simon
Jean-Jacques Hiblot Dec. 16, 2019, 10:09 a.m. UTC | #2
Hi Simon,

On 10/12/2019 16:18, Simon Glass wrote:
> Hi Jean-Jacques,
>
> On Tue, 5 Nov 2019 at 04:47, Jean-Jacques Hiblot <jjhiblot@ti.com> wrote:
>> Some linux drivers provide their own read/write functions to access data
>> from/of the regmap. Adding support for it.
>>
>> Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
>>
>> ---
>>
>> Changes in v2:
>> - Only use custom accessors if {,SPL,TPL}_REGMAP_ACCESSORS is enabled
>>
>>   drivers/core/Kconfig  | 25 +++++++++++++++++++++++++
>>   drivers/core/regmap.c | 22 ++++++++++++++++++++--
>>   include/regmap.h      | 28 +++++++++++++++++++++++++---
>>   3 files changed, 70 insertions(+), 5 deletions(-)
> Coming back to the discussion on driver model....
>
> How do you specify the fields? I would expect that this would be done
> in the driver tree? Perhaps in a subnode of the device?
>
> Just to state what I see as the advantages of using a separate device
> for access:
>
> - Remove the #ifdef in the regmap struct
> - Easy to specify the behaviour in a device-tree node
> - Easy to extend as the child device can do what it likes with respect to access

That sure is a better abstraction. However the goal of this patch is 
only to use the same API as linux. It allows porting the drivers as-is 
and thus reduce the burden of maintenance.

JJ

>
> Disadvantage is that it takes a bit more space.
>
> Regards,
> Simon
Simon Glass Dec. 24, 2019, 3:58 p.m. UTC | #3
Hi Jean-Jacques,

On Mon, 16 Dec 2019 at 03:10, Jean-Jacques Hiblot <jjhiblot@ti.com> wrote:
>
> Hi Simon,
>
> On 10/12/2019 16:18, Simon Glass wrote:
> > Hi Jean-Jacques,
> >
> > On Tue, 5 Nov 2019 at 04:47, Jean-Jacques Hiblot <jjhiblot@ti.com> wrote:
> >> Some linux drivers provide their own read/write functions to access data
> >> from/of the regmap. Adding support for it.
> >>
> >> Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
> >>
> >> ---
> >>
> >> Changes in v2:
> >> - Only use custom accessors if {,SPL,TPL}_REGMAP_ACCESSORS is enabled
> >>
> >>   drivers/core/Kconfig  | 25 +++++++++++++++++++++++++
> >>   drivers/core/regmap.c | 22 ++++++++++++++++++++--
> >>   include/regmap.h      | 28 +++++++++++++++++++++++++---
> >>   3 files changed, 70 insertions(+), 5 deletions(-)
> > Coming back to the discussion on driver model....
> >
> > How do you specify the fields? I would expect that this would be done
> > in the driver tree? Perhaps in a subnode of the device?
> >
> > Just to state what I see as the advantages of using a separate device
> > for access:
> >
> > - Remove the #ifdef in the regmap struct
> > - Easy to specify the behaviour in a device-tree node
> > - Easy to extend as the child device can do what it likes with respect to access
>
> That sure is a better abstraction. However the goal of this patch is
> only to use the same API as linux. It allows porting the drivers as-is
> and thus reduce the burden of maintenance.

So how do you specify the fields? See my question above.

It is not possible to use a similar API without importing the internal
implementation. Linux's driver model is less homogenous.

Regards,
Simon
Jean-Jacques Hiblot Jan. 8, 2020, 4:16 p.m. UTC | #4
Simon,

On 24/12/2019 16:58, Simon Glass wrote:
> Hi Jean-Jacques,
>
> On Mon, 16 Dec 2019 at 03:10, Jean-Jacques Hiblot <jjhiblot@ti.com> wrote:
>> Hi Simon,
>>
>> On 10/12/2019 16:18, Simon Glass wrote:
>>> Hi Jean-Jacques,
>>>
>>> On Tue, 5 Nov 2019 at 04:47, Jean-Jacques Hiblot <jjhiblot@ti.com> wrote:
>>>> Some linux drivers provide their own read/write functions to access data
>>>> from/of the regmap. Adding support for it.
>>>>
>>>> Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
>>>>
>>>> ---
>>>>
>>>> Changes in v2:
>>>> - Only use custom accessors if {,SPL,TPL}_REGMAP_ACCESSORS is enabled
>>>>
>>>>    drivers/core/Kconfig  | 25 +++++++++++++++++++++++++
>>>>    drivers/core/regmap.c | 22 ++++++++++++++++++++--
>>>>    include/regmap.h      | 28 +++++++++++++++++++++++++---
>>>>    3 files changed, 70 insertions(+), 5 deletions(-)
>>> Coming back to the discussion on driver model....
>>>
>>> How do you specify the fields? I would expect that this would be done
>>> in the driver tree? Perhaps in a subnode of the device?
>>>
>>> Just to state what I see as the advantages of using a separate device
>>> for access:
>>>
>>> - Remove the #ifdef in the regmap struct
>>> - Easy to specify the behaviour in a device-tree node
>>> - Easy to extend as the child device can do what it likes with respect to access
>> That sure is a better abstraction. However the goal of this patch is
>> only to use the same API as linux. It allows porting the drivers as-is
>> and thus reduce the burden of maintenance.
> So how do you specify the fields? See my question above.

The fields are filled when creating the regmap.

ex:

static struct regmap_config cfg = {
	.reg_write = regmaptest_write,
	.reg_read = regmaptest_read,
};
and then
regmap = devm_regmap_init(dev, NULL, &ctx, &cfg);

You can have a look at the tests in the last patch of the series.

JJ

> It is not possible to use a similar API without importing the internal
> implementation. Linux's driver model is less homogenous.
>
> Regards,
> Simon
Simon Glass Jan. 30, 2020, 2:17 a.m. UTC | #5
Hi Jean-Jacques,

On Wed, 8 Jan 2020 at 09:16, Jean-Jacques Hiblot <jjhiblot@ti.com> wrote:
>
> Simon,
>
> On 24/12/2019 16:58, Simon Glass wrote:
> > Hi Jean-Jacques,
> >
> > On Mon, 16 Dec 2019 at 03:10, Jean-Jacques Hiblot <jjhiblot@ti.com> wrote:
> >> Hi Simon,
> >>
> >> On 10/12/2019 16:18, Simon Glass wrote:
> >>> Hi Jean-Jacques,
> >>>
> >>> On Tue, 5 Nov 2019 at 04:47, Jean-Jacques Hiblot <jjhiblot@ti.com> wrote:
> >>>> Some linux drivers provide their own read/write functions to access data
> >>>> from/of the regmap. Adding support for it.
> >>>>
> >>>> Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
> >>>>
> >>>> ---
> >>>>
> >>>> Changes in v2:
> >>>> - Only use custom accessors if {,SPL,TPL}_REGMAP_ACCESSORS is enabled
> >>>>
> >>>>    drivers/core/Kconfig  | 25 +++++++++++++++++++++++++
> >>>>    drivers/core/regmap.c | 22 ++++++++++++++++++++--
> >>>>    include/regmap.h      | 28 +++++++++++++++++++++++++---
> >>>>    3 files changed, 70 insertions(+), 5 deletions(-)
> >>> Coming back to the discussion on driver model....
> >>>
> >>> How do you specify the fields? I would expect that this would be done
> >>> in the driver tree? Perhaps in a subnode of the device?
> >>>
> >>> Just to state what I see as the advantages of using a separate device
> >>> for access:
> >>>
> >>> - Remove the #ifdef in the regmap struct
> >>> - Easy to specify the behaviour in a device-tree node
> >>> - Easy to extend as the child device can do what it likes with respect to access
> >> That sure is a better abstraction. However the goal of this patch is
> >> only to use the same API as linux. It allows porting the drivers as-is
> >> and thus reduce the burden of maintenance.
> > So how do you specify the fields? See my question above.
>
> The fields are filled when creating the regmap.
>
> ex:
>
> static struct regmap_config cfg = {
>         .reg_write = regmaptest_write,
>         .reg_read = regmaptest_read,
> };
> and then
> regmap = devm_regmap_init(dev, NULL, &ctx, &cfg);
>
> You can have a look at the tests in the last patch of the series.
>
> JJ
>
> > It is not possible to use a similar API without importing the internal
> > implementation. Linux's driver model is less homogenous.

Then I really think we should try to use driver model for the accessors too.

IMO the access method could be described in the device tree. But if
not, we could bind the accessor driver as a child.

Regards,
Simon
Pratyush Yadav May 5, 2020, 7:47 p.m. UTC | #6
Hi Simon,

I would be taking up this series and address the comments.

On 10/12/19 03:18PM, Simon Glass wrote:
> Hi Jean-Jacques,
>
> On Tue, 5 Nov 2019 at 04:47, Jean-Jacques Hiblot <jjhiblot@ti.com> wrote:
> >
> > Some linux drivers provide their own read/write functions to access data
> > from/of the regmap. Adding support for it.
> >
> > Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
> >
> > ---
> >
> > Changes in v2:
> > - Only use custom accessors if {,SPL,TPL}_REGMAP_ACCESSORS is enabled
> >
> >  drivers/core/Kconfig  | 25 +++++++++++++++++++++++++
> >  drivers/core/regmap.c | 22 ++++++++++++++++++++--
> >  include/regmap.h      | 28 +++++++++++++++++++++++++---
> >  3 files changed, 70 insertions(+), 5 deletions(-)
>
> Coming back to the discussion on driver model....

IIUC, you are suggesting that we create a uclass for regmap, and fill in 
the ops with the driver's custom read/write functions, correct? This 
would mean we will have to create udevice for each regmap. A driver can 
have multiple regmaps (up to 18 for example in the Linux Cadence Sierra 
PHY driver in kernel). Creating a device for each regmap is very 
inefficient. Is the overhead really worth it? Does it solve any 
significant problem? Also, a regmap is not a device, it is an 
abstraction layer to simplify register access. Does it then make sense 
to model it as a device?

> How do you specify the fields? I would expect that this would be done
> in the driver tree? Perhaps in a subnode of the device?
>
> Just to state what I see as the advantages of using a separate device
> for access:
>
> - Remove the #ifdef in the regmap struct

If you really want to remove the #ifdefs, we can set reg_read to a 
default, and let drivers override if when creating a regmap. Then in 
regmap_read, just call reg_read. This gets rid of the #ifdefs with a 
small change. I suspect this will have a much smaller impact on memory 
usage than using a udevice.

> - Easy to specify the behaviour in a device-tree node

Quoting from the kernel's documentation of regmap_config:

  reg_read: Optional callback that if filled will be used to perform all 
  the reads from the registers. Should only be provided for devices 
  whose read operation cannot be represented as a simple read operation 
  on a bus such as SPI, I2C, etc. Most of the devices do not need this.
  reg_write: Same as above for writing.

These custom accessors are meant to be used when the read or write needs 
more work to be done than the standard regmap reads/writes. And so they 
are supposed to be driver-specific functions. I don't think it is at all 
possible to specify something like this in devicetree. Am I missing 
something?

> - Easy to extend as the child device can do what it likes with respect to access
>
> Disadvantage is that it takes a bit more space.
Simon Glass May 6, 2020, 2:47 p.m. UTC | #7
Hi Pratyush,

On Tue, 5 May 2020 at 13:47, Pratyush Yadav <p.yadav@ti.com> wrote:
>
> Hi Simon,
>
> I would be taking up this series and address the comments.
>
> On 10/12/19 03:18PM, Simon Glass wrote:
> > Hi Jean-Jacques,
> >
> > On Tue, 5 Nov 2019 at 04:47, Jean-Jacques Hiblot <jjhiblot@ti.com> wrote:
> > >
> > > Some linux drivers provide their own read/write functions to access data
> > > from/of the regmap. Adding support for it.
> > >
> > > Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
> > >
> > > ---
> > >
> > > Changes in v2:
> > > - Only use custom accessors if {,SPL,TPL}_REGMAP_ACCESSORS is enabled
> > >
> > >  drivers/core/Kconfig  | 25 +++++++++++++++++++++++++
> > >  drivers/core/regmap.c | 22 ++++++++++++++++++++--
> > >  include/regmap.h      | 28 +++++++++++++++++++++++++---
> > >  3 files changed, 70 insertions(+), 5 deletions(-)
> >
> > Coming back to the discussion on driver model....
>
> IIUC, you are suggesting that we create a uclass for regmap, and fill in
> the ops with the driver's custom read/write functions, correct? This
> would mean we will have to create udevice for each regmap. A driver can
> have multiple regmaps (up to 18 for example in the Linux Cadence Sierra
> PHY driver in kernel). Creating a device for each regmap is very
> inefficient. Is the overhead really worth it? Does it solve any
> significant problem? Also, a regmap is not a device, it is an
> abstraction layer to simplify register access. Does it then make sense
> to model it as a device?

I was actually referring to the access method of the regmap but I
suppose the effect is the same. This question has been running for a
while.

The issue is that this is getting more and more complicated. We use
devices to model complicated things. It is an abstraction. It doesn't
have to be a physical device.

With regmap we are creating an ad-hoc structure and associated
infrastructure to deal with this one case. It is not possible to see
the regmaps with 'dm dump', for example.

>
> > How do you specify the fields? I would expect that this would be done
> > in the driver tree? Perhaps in a subnode of the device?
> >
> > Just to state what I see as the advantages of using a separate device
> > for access:
> >
> > - Remove the #ifdef in the regmap struct
>
> If you really want to remove the #ifdefs, we can set reg_read to a
> default, and let drivers override if when creating a regmap. Then in
> regmap_read, just call reg_read. This gets rid of the #ifdefs with a
> small change. I suspect this will have a much smaller impact on memory
> usage than using a udevice.

Yes that sounds good, but you are getting closer and closer to it
being a device.

>
> > - Easy to specify the behaviour in a device-tree node
>
> Quoting from the kernel's documentation of regmap_config:
>
>   reg_read: Optional callback that if filled will be used to perform all
>   the reads from the registers. Should only be provided for devices
>   whose read operation cannot be represented as a simple read operation
>   on a bus such as SPI, I2C, etc. Most of the devices do not need this.
>   reg_write: Same as above for writing.
>
> These custom accessors are meant to be used when the read or write needs
> more work to be done than the standard regmap reads/writes. And so they
> are supposed to be driver-specific functions. I don't think it is at all
> possible to specify something like this in devicetree. Am I missing
> something?

Can you point to an example of this extra read/write code?

The kernel is a rabbit-warren of custom interfaces. I am trying to
keep driver model uniform, so long as the cost is reasonable. I'm not
sure that it is worth having a regmap device for simple things, but as
things get more complex, I think we should look at it.

Of course you can specify this in the device tree: just use a
compatible string to select the appropriate regmap driver.

spi {
    compatible = "vendor,myspi";
    regmaps = <&regmap_simple 4
           &regmap_mailbox 0 FLAGS>;
}

regmap_mailbox: regmap-mailbox {
    compatible = "regmap,mailbox";
    other props
}

struct regmap *regmap = regmap_get_by_index(dev, 1)

regmap_read(regmap, ...)

>
> > - Easy to extend as the child device can do what it likes with respect to access
> >
> > Disadvantage is that it takes a bit more space.

Yes space is a concern. A device takes about 84 bytes I think. But as
we add more and more complexity we might as well take the hit.

Regards,
Simon
Raghavendra, Vignesh May 7, 2020, 9:07 a.m. UTC | #8
On 06/05/20 8:17 pm, Simon Glass wrote:
> Hi Pratyush,
> 
> On Tue, 5 May 2020 at 13:47, Pratyush Yadav <p.yadav@ti.com> wrote:
>>
>> Hi Simon,
>>
>> I would be taking up this series and address the comments.
>>
>> On 10/12/19 03:18PM, Simon Glass wrote:
>>> Hi Jean-Jacques,
>>>
>>> On Tue, 5 Nov 2019 at 04:47, Jean-Jacques Hiblot <jjhiblot@ti.com> wrote:
>>>>
>>>> Some linux drivers provide their own read/write functions to access data
>>>> from/of the regmap. Adding support for it.
>>>>
>>>> Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
>>>>
>>>> ---
>>>>
>>>> Changes in v2:
>>>> - Only use custom accessors if {,SPL,TPL}_REGMAP_ACCESSORS is enabled
>>>>
>>>>  drivers/core/Kconfig  | 25 +++++++++++++++++++++++++
>>>>  drivers/core/regmap.c | 22 ++++++++++++++++++++--
>>>>  include/regmap.h      | 28 +++++++++++++++++++++++++---
>>>>  3 files changed, 70 insertions(+), 5 deletions(-)
>>>
>>> Coming back to the discussion on driver model....
>>
>> IIUC, you are suggesting that we create a uclass for regmap, and fill in
>> the ops with the driver's custom read/write functions, correct? This
>> would mean we will have to create udevice for each regmap. A driver can
>> have multiple regmaps (up to 18 for example in the Linux Cadence Sierra
>> PHY driver in kernel). Creating a device for each regmap is very
>> inefficient. Is the overhead really worth it? Does it solve any
>> significant problem? Also, a regmap is not a device, it is an
>> abstraction layer to simplify register access. Does it then make sense
>> to model it as a device?
> 
> I was actually referring to the access method of the regmap but I
> suppose the effect is the same. This question has been running for a
> while.
> 
> The issue is that this is getting more and more complicated. We use
> devices to model complicated things. It is an abstraction. It doesn't
> have to be a physical device.
> 
> With regmap we are creating an ad-hoc structure and associated
> infrastructure to deal with this one case. It is not possible to see
> the regmaps with 'dm dump', for example.
> 
>>
>>> How do you specify the fields? I would expect that this would be done
>>> in the driver tree? Perhaps in a subnode of the device?
>>>
>>> Just to state what I see as the advantages of using a separate device
>>> for access:
>>>
>>> - Remove the #ifdef in the regmap struct
>>
>> If you really want to remove the #ifdefs, we can set reg_read to a
>> default, and let drivers override if when creating a regmap. Then in
>> regmap_read, just call reg_read. This gets rid of the #ifdefs with a
>> small change. I suspect this will have a much smaller impact on memory
>> usage than using a udevice.
> 
> Yes that sounds good, but you are getting closer and closer to it
> being a device.
> 
>>
>>> - Easy to specify the behaviour in a device-tree node
>>
>> Quoting from the kernel's documentation of regmap_config:
>>
>>   reg_read: Optional callback that if filled will be used to perform all
>>   the reads from the registers. Should only be provided for devices
>>   whose read operation cannot be represented as a simple read operation
>>   on a bus such as SPI, I2C, etc. Most of the devices do not need this.
>>   reg_write: Same as above for writing.
>>
>> These custom accessors are meant to be used when the read or write needs
>> more work to be done than the standard regmap reads/writes. And so they
>> are supposed to be driver-specific functions. I don't think it is at all
>> possible to specify something like this in devicetree. Am I missing
>> something?
> 
> Can you point to an example of this extra read/write code?


Here is the cadence sierra PHY driver for which this series is a pre
requiste

https://elixir.bootlin.com/linux/latest/source/drivers/phy/cadence/phy-cadence-sierra.c

PHY Registers are 16 bit wide. Some implementations (SoCs) have arranged
these registers continuously (so they are aligned to 16 bit address
boundary) but some implementation place each register at 32 bit boundary
(wasting the upper 16 bits)

There are few other nits but above is the major one.

Custom regmap read()/write() hooks abstracts all these from actual
driver logic.

It is possible to re implement driver w/o regmap abstraction but this
would deviate the driver significantly from that of kernel. PHY drivers
often get updated with new register settings as and when HW
characterization progresses which need to be ported to kernel and
U-Boot. Having U-Boot driver same as kernel will ease porting effort and
also reduces the chances of errors.


> 
> The kernel is a rabbit-warren of custom interfaces. I am trying to
> keep driver model uniform, so long as the cost is reasonable. I'm not
> sure that it is worth having a regmap device for simple things, but as
> things get more complex, I think we should look at it.
> 
> Of course you can specify this in the device tree: just use a
> compatible string to select the appropriate regmap driver.
> 
> spi {
>     compatible = "vendor,myspi";
>     regmaps = <&regmap_simple 4
>            &regmap_mailbox 0 FLAGS>;
> }
> 
> regmap_mailbox: regmap-mailbox {
>     compatible = "regmap,mailbox";
>     other props
> }

This would mean U-Boot and Kernel DT files would be significantly
different and would defeat the whole purpose of maintaining common DT
bindings b/w kernel and U-Boot.

IMHO, regmap is pure SW abstraction that hides complexities of accessing
underlying register map therefore I don't think representing such
abstraction in DT will be accepted by upstream DT maintainers.

If there a way to use DM w/o DT changes, we can definitely explore that...

> 
> struct regmap *regmap = regmap_get_by_index(dev, 1)
> 
> regmap_read(regmap, ...)
> 
>>
>>> - Easy to extend as the child device can do what it likes with respect to access
>>>
>>> Disadvantage is that it takes a bit more space.
> 
> Yes space is a concern. A device takes about 84 bytes I think. But as
> we add more and more complexity we might as well take the hit.
> 
> Regards,
> Simon
>
Simon Glass May 8, 2020, 1:36 a.m. UTC | #9
Hi Vignesh,

On Thu, 7 May 2020 at 03:08, Vignesh Raghavendra <vigneshr@ti.com> wrote:
>
>
>
> On 06/05/20 8:17 pm, Simon Glass wrote:
> > Hi Pratyush,
> >
> > On Tue, 5 May 2020 at 13:47, Pratyush Yadav <p.yadav@ti.com> wrote:
> >>
> >> Hi Simon,
> >>
> >> I would be taking up this series and address the comments.
> >>
> >> On 10/12/19 03:18PM, Simon Glass wrote:
> >>> Hi Jean-Jacques,
> >>>
> >>> On Tue, 5 Nov 2019 at 04:47, Jean-Jacques Hiblot <jjhiblot@ti.com> wrote:
> >>>>
> >>>> Some linux drivers provide their own read/write functions to access data
> >>>> from/of the regmap. Adding support for it.
> >>>>
> >>>> Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
> >>>>
> >>>> ---
> >>>>
> >>>> Changes in v2:
> >>>> - Only use custom accessors if {,SPL,TPL}_REGMAP_ACCESSORS is enabled
> >>>>
> >>>>  drivers/core/Kconfig  | 25 +++++++++++++++++++++++++
> >>>>  drivers/core/regmap.c | 22 ++++++++++++++++++++--
> >>>>  include/regmap.h      | 28 +++++++++++++++++++++++++---
> >>>>  3 files changed, 70 insertions(+), 5 deletions(-)
> >>>
> >>> Coming back to the discussion on driver model....
> >>
> >> IIUC, you are suggesting that we create a uclass for regmap, and fill in
> >> the ops with the driver's custom read/write functions, correct? This
> >> would mean we will have to create udevice for each regmap. A driver can
> >> have multiple regmaps (up to 18 for example in the Linux Cadence Sierra
> >> PHY driver in kernel). Creating a device for each regmap is very
> >> inefficient. Is the overhead really worth it? Does it solve any
> >> significant problem? Also, a regmap is not a device, it is an
> >> abstraction layer to simplify register access. Does it then make sense
> >> to model it as a device?
> >
> > I was actually referring to the access method of the regmap but I
> > suppose the effect is the same. This question has been running for a
> > while.
> >
> > The issue is that this is getting more and more complicated. We use
> > devices to model complicated things. It is an abstraction. It doesn't
> > have to be a physical device.
> >
> > With regmap we are creating an ad-hoc structure and associated
> > infrastructure to deal with this one case. It is not possible to see
> > the regmaps with 'dm dump', for example.
> >
> >>
> >>> How do you specify the fields? I would expect that this would be done
> >>> in the driver tree? Perhaps in a subnode of the device?
> >>>
> >>> Just to state what I see as the advantages of using a separate device
> >>> for access:
> >>>
> >>> - Remove the #ifdef in the regmap struct
> >>
> >> If you really want to remove the #ifdefs, we can set reg_read to a
> >> default, and let drivers override if when creating a regmap. Then in
> >> regmap_read, just call reg_read. This gets rid of the #ifdefs with a
> >> small change. I suspect this will have a much smaller impact on memory
> >> usage than using a udevice.
> >
> > Yes that sounds good, but you are getting closer and closer to it
> > being a device.
> >
> >>
> >>> - Easy to specify the behaviour in a device-tree node
> >>
> >> Quoting from the kernel's documentation of regmap_config:
> >>
> >>   reg_read: Optional callback that if filled will be used to perform all
> >>   the reads from the registers. Should only be provided for devices
> >>   whose read operation cannot be represented as a simple read operation
> >>   on a bus such as SPI, I2C, etc. Most of the devices do not need this.
> >>   reg_write: Same as above for writing.
> >>
> >> These custom accessors are meant to be used when the read or write needs
> >> more work to be done than the standard regmap reads/writes. And so they
> >> are supposed to be driver-specific functions. I don't think it is at all
> >> possible to specify something like this in devicetree. Am I missing
> >> something?
> >
> > Can you point to an example of this extra read/write code?
>
>
> Here is the cadence sierra PHY driver for which this series is a pre
> requiste
>
> https://elixir.bootlin.com/linux/latest/source/drivers/phy/cadence/phy-cadence-sierra.c
>
> PHY Registers are 16 bit wide. Some implementations (SoCs) have arranged
> these registers continuously (so they are aligned to 16 bit address
> boundary) but some implementation place each register at 32 bit boundary
> (wasting the upper 16 bits)
>
> There are few other nits but above is the major one.
>

OK I see. So it's fairly simple, not accessing through a mailbox, etc.

> Custom regmap read()/write() hooks abstracts all these from actual
> driver logic.
>
> It is possible to re implement driver w/o regmap abstraction but this
> would deviate the driver significantly from that of kernel. PHY drivers
> often get updated with new register settings as and when HW
> characterization progresses which need to be ported to kernel and
> U-Boot. Having U-Boot driver same as kernel will ease porting effort and
> also reduces the chances of errors.

I actually don't think that argument holds much water. I am not
suggesting that the regmap interface be different, so the code should
remain the same in the driver. Perhaps the probe() code might change a
bit as it sets things up. But there are already differences there.

>
>
> >
> > The kernel is a rabbit-warren of custom interfaces. I am trying to
> > keep driver model uniform, so long as the cost is reasonable. I'm not
> > sure that it is worth having a regmap device for simple things, but as
> > things get more complex, I think we should look at it.
> >
> > Of course you can specify this in the device tree: just use a
> > compatible string to select the appropriate regmap driver.
> >
> > spi {
> >     compatible = "vendor,myspi";
> >     regmaps = <&regmap_simple 4
> >            &regmap_mailbox 0 FLAGS>;
> > }
> >
> > regmap_mailbox: regmap-mailbox {
> >     compatible = "regmap,mailbox";
> >     other props
> > }
>
> This would mean U-Boot and Kernel DT files would be significantly
> different and would defeat the whole purpose of maintaining common DT
> bindings b/w kernel and U-Boot.

Yes it means that U-Boot would have extra nodes that the kernel DT
does not have. We already have that problem, although I hope with the
DTE project U-Boot might finally get a say in what is allowed in the
bindings.

>
> IMHO, regmap is pure SW abstraction that hides complexities of accessing
> underlying register map therefore I don't think representing such
> abstraction in DT will be accepted by upstream DT maintainers.

That is a very strange argument. Above you told me that the access
mechanism is different in the hardware - 16 bits with different
positioning, for example. That is exactly the sort of thing the DT is
supposed to describe.

>
> If there a way to use DM w/o DT changes, we can definitely explore that...

You can certainly do that. Just device_bind() a driver that implements
your access mechanism. So long as the driver uses the same access
mechanism no matter what hardware it is running on, that makes sense.
But from what you say above, that might not be true, so you would end
up setting the platform data of the regmap driver from its parent.
That's not terrible, but not ideal.

Given the simple access you need above, I think you could just add
that as another option in the regmap, perhaps turning endianness into
some flags?


>
> >
> > struct regmap *regmap = regmap_get_by_index(dev, 1)
> >
> > regmap_read(regmap, ...)
> >
> >>
> >>> - Easy to extend as the child device can do what it likes with respect to access
> >>>
> >>> Disadvantage is that it takes a bit more space.
> >
> > Yes space is a concern. A device takes about 84 bytes I think. But as
> > we add more and more complexity we might as well take the hit.

Regards,
Simon
Pratyush Yadav May 11, 2020, noon UTC | #10
Hi Simon,

On 07/05/20 07:36PM, Simon Glass wrote:
> >
> > If there a way to use DM w/o DT changes, we can definitely explore that...
> 
> You can certainly do that. Just device_bind() a driver that implements
> your access mechanism. So long as the driver uses the same access
> mechanism no matter what hardware it is running on, that makes sense.
> But from what you say above, that might not be true, so you would end
> up setting the platform data of the regmap driver from its parent.
> That's not terrible, but not ideal.
> 
> Given the simple access you need above, I think you could just add
> that as another option in the regmap, perhaps turning endianness into
> some flags?

I tried doing it without custom regmap accessors. The rough patch below 
is what I came up with. Does it look any better than custom accessors?

PS: I can probably play around with regmap ranges instead of using
'base_offset', but it gets the job done minimally so I think it is good 
enough for a proof-of-concept.
 
 -- 8< --
Subject: [RFC PATCH] regmap: allow specifying base offset and register shift and
 access size

To accommodate more complex access patterns that are needed in the
Cadence Sierra PHY driver (which will be added as a follow-up),
introduce 'base_offset' and 'reg_offset_shift', two values that can be
used to adjust the final regmap read/write address.

'base_offset' is an extra offset on the regmap base discovered from the
device tree. This is useful when some regmaps of a device need to access
memory at one offset, and some at another.

'reg_offset_shift' will shift the register offset left before access.

'size' can be used to specify the width of reads (1/2/4/8 bytes). If 0,
defaults to 4 bytes to maintain backward compatibility.

Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
---
 drivers/core/regmap.c | 16 ++++++++++++----
 include/regmap.h      | 27 ++++++++++++++++++++++++++-
 2 files changed, 38 insertions(+), 5 deletions(-)

diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c
index 41293e5af0..9bce719b45 100644
--- a/drivers/core/regmap.c
+++ b/drivers/core/regmap.c
@@ -38,6 +38,7 @@ static struct regmap *regmap_alloc(int count)
 	map = malloc(sizeof(*map) + sizeof(map->ranges[0]) * count);
 	if (!map)
 		return NULL;
+	memset(map, 0, sizeof(*map));
 	map->range_count = count;

 	return map;
@@ -258,6 +259,10 @@ struct regmap *devm_regmap_init(struct udevice *dev,
 	if (rc)
 		return ERR_PTR(rc);

+	(*mapp)->base_offset = config->base_offset;
+	(*mapp)->reg_offset_shift = config->reg_offset_shift;
+	(*mapp)->size = config->size;
+
 	devres_add(dev, mapp);
 	return *mapp;
 }
@@ -343,7 +348,9 @@ int regmap_raw_read_range(struct regmap *map, uint range_num, uint offset,
 	}
 	range = &map->ranges[range_num];

-	ptr = map_physmem(range->start + offset, val_len, MAP_NOCACHE);
+	offset <<= map->reg_offset_shift;
+
+	ptr = map_physmem(range->start + map->base_offset + offset, val_len, MAP_NOCACHE);

 	if (offset + val_len > range->size) {
 		debug("%s: offset/size combination invalid\n", __func__);
@@ -380,7 +387,7 @@ int regmap_raw_read(struct regmap *map, uint offset, void *valp, size_t val_len)

 int regmap_read(struct regmap *map, uint offset, uint *valp)
 {
-	return regmap_raw_read(map, offset, valp, REGMAP_SIZE_32);
+	return regmap_raw_read(map, offset, valp, map->size ? map->size : REGMAP_SIZE_32);
 }

 static inline void __write_8(u8 *addr, const u8 *val,
@@ -452,7 +459,8 @@ int regmap_raw_write_range(struct regmap *map, uint range_num, uint offset,
 	}
 	range = &map->ranges[range_num];

-	ptr = map_physmem(range->start + offset, val_len, MAP_NOCACHE);
+	offset <<= map->reg_offset_shift;
+	ptr = map_physmem(range->start + map->base_offset + offset, val_len, MAP_NOCACHE);

 	if (offset + val_len > range->size) {
 		debug("%s: offset/size combination invalid\n", __func__);
@@ -490,7 +498,7 @@ int regmap_raw_write(struct regmap *map, uint offset, const void *val,

 int regmap_write(struct regmap *map, uint offset, uint val)
 {
-	return regmap_raw_write(map, offset, &val, REGMAP_SIZE_32);
+	return regmap_raw_write(map, offset, &val, map->size ? map->size : REGMAP_SIZE_32);
 }

 int regmap_update_bits(struct regmap *map, uint offset, uint mask, uint val)
diff --git a/include/regmap.h b/include/regmap.h
index 2edbf9359a..4adb04f7e3 100644
--- a/include/regmap.h
+++ b/include/regmap.h
@@ -74,16 +74,41 @@ struct regmap_range {
 };

 struct regmap_bus;
-struct regmap_config;
+/**
+ * struct regmap_config - a way of accessing hardware/bus registers
+ *
+ * @base_offset: Offset from the base of the regmap for reads and writes.
+ *		 (OPTIONAL)
+ * @reg_offset_shift: Left shift register offset by this value before
+ *		      performing reads or writes. (OPTIONAL)
+ * @size: Size/width of the read or write operation. Defaults to
+ *	  REGMAP_SIZE_32 if set to zero.
+ */
+struct regmap_config {
+	u32 base_offset;
+	u32 reg_offset_shift;
+	enum regmap_size_t size;
+};

 /**
  * struct regmap - a way of accessing hardware/bus registers
  *
+ * @base_offset: Offset from the base of the regmap for reads and writes.
+ *		 (OPTIONAL)
+ * @reg_offset_shift: Left shift register offset by this value before
+ *		      performing reads or writes. (OPTIONAL)
+ * @size: Size/width of the read or write operation. Defaults to
+ *	  REGMAP_SIZE_32 if set to zero.
  * @range_count:	Number of ranges available within the map
  * @ranges:		Array of ranges
  */
 struct regmap {
 	enum regmap_endianness_t endianness;
+
+	u32 base_offset;
+	u32 reg_offset_shift;
+	enum regmap_size_t size;
+
 	int range_count;
 	struct regmap_range ranges[0];
 };
Simon Glass May 11, 2020, 8:28 p.m. UTC | #11
Hi Pratyush,

On Mon, 11 May 2020 at 06:00, Yadav, Pratyush <p.yadav@ti.com> wrote:
>
> Hi Simon,
>
> On 07/05/20 07:36PM, Simon Glass wrote:
> > >
> > > If there a way to use DM w/o DT changes, we can definitely explore that...
> >
> > You can certainly do that. Just device_bind() a driver that implements
> > your access mechanism. So long as the driver uses the same access
> > mechanism no matter what hardware it is running on, that makes sense.
> > But from what you say above, that might not be true, so you would end
> > up setting the platform data of the regmap driver from its parent.
> > That's not terrible, but not ideal.
> >
> > Given the simple access you need above, I think you could just add
> > that as another option in the regmap, perhaps turning endianness into
> > some flags?
>
> I tried doing it without custom regmap accessors. The rough patch below
> is what I came up with. Does it look any better than custom accessors?

This looks OK. Should use a local variable instead of (*mapp)->
though. Also please add docs.


- SImon

>
> PS: I can probably play around with regmap ranges instead of using
> 'base_offset', but it gets the job done minimally so I think it is good
> enough for a proof-of-concept.
>
>  -- 8< --
> Subject: [RFC PATCH] regmap: allow specifying base offset and register shift and
>  access size
>
> To accommodate more complex access patterns that are needed in the
> Cadence Sierra PHY driver (which will be added as a follow-up),
> introduce 'base_offset' and 'reg_offset_shift', two values that can be
> used to adjust the final regmap read/write address.
>
> 'base_offset' is an extra offset on the regmap base discovered from the
> device tree. This is useful when some regmaps of a device need to access
> memory at one offset, and some at another.
>
> 'reg_offset_shift' will shift the register offset left before access.
>
> 'size' can be used to specify the width of reads (1/2/4/8 bytes). If 0,
> defaults to 4 bytes to maintain backward compatibility.
>
> Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
> ---
>  drivers/core/regmap.c | 16 ++++++++++++----
>  include/regmap.h      | 27 ++++++++++++++++++++++++++-
>  2 files changed, 38 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c
> index 41293e5af0..9bce719b45 100644
> --- a/drivers/core/regmap.c
> +++ b/drivers/core/regmap.c
> @@ -38,6 +38,7 @@ static struct regmap *regmap_alloc(int count)
>         map = malloc(sizeof(*map) + sizeof(map->ranges[0]) * count);
>         if (!map)
>                 return NULL;
> +       memset(map, 0, sizeof(*map));
>         map->range_count = count;
>
>         return map;
> @@ -258,6 +259,10 @@ struct regmap *devm_regmap_init(struct udevice *dev,
>         if (rc)
>                 return ERR_PTR(rc);
>
> +       (*mapp)->base_offset = config->base_offset;
> +       (*mapp)->reg_offset_shift = config->reg_offset_shift;
> +       (*mapp)->size = config->size;
> +
>         devres_add(dev, mapp);
>         return *mapp;
>  }
> @@ -343,7 +348,9 @@ int regmap_raw_read_range(struct regmap *map, uint range_num, uint offset,
>         }
>         range = &map->ranges[range_num];
>
> -       ptr = map_physmem(range->start + offset, val_len, MAP_NOCACHE);
> +       offset <<= map->reg_offset_shift;
> +
> +       ptr = map_physmem(range->start + map->base_offset + offset, val_len, MAP_NOCACHE);
>
>         if (offset + val_len > range->size) {
>                 debug("%s: offset/size combination invalid\n", __func__);
> @@ -380,7 +387,7 @@ int regmap_raw_read(struct regmap *map, uint offset, void *valp, size_t val_len)
>
>  int regmap_read(struct regmap *map, uint offset, uint *valp)
>  {
> -       return regmap_raw_read(map, offset, valp, REGMAP_SIZE_32);
> +       return regmap_raw_read(map, offset, valp, map->size ? map->size : REGMAP_SIZE_32);
>  }
>
>  static inline void __write_8(u8 *addr, const u8 *val,
> @@ -452,7 +459,8 @@ int regmap_raw_write_range(struct regmap *map, uint range_num, uint offset,
>         }
>         range = &map->ranges[range_num];
>
> -       ptr = map_physmem(range->start + offset, val_len, MAP_NOCACHE);
> +       offset <<= map->reg_offset_shift;
> +       ptr = map_physmem(range->start + map->base_offset + offset, val_len, MAP_NOCACHE);
>
>         if (offset + val_len > range->size) {
>                 debug("%s: offset/size combination invalid\n", __func__);
> @@ -490,7 +498,7 @@ int regmap_raw_write(struct regmap *map, uint offset, const void *val,
>
>  int regmap_write(struct regmap *map, uint offset, uint val)
>  {
> -       return regmap_raw_write(map, offset, &val, REGMAP_SIZE_32);
> +       return regmap_raw_write(map, offset, &val, map->size ? map->size : REGMAP_SIZE_32);
>  }
>
>  int regmap_update_bits(struct regmap *map, uint offset, uint mask, uint val)
> diff --git a/include/regmap.h b/include/regmap.h
> index 2edbf9359a..4adb04f7e3 100644
> --- a/include/regmap.h
> +++ b/include/regmap.h
> @@ -74,16 +74,41 @@ struct regmap_range {
>  };
>
>  struct regmap_bus;
> -struct regmap_config;
> +/**
> + * struct regmap_config - a way of accessing hardware/bus registers
> + *
> + * @base_offset: Offset from the base of the regmap for reads and writes.
> + *              (OPTIONAL)
> + * @reg_offset_shift: Left shift register offset by this value before
> + *                   performing reads or writes. (OPTIONAL)
> + * @size: Size/width of the read or write operation. Defaults to
> + *       REGMAP_SIZE_32 if set to zero.
> + */
> +struct regmap_config {
> +       u32 base_offset;
> +       u32 reg_offset_shift;
> +       enum regmap_size_t size;
> +};
>
>  /**
>   * struct regmap - a way of accessing hardware/bus registers
>   *
> + * @base_offset: Offset from the base of the regmap for reads and writes.
> + *              (OPTIONAL)
> + * @reg_offset_shift: Left shift register offset by this value before
> + *                   performing reads or writes. (OPTIONAL)
> + * @size: Size/width of the read or write operation. Defaults to
> + *       REGMAP_SIZE_32 if set to zero.
>   * @range_count:       Number of ranges available within the map
>   * @ranges:            Array of ranges
>   */
>  struct regmap {
>         enum regmap_endianness_t endianness;
> +
> +       u32 base_offset;
> +       u32 reg_offset_shift;
> +       enum regmap_size_t size;
> +
>         int range_count;
>         struct regmap_range ranges[0];
>  };
>
> --
> Regards,
> Pratyush Yadav
> Texas Instruments India
diff mbox series

Patch

diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig
index 3b95b5387b..3d836a63bf 100644
--- a/drivers/core/Kconfig
+++ b/drivers/core/Kconfig
@@ -129,6 +129,31 @@  config TPL_REGMAP
 	  support any bus type (I2C, SPI) but so far this only supports
 	  direct memory access.
 
+config REGMAP_ACCESSORS
+	bool
+	depends on REGMAP
+	default y
+
+config SPL_REGMAP_ACCESSORS
+	bool "Support custom regmap accessors in SPL"
+	depends on SPL_REGMAP
+	help
+	  Allow to use a regmap with custom accessors. The acessors are the
+	  low-level functions actually performing the read and write
+	  operations.
+	  This option can be used to access registers that are not
+	  memory-mapped.
+
+config TPL_REGMAP_ACCESSORS
+	bool "Support custom regmap accessors in TPL"
+	depends on TPL_REGMAP
+	help
+	  Allow to use a regmap with custom accessors. The acessors are the
+	  low-level functions actually performing the read and write
+	  operations.
+	  This option can be used to access registers that are not
+	  memory-mapped.
+
 config SYSCON
 	bool "Support system controllers"
 	depends on REGMAP
diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c
index f69ff6d12f..10ae9f918a 100644
--- a/drivers/core/regmap.c
+++ b/drivers/core/regmap.c
@@ -31,7 +31,11 @@  static struct regmap *regmap_alloc(int count)
 	if (!map)
 		return NULL;
 	map->range_count = count;
-
+#if CONFIG_IS_ENABLED(REGMAP_ACCESSORS)
+	map->bus_context = NULL;
+	map->reg_read = NULL;
+	map->reg_write = NULL;
+#endif
 	return map;
 }
 
@@ -241,7 +245,11 @@  struct regmap *devm_regmap_init(struct udevice *dev,
 	rc = regmap_init_mem(dev_ofnode(dev), mapp);
 	if (rc)
 		return ERR_PTR(rc);
-
+#if CONFIG_IS_ENABLED(REGMAP_ACCESSORS)
+	(*mapp)->reg_read = config->reg_read;
+	(*mapp)->reg_write = config->reg_write;
+	(*mapp)->bus_context = bus_context;
+#endif
 	devres_add(dev, mapp);
 	return *mapp;
 }
@@ -320,6 +328,11 @@  int regmap_raw_read_range(struct regmap *map, uint range_num, uint offset,
 	struct regmap_range *range;
 	void *ptr;
 
+#if CONFIG_IS_ENABLED(REGMAP_ACCESSORS)
+	if (map->reg_read)
+		return map->reg_read(map->bus_context, offset, valp);
+#endif
+
 	if (range_num >= map->range_count) {
 		debug("%s: range index %d larger than range count\n",
 		      __func__, range_num);
@@ -429,6 +442,11 @@  int regmap_raw_write_range(struct regmap *map, uint range_num, uint offset,
 	struct regmap_range *range;
 	void *ptr;
 
+#if CONFIG_IS_ENABLED(REGMAP_ACCESSORS)
+	if (map->reg_write)
+		return map->reg_write(map->bus_context, offset,
+				      *(unsigned int *)val);
+#endif
 	if (range_num >= map->range_count) {
 		debug("%s: range index %d larger than range count\n",
 		      __func__, range_num);
diff --git a/include/regmap.h b/include/regmap.h
index 624cdd8c98..730e747d90 100644
--- a/include/regmap.h
+++ b/include/regmap.h
@@ -74,16 +74,38 @@  struct regmap_range {
 };
 
 struct regmap_bus;
-struct regmap_config;
+/**
+ * struct regmap_config - a way of accessing hardware/bus registers
+ *
+ * @reg_read:	  Optional callback that if filled will be used to perform
+ *		  all the reads from the registers. Should only be provided for
+ *		  devices whose read operation cannot be represented as a simple
+ *		  read operation on a bus such as SPI, I2C, etc. Most of the
+ *		  devices do not need this.
+ * @reg_write:	  Same as above for writing.
+ */
+struct regmap_config {
+	int (*reg_read)(void *context, unsigned int reg, unsigned int *val);
+	int (*reg_write)(void *context, unsigned int reg, unsigned int val);
+};
 
 /**
  * struct regmap - a way of accessing hardware/bus registers
  *
  * @range_count:	Number of ranges available within the map
  * @ranges:		Array of ranges
+ * @bus_context:	Data passed to bus-specific callbacks
+ * @reg_read:		Optional callback that if filled will be used to perform
+ *			all the reads from the registers.
+ * @reg_write:		Same as above for writing.
  */
 struct regmap {
 	enum regmap_endianness_t endianness;
+#if CONFIG_IS_ENABLED(REGMAP_ACCESSORS)
+	void *bus_context;
+	int (*reg_read)(void *context, unsigned int reg, unsigned int *val);
+	int (*reg_write)(void *context, unsigned int reg, unsigned int val);
+#endif
 	int range_count;
 	struct regmap_range ranges[0];
 };
@@ -341,8 +363,8 @@  int regmap_init_mem_index(ofnode node, struct regmap **mapp, int index);
  *
  * @dev: Device that will be interacted with
  * @bus: Bus-specific callbacks to use with device (IGNORED)
- * @bus_context: Data passed to bus-specific callbacks (IGNORED)
- * @config: Configuration for register map (IGNORED)
+ * @bus_context: Data passed to bus-specific callbacks
+ * @config: Configuration for register map
  *
  * @Return a valid pointer to a struct regmap or a ERR_PTR() on error.
  * The structure is automatically freed when the device is unbound