diff mbox

[patch/rfc,2.6.29-rc6,1/2] regulator: enumerate voltages

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

Commit Message

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

Add a basic mechanism for regulators to report the discrete
voltages they support:  one method to count how many voltages
are available, and another to enumerate them.

Use those methods to force machine-level constraints into bounds.
(Example:  regulator supports 1.8V, 2.4V, 2.6V, 3.3V, and board
constraints for that rail are 2.0V to 3.6V ... so the range of
voltages is then 2.4V to 3.3V on this board.)

Export those voltages to the regulator consumer interface, so for
example regulator hooked up to an MMC/SD/SDIO slot can report the
actual voltage options available to cards connected there.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
---
I'm not particularly pleased with these names; suggestions?
This could also be done with one fewer method by designating a
special list_voltage() return value, but I like this better.

 drivers/regulator/core.c           |  107 +++++++++++++++++++++++++++++++++++
 include/linux/regulator/consumer.h |    2 
 include/linux/regulator/driver.h   |   10 +++
 3 files changed, 119 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. 24, 2009, 10:23 p.m. UTC | #1
On Mon, Feb 23, 2009 at 12:52:01PM -0800, David Brownell wrote:

> Use those methods to force machine-level constraints into bounds.
> (Example:  regulator supports 1.8V, 2.4V, 2.6V, 3.3V, and board
> constraints for that rail are 2.0V to 3.6V ... so the range of
> voltages is then 2.4V to 3.3V on this board.)

Being able to support this is definitely a win, thanks for looking at
this.

> +	/* maybe force machine-wide voltage constraints to match the
> +	 * voltages supported by this regulator.  use the regulator's
> +	 * entire range for boards with no particular constraints.
> +	 */

I'd really rather the second bit weren't here.  I'd like to see a
warning for the first part.

> + * @count_voltages: Return the number of supported voltage indices which
> + *	may be passed to @list_voltage().  Some indices may correspond to
> + *	voltages that are not usable on this system.
> + * @list_voltage: Return one of the supported voltages, in microvolts;
> + *	or negative errno.  Indices range from zero to one less than
> + *	@count_voltages().  Voltages may be reported in any order.

I'm having a hard time loving this interface for the driver.  It feels
fairly cumbersome to have to provide two functions to look up what I'd
expect to be static data - I'd be fairly surprised to see it change at
runtime.  I think I'd expect to see something more like the way ALSA
represents dB scales where the driver supplies a list of ranges that can
either be simple values or value ranges expressed as (start, step,
count).  That would cover both complicated cases like the TWL4030 and
the other common case with large regular ranges of voltages.

