diff mbox

[2.6.29-rc3-git,1/2] regulator: twl4030 regulators

Message ID 200902081037.06645.david-b@pacbell.net (mailing list archive)
State Awaiting Upstream, archived
Headers show

Commit Message

David Brownell Feb. 8, 2009, 6:37 p.m. UTC
From: David Brownell <dbrownell@users.sourceforge.net>

Support most of the LDO regulators in the twl4030 family chips.
In the case of LDOs supporting MMC/SD, the voltage controls are
used; but in most other cases, the regulator framework is only
used to enable/disable a supplies, conserving power when a given
voltage rail is not needed.

The drivers/mfd/twl4030-core.c code already sets up the various
regulators according to board-specific configuration, and knows
that some chips don't provide the full set of voltage rails.

The omitted regulators are intended to be under hardware control,
such as during the hardware-mediated system powerup, powerdown,
and suspend states.  Unless/until software hooks are known to
be safe, they won't be exported here.

These regulators implement the new get_status() operation, but
can't realistically implement get_mode(); the status output is
effectively the result of a vote, with the relevant hardware
inputs not exposed.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
---
Note a minor regulator API glitch:  there is no clean way to
convert voltages supported by a regulator like VMMC1 or VMMC2
to/from the MMC/SD framework's voltage masks.

 drivers/regulator/Kconfig             |    7 
 drivers/regulator/Makefile            |    1 
 drivers/regulator/twl4030-regulator.c |  511 ++++++++++++++++++++++++++++++++
 include/linux/i2c/twl4030.h           |   47 ++
 4 files changed, 566 insertions(+)

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Mark Brown Feb. 8, 2009, 11:29 p.m. UTC | #1
On Sun, Feb 08, 2009 at 10:37:06AM -0800, David Brownell wrote:

> +/*
> + * We list regulators here if systems need some level of
> + * software control over them after boot.
> + */
> +static struct twlreg_info twl4030_regs[] = {

> +	/*
> +	TWL_ADJUSTABLE_LDO(VPLL1, 0x2f, 7),
> +	TWL_ADJUSTABLE_LDO(VPLL2, 0x33, 8),
> +	*/

Minor nit, but I guess the comment would be a bit more accurate if the
comment said that the regulators that aren't likely to be changed have
been commented out (it required that little extra bit of thinking).

> +	/* Constrain board-specific capabilities according to what
> +	 * this driver and the chip itself can actually do.
> +	 */
> +	c = &initdata->constraints;
> +	if (!c->min_uV || c->min_uV < min_uV)
> +		c->min_uV = min_uV;

If we're going to do this I think it'd be better to push it into the
core and let the regulators pass in a set of constraints so that the
behaviour will be consistent between drivers.

I'd also expect to have the registration fail or at least issue a
warning if the code kicks in since that indicates that the board
constraints have been set up incorrectly.  There's a reasonable chance
that the fixed up constraints will still need to be changed for the
board to be configured properly and things may end up being driven out
of spec, potentially causing damage.
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Brownell Feb. 9, 2009, 12:04 a.m. UTC | #2
On Sunday 08 February 2009, Mark Brown wrote:
> > +     /* Constrain board-specific capabilities according to what
> > +      * this driver and the chip itself can actually do.
> > +      */
> > +     c = &initdata->constraints;
> > +     if (!c->min_uV || c->min_uV < min_uV)
> > +             c->min_uV = min_uV;
> 
> If we're going to do this I think it'd be better to push it into the
> core and let the regulators pass in a set of constraints so that the
> behaviour will be consistent between drivers.

Maybe, but there is no such mechanism right yet.
When it's created, then this could switch over.


> I'd also expect to have the registration fail or at least issue a
> warning if the code kicks in since that indicates that the board
> constraints have been set up incorrectly.

A warning might make sense in some cases ... that's
something I would expect to see from the regulator
core, though.  Example, I see no "max < min" checks
triggering registration errors.


> There's a reasonable chance 
> that the fixed up constraints will still need to be changed for the
> board to be configured properly and things may end up being driven out
> of spec, potentially causing damage.

I don't see that happening ... all that code does is
tighten existing constraints to match what the hardware
can do.  The result is just a subset of the range the
board already said was OK.  If no valid subset exists,
that's a board design bug ... albeit one the regulator
core could detect.  (E.g. those "max < min" checks that
don't currently exist.)

I can easily imagine having things partially set up, and
not really caring whether, on a particular board, those
initial constraints are really the most specific ones
applicable.  One component tolerates a range of 1V8..3V6
maybe, but on any given board it can be hooked up to any
supply that's even partially in-range.

If I hook such a component up to a supply supporting 1V2
through 2V5, it's really no worry that the 1V2..1V8 part
of that range won't be used; or if 2V5..3V6 could also
work.  Those options really don't matter at all.  The
only significant part is that only the 1V8..2V5 will be
software-accessible on that board.

- Dave

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mark Brown Feb. 9, 2009, 5:27 p.m. UTC | #3
On Sun, Feb 08, 2009 at 04:04:29PM -0800, David Brownell wrote:
> On Sunday 08 February 2009, Mark Brown wrote:

> > If we're going to do this I think it'd be better to push it into the
> > core and let the regulators pass in a set of constraints so that the
> > behaviour will be consistent between drivers.

> Maybe, but there is no such mechanism right yet.
> When it's created, then this could switch over.

Since you appear to be writing the code already... :)

> > I'd also expect to have the registration fail or at least issue a
> > warning if the code kicks in since that indicates that the board
> > constraints have been set up incorrectly.

> A warning might make sense in some cases ... that's
> something I would expect to see from the regulator
> core, though.

That's what I'm suggesting should happen - that things like this should
be implemented in the core so that the behaviour of the API remains
consistent for users moving between platforms and everyone benefits from
new features.

>                Example, I see no "max < min" checks
> triggering registration errors.

Not a bad idea, though.  The core currently doesn't do much checking of
the constraints but that's as much because nobody spent the time on it
as anything else.  To the extent it's a deliberate design decision it's
because the constraints and consumer lists are where the information
about what's possible on a given system comes from and so the checking
that can be done by software is relatively minor.

> > There's a reasonable chance 
> > that the fixed up constraints will still need to be changed for the
> > board to be configured properly and things may end up being driven out
> > of spec, potentially causing damage.

> I don't see that happening ... all that code does is
> tighten existing constraints to match what the hardware
> can do.  The result is just a subset of the range the
> board already said was OK.  If no valid subset exists,

The trouble is that this code should only do anything if the board code
provided a configuration that can't be supported by the hardware, which
is a bit of a red flag.  I'd expect it'd end up catching things like the
user typing extra digits by mistake (this has definitely happened when
writing consumer drivers).

Your current patch does also set constraints for the voltages if they
weren't there previously (though this shouldn't matter since voltage
setting shouldn't be enabled without voltage value constraints).

> I can easily imagine having things partially set up, and
> not really caring whether, on a particular board, those
> initial constraints are really the most specific ones
> applicable.  One component tolerates a range of 1V8..3V6
> maybe, but on any given board it can be hooked up to any
> supply that's even partially in-range.

The pattern you're describing is very much that for consumer and
regulator drivers.  They should work with as wide a set of constraints
as possible to allow them to be used on different systems with different
capabilities and needs - allowing this is essential for the API to be
usable since so many chips are flexible about the supplies they can use.

It's different for the machine constraints since they are by definition
specific to a given system.  While it's expected that users (especially
those sensitive to power consumption) may want to optimise the
configuration of their system during development to get the best
performance out of it there is also an expectation that users will be
making decisions based on knowledge of the hardware design.
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Brownell Feb. 10, 2009, 12:24 a.m. UTC | #4
On Monday 09 February 2009, Mark Brown wrote:
> On Sun, Feb 08, 2009 at 04:04:29PM -0800, David Brownell wrote:
> > On Sunday 08 February 2009, Mark Brown wrote:
> 
> > > If we're going to do this I think it'd be better to push it into the
> > > core and let the regulators pass in a set of constraints so that the
> > > behaviour will be consistent between drivers.
> 
> > Maybe, but there is no such mechanism right yet.
> > When it's created, then this could switch over.
> 
> Since you appear to be writing the code already... :)

