diff mbox

[03/04] PM: Add platform bus runtime dev_pm_ops

Message ID 20090527100650.29671.82139.sendpatchset@rx1.opensource.se (mailing list archive)
State RFC
Headers show

Commit Message

Magnus Damm May 27, 2009, 10:06 a.m. UTC
From: Magnus Damm <damm@igel.co.jp>

Wrap the platform device bus dev_pm_ops to allow runtime
pm and regular suspend and resume to coexist.

Platform device data is extended with flags that allow
us to keep track of which dev_pm_ops that has been called.

Basically, if a device has been frozen by the runtime pm
code, don't call ->freeze() again when hibernating.

Architecture code can use platform_runtime_dev_pm_ops to
call driver dev_pm_ops associated with a certain device.

Enable with CONFIG_HAVE_PLATFORM_DEVICE_RUNTIME_PM.

Signed-off-by: Magnus Damm <damm@igel.co.jp>
---

 This is a bit of a hack, any better way to wrap dev_pm_ops?

 arch/Kconfig                    |    3 
 drivers/base/platform.c         |  193 ++++++++++++++++++++++++++++++++++++++-
 include/linux/platform_device.h |    8 +
 3 files changed, 203 insertions(+), 1 deletion(-)

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

Comments

Rafael Wysocki May 29, 2009, 11:23 p.m. UTC | #1
On Wednesday 27 May 2009, Magnus Damm wrote:
> From: Magnus Damm <damm@igel.co.jp>
> 
> Wrap the platform device bus dev_pm_ops to allow runtime
> pm and regular suspend and resume to coexist.
> 
> Platform device data is extended with flags that allow
> us to keep track of which dev_pm_ops that has been called.
> 
> Basically, if a device has been frozen by the runtime pm
> code, don't call ->freeze() again when hibernating.
> 
> Architecture code can use platform_runtime_dev_pm_ops to
> call driver dev_pm_ops associated with a certain device.
> 
> Enable with CONFIG_HAVE_PLATFORM_DEVICE_RUNTIME_PM.
> 
> Signed-off-by: Magnus Damm <damm@igel.co.jp>
> ---
> 
>  This is a bit of a hack, any better way to wrap dev_pm_ops?

I'm not really sure you need to wrap them at all.

There are a few choices:

(1) You can use the platform_pm_* functions directly for run-time PM, but
in that case you'll need to make sure that the "suspend" ones return 0
immediately when called during system-wide suspend or hibernation (there's the
question whether the "resume" ones should still put the device into the full
power state in that case).  For this purpose you can add a single flag to
struct platform_device and set it for devices that have already been
"suspended" (this flag, when set, will make all of the "suspend" callbacks
return 0 without doing anything until the device is "resumed").

(2) You can add separate platform callbacks for run-time PM that will execute
the drivers' dev_pm_ops callbacks and presumably do something else (I don't
know what that may be for platform devices, though).  In that case, again,
adding a flag to struct platform_device and making platform_pm_* check it
should be sufficient to prevent devices from being suspended twice in a row.

(3) You can add separate platform callbacks for run-time PM for both the
bus type and the drivers, in which dev_pm_ops will be totally separate from
these new callbacks, although of course you'll need provide some kind of
synchronization bettween them all.  That also may be done through a flag
in struct platform_device IMO.

Now, since other bus types will most probably also need a flag in their
_device structures, it may be worth putting it into struct device (we've
discsussed that already).