This mostly applies to the driver interface - on the consumer side it
feels a bit cumbersome to use but I can't think of anything that's
particularly better.  An interface that also allows consumers to ask if
particular ranges can be satisfied might help here - it'd be nice for
things like MMC that want to check for a relatively small set of
voltages or voltage ranges (which I'd expect is the common case).
--
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. 25, 2009, 12:17 a.m. UTC | #2
On Tuesday 24 February 2009, Mark Brown wrote:
> On Mon, Feb 23, 2009 at 12:52:01PM -0800, David Brownell wrote:
> 
> > Use those methods to force machine-level constraints into bounds.
> > (Example:  regulator supports 1.8V, 2.4V, 2.6V, 3.3V, and board
> > constraints for that rail are 2.0V to 3.6V ... so the range of
> > voltages is then 2.4V to 3.3V on this board.)
> 
> Being able to support this is definitely a win, thanks for looking at
> this.

Likewise consumers being able to see what voltages are available...


> > +	/* maybe force machine-wide voltage constraints to match the
> > +	 * voltages supported by this regulator.  use the regulator's
> > +	 * entire range for boards with no particular constraints.
> > +	 */
> 
> I'd really rather the second bit weren't here.  I'd like to see a
> warning for the first part.

Fixable in an update.  I still think it's better to require less
manual configuration, not more ... manual configuration is by
definition error prone; requiring more manual configuration makes
systems be more fragile.  Which is why I wouldn't naturally want
to see a warning:  it implies manual configuration is desirable.


> > + * @count_voltages: Return the number of supported voltage indices which
> > + *	may be passed to @list_voltage().  Some indices may correspond to
> > + *	voltages that are not usable on this system.
> > + * @list_voltage: Return one of the supported voltages, in microvolts;
> > + *	or negative errno.  Indices range from zero to one less than
> > + *	@count_voltages().  Voltages may be reported in any order.
> 
> I'm having a hard time loving this interface for the driver.  It feels
> fairly cumbersome to have to provide two functions to look up what I'd
> expect to be static data - I'd be fairly surprised to see it change at
> runtime. 

It can be a function of configuration, and I didn't want to force
such seldom-used data into wasteful standardized-format tables.
Notice that with the twl4030 code, a functional interface takes
less space ... and is more flexible, since it copes with the
voltage options that are defined as "not supported".

Function accessors can use static const data when that's appropriate.
But going the other way around isn't very straightforward...

Consider also the TPS6235x regulators:  the voltages they support are
a simple linear function of an index 0..63, and that driver handles
seven such chips.  64 values * 4 bytes * 7 chips == about 2KB of
table data ... vs a few dozen bytes of function code.

Again, the tradeoff looks to me like a clear win:  this functional
interface is small, simple, clear, flexible.


> I think I'd expect to see something more like the way ALSA 
> represents dB scales where the driver supplies a list of ranges that can
> either be simple values or value ranges expressed as (start, step,
> count).  That would cover both complicated cases like the TWL4030 and
> the other common case with large regular ranges of voltages.

Another virtue of functional interfaces for enumeration is
they avoid the need for callers to see and handle a variety
of different models, like that!!

Do you really think it's easier to have to write code like

	if (regulator uses table model) {
		table iteration code {
			check(get(i))
		}
	else if (regulator uses start/step/count model) {
		start/step iteration {
			check(something)
		}
	else if ... another model-du-jour ... {
		...
	} else
		error

Instead of a one simple flexible model?

	limit = get_limit();
	for (i = 0; i < limit; i++)
		check(get(i));

 
> This mostly applies to the driver interface - on the consumer side it
> feels a bit cumbersome to use but I can't think of anything that's
> particularly better. 

There's a LONG history of functional iterator models, such as
the one I used.  I think they are clearly better, and don't
understand why you'd prefer that more cumbersome approach.


> An interface that also allows consumers to ask if 
> particular ranges can be satisfied might help here - it'd be nice for
> things like MMC that want to check for a relatively small set of
> voltages or voltage ranges (which I'd expect is the common case).

Umm, did you look at the MMC patch I sent?  It shows
how the $SUBJECT interface fits nicely with what the
MMC framework needs.  mmc_regulator_get_ocrmask() took
just thirty (ARM) instructions.

MMC doesn't want to "check" like that.  It wants to get
a mask of supported voltages, then AND it with the mask
reported by the MMC/SD/SDIO/eMMC/CE-ATA/... device to
pick a voltage supported by both host and card.

- 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. 25, 2009, 3:17 p.m. UTC | #3
On Tue, Feb 24, 2009 at 04:17:22PM -0800, David Brownell wrote:
> On Tuesday 24 February 2009, Mark Brown wrote:

> > > +	/* maybe force machine-wide voltage constraints to match the
> > > +	 * voltages supported by this regulator.  use the regulator's
> > > +	 * entire range for boards with no particular constraints.
> > > +	 */

> > I'd really rather the second bit weren't here.  I'd like to see a
> > warning for the first part.

> Fixable in an update.  I still think it's better to require less
> manual configuration, not more ... manual configuration is by
> definition error prone; requiring more manual configuration makes

This whole interface is structured around the idea that the consequences
of getting this wrong include things like lasting hardware damage.  This
hardware damage may not be immediately obvious but may develop over time
if components are kept running out of spec, either way it's not likely
to make users happy.

> systems be more fragile.  Which is why I wouldn't naturally want
> to see a warning:  it implies manual configuration is desirable.

If we weren't so reliant on the machine driver getting things right I'd
agree with you.  My thought here is that because there is room for human
error here it'd be good to use the information we do have to flag
potential problems to people, helping catch any mistakes that they make.

> > I'm having a hard time loving this interface for the driver.  It feels
> > fairly cumbersome to have to provide two functions to look up what I'd
> > expect to be static data - I'd be fairly surprised to see it change at
> > runtime. 

> It can be a function of configuration, and I didn't want to force
> such seldom-used data into wasteful standardized-format tables.
> Notice that with the twl4030 code, a functional interface takes
> less space ... and is more flexible, since it copes with the
> voltage options that are defined as "not supported".

Yeah, TWL4030 is pretty special here :/ .  The only gotcha I can see is
having to have a second table with only supported values in it for the
case where you're not allowing the out of spec values but TBH I don't
see that as a big deal.

> Consider also the TPS6235x regulators:  the voltages they support are
> a simple linear function of an index 0..63, and that driver handles
> seven such chips.  64 values * 4 bytes * 7 chips == about 2KB of
> table data ... vs a few dozen bytes of function code.

That's actually the most common case in the regulators I'd seen and is
why I'd suggested doing something like the ALSA dB scales which handle
this nicely - you don't need to actually have a table with all the
values, you just provide parmeters that expresses each sub range.  You
say things like

   DECLARE_TLV_DB_SCALE(mix_tlv, -1500, 300, 0);

As far as hardware requirements go I've seen regulators which provide:

 - A set of irregularly distributed values (usually fairly small).
 - A range of regularly distributed values.
 - A large range of values with several regular ranges in it (usually
   you get higher resolution at the low end).

Either way can be made to work for all of these, the concerns I have are
that the fact that it's a function based interface makes it look like
this might be dynamic data and that it's exposing a bit too much of the
implementation details (see below) which made that suggestion seem even
stronger.

[ALSA dB scale style]
> Another virtue of functional interfaces for enumeration is
> they avoid the need for callers to see and handle a variety
> of different models, like that!!

I'd expect the core to deal with unrolling the data rather than the
consumers, this is why...

> > This mostly applies to the driver interface - on the consumer side it
> > feels a bit cumbersome to use but I can't think of anything that's
> > particularly better. 

> There's a LONG history of functional iterator models, such as
> the one I used.  I think they are clearly better, and don't
> understand why you'd prefer that more cumbersome approach.

...I am, as I say, reasonably OK with it on the consumer side.

The only issue I have with it on the consumer side is that the invalid
slots in the array are visible to users since it feels icky to have
error conditions be part of the normal iteration process for what should
be well known constant data.  I worry that it's going to catch people
out since relatively few regulator drivers do that (the fact that it's
there is an implementation detail for drivers which have holes in the
range of register values they can set).

Thinking about it that could be hidden by mapping the invalid values to
zero or some value that is actually valid instead of returning an error
- not entirely nice but it keeps the pain away from the consumers.

> > An interface that also allows consumers to ask if 
> > particular ranges can be satisfied might help here - it'd be nice for
> > things like MMC that want to check for a relatively small set of
> > voltages or voltage ranges (which I'd expect is the common case).

> Umm, did you look at the MMC patch I sent?  It shows
> how the $SUBJECT interface fits nicely with what the
> MMC framework needs.  mmc_regulator_get_ocrmask() took
> just thirty (ARM) instructions.

> MMC doesn't want to "check" like that.  It wants to get
> a mask of supported voltages, then AND it with the mask
> reported by the MMC/SD/SDIO/eMMC/CE-ATA/... device to
> pick a voltage supported by both host and card.

You can either write the loop the way you have by iterating over the
voltages offered or you can write it by asking for voltage ranges that
the device might want.  It seems like it'd be useful for driver authors
if the core allowed either method so they can use whichever idiom fits
more comfortably with their needs.
--
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. 25, 2009, 10:12 p.m. UTC | #4
On Wednesday 25 February 2009, Mark Brown wrote:
> On Tue, Feb 24, 2009 at 04:17:22PM -0800, David Brownell wrote:
> 
> > Fixable in an update.  I still think it's better to require less
> > manual configuration, not more ... manual configuration is by
> > definition error prone; requiring more manual configuration makes
> 
> This whole interface is structured around the idea that the consequences
> of getting this wrong include things like lasting hardware damage.  This
> hardware damage may not be immediately obvious but may develop over time
> if components are kept running out of spec, either way it's not likely
> to make users happy.

And as I noted:  *hardware* designers don't like to make
such goofage possible.  So that's not a common scenario.

I'll update the patch to be noisier about such situations,
since you insist.  And since braindamaged hardware designers
have actually been observed in the wild.  ;)


> > > 	 It feels
> > > fairly cumbersome to have to provide two functions to look up what I'd
> > > expect to be static data - I'd be fairly surprised to see it change at
> > > runtime. 
> 
> > It can be a function of configuration, and I didn't want to force
> > such seldom-used data into wasteful standardized-format tables.
> > Notice that with the twl4030 code, a functional interface takes
> > less space ... and is more flexible, since it copes with the
> > voltage options that are defined as "not supported".
> 
> Yeah, TWL4030 is pretty special here :/ .

Those "not supported" cases seem to be mostly fallout from using
four bit voltage selectors, and wanting future family members to
be able to add new "supported" cases.  A slightly more typical
model would be to have those bit values be "undefined".

Part of the space savings comes of course from tables being able
to use milliVolts, not microVolts ... two bytes for each entry
instead of four.  :)


> > Consider also the TPS6235x regulators:  the voltages they support are
> > a simple linear function of an index 0..63, and that driver handles
> > seven such chips.  64 values * 4 bytes * 7 chips == about 2KB of
> > table data ... vs a few dozen bytes of function code.
> 
> That's actually the most common case in the regulators I'd seen

Not for me.  I had seen two and three bit voltage selector fields,
defining fairly irregular sets of voltages.

I think the rationale has to do with getting better system-wide
efficiency, to stretch battery life.  Circuits generating the
reference voltages can be more efficient if they don't need to
be continually adjustable over some range(s).


> As far as hardware requirements go I've seen regulators which provide:
> 
>  - A set of irregularly distributed values (usually fairly small).
>  - A range of regularly distributed values.
>  - A large range of values with several regular ranges in it (usually
>    you get higher resolution at the low end).

All of which model nicely as a mapping { selector --> voltage }.

Hardware probably even has a register bitfield holding selector
values.  Maybe in that third case there's a second bitfield to
hold selector bits which specify the range.


> Either way can be made to work for all of these, the concerns I have are
> that the fact that it's a function based interface makes it look like
> this might be dynamic data and that it's exposing a bit too much of the
> implementation details (see below) which made that suggestion seem even
> stronger.

That still doesn't make sense to me.  It doesn't say a thing
about what it *is* ... just how to find the voltage associated
with a given index/selector.  

 
> [ALSA dB scale style]
> > Another virtue of functional interfaces for enumeration is
> > they avoid the need for callers to see and handle a variety
> > of different models, like that!!
> 
> I'd expect the core to deal with unrolling the data rather than the
> consumers, this is why...

I don't see why the core should "unroll" anything at all!
The regulator driver is already doing that for get_voltage:

	get_voltage() {
		read selector from hardware
		map selector to voltage
		return that voltage
	}

So it's trivial for similar code to take the selector as
a function parameter, and do the same thing.  Repackage
the existing code a bit; bzzt, done!


> > > This mostly applies to the driver interface - on the consumer side it
> > > feels a bit cumbersome to use but I can't think of anything that's
> > > particularly better. 
> 
> > There's a LONG history of functional iterator models, such as
> > the one I used.  I think they are clearly better, and don't
> > understand why you'd prefer that more cumbersome approach.
> 
> ...I am, as I say, reasonably OK with it on the consumer side.
> 
> The only issue I have with it on the consumer side is that the invalid
> slots in the array are visible to users since it feels icky to have
> error conditions be part of the normal iteration process for what should
> be well known constant data.

They are "fault" conditions (like "page fault"), not errors.  ;)


> I worry that it's going to catch people 
> out since relatively few regulator drivers do that (the fact that it's
> there is an implementation detail for drivers which have holes in the
> range of register values they can set).

It will be fairly common for the regulator to support voltages
that are disallowed by the machine constraints, though.  That
can produce "holes" too; and not necessarily only for the lowest
or highest selector codes.

IMO it's reasonable to expect users of a programming interface
to handle common cases like that.  :)

 
> Thinking about it that could be hidden by mapping the invalid values to
> zero or some value that is actually valid instead of returning an error
> - not entirely nice but it keeps the pain away from the consumers.

The test for an invalid voltage is "v <= 0" regardless.

I'll switch the return code for those out-of-range cases to
use zero, and update the spec for regulator_list_voltage()
to include that third outcome.


> > MMC doesn't want to "check" like that.  It wants to get
> > a mask of supported voltages, then AND it with the mask
> > reported by the MMC/SD/SDIO/eMMC/CE-ATA/... device to
> > pick a voltage supported by both host and card.
> 
> You can either write the loop the way you have by iterating over the
> voltages offered or you can write it by asking for voltage ranges that
> the device might want.

The MMC stack is written to work the way I described.
I don't see that model changing any time soon; most MMC
adapters don't seem to have a switchable Vdd rail, so
they've got a fixed mask reporting 3.2-3.4V support and
won't have any reason to use (or depend on) the regulator
framework.


True, *other* stacks might want something else:

> It seems like it'd be useful for driver authors 
> if the core allowed either method so they can use whichever idiom fits
> more comfortably with their needs.

A patch could be added later, when some system needs
some other model.  I'm not exactly sure what would be
returned by "asking for a voltage range".  That sounds
like it might be a different regulator capability model
than the "discrete voltage options" one.


My focus this time around was on exposing the regulator
capabilities to the core to support two simple use cases:
(a) validating machine constraints, (b) supporting MMC/SD
usage idiom, so the omap_hsmmc driver can fully decouple
from the twl4030-family regulators.

I'll send an updated version of this patch in a bit.

- 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. 25, 2009, 11:01 p.m. UTC | #5
On Wed, Feb 25, 2009 at 02:12:26PM -0800, David Brownell wrote:
> On Wednesday 25 February 2009, Mark Brown wrote:

> > This whole interface is structured around the idea that the consequences
> > of getting this wrong include things like lasting hardware damage.  This
> > hardware damage may not be immediately obvious but may develop over time
> > if components are kept running out of spec, either way it's not likely
> > to make users happy.

> And as I noted:  *hardware* designers don't like to make
> such goofage possible.  So that's not a common scenario.

That's often not possible with software controllable regulators - it's
usually hard to stop them being set to any value they support and the
desire for any additional protection needs to be traded off against
power consumption and space and BoM costs.

> Not for me.  I had seen two and three bit voltage selector fields,
> defining fairly irregular sets of voltages.

> I think the rationale has to do with getting better system-wide
> efficiency, to stretch battery life.  Circuits generating the
> reference voltages can be more efficient if they don't need to
> be continually adjustable over some range(s).

It's certainly not the common case for regulators that people are
contributing to the kernel (most of which seem to be intended to be
primary PMICs).  Make of that what you will :)