Not for the regulator core, though.  Switching from
a simplistic constraint engine to one that starts to
handle a more realistic "union of constraints" model
would be doable, but is a bit more off-topic work than
I'd want to sign up for just now.


> > > I'd also expect to have the registration fail or at least issue a
> > > warning if the code kicks in since that indicates that the board
> > > constraints have been set up incorrectly.
> 
> > A warning might make sense in some cases ... that's
> > something I would expect to see from the regulator
> > core, though.
> 
> That's what I'm suggesting should happen - that things like this should
> be implemented in the core so that the behaviour of the API remains
> consistent for users moving between platforms and everyone benefits from
> new features.
> 
> >                Example, I see no "max < min" checks
> > triggering registration errors.
> 
> Not a bad idea, though.  The core currently doesn't do much checking of
> the constraints but that's as much because nobody spent the time on it
> as anything else.  To the extent it's a deliberate design decision it's
> because the constraints and consumer lists are where the information
> about what's possible on a given system comes from and so the checking
> that can be done by software is relatively minor.

Or as I put it earlier:  the current constraint model is
a bit simplistic.

Such things can *EASILY* be over-done; starting under-done
isn't a bad model.  Better to collect a few real examples of
how/why "under-done" needs to be improved, than overdesign
from the start.  (And I've seen some power "constraint"
frameworks that seemed way overdone.)

 
> > > There's a reasonable chance 
> > > that the fixed up constraints will still need to be changed for the
> > > board to be configured properly and things may end up being driven out
> > > of spec, potentially causing damage.
> 
> > I don't see that happening ... all that code does is
> > tighten existing constraints to match what the hardware
> > can do.  The result is just a subset of the range the
> > board already said was OK.  If no valid subset exists,
> 
> The trouble is that this code should only do anything if the board code
> provided a configuration that can't be supported by the hardware, which
> is a bit of a red flag.  I'd expect it'd end up catching things like the
> user typing extra digits by mistake (this has definitely happened when
> writing consumer drivers).

The model you're working with doesn't do a good job of
component-izing things ... "board" may be "board stack",
where notions like "the" hardware are fluid.

And in particular, "can't be supported" was NOT an issue
in the scenarios I gave.  The same mainboard could easily
support two regulators with different selections of output
voltages.  The problem was the model where the constraints
from the mainboard would be specific to one regulator,
instead of just to the mainboard.


> Your current patch does also set constraints for the voltages if they
> weren't there previously

I was thinking that boards which don't need constraints
shouldn't need to create any ... they could just pass on
the capabilities of the underlying regulator.


> > I can easily imagine having things partially set up, and
> > not really caring whether, on a particular board, those
> > initial constraints are really the most specific ones
> > applicable.  One component tolerates a range of 1V8..3V6
> > maybe, but on any given board it can be hooked up to any
> > supply that's even partially in-range.
> 
> The pattern you're describing is very much that for consumer and
> regulator drivers.  They should work with as wide a set of constraints
> as possible to allow them to be used on different systems with different
> capabilities and needs - allowing this is essential for the API to be
> usable since so many chips are flexible about the supplies they can use.
> 
> It's different for the machine constraints since they are by definition
> specific to a given system.

Only when that "system" is componentized that way.
Not all are.

Modular systems can have plug-in regulator boards;
constraints on a mainboard would necessarily overlap
with supported regulator boards ... but the regulators
themselves would naturally have different constraints.

One way to view this:  what you're calling "regulator"
constraints are really coming from the "machine".

Those few lines of code that seem to bother you are
only recognizing that they are, in fact, two very
different entities.

Without changing the regulator core, the only way
to handle contstraints which come from the actual
regulators is to force the machine constraints
to be in-range with respect to whatever regulator
driver ends up using them.

- Dave

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mark Brown Feb. 10, 2009, 10:48 p.m. UTC | #5
On Mon, Feb 09, 2009 at 04:24:01PM -0800, David Brownell wrote:
> On Monday 09 February 2009, Mark Brown wrote:

> > > Maybe, but there is no such mechanism right yet.
> > > When it's created, then this could switch over.

> > Since you appear to be writing the code already... :)

> Not for the regulator core, though.  Switching from
> a simplistic constraint engine to one that starts to

There's nothing specific to the driver in this code - it's just doing
basic comparisons of two sets of constraints and acting on them and
would work just as well if it were pushed into the core.  You're going
to need this in multiple drivers to use it in a system anyway (it'll
need to be in at least the drivers which might be used on that system).

> handle a more realistic "union of constraints" model
> would be doable, but is a bit more off-topic work than
> I'd want to sign up for just now.

Solving all possible problems is, obviously, a bigger task but I don't
think we need to solve everything in order to avoid having this be
driver specific.

What I would suggest that you do for this is submit a patch allowing the
regulators to supply a set of constraints when they register (but not
doing anything with them), another with a TWL4030 driver using that API
and a third patch making the core do something with that data.  This
would result in something which maintains consistent behaviour over all
regulator drivers, which is my main concern here, and avoids tying up
the TWL4030 driver merge with any debate about how to use information
about the capabilities of the regulator.

I have some regulator API patches I need to test (should be sometime
this week) so I may be inspired to do at least the first patch myself.
I don't think there's any doubt that the core can do something useful
with the information.

> The model you're working with doesn't do a good job of
> component-izing things ... "board" may be "board stack",
> where notions like "the" hardware are fluid.

Most of the development work for the regulator API has been done on
reference platforms with many pluggable boards (often including the PMIC
board) so thought has been given as to how to handle these systems.

For daughtercards other than the primary PMIC (which are vastly more
common in production systems) one approach has been to represent the
daughtercards as a device that gets whatever supplies the daughtercard
has.  The distribution of power within the daughtercard is then be done
by adding child regulators.

