Skip to content

Commit

Permalink
[PATCH] DRIVER MODEL: Get rid of the obsolete tri-level suspend/resum…
Browse files Browse the repository at this point in the history
…e callbacks

In PM v1, all devices were called at SUSPEND_DISABLE level.  Then
all devices were called at SUSPEND_SAVE_STATE level, and finally
SUSPEND_POWER_DOWN level.  However, with PM v2, to maintain
compatibility for platform devices, I arranged for the PM v2
suspend/resume callbacks to call the old PM v1 suspend/resume
callbacks three times with each level in order so that existing
drivers continued to work.

Since this is obsolete infrastructure which is no longer necessary,
we can remove it.  Here's an (untested) patch to do exactly that.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Russell King authored and gregkh committed Oct 28, 2005
1 parent a3a3395 commit 9480e30
Show file tree
Hide file tree
Showing 66 changed files with 325 additions and 692 deletions.
60 changes: 2 additions & 58 deletions Documentation/driver-model/driver.txt
Original file line number Diff line number Diff line change
Expand Up @@ -196,67 +196,11 @@ it into a supported low-power state.

int (*suspend) (struct device * dev, pm_message_t state, u32 level);

suspend is called to put the device in a low power state. There are
several stages to successfully suspending a device, which is denoted in
the @level parameter. Breaking the suspend transition into several
stages affords the platform flexibility in performing device power
management based on the requirements of the system and the
user-defined policy.

SUSPEND_NOTIFY notifies the device that a suspend transition is about
to happen. This happens on system power state transitions to verify
that all devices can successfully suspend.

A driver may choose to fail on this call, which should cause the
entire suspend transition to fail. A driver should fail only if it
knows that the device will not be able to be resumed properly when the
system wakes up again. It could also fail if it somehow determines it
is in the middle of an operation too important to stop.

SUSPEND_DISABLE tells the device to stop I/O transactions. When it
stops transactions, or what it should do with unfinished transactions
is a policy of the driver. After this call, the driver should not
accept any other I/O requests.

SUSPEND_SAVE_STATE tells the device to save the context of the
hardware. This includes any bus-specific hardware state and
device-specific hardware state. A pointer to this saved state can be
stored in the device's saved_state field.

SUSPEND_POWER_DOWN tells the driver to place the device in the low
power state requested.

Whether suspend is called with a given level is a policy of the
platform. Some levels may be omitted; drivers must not assume the
reception of any level. However, all levels must be called in the
order above; i.e. notification will always come before disabling;
disabling the device will come before suspending the device.

All calls are made with interrupts enabled, except for the
SUSPEND_POWER_DOWN level.
suspend is called to put the device in a low power state.

int (*resume) (struct device * dev, u32 level);

Resume is used to bring a device back from a low power state. Like the
suspend transition, it happens in several stages.

RESUME_POWER_ON tells the driver to set the power state to the state
before the suspend call (The device could have already been in a low
power state before the suspend call to put in a lower power state).

RESUME_RESTORE_STATE tells the driver to restore the state saved by
the SUSPEND_SAVE_STATE suspend call.

RESUME_ENABLE tells the driver to start accepting I/O transactions
again. Depending on driver policy, the device may already have pending
I/O requests.

RESUME_POWER_ON is called with interrupts disabled. The other resume
levels are called with interrupts enabled.

As with the various suspend stages, the driver must not assume that
any other resume calls have been or will be made. Each call should be
self-contained and not dependent on any external state.
Resume is used to bring a device back from a low power state.


Attributes
Expand Down
10 changes: 2 additions & 8 deletions arch/arm/common/locomo.c
Original file line number Diff line number Diff line change
Expand Up @@ -550,15 +550,12 @@ struct locomo_save_data {
u16 LCM_SPIMD;
};

static int locomo_suspend(struct device *dev, pm_message_t state, u32 level)
static int locomo_suspend(struct device *dev, pm_message_t state)
{
struct locomo *lchip = dev_get_drvdata(dev);
struct locomo_save_data *save;
unsigned long flags;

if (level != SUSPEND_DISABLE)
return 0;

save = kmalloc(sizeof(struct locomo_save_data), GFP_KERNEL);
if (!save)
return -ENOMEM;
Expand Down Expand Up @@ -597,16 +594,13 @@ static int locomo_suspend(struct device *dev, pm_message_t state, u32 level)
return 0;
}