> > As far as hardware requirements go I've seen regulators which provide:

> >  - A set of irregularly distributed values (usually fairly small).
> >  - A range of regularly distributed values.
> >  - A large range of values with several regular ranges in it (usually
> >    you get higher resolution at the low end).

> All of which model nicely as a mapping { selector --> voltage }.

> Hardware probably even has a register bitfield holding selector
> values.  Maybe in that third case there's a second bitfield to
> hold selector bits which specify the range.

Yes, you can clearly always do selector->voltage since there's going to
be a finite number of register bits that it'll be possible to set.

> > Either way can be made to work for all of these, the concerns I have are
> > that the fact that it's a function based interface makes it look like
> > this might be dynamic data and that it's exposing a bit too much of the
> > implementation details (see below) which made that suggestion seem even
> > stronger.

> That still doesn't make sense to me.  It doesn't say a thing
> about what it *is* ... just how to find the voltage associated
> with a given index/selector.  

A function that return errors suggests something non-static to me.

> > I'd expect the core to deal with unrolling the data rather than the
> > consumers, this is why...

> I don't see why the core should "unroll" anything at all!
> The regulator driver is already doing that for get_voltage:

> 	get_voltage() {
> 		read selector from hardware
> 		map selector to voltage
> 		return that voltage
> 	}