> > Your current patch does also set constraints for the voltages if they
> > weren't there previously

> I was thinking that boards which don't need constraints
> shouldn't need to create any ... they could just pass on
> the capabilities of the underlying regulator.

For safety the regulator API won't do anything without being explicitly
told that it's OK to do so - if we were to do this we'd need to have an
explicit flag in the constraints which says that this is what to do.
Constraints are also permission grants.

> Only when that "system" is componentized that way.
> Not all are.

> Modular systems can have plug-in regulator boards;
> constraints on a mainboard would necessarily overlap
> with supported regulator boards ... but the regulators
> themselves would naturally have different constraints.

Indeed.  Like I say, a very large proportion of the development of the
regulator API has been done on reference designs which are built in this
fashion, including both pluggable PMIC boards and other daughtercards.
Normally the primary PMIC cards are handled with conditional code in the
machine file (either compile time or run time) or by registering drivers
for all the PMICs and allowing failed device probes to sort everything
out.  So far handling things this way hasn't been a big deal - there are
usually relatively few PMIC boards out there for a given platform and
the PMIC itself is rarely a major restriction.

This conditional code would normally do the setup that is specific to
each PMIC board, including matching the regulators on the PMIC board
with the rest of the system and any devices on the PMIC board itself
that require supplies.  A lot of the time there is a one to many mapping
between regulators on the PMIC board and power domains in the base
system and there are often additional devices on the PMIC board in
addition to the base board.  It's not unknown for the contraints applied
to not be straight combinations of supply constraints (normally due to a
lack of desire for runtime flexibility on supplies).

At the end of the day board code is still always going to have to at
some point know what regulators are fitted and how they are connected
up.  There are some things we could do to make handling runtime
decisions on this easier, like allowing multiple sets of constraints
and supplies to be supplied so the machine drivers can set up the
various combinations of supplies more easily when that's possible (which
is I think what you were getting at above), but they don't remove the
need for board code to know what's there.

> One way to view this:  what you're calling "regulator"
> constraints are really coming from the "machine".

Yes, of course.  The constraints are applied to the regulator by the
core, they are constraints for the regulator not constraints imposed by
the regulator.

> Those few lines of code that seem to bother you are
> only recognizing that they are, in fact, two very
> different entities.

What's really bothering me is the *location* of the code.  As I've said,
my primary concern is that this introduces what are effectively API
changes which will mean that this driver behaves differently to other
drivers.  Other concerns about precisely what we do with any information
from the regulator driver are very much less important.

> Without changing the regulator core, the only way
> to handle contstraints which come from the actual
> regulators is to force the machine constraints
> to be in-range with respect to whatever regulator
> driver ends up using them.

Modifying the core is, of course, an option.
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Brownell Feb. 23, 2009, 8:45 p.m. UTC | #6
On Tuesday 10 February 2009, Mark Brown wrote:

> What I would suggest that you do for this is submit a patch allowing the 
> regulators to supply a set of constraints when they register (but not
> doing anything with them),

That pretty much needs to allow a list of discrete
voltages, not just be a range ... and have a way
for clients to retrieve that list.  Else I have a
very hard time imagining how to plug in MMC supplies
without writing the type of regulator-specific code
that this framework is intended to supplant.


> another with a TWL4030 driver using that API 
> and a third patch making the core do something with that data.

Best IMO to switch the last two around.  Effectively
there'd be one patch "add new features to regulator
core", followed by the first of a set of "implement
those new features in the driver for regulator X".

And in fact that's what I've done with the two patches
I'll be sending in a moment.


> This 
> would result in something which maintains consistent behaviour over all
> regulator drivers,

It's already consistent, even without such patches!!

There is no driver which pays attention to regulator(_dev)
constraints that does it any differently than this one.


> > > Your current patch does also set constraints for the voltages if they
> > > weren't there previously
> 
> > I was thinking that boards which don't need constraints
> > shouldn't need to create any ... they could just pass on
> > the capabilities of the underlying regulator.
> 
> For safety the regulator API won't do anything without being explicitly
> told that it's OK to do so - if we were to do this we'd need to have an
> explicit flag in the constraints which says that this is what to do.
> Constraints are also permission grants.

I like to avoid flags unless they're absolutely required.
In this case my initial reaction is to say that hooking up
the components in the first place was the permission grant.

 
> > Only when that "system" is componentized that way.
> > Not all are.
> 
> > Modular systems can have plug-in regulator boards;
> > constraints on a mainboard would necessarily overlap
> > with supported regulator boards ... but the regulators
> > themselves would naturally have different constraints.
> 
> Indeed.  Like I say, a very large proportion of the development of the
> regulator API has been done on reference designs which are built in this
> fashion, including both pluggable PMIC boards and other daughtercards.

That doesn't seem to have escaped its development cage yet.  ;)


> Normally the primary PMIC cards are handled with conditional code in the
> machine file (either compile time or run time) or by registering drivers
> for all the PMICs and allowing failed device probes to sort everything
> out.  So far handling things this way hasn't been a big deal - there are
> usually relatively few PMIC boards out there for a given platform and
> the PMIC itself is rarely a major restriction.

Fair enough.  I'd de-emphasize "conditional", since that sounds
way too much like #ifdeffing.  The source code should just call
something like is_pmic_cardX(), and not care how that works.

 
> > One way to view this:  what you're calling "regulator"
> > constraints are really coming from the "machine".
> 
> Yes, of course.  The constraints are applied to the regulator by the
> core, they are constraints for the regulator not constraints imposed by
> the regulator.

Then what would you call constraints by/from the regulator?

I suggest updating your terminology.  "machine constraints"
would be much more clear for what's there now:  they relate
to the machine.  Other constraints (regulator, consumer)
relate to the other components ... the ones for which they
are an adjective.


> > Those few lines of code that seem to bother you are
> > only recognizing that they are, in fact, two very
> > different entities.
> 
> What's really bothering me is the *location* of the code.  As I've said,
> my primary concern is that this introduces what are effectively API
> changes which will mean that this driver behaves differently to other
> drivers.  Other concerns about precisely what we do with any information
> from the regulator driver are very much less important.

I don't mind moving it ... later, after the regulator
core has proper support for decoupling machine-specific
constraints from regulator-specific ones.  I view that
code as a workaround for a current limitation of that
core, so like all such workarounds it should vanish
when it's no longer relevant.

- Dave

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mark Brown Feb. 23, 2009, 10:04 p.m. UTC | #7
On Mon, Feb 23, 2009 at 12:45:44PM -0800, David Brownell wrote:

> > another with a TWL4030 driver using that API 
> > and a third patch making the core do something with that data.

> Best IMO to switch the last two around.  Effectively
> there'd be one patch "add new features to regulator
> core", followed by the first of a set of "implement
> those new features in the driver for regulator X".

> And in fact that's what I've done with the two patches
> I'll be sending in a moment.