static int locomo_resume(struct device *dev, u32 level)
static int locomo_resume(struct device *dev)
{
struct locomo *lchip = dev_get_drvdata(dev);
struct locomo_save_data *save;
unsigned long r;
unsigned long flags;

if (level != RESUME_ENABLE)
return 0;

save = (struct locomo_save_data *) dev->power.saved_state;
if (!save)
return 0;
Expand Down
11 changes: 2 additions & 9 deletions arch/arm/common/sa1111.c
Original file line number Diff line number Diff line change
Expand Up @@ -801,17 +801,14 @@ struct sa1111_save_data {

#ifdef CONFIG_PM

static int sa1111_suspend(struct device *dev, pm_message_t state, u32 level)
static int sa1111_suspend(struct device *dev, pm_message_t state)
{
struct sa1111 *sachip = dev_get_drvdata(dev);
struct sa1111_save_data *save;
unsigned long flags;
unsigned int val;
void __iomem *base;

if (level != SUSPEND_DISABLE)
return 0;

save = kmalloc(sizeof(struct sa1111_save_data), GFP_KERNEL);
if (!save)
return -ENOMEM;
Expand Down Expand Up @@ -856,23 +853,19 @@ static int sa1111_suspend(struct device *dev, pm_message_t state, u32 level)
/*
* sa1111_resume - Restore the SA1111 device state.
* @dev: device to restore
* @level: resume level
*
* Restore the general state of the SA1111; clock control and
* interrupt controller. Other parts of the SA1111 must be
* restored by their respective drivers, and must be called
* via LDM after this function.
*/
static int sa1111_resume(struct device *dev, u32 level)
static int sa1111_resume(struct device *dev)
{
struct sa1111 *sachip = dev_get_drvdata(dev);
struct sa1111_save_data *save;
unsigned long flags, id;
void __iomem *base;

if (level != RESUME_ENABLE)
return 0;

save = (struct sa1111_save_data *)dev->power.saved_state;
if (!save)
return 0;
Expand Down
24 changes: 11 additions & 13 deletions arch/arm/common/scoop.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,26 +102,24 @@ static void check_scoop_reg(struct scoop_dev *sdev)
}

#ifdef CONFIG_PM
static int scoop_suspend(struct device *dev, pm_message_t state, uint32_t level)
static int scoop_suspend(struct device *dev, pm_message_t state)
{
if (level == SUSPEND_POWER_DOWN) {
struct scoop_dev *sdev = dev_get_drvdata(dev);
struct scoop_dev *sdev = dev_get_drvdata(dev);

check_scoop_reg(sdev);
sdev->scoop_gpwr = SCOOP_REG(sdev->base, SCOOP_GPWR);
SCOOP_REG(sdev->base, SCOOP_GPWR) = (sdev->scoop_gpwr & ~sdev->suspend_clr) | sdev->suspend_set;

check_scoop_reg(sdev);
sdev->scoop_gpwr = SCOOP_REG(sdev->base, SCOOP_GPWR);
SCOOP_REG(sdev->base, SCOOP_GPWR) = (sdev->scoop_gpwr & ~sdev->suspend_clr) | sdev->suspend_set;
}
return 0;
}

static int scoop_resume(struct device *dev, uint32_t level)
static int scoop_resume(struct device *dev)
{
if (level == RESUME_POWER_ON) {
struct scoop_dev *sdev = dev_get_drvdata(dev);
struct scoop_dev *sdev = dev_get_drvdata(dev);

check_scoop_reg(sdev);
SCOOP_REG(sdev->base,SCOOP_GPWR) = sdev->scoop_gpwr;

check_scoop_reg(sdev);
SCOOP_REG(sdev->base,SCOOP_GPWR) = sdev->scoop_gpwr;
}
return 0;
}
#else
Expand Down
24 changes: 11 additions & 13 deletions arch/arm/mach-pxa/corgi_ssp.c
Original file line number Diff line number Diff line change
Expand Up @@ -222,24 +222,22 @@ static int corgi_ssp_remove(struct device *dev)
return 0;
}

static int corgi_ssp_suspend(struct device *dev, pm_message_t state, u32 level)
static int corgi_ssp_suspend(struct device *dev, pm_message_t state)
{
if (level == SUSPEND_POWER_DOWN) {
ssp_flush(&corgi_ssp_dev);
ssp_save_state(&corgi_ssp_dev,&corgi_ssp_state);
}
ssp_flush(&corgi_ssp_dev);
ssp_save_state(&corgi_ssp_dev,&corgi_ssp_state);

return 0;
}

static int corgi_ssp_resume(struct device *dev, u32 level)
static int corgi_ssp_resume(struct device *dev)
{
if (level == RESUME_POWER_ON) {
GPSR(ssp_machinfo->cs_lcdcon) = GPIO_bit(ssp_machinfo->cs_lcdcon); /* High - Disable LCD Control/Timing Gen */
GPSR(ssp_machinfo->cs_max1111) = GPIO_bit(ssp_machinfo->cs_max1111); /* High - Disable MAX1111*/
GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846); /* High - Disable ADS7846*/
ssp_restore_state(&corgi_ssp_dev,&corgi_ssp_state);
ssp_enable(&corgi_ssp_dev);
}
GPSR(ssp_machinfo->cs_lcdcon) = GPIO_bit(ssp_machinfo->cs_lcdcon); /* High - Disable LCD Control/Timing Gen */
GPSR(ssp_machinfo->cs_max1111) = GPIO_bit(ssp_machinfo->cs_max1111); /* High - Disable MAX1111*/
GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846); /* High - Disable ADS7846*/
ssp_restore_state(&corgi_ssp_dev,&corgi_ssp_state);
ssp_enable(&corgi_ssp_dev);

return 0;
}