> So it's trivial for similar code to take the selector as
> a function parameter, and do the same thing.  Repackage
> the existing code a bit; bzzt, done!

Yes, that's a reasonable point (though I'd still like to see the maximum
turn into a static value now I think about it).

> > I worry that it's going to catch people 
> > out since relatively few regulator drivers do that (the fact that it's
> > there is an implementation detail for drivers which have holes in the
> > range of register values they can set).

> It will be fairly common for the regulator to support voltages
> that are disallowed by the machine constraints, though.  That
> can produce "holes" too; and not necessarily only for the lowest
> or highest selector codes.

At present only continous ranges are possible, though.  I can't think of
any systems I've seen that'd want discontinous constraints, though I'm
sure there are some.

> > Thinking about it that could be hidden by mapping the invalid values to
> > zero or some value that is actually valid instead of returning an error
> > - not entirely nice but it keeps the pain away from the consumers.

> The test for an invalid voltage is "v <= 0" regardless.

If you're looking for a bound you'd just check for things within that
bound anyway.  It's if there's explicit "this is an error" return that
people start wanting to do something with it rather than silently ignore
it (we hope, anyway).

> > You can either write the loop the way you have by iterating over the
> > voltages offered or you can write it by asking for voltage ranges that
> > the device might want.

> The MMC stack is written to work the way I described.
...
> True, *other* stacks might want something else:

Indeed, I'm not talking about MMC in particular here - other things are
going to want to ask the same questions.

> > It seems like it'd be useful for driver authors 
> > if the core allowed either method so they can use whichever idiom fits
> > more comfortably with their needs.

> A patch could be added later, when some system needs
> some other model.  I'm not exactly sure what would be
> returned by "asking for a voltage range".  That sounds
> like it might be a different regulator capability model
> than the "discrete voltage options" one.