The reason I'm suggesting splitting things up the way I am is that it
separates out the TWL4030 driver (which looks very mergable to me right
now) from the behaviour changes.  Ordering things that way makes it
clear what the dependency is.  Another way of splitting it out would be
to remove the new API from the TWL4030, make that the first patch, then
have further patches adding the new API and the TWL4030 code to use it.

I don't see any reason why the TWL4030 regulator support needs to be
blocked on adding the new API and it makes review easier to keep them
separate.

> > This 
> > would result in something which maintains consistent behaviour over all
> > regulator drivers,

> It's already consistent, even without such patches!!

> There is no driver which pays attention to regulator(_dev)
> constraints that does it any differently than this one.

That's because nobody's doing it at all; once we add a custom
implementation in one driver we then need to police each driver
individually for consistency with the new interface.  If the logic is
factored out then that problem doesn't exist and drivers don't need to
reimplement any of it.

> > > > Your current patch does also set constraints for the voltages if they
> > > > weren't there previously

> > > I was thinking that boards which don't need constraints
> > > shouldn't need to create any ... they could just pass on
> > > the capabilities of the underlying regulator.

> > For safety the regulator API won't do anything without being explicitly
> > told that it's OK to do so - if we were to do this we'd need to have an
> > explicit flag in the constraints which says that this is what to do.
> > Constraints are also permission grants.

> I like to avoid flags unless they're absolutely required.
> In this case my initial reaction is to say that hooking up
> the components in the first place was the permission grant.

The trouble is we don't know what's connected to the regulator without
being told - even if some of the components hanging off the supply are
visible to software that's no guarantee that all of them are.  Keeping
the responsibility in the hands of the machine driver helps ensure that
users have made a concious decision that their settings are OK for their
design.

> > Indeed.  Like I say, a very large proportion of the development of the
> > regulator API has been done on reference designs which are built in this
> > fashion, including both pluggable PMIC boards and other daughtercards.

> That doesn't seem to have escaped its development cage yet.  ;)

There's a couple on their way to mainline right now, should make it in
the next merge window hopefully.  Unfortunately they're for systems that
aren't very completely supported in mainline right now which makes them
less useful as examples than they might be.  There's also none of them
where there's any immediate prospect of more than one of the PMIC board
options going into mainline.

> > Normally the primary PMIC cards are handled with conditional code in the
> > machine file (either compile time or run time) or by registering drivers

> Fair enough.  I'd de-emphasize "conditional", since that sounds
> way too much like #ifdeffing.  The source code should just call
> something like is_pmic_cardX(), and not care how that works.

It's normally a combination of the two - normally you don't get any form
of board ID readback and you get things like mutually exclusive options
for I2C or SPI control due to shared multi function pin setup that can't
be autoprobed entirely safely, for example.  Once you've decided on the
control bus it's normally safe to do autoprobing, though.

> Then what would you call constraints by/from the regulator?

They're subsumed within the constraints supplied by the machine driver
at the minute.

> I suggest updating your terminology.  "machine constraints"
> would be much more clear for what's there now:  they relate
> to the machine.  Other constraints (regulator, consumer)
> relate to the other components ... the ones for which they
> are an adjective.

Yeah, I kind of agree.  To avoid confusion from changing the names I'd
be tempted to go for something like "regulator driver constraints" but
it's not desparately nice.

> I don't mind moving it ... later, after the regulator
> core has proper support for decoupling machine-specific
> constraints from regulator-specific ones.  I view that
> code as a workaround for a current limitation of that
> core, so like all such workarounds it should vanish
> when it's no longer relevant.

I'd strongly suggest that if you're adding workarounds like this it's
worth at least calling them out in the changelog.  To be honest I'm not
100% clear why this new feature is essential to supporting the TWL4030 -
I can see that it could be useful but I'm not clear on what makes it
essential for this driver.
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Brownell Feb. 23, 2009, 10:43 p.m. UTC | #8
On Monday 23 February 2009, Mark Brown wrote:
> On Mon, Feb 23, 2009 at 12:45:44PM -0800, David Brownell wrote:
> 
> > > another with a TWL4030 driver using that API 
> > > and a third patch making the core do something with that data.
> 
> > Best IMO to switch the last two around.  Effectively
> > there'd be one patch "add new features to regulator
> > core", followed by the first of a set of "implement
> > those new features in the driver for regulator X".
> 
> > And in fact that's what I've done with the two patches
> > I'll be sending in a moment.
> 
> The reason I'm suggesting splitting things up the way I am is that it
> separates out the TWL4030 driver (which looks very mergable to me right
> now) from the behaviour changes.  Ordering things that way makes it
> clear what the dependency is.  Another way of splitting it out would be
> to remove the new API from the TWL4030, make that the first patch, then
> have further patches adding the new API and the TWL4030 code to use it.
> 
> I don't see any reason why the TWL4030 regulator support needs to be
> blocked on adding the new API and it makes review easier to keep them
> separate.

I think we're talking past each other.  I agree the twl4030 driver
is very mergeable right now; that's why it was submitted.  You could
do so, and then apply the two patches on top ... very clear what the
dependency is, and as I understand it the result would be more or less
to your liking.

My comment was more along the lines of "avoid adding unused hooks,
just merge the create-hook and use-hook patches".  Having "create"
separate from "use" is often troublesome.


> > Then what would you call constraints by/from the regulator?
> 
> They're subsumed within the constraints supplied by the machine driver
> at the minute.

That is, they are not named.  :)


> > I suggest updating your terminology.  "machine constraints"
> > would be much more clear for what's there now:  they relate
> > to the machine.  Other constraints (regulator, consumer)
> > relate to the other components ... the ones for which they
> > are an adjective.
> 
> Yeah, I kind of agree.  To avoid confusion from changing the names I'd
> be tempted to go for something like "regulator driver constraints" but
> it's not desparately nice.

Hence my suggestion:  {regulator,machine,consumer} constraints,
going from bottom up.  They aren't driver constraints; they
are hardware constraints:  regulators can't supply arbitrary
voltages.


> 	 To be honest I'm not
> 100% clear why this new feature is essential to supporting the TWL4030 -
> I can see that it could be useful but I'm not clear on what makes it
> essential for this driver.

I never said it was "essential".  However it does simplify
the core driver code a lot by moving a lot of error checks
to the init code; the checks need to live someplace.  You're
the one asking for them to be packaged as a new framework
feature.

- Dave

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mark Brown Feb. 24, 2009, 12:55 a.m. UTC | #9
On Mon, Feb 23, 2009 at 02:43:16PM -0800, David Brownell wrote:
> On Monday 23 February 2009, Mark Brown wrote:

> > Yeah, I kind of agree.  To avoid confusion from changing the names I'd
> > be tempted to go for something like "regulator driver constraints" but
> > it's not desparately nice.

> Hence my suggestion:  {regulator,machine,consumer} constraints,
> going from bottom up.  They aren't driver constraints; they
> are hardware constraints:  regulators can't supply arbitrary
> voltages.