I'm not sure which of (1) - (3) are the most suitable for the platform bus
type.  For PCI I'd probably choose (2), because the current PCI bus type's
dev_pm_ops callbacks are tailored to system-wide power transitions.
Moreover, PCI devices can generally be put first into D1, then into D2 and
finally into D3, which only makes sense at run time, and some of them may
have to be put back into the full power state before a system-wide transition
(apparently, we'll need a separate flag to mark such devices).

Of course, if you decide to add separate run-time PM callbacks for the
platform bus type, you won't need to wrap its dev_pm_ops callbacks any more,
but you'll need to modify them to check the appropriate flag(s).  For example,
you may choose to use a two-bit pm_suspend_level field such that

* if pm_suspend_level = 1, platform_pm_prepare() will return immediately
* if pm_suspend_level = 2, platform_pm_prepare() and platform_pm_suspend()
  will return immediately
* if pm_suspend_level = 3, platform_pm_prepare(), platform_pm_suspend()
  and platform_pm_suspend_noirq() will return immediately

(and analogously for the hibernation callbacks) and make your run-time PM
callbacks set this field appropriately.

Thanks,
Rafael
--
To unsubscribe from this list: send the line "unsubscribe linux-sh" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Magnus Damm June 2, 2009, 1:37 p.m. UTC | #2
Hi Rafael,

Thanks for your feedback!

2009/5/30 Rafael J. Wysocki <rjw@sisk.pl>:
> On Wednesday 27 May 2009, Magnus Damm wrote:
>> From: Magnus Damm <damm@igel.co.jp>
>>
>> Wrap the platform device bus dev_pm_ops to allow runtime
>> pm and regular suspend and resume to coexist.
>>
>> Platform device data is extended with flags that allow
>> us to keep track of which dev_pm_ops that has been called.
>>
>> Basically, if a device has been frozen by the runtime pm
>> code, don't call ->freeze() again when hibernating.
>>
>> Architecture code can use platform_runtime_dev_pm_ops to
>> call driver dev_pm_ops associated with a certain device.
>>
>> Enable with CONFIG_HAVE_PLATFORM_DEVICE_RUNTIME_PM.
>>
>> Signed-off-by: Magnus Damm <damm@igel.co.jp>
>> ---
>>
>>  This is a bit of a hack, any better way to wrap dev_pm_ops?
>
> I'm not really sure you need to wrap them at all.

I realize that I didn't explain very well why I decided to wrap
dev_pm_ops. Sorry about that. Basically there are two reasons:
1) Wrap to always have the runtime dev_pm_ops functions regardless of kconfig.
2) Wrap to make sure runtime and system-wide dev_pm_ops can coexist.

> There are a few choices:
>
> (1) You can use the platform_pm_* functions directly for run-time PM, but
> in that case you'll need to make sure that the "suspend" ones return 0
> immediately when called during system-wide suspend or hibernation (there's the
> question whether the "resume" ones should still put the device into the full
> power state in that case).  For this purpose you can add a single flag to
> struct platform_device and set it for devices that have already been
> "suspended" (this flag, when set, will make all of the "suspend" callbacks
> return 0 without doing anything until the device is "resumed").

I have to make sure that the right Kconfig bits are enabled though,
otherwise some platform_pm_* functions will be missing. So one merit
for the wrapped functions is in this patch is that they are always
there regardless of CONFIG_SUSPEND and CONFIG_HIBERNATION.

Is one flag really enough? Isn't it a bit strange from the driver
point of view to always get their ->prepare() callback executed, but
->suspend() gets filtered?

The bitmap in this patch is more fine-grained, so struct
platform_device remember which of each dev_pm_ops callback that have
been called. It may be overly complex though. Also, please note that
both runtime dev_pm_ops and system-wide dev_pm_ops go through the same
dev_pm_ops that keep track of which callbacks that have been called.

Using some kind of flag(s) for coexisting with system-wide
suspend-to-ram/disk sounds good.

> (2) You can add separate platform callbacks for run-time PM that will execute
> the drivers' dev_pm_ops callbacks and presumably do something else (I don't
> know what that may be for platform devices, though).  In that case, again,
> adding a flag to struct platform_device and making platform_pm_* check it
> should be sufficient to prevent devices from being suspended twice in a row.

We may need to do other things as well - not sure - but regardless we
still need flag(s) to avoid double suspend.