Yes, I'm suggesting something like:

  int regulator_available_voltage(min, max);

It's wrapping the discrete values for consumers that find that idiom
easier.
--
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. 25, 2009, 11:47 p.m. UTC | #6
On Wednesday 25 February 2009, Mark Brown wrote:
> >       get_voltage() {
> >               read selector from hardware
> >               map selector to voltage
> >               return that voltage
> >       }
> 
> > So it's trivial for similar code to take the selector as
> > a function parameter, and do the same thing.  Repackage
> > the existing code a bit; bzzt, done!
> 
> Yes, that's a reasonable point (though I'd still like to see the maximum
> turn into a static value now I think about it).

At the regulator_desc level, that's trivial; I'll do that
in the patch you'll see.

In terms of the consumer interface, not -- "struct regulator"
is opaque to consumers, and everything is a functional accessor.
So I'll leave that as-is.


> > It will be fairly common for the regulator to support voltages
> > that are disallowed by the machine constraints, though.  That
> > can produce "holes" too; and not necessarily only for the lowest
> > or highest selector codes.
>
> At present only continous ranges are possible, though.  I can't think of
> any systems I've seen that'd want discontinous constraints, though I'm
> sure there are some.

Consider a regulator where voltage selectors 0..3 correspond to
voltages

	{ 3.3V, 1.8V, 4.2V, 5.0V }

With machine constraints that say voltages go from 3V to 4.5V ...

- 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. 26, 2009, 1:02 a.m. UTC | #7
On Wednesday 25 February 2009, Mark Brown wrote:
> > Fixable in an update.  I still think it's better to require less
> > manual configuration, not more ... manual configuration is by
> > definition error prone; requiring more manual configuration makes
> 
> This whole interface is structured around the idea that the consequences
> of getting this wrong include things like lasting hardware damage.

Oh, one more comment.  Requiring manual configuration
of fixed-voltage regulators is pure time-wastage.

--
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. 26, 2009, 10:46 a.m. UTC | #8
On Wed, Feb 25, 2009 at 05:02:03PM -0800, David Brownell wrote:

> Oh, one more comment.  Requiring manual configuration
> of fixed-voltage regulators is pure time-wastage.

Unless, of course, you happen to be using one of those consumers that
wants to know the voltage it's running at to configure itself.  Examples
I've seen include sensors and analogue components which can be
configured for better performance if they know the voltage they run at -
and yes, people do run these things off regulators that they vary at
runtime.

If you want to submit a patch making it optional that's fine.
--
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. 26, 2009, 11:05 a.m. UTC | #9
On Wed, Feb 25, 2009 at 03:47:52PM -0800, David Brownell wrote:
> On Wednesday 25 February 2009, Mark Brown wrote:

> In terms of the consumer interface, not -- "struct regulator"
> is opaque to consumers, and everything is a functional accessor.
> So I'll leave that as-is.

Yes, obviously.

> > At present only continous ranges are possible, though. ?I can't think of
> > any systems I've seen that'd want discontinous constraints, though I'm
> > sure there are some.

> Consider a regulator where voltage selectors 0..3 correspond to
> voltages

> 	{ 3.3V, 1.8V, 4.2V, 5.0V }

> With machine constraints that say voltages go from 3V to 4.5V ...

Continuous ranges of voltages, not continous indexes.  The indexes are
meaningless.  At the minute consumers and machines always supply
constraints as min,max pairs.
--
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. 26, 2009, 6:56 p.m. UTC | #10
On Thursday 26 February 2009, Mark Brown wrote:
> On Wed, Feb 25, 2009 at 05:02:03PM -0800, David Brownell wrote:
> 
> > Oh, one more comment.  Requiring manual configuration
> > of fixed-voltage regulators is pure time-wastage.
> 
> Unless, of course, you happen to be using one of those consumers that
> wants to know the voltage it's running at to configure itself.

In which case it can ask the regulator what voltage it's using.  :)

--
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. 26, 2009, 7:05 p.m. UTC | #11
On Thu, Feb 26, 2009 at 10:56:05AM -0800, David Brownell wrote:
> On Thursday 26 February 2009, Mark Brown wrote:

> > Unless, of course, you happen to be using one of those consumers that
> > wants to know the voltage it's running at to configure itself.

> In which case it can ask the regulator what voltage it's using.  :)

I suspect we're talking at cross purposes here - I was talking about the
fixed voltage regulator driver.  I suspect you were talking about
something else?
--
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. 26, 2009, 7:38 p.m. UTC | #12
On Thursday 26 February 2009, Mark Brown wrote:
> On Thu, Feb 26, 2009 at 10:56:05AM -0800, David Brownell wrote:
> > On Thursday 26 February 2009, Mark Brown wrote:
> 
> > > Unless, of course, you happen to be using one of those consumers that
> > > wants to know the voltage it's running at to configure itself.
> 
> > In which case it can ask the regulator what voltage it's using.  :)
> 
> I suspect we're talking at cross purposes here - I was talking about the
> fixed voltage regulator driver.  I suspect you were talking about
> something else?

Yes ... e.g. the USB1V5, USB1V, and USB3V1 regulators
exported through the twl4030 regulator driver.


Semi-related:  someone with time to spend on it might
find and fix the bug causing the regulator framework
to oops when regulator/core.c::set_machine_constraints()
returns an error code.

- 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
Liam Girdwood Feb. 26, 2009, 8:02 p.m. UTC | #13
On Thu, 2009-02-26 at 11:38 -0800, David Brownell wrote:

> 
> Semi-related:  someone with time to spend on it might
> find and fix the bug causing the regulator framework
> to oops when regulator/core.c::set_machine_constraints()
> returns an error code.