Trouble is that the term regulator gets very overloaded and causes
confusion.  There's also fun and games to be had with accuracy once you
start looking too closely at the discrete voltages.

> > 	 To be honest I'm not
> > 100% clear why this new feature is essential to supporting the TWL4030 -
> > I can see that it could be useful but I'm not clear on what makes it
> > essential for this driver.

> I never said it was "essential".  However it does simplify

Apologies, you didn't actually say that, no - I was reading between the
lines there.

> the core driver code a lot by moving a lot of error checks
> to the init code; the checks need to live someplace.  You're

I'm not sure I see that for the constraint tightening, and indeed the
TWL4030 set_voltage() operation does have a range check in it.  Unless
I'm missing something if the tightened constraint is usable then it
should flop out of the range based requests with the constraints left
unmodified.  The reason the TWL4030 driver still has the range check in
the set_voltage() operation is that it is checking to make sure that the
requests that come in can be satisfied from the discrete values the
regulator is able to produce which is a good thing to do.

> the one asking for them to be packaged as a new framework
> feature.

The change to add voltage range constraints if none were supplied is a
noticable policy change from the existing framework standard - it allows
machines to enable voltage changes without specifying what the valid
values are.  I'm not convinced that this is a good idea in the first
place and it will result in the opposite behaviour to the current core
code (which should end up erroring out in constraint checking at runtime).
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Brownell Feb. 24, 2009, 2:03 a.m. UTC | #10
On Monday 23 February 2009, Mark Brown wrote:
> The change to add voltage range constraints if none were supplied is a
> noticable policy change from the existing framework standard - it allows
> machines to enable voltage changes without specifying what the valid
> values are. 

"Whatever the hardware handles" *is* a specification.

And there's no more assurance it's right than any
other specification would be ... except that, as a
rule, hardware designers like to avoid assemblies
subject to trivial misconfiguration mistakes (like
firing up a 2.5V-max rail at 5V).


> I'm not convinced that this is a good idea in the first 
> place and it will result in the opposite behaviour to the current core
> code (which should end up erroring out in constraint checking at runtime).

Well, if you really dislike it so much, that can
easily be removed.  Got any comments on the
framework patch I sent?  I'll take that as the
first one, even though it's a different thread.

- Dave



--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Brownell Feb. 24, 2009, 2:22 a.m. UTC | #11
On Monday 23 February 2009, Mark Brown wrote:
> > > Yeah, I kind of agree.  To avoid confusion from changing the names I'd
> > > be tempted to go for something like "regulator driver constraints" but
> > > it's not desparately nice.
> 
> > Hence my suggestion:  {regulator,machine,consumer} constraints,
> > going from bottom up.  They aren't driver constraints; they
> > are hardware constraints:  regulators can't supply arbitrary
> > voltages.
> 
> Trouble is that the term regulator gets very overloaded and causes
> confusion.

That's why one of the *first* jobs in architecture is to
ensure the terminology doesn't easily overload ... there's
always trouble when it isn't.  Despite early groans from
peanut galleries about "language lawyering" and "wanting
to code in C not English", etc.  ;)

Thing is, there's already overloading here.  Two types
of regulator -- "struct regulator_dev" wrapping hardware,
and the "struct regulator" is a client/consumer handle.
(And thus confusing to me, since it sounds like the more
fundamental concept, but instead it's a few layers up.)

If you're concerned about overloading terminology, then
best to address it sooner than later.  I've noticed you
using the "consumer", "machine", and "regulator" terms
more or less like I suggested, and those make sense; but
the current struct names don't encourage that usage.  It's
possible to adjust usage before changing names in "C".
Thankfully, in Linux global name struct changes are not
rejected out of hand.


> There's also fun and games to be had with accuracy once you 
> start looking too closely at the discrete voltages.

Yes; the patch I sent is explicitly making those available.

But I ignored issues like "+/- 3% accurate output" for LDOs
(or switchers) ... if anyone really needs to address them,
patches will be needed.  For now I only care that a 3.1 Volt
output can match both MMC_VDD_30_31 and MMC_VDD_31_32! ;)

- Dave



--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mark Brown Feb. 24, 2009, 12:41 p.m. UTC | #12
On Mon, Feb 23, 2009 at 06:03:49PM -0800, David Brownell wrote:
> On Monday 23 February 2009, Mark Brown wrote:

> > The change to add voltage range constraints if none were supplied is a
> > noticable policy change from the existing framework standard - it allows
> > machines to enable voltage changes without specifying what the valid
> > values are. 

> "Whatever the hardware handles" *is* a specification.

> And there's no more assurance it's right than any
> other specification would be ... except that, as a

You're right that we can't guarantee that users get everything correct,
the goal is more to ensure that some machine specific checks have been
done and that the regulator API won't go off by itself and start doing
things since it has no idea at all what's supportable.

> rule, hardware designers like to avoid assemblies
> subject to trivial misconfiguration mistakes (like
> firing up a 2.5V-max rail at 5V).

The issue is what happens when software starts changing the
configuration, for static configurations it doesn't make any difference.

> > I'm not convinced that this is a good idea in the first 
> > place and it will result in the opposite behaviour to the current core
> > code (which should end up erroring out in constraint checking at runtime).

> Well, if you really dislike it so much, that can
> easily be removed.  Got any comments on the
> framework patch I sent?  I'll take that as the
> first one, even though it's a different thread.

Yes, I wanted to sleep on it.  I'll reply at some point today.
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Liam Girdwood Feb. 26, 2009, 10:15 p.m. UTC | #13
On Sun, 2009-02-08 at 10:37 -0800, David Brownell wrote:
> From: David Brownell <dbrownell@users.sourceforge.net>
> 
> Support most of the LDO regulators in the twl4030 family chips.
> In the case of LDOs supporting MMC/SD, the voltage controls are
> used; but in most other cases, the regulator framework is only
> used to enable/disable a supplies, conserving power when a given
> voltage rail is not needed.
> 
> The drivers/mfd/twl4030-core.c code already sets up the various
> regulators according to board-specific configuration, and knows
> that some chips don't provide the full set of voltage rails.
> 
> The omitted regulators are intended to be under hardware control,
> such as during the hardware-mediated system powerup, powerdown,
> and suspend states.  Unless/until software hooks are known to
> be safe, they won't be exported here.
> 
> These regulators implement the new get_status() operation, but
> can't realistically implement get_mode(); the status output is
> effectively the result of a vote, with the relevant hardware
> inputs not exposed.
> 
> Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>

Applied.

Thanks

Liam

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -52,6 +52,13 @@  config REGULATOR_BQ24022
 	  charging select between 100 mA and 500 mA charging current
 	  limit.
 
+config REGULATOR_TWL4030
+	bool "TI TWL4030/TWL5030/TPS695x0 PMIC"
+	depends on TWL4030_CORE
+	help
+	  This driver supports the voltage regulators provided by
+	  this family of companion chips.
+
 config REGULATOR_WM8350
 	tristate "Wolfson Microelectroncis WM8350 AudioPlus PMIC"
 	depends on MFD_WM8350
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -8,6 +8,7 @@  obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) +=
 obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
 
 obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o