Expand Down
30 changes: 12 additions & 18 deletions arch/arm/mach-sa1100/neponset.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,33 +178,27 @@ static int neponset_probe(struct device *dev)
/*
* LDM power management.
*/
static int neponset_suspend(struct device *dev, pm_message_t state, u32 level)
static int neponset_suspend(struct device *dev, pm_message_t state)
{
/*
* Save state.
*/
if (level == SUSPEND_SAVE_STATE ||
level == SUSPEND_DISABLE ||
level == SUSPEND_POWER_DOWN) {
if (!dev->power.saved_state)
dev->power.saved_state = kmalloc(sizeof(unsigned int), GFP_KERNEL);
if (!dev->power.saved_state)
return -ENOMEM;

*(unsigned int *)dev->power.saved_state = NCR_0;
}
if (!dev->power.saved_state)
dev->power.saved_state = kmalloc(sizeof(unsigned int), GFP_KERNEL);
if (!dev->power.saved_state)
return -ENOMEM;

*(unsigned int *)dev->power.saved_state = NCR_0;

return 0;
}

static int neponset_resume(struct device *dev, u32 level)
static int neponset_resume(struct device *dev)
{
if (level == RESUME_RESTORE_STATE || level == RESUME_ENABLE) {
if (dev->power.saved_state) {
NCR_0 = *(unsigned int *)dev->power.saved_state;
kfree(dev->power.saved_state);
dev->power.saved_state = NULL;
}
if (dev->power.saved_state) {
NCR_0 = *(unsigned int *)dev->power.saved_state;
kfree(dev->power.saved_state);
dev->power.saved_state = NULL;
}

return 0;
Expand Down
20 changes: 6 additions & 14 deletions drivers/base/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -281,27 +281,19 @@ static int platform_suspend(struct device * dev, pm_message_t state)
{
int ret = 0;

if (dev->driver && dev->driver->suspend) {
ret = dev->driver->suspend(dev, state, SUSPEND_DISABLE);
if (ret == 0)
ret = dev->driver->suspend(dev, state, SUSPEND_SAVE_STATE);
if (ret == 0)
ret = dev->driver->suspend(dev, state, SUSPEND_POWER_DOWN);
}
if (dev->driver && dev->driver->suspend)
ret = dev->driver->suspend(dev, state);

return ret;
}

static int platform_resume(struct device * dev)
{
int ret = 0;

if (dev->driver && dev->driver->resume) {
ret = dev->driver->resume(dev, RESUME_POWER_ON);
if (ret == 0)
ret = dev->driver->resume(dev, RESUME_RESTORE_STATE);
if (ret == 0)
ret = dev->driver->resume(dev, RESUME_ENABLE);
}
if (dev->driver && dev->driver->resume)
ret = dev->driver->resume(dev);

return ret;
}

Expand Down
20 changes: 9 additions & 11 deletions drivers/char/s3c2410-rtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -519,30 +519,28 @@ static struct timespec s3c2410_rtc_delta;

static int ticnt_save;

static int s3c2410_rtc_suspend(struct device *dev, pm_message_t state, u32 level)
static int s3c2410_rtc_suspend(struct device *dev, pm_message_t state)
{
struct rtc_time tm;
struct timespec time;

time.tv_nsec = 0;

if (level == SUSPEND_POWER_DOWN) {
/* save TICNT for anyone using periodic interrupts */
/* save TICNT for anyone using periodic interrupts */

ticnt_save = readb(S3C2410_TICNT);
ticnt_save = readb(S3C2410_TICNT);

/* calculate time delta for suspend */
/* calculate time delta for suspend */

s3c2410_rtc_gettime(&tm);
rtc_tm_to_time(&tm, &time.tv_sec);
save_time_delta(&s3c2410_rtc_delta, &time);
s3c2410_rtc_enable(dev, 0);
}
s3c2410_rtc_gettime(&tm);
rtc_tm_to_time(&tm, &time.tv_sec);
save_time_delta(&s3c2410_rtc_delta, &time);
s3c2410_rtc_enable(dev, 0);

return 0;
}

static int s3c2410_rtc_resume(struct device *dev, u32 level)
static int s3c2410_rtc_resume(struct device *dev)
{
struct rtc_time tm;
struct timespec time;
Expand Down
14 changes: 6 additions & 8 deletions drivers/char/sonypi.c
Original file line number Diff line number Diff line change
Expand Up @@ -1167,19 +1167,17 @@ static int sonypi_disable(void)
#ifdef CONFIG_PM
static int old_camera_power;

static int sonypi_suspend(struct device *dev, pm_message_t state, u32 level)
static int sonypi_suspend(struct device *dev, pm_message_t state)
{
if (level == SUSPEND_DISABLE) {
old_camera_power = sonypi_device.camera_power;
sonypi_disable();
}
old_camera_power = sonypi_device.camera_power;
sonypi_disable();

return 0;
}

static int sonypi_resume(struct device *dev, u32 level)
static int sonypi_resume(struct device *dev)
{
if (level == RESUME_ENABLE)
sonypi_enable(old_camera_power);
sonypi_enable(old_camera_power);
return 0;
}
#endif
Expand Down
Loading

0 comments on commit 9480e30

Please sign in to comment.