Any chance you can post the oops. Is it happening within the
set_constraints() error path or sometime later on ?  

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
David Brownell Feb. 26, 2009, 8:59 p.m. UTC | #14
On Thursday 26 February 2009, Liam Girdwood wrote:
> > 
> > Semi-related:  someone with time to spend on it might
> > find and fix the bug causing the regulator framework
> > to oops when regulator/core.c::set_machine_constraints()
> > returns an error code.
> 
> Any chance you can post the oops. Is it happening within the
> set_constraints() error path or sometime later on ?  

Later, after it returns.  This particular oops went away
with the tweak eliminating the need for pointless init of
constraints for fixed voltage (1.8V in this case) regulators.

- Dave


<3>set_machine_constraints: invalid 'VUSB1V8' voltage constraints
<1>Unable to handle kernel NULL pointer dereference at virtual address 00000004
<1>pgd = c0004000
<1>[00000004] *pgd=00000000
Internal error: Oops: 805 [#1] PREEMPT
CPU: 0    Not tainted  (2.6.29-rc6-omap1 #517)
PC is at kobj_kset_leave+0x34/0x5c
LR is at _spin_lock+0x50/0x58
pc : [<c01748a0>]    lr : [<c0336e84>]    psr: 20000013
sp : c7821978  ip : c7821950  fp : c782198c
r10: c785f8a8  r9 : c7888a08  r8 : c78dade0
r7 : ffffffea  r6 : 00000000  r5 : c785f8a8  r4 : c785f908
r3 : 00000000  r2 : c7888a6c  r1 : c785f90c  r0 : c7815308
Flags: nzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment kernel
Control: 10c5387f  Table: 80004019  DAC: 00000017
Process swapper (pid: 1, stack limit = 0xc78202e8)
Stack: (0xc7821978 to 0xc7822000)
1960:                                                       c785f908 c785f8a8 
1980: 		... deletia ...
1fe0: 00000000 00000000 00000000 c7821ff8 c004d6c8 c0008668 8b77de58 01fbdd0a 
Backtrace: 
[<c017486c>] (kobj_kset_leave+0x0/0x5c) from [<c01748f4>] (kobject_del+0x2c/0x40)
 r5:c785f8a8 r4:c785f908
[<c01748c8>] (kobject_del+0x0/0x40) from [<c01a94fc>] (device_del+0x158/0x170)
 r5:c785f8a8 r4:c785f908
[<c01a93a4>] (device_del+0x0/0x170) from [<c01a9528>] (device_unregister+0x14/0x20)
 r7:ffffffea r6:c785f808 r5:c0437150 r4:c785f8a8
[<c01a9514>] (device_unregister+0x0/0x20) from [<c0188614>] (regulator_register+0x208/0x248)
 r5:c0437150 r4:c785f800
[<c018840c>] (regulator_register+0x0/0x248) from [<c0189894>] (twl4030reg_probe+0xa4/0x108)
[<c01897f0>] (twl4030reg_probe+0x0/0x108) from [<c01ac778>] (platform_drv_probe+0x20/0x24)
 r6:c04371b0 r5:c7888a08 r4:c04371b0
[<c01ac758>] (platform_drv_probe+0x0/0x24) from [<c01ab920>] (really_probe+0x9c/0x148)
[<c01ab884>] (really_probe+0x0/0x148) from [<c01aba20>] (driver_probe_device+0x54/0x58)
 r7:c7888a68 r6:c7888a08 r5:c7888a08 r4:c04371b0
[<c01ab9cc>] (driver_probe_device+0x0/0x58) from [<c01abac0>] (__device_attach+0x10/0x14)
 r5:c01abab0 r4:00000000
[<c01abab0>] (__device_attach+0x0/0x14) from [<c01aae9c>] (bus_for_each_drv+0x50/0x84)
[<c01aae4c>] (bus_for_each_drv+0x0/0x84) from [<c01abb48>] (device_attach+0x58/0x70)
 r6:00000000 r5:c7888aac r4:c7888a08
[<c01abaf0>] (device_attach+0x0/0x70) from [<c01aacb8>] (bus_attach_device+0x30/0x64)
 r5:c7888a08 r4:c043b3f8
[<c01aac88>] (bus_attach_device+0x0/0x64) from [<c01a9830>] (device_add+0x148/0x284)
 r5:c7886820 r4:c7888a08
[<c01a96e8>] (device_add+0x0/0x284) from [<c01ace24>] (platform_device_add+0xf8/0x150)
 r7:c7888a8c r6:c7888a00 r5:00000000 r4:00000000
[<c01acd2c>] (platform_device_add+0x0/0x150) from [<c01b0714>] (add_numbered_child+0xe4/0x130)
 r7:00000120 r6:c7821bc0 r5:c7888a00 r4:00000000
[<c01b0630>] (add_numbered_child+0x0/0x130) from [<c01b07b0>] (add_regulator_linked+0x50/0x5c)
[<c01b0760>] (add_regulator_linked+0x0/0x5c) from [<c01b09f8>] (add_children+0x220/0x2d4)
[<c01b07d8>] (add_children+0x0/0x2d4) from [<c01b0eac>] (twl4030_probe+0x148/0x174)
 r8:c08010f4 r7:c041e848 r6:c7886200 r5:00000004 r4:00000178
[<c01b0d64>] (twl4030_probe+0x0/0x174) from [<c01cf6dc>] (i2c_device_probe+0x70/0x88)
[<c01cf66c>] (i2c_device_probe+0x0/0x88) from [<c01ab920>] (really_probe+0x9c/0x148)
 r7:c7886280 r6:c043b6f8 r5:c7886220 r4:c043b6f8
[<c01ab884>] (really_probe+0x0/0x148) from [<c01aba20>] (driver_probe_device+0x54/0x58)
 r7:c7886280 r6:c7886220 r5:c7886220 r4:c043b6f8
[<c01ab9cc>] (driver_probe_device+0x0/0x58) from [<c01abac0>] (__device_attach+0x10/0x14)
 r5:c01abab0 r4:00000000
[<c01abab0>] (__device_attach+0x0/0x14) from [<c01aae9c>] (bus_for_each_drv+0x50/0x84)
[<c01aae4c>] (bus_for_each_drv+0x0/0x84) from [<c01abb48>] (device_attach+0x58/0x70)
 r6:00000000 r5:c78862c4 r4:c7886220
[<c01abaf0>] (device_attach+0x0/0x70) from [<c01aacb8>] (bus_attach_device+0x30/0x64)
 r5:c7886220 r4:c043d558
[<c01aac88>] (bus_attach_device+0x0/0x64) from [<c01a9830>] (device_add+0x148/0x284)
 r5:c785ecf8 r4:c7886220
[<c01a96e8>] (device_add+0x0/0x284) from [<c01a9988>] (device_register+0x1c/0x20)
 r7:00000000 r6:c785ec50 r5:c7886200 r4:c7886220
[<c01a996c>] (device_register+0x0/0x20) from [<c01d069c>] (i2c_attach_client+0xc0/0x150)
 r5:c7886200 r4:c7886220
[<c01d05dc>] (i2c_attach_client+0x0/0x150) from [<c01d0d48>] (i2c_new_device+0x64/0x84)
 r7:c0420c90 r6:c785ec50 r5:c78064cc r4:c7886200
[<c01d0ce4>] (i2c_new_device+0x0/0x84) from [<c01d1388>] (i2c_scan_static_board_info+0x44/0x8c)
 r7:c0420c90 r6:00000000 r5:c785ec50 r4:c78064c0
[<c01d1344>] (i2c_scan_static_board_info+0x0/0x8c) from [<c01d145c>] (i2c_register_adapter+0x8c/0x144)
 r5:c785ec50 r4:00000000
[<c01d13d0>] (i2c_register_adapter+0x0/0x144) from [<c01d15b4>] (i2c_add_numbered_adapter+0xa0/0xb8)
 r5:c785ec50 r4:00000000
[<c01d1514>] (i2c_add_numbered_adapter+0x0/0xb8) from [<c0018c60>] (omap_i2c_probe+0x254/0x304)
 r5:c0420858 r4:c785ec00
[<c0018a0c>] (omap_i2c_probe+0x0/0x304) from [<c01ac778>] (platform_drv_probe+0x20/0x24)
 r8:00000001 r7:c043b3f8 r6:c043d7c8 r5:c0420860 r4:c043d7c8
[<c01ac758>] (platform_drv_probe+0x0/0x24) from [<c01ab920>] (really_probe+0x9c/0x148)
[<c01ab884>] (really_probe+0x0/0x148) from [<c01aba20>] (driver_probe_device+0x54/0x58)
 r7:c043b3f8 r6:c043d7c8 r5:c0420860 r4:c043d7c8
[<c01ab9cc>] (driver_probe_device+0x0/0x58) from [<c01aba8c>] (__driver_attach+0x68/0x8c)
 r5:c0420904 r4:c0420860
[<c01aba24>] (__driver_attach+0x0/0x8c) from [<c01ab170>] (bus_for_each_dev+0x4c/0x80)
 r7:c043b3f8 r6:c043d7c8 r5:c01aba24 r4:00000000
[<c01ab124>] (bus_for_each_dev+0x0/0x80) from [<c01ab79c>] (driver_attach+0x20/0x28)
 r6:c7887300 r5:00000000 r4:c043d7c8
[<c01ab77c>] (driver_attach+0x0/0x28) from [<c01aaaec>] (bus_add_driver+0xa4/0x170)
[<c01aaa48>] (bus_add_driver+0x0/0x170) from [<c01abd40>] (driver_register+0x98/0xcc)
 r7:c0018970 r6:00000000 r5:00000000 r4:c043d7c8
[<c01abca8>] (driver_register+0x0/0xcc) from [<c01accb0>] (platform_driver_register+0x6c/0x88)
 r5:00000000 r4:c0023fd8
[<c01acc44>] (platform_driver_register+0x0/0x88) from [<c0018984>] (omap_i2c_init_driver+0x14/0x1c)
[<c0018970>] (omap_i2c_init_driver+0x0/0x1c) from [<c002923c>] (__exception_text_end+0x5c/0x1a0)
[<c00291e0>] (__exception_text_end+0x0/0x1a0) from [<c000861c>] (do_initcalls+0x1c/0x38)
 r8:00000000 r7:00000000 r6:00000000 r5:00000000 r4:c0023fd8
[<c0008600>] (do_initcalls+0x0/0x38) from [<c0008658>] (do_basic_setup+0x20/0x24)
 r5:00000000 r4:c044b640
[<c0008638>] (do_basic_setup+0x0/0x24) from [<c00086b0>] (kernel_init+0x54/0xa8)
[<c000865c>] (kernel_init+0x0/0xa8) from [<c004d6c8>] (do_exit+0x0/0x254)
 r4:00000000
Code: e5942008 e5943004 e2841004 e5823000 (e5832004) 
<4>---[ end trace 1b75b31a2719ed1c ]---
<6>note: swapper[1] exited with preempt_count 2
<0>Kernel panic - not syncing: Attempted to kill init!



--
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/core.c
+++ b/drivers/regulator/core.c
@@ -719,6 +719,44 @@  static int set_machine_constraints(struc
 	else
 		name = "regulator";
 
+	/* maybe force machine-wide voltage constraints to match the
+	 * voltages supported by this regulator.  use the regulator's
+	 * entire range for boards with no particular constraints.
+	 */
+	if (ops->list_voltage) {
+		int	count = ops->count_voltages(rdev);
+		int	i;
+		int	min_uV = INT_MAX;
+		int	max_uV = INT_MIN;
+		int	cmin = constraints->min_uV ? : INT_MIN;
+		int	cmax = constraints->max_uV ? : INT_MAX;
+
+		/* initial: [cmin..cmax] valid, [min_uV..max_uV] not */
+		for (i = 0; i < count; i++) {
+			int	value;
+
+			value = ops->list_voltage(rdev, i);
+			if (value <= 0)
+				continue;
+
+			/* maybe adjust [min_uV..max_uV] */
+			if (value >= cmin && value < min_uV)
+				min_uV = value;
+			if (value <= cmax && value > max_uV)
+				max_uV = value;
+		}
+
+		/* final: [min_uV..max_uV] valid iff constraints valid */
+		if (max_uV < min_uV) {
+			pr_err("%s: bad '%s' voltage constraints\n",
+				       __func__, name);
+			ret = -EINVAL;
+			goto out;
+		}
+		constraints->min_uV = min_uV;
+		constraints->max_uV = max_uV;
+	}
+
 	rdev->constraints = constraints;
 
 	/* do we need to apply the constraint voltage */
@@ -1245,6 +1283,75 @@  int regulator_is_enabled(struct regulato
 EXPORT_SYMBOL_GPL(regulator_is_enabled);
 
 /**
+ * regulator_count_voltages - count regulator_list_voltage() indices
+ * @regulator: regulator source
+ *
+ * Returns number of indices, or negative errno.
+ */
+int regulator_count_voltages(struct regulator *regulator)
+{
+	struct regulator_dev	*rdev = regulator->rdev;
+	struct regulator_ops	*ops;
+	int			ret = -EINVAL;
+
+	mutex_lock(&rdev->mutex);
+
+	ops = rdev->desc->ops;
+	if (ops->count_voltages)
+		ret = ops->count_voltages(rdev);
+
+	mutex_unlock(&rdev->mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_count_voltages);
+
+/**
+ * regulator_list_voltage - enumerate supported voltages
+ * @regulator: regulator source
+ * @index: identify voltage to list
+ *
+ * Returns a voltage that can be passed to @regulator_set_voltage(),
+ * or negative fault code.
+ *
+ * Faults include passing in invalid index, and using an index
+ * corresponding to a voltage that can't be used on this system.
+ */
+int regulator_list_voltage(struct regulator *regulator, unsigned index)
+{
+	struct regulator_dev	*rdev = regulator->rdev;
+	struct regulator_ops	*ops;
+	int			ret = -EINVAL;
+
+	mutex_lock(&rdev->mutex);
+
+	ops = rdev->desc->ops;
+	if (ops->count_voltages && ops->list_voltage)
+		ret = ops->count_voltages(rdev);
+
+	if (ret == 0)
+		ret = -EIO;
+	else if (ret > 0) {
+		if (index >= ret)
+			ret = -EDOM;
+		else
+			ret = ops->list_voltage(rdev, index);
+	}
+
+	if (ret >= 0) {
+		if (ret < rdev->constraints->min_uV)
+			ret = -ERANGE;
+		else if (ret > rdev->constraints->max_uV)
+			ret = -ERANGE;
+	}
+
+	mutex_unlock(&rdev->mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_list_voltage);
+
+/**
  * regulator_set_voltage - set regulator output voltage
  * @regulator: regulator source
  * @min_uV: Minimum required voltage in uV
--- a/include/linux/regulator/consumer.h
+++ b/include/linux/regulator/consumer.h
@@ -140,6 +140,8 @@  int regulator_bulk_disable(int num_consu
 void regulator_bulk_free(int num_consumers,
 			 struct regulator_bulk_data *consumers);
 
+int regulator_count_voltages(struct regulator *regulator);
+int regulator_list_voltage(struct regulator *regulator, unsigned index);
 int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV);
 int regulator_get_voltage(struct regulator *regulator);
 int regulator_set_current_limit(struct regulator *regulator,
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -40,6 +40,12 @@  enum regulator_status {
  * @set_voltage: Set the voltage for the regulator within the range specified.
  *               The driver should select the voltage closest to min_uV.
  * @get_voltage: Return the currently configured voltage for the regulator.
+ * @count_voltages: Return the number of supported voltage indices which
+ *	may be passed to @list_voltage().  Some indices may correspond to
+ *	voltages that are not usable on this system.
+ * @list_voltage: Return one of the supported voltages, in microvolts;
+ *	or negative errno.  Indices range from zero to one less than
+ *	@count_voltages().  Voltages may be reported in any order.
  * @set_current_limit: Configure a limit for a current-limited regulator.
  * @get_current_limit: Get the configured limit for a current-limited regulator.
  * @set_mode: Set the operating mode for the regulator.
@@ -62,6 +68,10 @@  enum regulator_status {
  */
 struct regulator_ops {
 
+	/* enumerate supported voltages */
+	int (*count_voltages) (struct regulator_dev *);
+	int (*list_voltage) (struct regulator_dev *, unsigned index);
+
 	/* get/set regulator voltage */
 	int (*set_voltage) (struct regulator_dev *, int min_uV, int max_uV);
 	int (*get_voltage) (struct regulator_dev *);