+obj-$(CONFIG_REGULATOR_TWL4030) += twl4030-regulator.o
 obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o
 obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
 obj-$(CONFIG_REGULATOR_DA903X)	+= da903x.o
--- /dev/null
+++ b/drivers/regulator/twl4030-regulator.c
@@ -0,0 +1,511 @@ 
+/*
+ * twl4030-regulator.c -- support regulators in twl4030 family chips
+ *
+ * Copyright (C) 2008 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/i2c/twl4030.h>
+
+
+/*
+ * The TWL4030/TW5030/TPS659x0 family chips include power management, a
+ * USB OTG transceiver, an RTC, ADC, PWM, and lots more.  Some versions
+ * include an audio codec, battery charger, and more voltage regulators.
+ * These chips are often used in OMAP-based systems.
+ *
+ * This driver implements software-based resource control for various
+ * voltage regulators.  This is usually augmented with state machine
+ * based control.
+ */
+
+struct twlreg_info {
+	/* start of regulator's PM_RECEIVER control register bank */
+	u8			base;
+
+	/* twl4030 resource ID, for resource control state machine */
+	u8			id;
+
+	/* voltage in mV = table[VSEL]; table_len must be a power-of-two */
+	u8			table_len;
+	const u16		*table;
+
+	/* chip constraints on regulator behavior */
+	u16			min_mV;
+	u16			max_mV;
+
+	/* used by regulator core */
+	struct regulator_desc	desc;
+};
+
+
+/* LDO control registers ... offset is from the base of its register bank.
+ * The first three registers of all power resource banks help hardware to
+ * manage the various resource groups.
+ */
+#define VREG_GRP		0
+#define VREG_TYPE		1
+#define VREG_REMAP		2
+#define VREG_DEDICATED		3	/* LDO control */
+
+
+static inline int
+twl4030reg_read(struct twlreg_info *info, unsigned offset)
+{
+	u8 value;
+	int status;
+
+	status = twl4030_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER,
+			&value, info->base + offset);
+	return (status < 0) ? status : value;
+}
+
+static inline int
+twl4030reg_write(struct twlreg_info *info, unsigned offset, u8 value)
+{
+	return twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+			value, info->base + offset);
+}
+
+/*----------------------------------------------------------------------*/
+
+/* generic power resource operations, which work on all regulators */
+
+static int twl4030reg_grp(struct regulator_dev *rdev)
+{
+	return twl4030reg_read(rdev_get_drvdata(rdev), VREG_GRP);
+}
+
+/*
+ * Enable/disable regulators by joining/leaving the P1 (processor) group.
+ * We assume nobody else is updating the DEV_GRP registers.
+ */
+
+#define P3_GRP		BIT(7)		/* "peripherals" */
+#define P2_GRP		BIT(6)		/* secondary processor, modem, etc */
+#define P1_GRP		BIT(5)		/* CPU/Linux */
+
+static int twl4030reg_is_enabled(struct regulator_dev *rdev)
+{
+	int	state = twl4030reg_grp(rdev);
+
+	if (state < 0)
+		return state;
+
+	return (state & P1_GRP) != 0;
+}
+
+static int twl4030reg_enable(struct regulator_dev *rdev)
+{
+	struct twlreg_info	*info = rdev_get_drvdata(rdev);
+	int			grp;
+
+	grp = twl4030reg_read(info, VREG_GRP);
+	if (grp < 0)
+		return grp;
+
+	grp |= P1_GRP;
+	return twl4030reg_write(info, VREG_GRP, grp);
+}
+
+static int twl4030reg_disable(struct regulator_dev *rdev)
+{
+	struct twlreg_info	*info = rdev_get_drvdata(rdev);
+	int			grp;
+
+	grp = twl4030reg_read(info, VREG_GRP);
+	if (grp < 0)
+		return grp;
+
+	grp &= ~P1_GRP;
+	return twl4030reg_write(info, VREG_GRP, grp);
+}
+
+static int twl4030reg_get_status(struct regulator_dev *rdev)
+{
+	int	state = twl4030reg_grp(rdev);
+
+	if (state < 0)
+		return state;
+	state &= 0x0f;
+
+	/* assume state != WARM_RESET; we'd not be running...  */
+	if (!state)
+		return REGULATOR_STATUS_OFF;
+	return (state & BIT(3))
+		? REGULATOR_STATUS_NORMAL
+		: REGULATOR_STATUS_STANDBY;
+}
+
+static int twl4030reg_set_mode(struct regulator_dev *rdev, unsigned mode)
+{
+	struct twlreg_info	*info = rdev_get_drvdata(rdev);
+	unsigned		message;
+	int			status;
+
+	/* We can only set the mode through state machine commands... */
+	switch (mode) {
+	case REGULATOR_MODE_NORMAL:
+		message = MSG_SINGULAR(DEV_GRP_P1, info->id, RES_STATE_ACTIVE);
+		break;
+	case REGULATOR_MODE_STANDBY:
+		message = MSG_SINGULAR(DEV_GRP_P1, info->id, RES_STATE_SLEEP);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Ensure the resource is associated with some group */
+	status = twl4030reg_grp(rdev);
+	if (status < 0)
+		return status;
+	if (!(status & (P3_GRP | P2_GRP | P1_GRP)))
+		return -EACCES;
+
+	status = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
+			message >> 8, 0x15 /* PB_WORD_MSB */ );
+	if (status >= 0)
+		return status;
+
+	return twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
+			message, 0x16 /* PB_WORD_LSB */ );
+}
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * Support for adjustable-voltage LDOs uses a four bit (or less) voltage
+ * select field in its control register.   We use tables indexed by VSEL
+ * to record voltages in milliVolts.  (Accuracy is about three percent.)
+ *
+ * Note that VSEL values for VAUX2 changed in twl5030 and newer silicon;
+ * currently handled by listing two slightly different VAUX2 regulators,
+ * only one of which will be configured.
+ *
+ * VSEL values documented as "TI cannot support these values" are flagged
+ * in these tables as UNSUP() values; we normally won't assign them.
+ */
+#ifdef CONFIG_TWL4030_ALLOW_UNSUPPORTED
+#define UNSUP_MASK	0x0000
+#else
+#define UNSUP_MASK	0x8000
+#endif
+
+#define UNSUP(x)	(UNSUP_MASK | (x))
+#define IS_UNSUP(x)	(UNSUP_MASK & (x))
+#define LDO_MV(x)	(~UNSUP_MASK & (x))
+
+
+static const u16 VAUX1_VSEL_table[] = {
+	UNSUP(1500), UNSUP(1800), 2500, 2800,
+	3000, 3000, 3000, 3000,
+};
+static const u16 VAUX2_4030_VSEL_table[] = {
+	UNSUP(1000), UNSUP(1000), UNSUP(1200), 1300,
+	1500, 1800, UNSUP(1850), 2500,
+	UNSUP(2600), 2800, UNSUP(2850), UNSUP(3000),
+	UNSUP(3150), UNSUP(3150), UNSUP(3150), UNSUP(3150),
+};
+static const u16 VAUX2_VSEL_table[] = {
+	1700, 1700, 1900, 1300,
+	1500, 1800, 2000, 2500,
+	2100, 2800, 2200, 2300,
+	2400, 2400, 2400, 2400,
+};
+static const u16 VAUX3_VSEL_table[] = {
+	1500, 1800, 2500, 2800,
+	UNSUP(3000), UNSUP(3000), UNSUP(3000), UNSUP(3000),
+};
+static const u16 VAUX4_VSEL_table[] = {
+	700, 1000, 1200, UNSUP(1300),
+	1500, 1800, UNSUP(1850), 2500,
+};
+static const u16 VMMC1_VSEL_table[] = {
+	1850, 2850, 3000, 3150,
+};
+static const u16 VMMC2_VSEL_table[] = {
+	UNSUP(1000), UNSUP(1000), UNSUP(1200), UNSUP(1300),
+	UNSUP(1500), UNSUP(1800), 1850, UNSUP(2500),
+	2600, 2800, 2850, 3000,
+	3150, 3150, 3150, 3150,
+};
+static const u16 VPLL1_VSEL_table[] = {
+	1000, 1200, 1300, 1800,
+	UNSUP(2800), UNSUP(3000), UNSUP(3000), UNSUP(3000),
+};
+static const u16 VPLL2_VSEL_table[] = {
+	700, 1000, 1200, 1300,
+	UNSUP(1500), 1800, UNSUP(1850), UNSUP(2500),
+	UNSUP(2600), UNSUP(2800), UNSUP(2850), UNSUP(3000),
+	UNSUP(3150), UNSUP(3150), UNSUP(3150), UNSUP(3150),
+};
+static const u16 VSIM_VSEL_table[] = {
+	UNSUP(1000), UNSUP(1200), UNSUP(1300), 1800,
+	2800, 3000, 3000, 3000,
+};
+static const u16 VDAC_VSEL_table[] = {
+	1200, 1300, 1800, 1800,
+};
+
+
+static int
+twl4030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
+{
+	struct twlreg_info	*info = rdev_get_drvdata(rdev);
+	int			vsel;
+
+	for (vsel = 0; vsel < info->table_len; vsel++) {
+		int mV = info->table[vsel];
+		int uV;
+
+		if (IS_UNSUP(mV))
+			continue;
+		uV = LDO_MV(mV) * 1000;
+
+		/* use the first in-range value */
+		if (min_uV <= uV && uV <= max_uV)
+			return twl4030reg_write(info, VREG_DEDICATED, vsel);
+	}
+
+	return -EDOM;
+}
+
+static int twl4030ldo_get_voltage(struct regulator_dev *rdev)
+{
+	struct twlreg_info	*info = rdev_get_drvdata(rdev);
+	int			vsel = twl4030reg_read(info, VREG_DEDICATED);
+
+	if (vsel < 0)
+		return vsel;
+
+	vsel &= info->table_len - 1;
+	return LDO_MV(info->table[vsel]) * 1000;
+}
+
+static struct regulator_ops twl4030ldo_ops = {
+	.set_voltage	= twl4030ldo_set_voltage,
+	.get_voltage	= twl4030ldo_get_voltage,
+
+	.enable		= twl4030reg_enable,
+	.disable	= twl4030reg_disable,
+	.is_enabled	= twl4030reg_is_enabled,
+
+	.set_mode	= twl4030reg_set_mode,
+
+	.get_status	= twl4030reg_get_status,
+};
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * Fixed voltage LDOs don't have a VSEL field to update.
+ */
+static int twl4030fixed_get_voltage(struct regulator_dev *rdev)
+{
+	struct twlreg_info	*info = rdev_get_drvdata(rdev);
+
+	return info->min_mV * 1000;
+}
+
+static struct regulator_ops twl4030fixed_ops = {
+	.get_voltage	= twl4030fixed_get_voltage,
+
+	.enable		= twl4030reg_enable,
+	.disable	= twl4030reg_disable,
+	.is_enabled	= twl4030reg_is_enabled,
+
+	.set_mode	= twl4030reg_set_mode,
+
+	.get_status	= twl4030reg_get_status,
+};
+
+/*----------------------------------------------------------------------*/
+
+#define TWL_ADJUSTABLE_LDO(label, offset, num) { \
+	.base = offset, \
+	.id = num, \
+	.table_len = ARRAY_SIZE(label##_VSEL_table), \
+	.table = label##_VSEL_table, \
+	.desc = { \
+		.name = #label, \
+		.id = TWL4030_REG_##label, \
+		.ops = &twl4030ldo_ops, \
+		.type = REGULATOR_VOLTAGE, \
+		.owner = THIS_MODULE, \
+		}, \
+	}
+
+#define TWL_FIXED_LDO(label, offset, mVolts, num) { \
+	.base = offset, \
+	.id = num, \
+	.min_mV = mVolts, \
+	.max_mV = mVolts, \
+	.desc = { \
+		.name = #label, \
+		.id = TWL4030_REG_##label, \
+		.ops = &twl4030fixed_ops, \
+		.type = REGULATOR_VOLTAGE, \
+		.owner = THIS_MODULE, \
+		}, \
+	}
+
+/*
+ * We list regulators here if systems need some level of
+ * software control over them after boot.
+ */
+static struct twlreg_info twl4030_regs[] = {
+	TWL_ADJUSTABLE_LDO(VAUX1, 0x17, 1),
+	TWL_ADJUSTABLE_LDO(VAUX2_4030, 0x1b, 2),
+	TWL_ADJUSTABLE_LDO(VAUX2, 0x1b, 2),
+	TWL_ADJUSTABLE_LDO(VAUX3, 0x1f, 3),
+	TWL_ADJUSTABLE_LDO(VAUX4, 0x23, 4),
+	TWL_ADJUSTABLE_LDO(VMMC1, 0x27, 5),
+	TWL_ADJUSTABLE_LDO(VMMC2, 0x2b, 6),
+	/*
+	TWL_ADJUSTABLE_LDO(VPLL1, 0x2f, 7),
+	TWL_ADJUSTABLE_LDO(VPLL2, 0x33, 8),
+	*/
+	TWL_ADJUSTABLE_LDO(VSIM, 0x37, 9),
+	TWL_ADJUSTABLE_LDO(VDAC, 0x3b, 10),
+	/*
+	TWL_ADJUSTABLE_LDO(VINTANA1, 0x3f, 11),
+	TWL_ADJUSTABLE_LDO(VINTANA2, 0x43, 12),
+	TWL_ADJUSTABLE_LDO(VINTDIG, 0x47, 13),
+	TWL_SMPS(VIO, 0x4b, 14),
+	TWL_SMPS(VDD1, 0x55, 15),
+	TWL_SMPS(VDD2, 0x63, 16),
+	 */
+	TWL_FIXED_LDO(VUSB1V5, 0x71, 1500, 17),
+	TWL_FIXED_LDO(VUSB1V8, 0x74, 1800, 18),
+	TWL_FIXED_LDO(VUSB3V1, 0x77, 3100, 19),
+	/* VUSBCP is managed *only* by the USB subchip */
+};
+
+static int twl4030reg_probe(struct platform_device *pdev)
+{
+	int				i;
+	struct twlreg_info		*info;
+	struct regulator_init_data	*initdata;
+	struct regulation_constraints	*c;
+	struct regulator_dev		*rdev;
+	int				min_uV, max_uV;
+
+	for (i = 0, info = NULL; i < ARRAY_SIZE(twl4030_regs); i++) {
+		if (twl4030_regs[i].desc.id != pdev->id)
+			continue;
+		info = twl4030_regs + i;
+		min_uV = info->min_mV * 1000;
+		max_uV = info->max_mV * 1000;
+		break;
+	}
+	if (!info)
+		return -ENODEV;
+
+	initdata = pdev->dev.platform_data;
+	if (!initdata)
+		return -EINVAL;
+
+	/* Constrain board-specific capabilities according to what
+	 * this driver and the chip itself can actually do.
+	 */
+	c = &initdata->constraints;
+	if (!c->min_uV || c->min_uV < min_uV)
+		c->min_uV = min_uV;
+	if (!c->max_uV || c->max_uV > max_uV)
+		c->max_uV = max_uV;
+	c->valid_modes_mask &= REGULATOR_MODE_NORMAL | REGULATOR_MODE_STANDBY;
+	c->valid_ops_mask &= REGULATOR_CHANGE_VOLTAGE
+				| REGULATOR_CHANGE_MODE
+				| REGULATOR_CHANGE_STATUS;
+
+	rdev = regulator_register(&info->desc, &pdev->dev, info);
+	if (IS_ERR(rdev)) {
+		dev_err(&pdev->dev, "can't register %s, %ld\n",
+				info->desc.name, PTR_ERR(rdev));
+		return PTR_ERR(rdev);
+	}
+	platform_set_drvdata(pdev, rdev);
+
+	/* NOTE:  many regulators support short-circuit IRQs (presentable
+	 * as REGULATOR_OVER_CURRENT notifications?) configured via:
+	 *  - SC_CONFIG
+	 *  - SC_DETECT1 (vintana2, vmmc1/2, vaux1/2/3/4)
+	 *  - SC_DETECT2 (vusb, vdac, vio, vdd1/2, vpll2)
+	 *  - IT_CONFIG
+	 */
+
+	return 0;
+}
+
+static int __devexit twl4030reg_remove(struct platform_device *pdev)
+{
+	regulator_unregister(platform_get_drvdata(pdev));
+	return 0;
+}
+
+MODULE_ALIAS("platform:twl4030_reg");
+
+static struct platform_driver twl4030reg_driver = {
+	.probe		= twl4030reg_probe,
+	.remove		= __devexit_p(twl4030reg_remove),
+	/* NOTE: short name, to work around driver model truncation of
+	 * "twl4030_regulator.12" (and friends) to "twl4030_regulator.1".
+	 */
+	.driver.name	= "twl4030_reg",
+	.driver.owner	= THIS_MODULE,
+};
+
+static int __init twl4030reg_init(void)
+{
+	unsigned i, j;
+
+	/* determine min/max voltage constraints, taking into account
+	 * whether set_voltage() will use the "unsupported" settings
+	 */
+	for (i = 0; i < ARRAY_SIZE(twl4030_regs); i++) {
+		struct twlreg_info	*info = twl4030_regs + i;
+		const u16		*table;
+
+		/* fixed-voltage regulators */
+		if (!info->table_len)
+			continue;
+
+		/* LDO regulators: */
+		for (j = 0, table = info->table;
+				j < info->table_len;
+				j++, table++) {
+			u16		mV = *table;
+
+			if (IS_UNSUP(mV))
+				continue;
+			mV = LDO_MV(mV);
+
+			if (info->min_mV == 0 || info->min_mV > mV)
+				info->min_mV = mV;
+			if (info->max_mV < mV)
+				info->max_mV = mV;
+		}
+	}
+
+	return platform_driver_register(&twl4030reg_driver);
+}
+subsys_initcall(twl4030reg_init);
+
+static void __exit twl4030reg_exit(void)
+{
+	platform_driver_unregister(&twl4030reg_driver);
+}
+module_exit(twl4030reg_exit)
+
+MODULE_DESCRIPTION("TWL4030 regulator driver");
+MODULE_LICENSE("GPL");
--- a/include/linux/i2c/twl4030.h
+++ b/include/linux/i2c/twl4030.h
@@ -218,6 +218,53 @@  int twl4030_i2c_read(u8 mod_no, u8 *valu
 
 /*----------------------------------------------------------------------*/
 
+/* Power bus message definitions */
+
+#define DEV_GRP_NULL		0x0
+#define DEV_GRP_P1		0x1
+#define DEV_GRP_P2		0x2
+#define DEV_GRP_P3		0x4
+
+#define RES_GRP_RES		0x0
+#define RES_GRP_PP		0x1
+#define RES_GRP_RC		0x2
+#define RES_GRP_PP_RC		0x3
+#define RES_GRP_PR		0x4
+#define RES_GRP_PP_PR		0x5
+#define RES_GRP_RC_PR		0x6
+#define RES_GRP_ALL		0x7
+
+#define RES_TYPE2_R0		0x0
+
+#define RES_TYPE_ALL		0x7
+
+#define RES_STATE_WRST		0xF
+#define RES_STATE_ACTIVE	0xE
+#define RES_STATE_SLEEP		0x8
+#define RES_STATE_OFF		0x0
+
+/*
+ * Power Bus Message Format ... these can be sent individually by Linux,
+ * but are usually part of downloaded scripts that are run when various
+ * power events are triggered.
+ *
+ *  Broadcast Message (16 Bits):
+ *    DEV_GRP[15:13] MT[12]  RES_GRP[11:9]  RES_TYPE2[8:7] RES_TYPE[6:4]
+ *    RES_STATE[3:0]
+ *
+ *  Singular Message (16 Bits):
+ *    DEV_GRP[15:13] MT[12]  RES_ID[11:4]  RES_STATE[3:0]
+ */
+
+#define MSG_BROADCAST(devgrp, grp, type, type2, state) \
+	( (devgrp) << 13 | 1 << 12 | (grp) << 9 | (type2) << 7 \
+	| (type) << 4 | (state))
+
+#define MSG_SINGULAR(devgrp, id, state) \
+	((devgrp) << 13 | 0 << 12 | (id) << 4 | (state))
+
+/*----------------------------------------------------------------------*/
+
 struct twl4030_bci_platform_data {
 	int *battery_tmp_tbl;
 	unsigned int tblsize;