> (3) You can add separate platform callbacks for run-time PM for both the
> bus type and the drivers, in which dev_pm_ops will be totally separate from
> these new callbacks, although of course you'll need provide some kind of
> synchronization bettween them all.  That also may be done through a flag
> in struct platform_device IMO.

Yeah, that's also one way. I wonder if that helps us though, I feel
that we already have a pretty wide range of callbacks in dev_pm_ops.
I'm not sure if they cover all cases we need though, I guess future
experiments will tell.

> Now, since other bus types will most probably also need a flag in their
> _device structures, it may be worth putting it into struct device (we've
> discsussed that already).

Yeah, I wonder if a single flag is enough though? Aren't we coexisting
with CONFIG_SUSPEND, CONFIG_HIBERNATION and CONFIG_KEXEC_JUMP?

> I'm not sure which of (1) - (3) are the most suitable for the platform bus
> type.  For PCI I'd probably choose (2), because the current PCI bus type's
> dev_pm_ops callbacks are tailored to system-wide power transitions.
> Moreover, PCI devices can generally be put first into D1, then into D2 and
> finally into D3, which only makes sense at run time, and some of them may
> have to be put back into the full power state before a system-wide transition
> (apparently, we'll need a separate flag to mark such devices).

If I understand (1)-(3) correctly, then I think (1) is probably the
best choice for our platform devices. I guess (2) is not very far from
(1), so if we go with (1) to begin with then we can deal with SoC
specific things in our arch code to come closer to (2) over time if
needed.

> Of course, if you decide to add separate run-time PM callbacks for the
> platform bus type, you won't need to wrap its dev_pm_ops callbacks any more,
> but you'll need to modify them to check the appropriate flag(s).  For example,
> you may choose to use a two-bit pm_suspend_level field such that
>
> * if pm_suspend_level = 1, platform_pm_prepare() will return immediately
> * if pm_suspend_level = 2, platform_pm_prepare() and platform_pm_suspend()
>  will return immediately
> * if pm_suspend_level = 3, platform_pm_prepare(), platform_pm_suspend()
>  and platform_pm_suspend_noirq() will return immediately
>
> (and analogously for the hibernation callbacks) and make your run-time PM
> callbacks set this field appropriately.

That is true, but this checking is not needed for systems where
runtime PM is disabled. Or am I misunderstanding?

Maybe it's worth to discuss how to integrate this. I suspect that this
will only affect some selected architectures to begin with, and the
rest of the code base should be unaffected by this change as long as
the runtime kconfig is disabled.

So I decided to wrap dev_pm_ops to make the impact for non runtime PM
systems as small as possible. This while giving the runtime PM case
access to all dev_pm_ops regardless of suspend/hibernation kconfig.

Does it make sense?

Thank you!

/ magnus
--
To unsubscribe from this list: send the line "unsubscribe linux-sh" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Magnus Damm June 5, 2009, 10:40 a.m. UTC | #3
Hi Rafael,

On Wed, Jun 3, 2009 at 6:47 PM, Rafael J. Wysocki<rjw@sisk.pl> wrote:
> On Tuesday 02 June 2009, Magnus Damm wrote:
>> I have to make sure that the right Kconfig bits are enabled though,
>> otherwise some platform_pm_* functions will be missing. So one merit
>> for the wrapped functions is in this patch is that they are always
>> there regardless of CONFIG_SUSPEND and CONFIG_HIBERNATION.
>
> Make them depend on CONFIG_PM, then. They are not _that_ much code anyway,
> we can easily afford building them even on platforms that really don't use
> them,
> but I expect them to be used by more and more platforms over time anyway.

Sure, good idea!

>> Is one flag really enough?
>
> Not necessarily, although I think we'll end up using one flag only.
>
>> Isn't it a bit strange from the driver point of view to always get their
>> ->prepare() callback executed, but ->suspend() gets filtered?
>
> In fact, from the run-time PM POV, ->prepare() and ->suspend() should
> always be executed together and ->suspend_noirq() shouldn't be executed
> at all. Now, it may be necessary to execute some code from ->suspend_noirq()
> for run-time PM too, but not by using this callback directly.

Why shouldn't _noirq() be used? I understand that _noirq callbacks
assume that interrupts are not delivered.

It looks to me that most drivers seem to misuse _noirq to work around
ordering issues. They basically use suspend_late() or suspend_noirq()
because they want to be sure that they are suspended after other
drivers. For instance, i2c master controllers seem to want to suspend
using suspend_late() to suspend after the i2c devices on the bus.

Do you have any pointer to code that manages the device hierarchy? Or
is it up to the bus_type?

> Of course we should be avoiding double suspend, so some kind of
> sychronization
> between the "sleep" suspend and run-time suspend is necessary and I agree
> that
> it's probably most convenient to use some flags for this purpose. The
> questions are how many flags we're going to need and how exactly we're going
> to use them.

Exactly!

>> > (3) You can add separate platform callbacks for run-time PM for both the
>> > bus type and the drivers, in which dev_pm_ops will be totally separate
>> > from
>> > these new callbacks, although of course you'll need provide some kind of
>> > synchronization bettween them all.  That also may be done through a flag
>> > in struct platform_device IMO.
>>
>> Yeah, that's also one way. I wonder if that helps us though, I feel
>> that we already have a pretty wide range of callbacks in dev_pm_ops.
>> I'm not sure if they cover all cases we need though, I guess future
>> experiments will tell.
>
> Yes. Still, we can anticipate that the run-time PM operations may be
> slightly
> different from the 'sleep state' PM ones, in which case it makes sens to
> introduce new callbacks, because that makes it clear(er) what the code is
> supposed to do.

Sure, new callbacks are fine as well if you think that's better.

>> If I understand (1)-(3) correctly, then I think (1) is probably the
>> best choice for our platform devices.
>
> OK, for _your_ platform devices it may be the best choice, but what about
> the other platforms' platform devices? Do you think (1) will be suitable for
> them all and if so then why?

I can only speak for SuperH and a bit for ARM. I see a clear need for
for run-time state saving at least. And I think dev_pm_ops ->freeze()
and ->restore() seem like good matches for this, so yes, it's enough
to begin with.

>> I guess (2) is not very far from (1), so if we go with (1) to begin with
>> then we can deal with SoC specific things in our arch code to come closer
>> to
>> (2) over time if needed.

I think (1) is the simplest and does not require much changes to begin
with. People can build stuff on top of this which we later can break
out and make generic.

>> Maybe it's worth to discuss how to integrate this. I suspect that this
>> will only affect some selected architectures to begin with, and the
>> rest of the code base should be unaffected by this change as long as
>> the runtime kconfig is disabled.
>>
>> So I decided to wrap dev_pm_ops to make the impact for non runtime PM
>> systems as small as possible. This while giving the runtime PM case
>> access to all dev_pm_ops regardless of suspend/hibernation kconfig.
>>
>> Does it make sense?
>
> Well, as I said above, I don't really think that run-time PM is going to
> need
> all of the callbacks from dev_pm_ops. Moreover, I'm not sure if it makes
> sense to have more than two (call it 'autosuspend' and 'autoresume' using
> the
> already existing USB terminology) callbacks for run-time PM, at least at
> the driver level.

For SuperH two callbacks for state saving and restoring is enough to
begin with. Functionality wise this is very similar to dev_pm_ops
->freeze() and ->restore() so I think just using those should be fine.

Cheers,

/ magnus
--
To unsubscribe from this list: send the line "unsubscribe linux-sh" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Rafael Wysocki June 5, 2009, 9:24 p.m. UTC | #4
On Friday 05 June 2009, Magnus Damm wrote:
> Hi Rafael,
> 
> On Wed, Jun 3, 2009 at 6:47 PM, Rafael J. Wysocki<rjw@sisk.pl> wrote:
> > On Tuesday 02 June 2009, Magnus Damm wrote:
> >> I have to make sure that the right Kconfig bits are enabled though,
> >> otherwise some platform_pm_* functions will be missing. So one merit
> >> for the wrapped functions is in this patch is that they are always
> >> there regardless of CONFIG_SUSPEND and CONFIG_HIBERNATION.
> >
> > Make them depend on CONFIG_PM, then. They are not _that_ much code anyway,
> > we can easily afford building them even on platforms that really don't use
> > them,
> > but I expect them to be used by more and more platforms over time anyway.
> 
> Sure, good idea!
> 
> >> Is one flag really enough?
> >
> > Not necessarily, although I think we'll end up using one flag only.
> >
> >> Isn't it a bit strange from the driver point of view to always get their
> >> ->prepare() callback executed, but ->suspend() gets filtered?
> >
> > In fact, from the run-time PM POV, ->prepare() and ->suspend() should
> > always be executed together and ->suspend_noirq() shouldn't be executed
> > at all. Now, it may be necessary to execute some code from ->suspend_noirq()
> > for run-time PM too, but not by using this callback directly.
> 
> Why shouldn't _noirq() be used? I understand that _noirq callbacks
> assume that interrupts are not delivered.

Yes, the callbacks are exactly for this purpose.

> It looks to me that most drivers seem to misuse _noirq to work around
> ordering issues.

Yes, they do.

> They basically use suspend_late() or suspend_noirq()
> because they want to be sure that they are suspended after other
> drivers. For instance, i2c master controllers seem to want to suspend
> using suspend_late() to suspend after the i2c devices on the bus.
> 
> Do you have any pointer to code that manages the device hierarchy? Or
> is it up to the bus_type?

It should be up to the bus type.  In theory.

In fact we assume that the hierarchy is reflected by the ordering of dpm_list
(ie. "parent" devices should be put on the list before the "child" ones and
therefore they should be suspened later and resumed earlier).  This works
in the majority of cases, because bus controllers are usually registered
before the devices on the bus.  Still, there are other dependencies between
devices that we don't have any means to take into account at the moment.

> > Of course we should be avoiding double suspend, so some kind of
> > sychronization
> > between the "sleep" suspend and run-time suspend is necessary and I agree
> > that
> > it's probably most convenient to use some flags for this purpose. The
> > questions are how many flags we're going to need and how exactly we're going
> > to use them.
> 
> Exactly!
> 
> >> > (3) You can add separate platform callbacks for run-time PM for both the
> >> > bus type and the drivers, in which dev_pm_ops will be totally separate
> >> > from
> >> > these new callbacks, although of course you'll need provide some kind of
> >> > synchronization bettween them all.  That also may be done through a flag
> >> > in struct platform_device IMO.
> >>
> >> Yeah, that's also one way. I wonder if that helps us though, I feel
> >> that we already have a pretty wide range of callbacks in dev_pm_ops.
> >> I'm not sure if they cover all cases we need though, I guess future
> >> experiments will tell.
> >
> > Yes. Still, we can anticipate that the run-time PM operations may be
> > slightly
> > different from the 'sleep state' PM ones, in which case it makes sens to
> > introduce new callbacks, because that makes it clear(er) what the code is
> > supposed to do.
> 
> Sure, new callbacks are fine as well if you think that's better.

I really think so.

> >> If I understand (1)-(3) correctly, then I think (1) is probably the
> >> best choice for our platform devices.
> >
> > OK, for _your_ platform devices it may be the best choice, but what about
> > the other platforms' platform devices? Do you think (1) will be suitable for
> > them all and if so then why?
> 
> I can only speak for SuperH and a bit for ARM. I see a clear need for
> for run-time state saving at least. And I think dev_pm_ops ->freeze()
> and ->restore() seem like good matches for this, so yes, it's enough
> to begin with.
> 
> >> I guess (2) is not very far from (1), so if we go with (1) to begin with
> >> then we can deal with SoC specific things in our arch code to come closer
> >> to
> >> (2) over time if needed.
> 
> I think (1) is the simplest and does not require much changes to begin
> with. People can build stuff on top of this which we later can break
> out and make generic.

I'm not really comfortable with this approach, because it adds the constraint
that the 'system sleep' callbacks should _also_ be suitable for run-time PM.
That need not be the case in principle. 

> >> Maybe it's worth to discuss how to integrate this. I suspect that this
> >> will only affect some selected architectures to begin with, and the
> >> rest of the code base should be unaffected by this change as long as
> >> the runtime kconfig is disabled.
> >>
> >> So I decided to wrap dev_pm_ops to make the impact for non runtime PM
> >> systems as small as possible. This while giving the runtime PM case
> >> access to all dev_pm_ops regardless of suspend/hibernation kconfig.
> >>
> >> Does it make sense?
> >
> > Well, as I said above, I don't really think that run-time PM is going to
> > need
> > all of the callbacks from dev_pm_ops. Moreover, I'm not sure if it makes
> > sense to have more than two (call it 'autosuspend' and 'autoresume' using
> > the
> > already existing USB terminology) callbacks for run-time PM, at least at
> > the driver level.
> 
> For SuperH two callbacks for state saving and restoring is enough to
> begin with. Functionality wise this is very similar to dev_pm_ops
> ->freeze() and ->restore() so I think just using those should be fine.

I'd vote in favor of adding new callbacks.  If they happen to point to the same
code as the other dev_pm_ops callbacks in all cases, we can just drop them
later.  That should be easier than adding new callbacks when it appears they
are actually necessary at one point in future.

Best,
Rafael
--
To unsubscribe from this list: send the line "unsubscribe linux-sh" 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

--- 0003/arch/Kconfig
+++ work/arch/Kconfig	2009-05-26 21:22:17.000000000 +0900
@@ -118,3 +118,6 @@  config HAVE_PLATFORM_DEVICE_ARCHDATA
 
 config HAVE_PLATFORM_DEVICE_IDLE_WAKEUP
 	bool
+
+config HAVE_PLATFORM_DEVICE_RUNTIME_PM
+	bool
--- 0001/drivers/base/platform.c
+++ work/drivers/base/platform.c	2009-05-27 17:31:06.000000000 +0900
@@ -962,12 +962,203 @@  static struct dev_pm_ops platform_dev_pm
 
 #endif /* !CONFIG_PM_SLEEP */
 
+#ifdef CONFIG_HAVE_PLATFORM_DEVICE_RUNTIME_PM
+
+#define DEV_PM_OP_PREPARE offsetof(struct dev_pm_ops, prepare)
+#define DEV_PM_OP_COMPLETE offsetof(struct dev_pm_ops, complete)
+#define DEV_PM_OP_SUSPEND offsetof(struct dev_pm_ops, suspend)
+#define DEV_PM_OP_RESUME offsetof(struct dev_pm_ops, resume)
+#define DEV_PM_OP_FREEZE offsetof(struct dev_pm_ops, freeze)
+#define DEV_PM_OP_THAW offsetof(struct dev_pm_ops, thaw)
+#define DEV_PM_OP_POWEROFF offsetof(struct dev_pm_ops, poweroff)
+#define DEV_PM_OP_RESTORE offsetof(struct dev_pm_ops, restore)
+#define DEV_PM_OP_SUSPEND_NOIRQ offsetof(struct dev_pm_ops, suspend_noirq)
+#define DEV_PM_OP_RESUME_NOIRQ offsetof(struct dev_pm_ops, resume_noirq)
+#define DEV_PM_OP_FREEZE_NOIRQ offsetof(struct dev_pm_ops, freeze_noirq)
+#define DEV_PM_OP_THAW_NOIRQ offsetof(struct dev_pm_ops, thaw_noirq)
+#define DEV_PM_OP_POWEROFF_NOIRQ offsetof(struct dev_pm_ops, poweroff_noirq)
+#define DEV_PM_OP_RESTORE_NOIRQ offsetof(struct dev_pm_ops, restore_noirq)
+
+static DEFINE_SPINLOCK(platform_runtime_lock);
+
+static int platform_runtime_call_op(struct device *dev, unsigned int op)
+{
+	struct dev_pm_ops *dev_pm_ops = PLATFORM_PM_OPS_PTR;
+	void **vp = (void **)dev_pm_ops;
+	int (*int_op)(struct device *);
+
+	if (dev_pm_ops) {
+		if (op == DEV_PM_OP_COMPLETE) {
+			if (dev_pm_ops->complete)
+				dev_pm_ops->complete(dev);
+		} else {
+			int_op = vp[op / sizeof(void *)];
+			if (int_op)
+				return int_op(dev);
+		}
+	}
+
+	return 0;
+}
+
+static int platform_runtime_call_once(struct device *dev,
+				      unsigned int op)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	unsigned long flags;
+	int bit, bit_op, is_suspend, ret;
+
+	ret = 0;
+	is_suspend = 0;
+
+	switch (op) {
+	case DEV_PM_OP_COMPLETE:
+		bit_op = DEV_PM_OP_PREPARE;
+		break;
+	case DEV_PM_OP_RESUME:
+		bit_op = DEV_PM_OP_SUSPEND;
+		break;
+	case DEV_PM_OP_THAW:
+		bit_op = DEV_PM_OP_FREEZE;
+		break;
+	case DEV_PM_OP_RESTORE:
+		bit_op = DEV_PM_OP_POWEROFF;
+		break;
+	case DEV_PM_OP_RESUME_NOIRQ:
+		bit_op = DEV_PM_OP_SUSPEND_NOIRQ;
+		break;
+	case DEV_PM_OP_THAW_NOIRQ:
+		bit_op = DEV_PM_OP_FREEZE_NOIRQ;
+		break;
+	case DEV_PM_OP_RESTORE_NOIRQ:
+		bit_op = DEV_PM_OP_POWEROFF_NOIRQ;
+		break;
+	default:
+		bit_op = op;
+		is_suspend = 1;
+	}
+
+	bit = bit_op / sizeof(void *);
+
+	spin_lock_irqsave(&platform_runtime_lock, flags);
+
+	if (test_bit(bit, &pdev->runtime_flags) != is_suspend) {
+		ret = platform_runtime_call_op(dev, op);
+
+		if (!ret) {
+			if (is_suspend)
+				__set_bit(bit, &pdev->runtime_flags);
+			else
+				__clear_bit(bit, &pdev->runtime_flags);
+		}
+	}
+
+	spin_unlock_irqrestore(&platform_runtime_lock, flags);
+
+	return ret;
+}
+
+static int platform_runtime_prepare(struct device *dev)
+{
+	return platform_runtime_call_once(dev, DEV_PM_OP_PREPARE);
+}
+
+static void platform_runtime_complete(struct device *dev)
+{
+	platform_runtime_call_once(dev, DEV_PM_OP_COMPLETE);
+}
+
+static int platform_runtime_suspend(struct device *dev)
+{
+	return platform_runtime_call_once(dev, DEV_PM_OP_SUSPEND);
+}
+
+static int platform_runtime_resume(struct device *dev)
+{
+	return platform_runtime_call_once(dev, DEV_PM_OP_RESUME);
+}
+
+static int platform_runtime_freeze(struct device *dev)
+{
+	return platform_runtime_call_once(dev, DEV_PM_OP_FREEZE);
+}
+
+static int platform_runtime_thaw(struct device *dev)
+{
+	return platform_runtime_call_once(dev, DEV_PM_OP_THAW);
+}
+
+static int platform_runtime_poweroff(struct device *dev)
+{
+	return platform_runtime_call_once(dev, DEV_PM_OP_POWEROFF);
+}
+
+static int platform_runtime_restore(struct device *dev)
+{
+	return platform_runtime_call_once(dev, DEV_PM_OP_RESTORE);
+}
+
+static int platform_runtime_suspend_noirq(struct device *dev)
+{
+	return platform_runtime_call_once(dev, DEV_PM_OP_SUSPEND_NOIRQ);
+}
+
+static int platform_runtime_resume_noirq(struct device *dev)
+{
+	return platform_runtime_call_once(dev, DEV_PM_OP_RESUME_NOIRQ);
+}
+
+static int platform_runtime_freeze_noirq(struct device *dev)
+{
+	return platform_runtime_call_once(dev, DEV_PM_OP_FREEZE_NOIRQ);
+}
+
+static int platform_runtime_thaw_noirq(struct device *dev)
+{
+	return platform_runtime_call_once(dev, DEV_PM_OP_THAW_NOIRQ);
+}
+
+static int platform_runtime_poweroff_noirq(struct device *dev)
+{
+	return platform_runtime_call_once(dev, DEV_PM_OP_POWEROFF_NOIRQ);
+}
+
+static int platform_runtime_restore_noirq(struct device *dev)
+{
+	return platform_runtime_call_once(dev, DEV_PM_OP_RESTORE_NOIRQ);
+}
+
+struct dev_pm_ops platform_runtime_dev_pm_ops = {
+	.prepare = platform_runtime_prepare,
+	.complete = platform_runtime_complete,
+	.suspend = platform_runtime_suspend,
+	.resume = platform_runtime_resume,
+	.freeze = platform_runtime_freeze,
+	.thaw = platform_runtime_thaw,
+	.poweroff = platform_runtime_poweroff,
+	.restore = platform_runtime_restore,
+	.suspend_noirq = platform_runtime_suspend_noirq,
+	.resume_noirq = platform_runtime_resume_noirq,
+	.freeze_noirq = platform_runtime_freeze_noirq,
+	.thaw_noirq = platform_runtime_thaw_noirq,
+	.poweroff_noirq = platform_runtime_poweroff_noirq,
+	.restore_noirq = platform_runtime_restore_noirq,
+};
+
+#define PLATFORM_RUNTIME_PM_OPS_PTR	(&platform_runtime_dev_pm_ops)
+
+#else /* !CONFIG_HAVE_PLATFORM_DEVICE_RUNTIME_PM */
+
+#define PLATFORM_RUNTIME_PM_OPS_PTR	PLATFORM_PM_OPS_PTR
+
+#endif /* !CONFIG_HAVE_PLATFORM_DEVICE_RUNTIME_PM */
+
 struct bus_type platform_bus_type = {
 	.name		= "platform",
 	.dev_attrs	= platform_dev_attrs,
 	.match		= platform_match,
 	.uevent		= platform_uevent,
-	.pm		= PLATFORM_PM_OPS_PTR,
+	.pm		= PLATFORM_RUNTIME_PM_OPS_PTR,
 };
 EXPORT_SYMBOL_GPL(platform_bus_type);
 
--- 0003/include/linux/platform_device.h
+++ work/include/linux/platform_device.h	2009-05-26 21:22:17.000000000 +0900
@@ -27,6 +27,10 @@  struct platform_device {
 	/* arch specific additions */
 	struct pdev_archdata	archdata;
 #endif
+#ifdef CONFIG_HAVE_PLATFORM_DEVICE_RUNTIME_PM
+	unsigned long runtime_flags;
+#endif
+
 };
 
 #define platform_get_device_id(pdev)	((pdev)->id_entry)
@@ -65,6 +69,10 @@  static inline void platform_device_idle(
 static inline void platform_device_wakeup(struct platform_device *pdev) {}
 #endif
 
+#ifdef CONFIG_HAVE_PLATFORM_DEVICE_RUNTIME_PM
+extern struct dev_pm_ops platform_runtime_dev_pm_ops;
+#endif
+
 struct platform_driver {
 	int (*probe)(struct platform_device *);
 	int (*remove)(struct platform_device *);