ARM: Use struct syscore_ops instead of sysdevs for PM in common code

Convert some ARM architecture's common code to using
struct syscore_ops objects for power management instead of sysdev
classes and sysdevs.

This simplifies the code and reduces the kernel's memory footprint.
It also is necessary for removing sysdevs from the kernel entirely in
the future.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Rafael J. Wysocki 2011-04-22 22:02:33 +02:00
parent 5dd12af05c
commit 328f5cc302
5 changed files with 68 additions and 104 deletions

View File

@ -22,17 +22,16 @@
#include <linux/init.h>
#include <linux/list.h>
#include <linux/io.h>
#include <linux/sysdev.h>
#include <linux/syscore_ops.h>
#include <linux/device.h>
#include <linux/amba/bus.h>
#include <asm/mach/irq.h>
#include <asm/hardware/vic.h>
#if defined(CONFIG_PM)
#ifdef CONFIG_PM
/**
* struct vic_device - VIC PM device
* @sysdev: The system device which is registered.
* @irq: The IRQ number for the base of the VIC.
* @base: The register base for the VIC.
* @resume_sources: A bitmask of interrupts for resume.
@ -43,8 +42,6 @@
* @protect: Save for VIC_PROTECT.
*/
struct vic_device {
struct sys_device sysdev;
void __iomem *base;
int irq;
u32 resume_sources;
@ -59,11 +56,6 @@ struct vic_device {
static struct vic_device vic_devices[CONFIG_ARM_VIC_NR];
static int vic_id;
static inline struct vic_device *to_vic(struct sys_device *sys)
{
return container_of(sys, struct vic_device, sysdev);
}
#endif /* CONFIG_PM */
/**
@ -85,10 +77,9 @@ static void vic_init2(void __iomem *base)
writel(32, base + VIC_PL190_DEF_VECT_ADDR);
}
#if defined(CONFIG_PM)
static int vic_class_resume(struct sys_device *dev)
#ifdef CONFIG_PM
static void resume_one_vic(struct vic_device *vic)
{
struct vic_device *vic = to_vic(dev);
void __iomem *base = vic->base;
printk(KERN_DEBUG "%s: resuming vic at %p\n", __func__, base);
@ -107,13 +98,18 @@ static int vic_class_resume(struct sys_device *dev)
writel(vic->soft_int, base + VIC_INT_SOFT);
writel(~vic->soft_int, base + VIC_INT_SOFT_CLEAR);
return 0;
}
static int vic_class_suspend(struct sys_device *dev, pm_message_t state)
static void vic_resume(void)
{
int id;
for (id = vic_id - 1; id >= 0; id--)
resume_one_vic(vic_devices + id);
}
static void suspend_one_vic(struct vic_device *vic)
{
struct vic_device *vic = to_vic(dev);
void __iomem *base = vic->base;
printk(KERN_DEBUG "%s: suspending vic at %p\n", __func__, base);
@ -128,14 +124,21 @@ static int vic_class_suspend(struct sys_device *dev, pm_message_t state)
writel(vic->resume_irqs, base + VIC_INT_ENABLE);
writel(~vic->resume_irqs, base + VIC_INT_ENABLE_CLEAR);
}
static int vic_suspend(void)
{
int id;
for (id = 0; id < vic_id; id++)
suspend_one_vic(vic_devices + id);
return 0;
}
struct sysdev_class vic_class = {
.name = "vic",
.suspend = vic_class_suspend,
.resume = vic_class_resume,
struct syscore_ops vic_syscore_ops = {
.suspend = vic_suspend,
.resume = vic_resume,
};
/**
@ -147,30 +150,8 @@ struct sysdev_class vic_class = {
*/
static int __init vic_pm_init(void)
{
struct vic_device *dev = vic_devices;
int err;
int id;
if (vic_id == 0)
return 0;
err = sysdev_class_register(&vic_class);
if (err) {
printk(KERN_ERR "%s: cannot register class\n", __func__);
return err;
}
for (id = 0; id < vic_id; id++, dev++) {
dev->sysdev.id = id;
dev->sysdev.cls = &vic_class;
err = sysdev_register(&dev->sysdev);
if (err) {
printk(KERN_ERR "%s: failed to register device\n",
__func__);
return err;
}
}
if (vic_id > 0)
register_syscore_ops(&vic_syscore_ops);
return 0;
}

View File

@ -34,7 +34,6 @@
* timer interrupt which may be pending.
*/
struct sys_timer {
struct sys_device dev;
void (*init)(void);
void (*suspend)(void);
void (*resume)(void);

View File

@ -10,6 +10,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sysdev.h>
#include <linux/syscore_ops.h>
#include <asm/leds.h>
@ -69,29 +70,8 @@ static ssize_t leds_store(struct sys_device *dev,
static SYSDEV_ATTR(event, 0200, NULL, leds_store);
static int leds_suspend(struct sys_device *dev, pm_message_t state)
{
leds_event(led_stop);
return 0;
}
static int leds_resume(struct sys_device *dev)
{
leds_event(led_start);
return 0;
}
static int leds_shutdown(struct sys_device *dev)
{
leds_event(led_halted);
return 0;
}
static struct sysdev_class leds_sysclass = {
.name = "leds",
.shutdown = leds_shutdown,
.suspend = leds_suspend,
.resume = leds_resume,
};
static struct sys_device leds_device = {
@ -99,6 +79,28 @@ static struct sys_device leds_device = {
.cls = &leds_sysclass,
};
static int leds_suspend(void)
{
leds_event(led_stop);
return 0;
}
static void leds_resume(void)
{
leds_event(led_start);
}
static void leds_shutdown(void)
{
leds_event(led_halted);
}
static struct syscore_ops leds_syscore_ops = {
.shutdown = leds_shutdown,
.suspend = leds_suspend,
.resume = leds_resume,
};
static int __init leds_init(void)
{
int ret;
@ -107,6 +109,8 @@ static int __init leds_init(void)
ret = sysdev_register(&leds_device);
if (ret == 0)
ret = sysdev_create_file(&leds_device, &attr_event);
if (ret == 0)
register_syscore_ops(&leds_syscore_ops);
return ret;
}

View File

@ -21,7 +21,7 @@
#include <linux/timex.h>
#include <linux/errno.h>
#include <linux/profile.h>
#include <linux/sysdev.h>
#include <linux/syscore_ops.h>
#include <linux/timer.h>
#include <linux/irq.h>
@ -115,48 +115,37 @@ void timer_tick(void)
#endif
#if defined(CONFIG_PM) && !defined(CONFIG_GENERIC_CLOCKEVENTS)
static int timer_suspend(struct sys_device *dev, pm_message_t state)
static int timer_suspend(void)
{
struct sys_timer *timer = container_of(dev, struct sys_timer, dev);
if (timer->suspend != NULL)
timer->suspend();
if (system_timer->suspend)
system_timer->suspend();
return 0;
}
static int timer_resume(struct sys_device *dev)
static void timer_resume(void)
{
struct sys_timer *timer = container_of(dev, struct sys_timer, dev);
if (timer->resume != NULL)
timer->resume();
return 0;
if (system_timer->resume)
system_timer->resume();
}
#else
#define timer_suspend NULL
#define timer_resume NULL
#endif
static struct sysdev_class timer_sysclass = {
.name = "timer",
static struct syscore_ops timer_syscore_ops = {
.suspend = timer_suspend,
.resume = timer_resume,
};
static int __init timer_init_sysfs(void)
static int __init timer_init_syscore_ops(void)
{
int ret = sysdev_class_register(&timer_sysclass);
if (ret == 0) {
system_timer->dev.cls = &timer_sysclass;
ret = sysdev_register(&system_timer->dev);
}
register_syscore_ops(&timer_syscore_ops);
return ret;
return 0;
}
device_initcall(timer_init_sysfs);
device_initcall(timer_init_syscore_ops);
void __init time_init(void)
{

View File

@ -398,9 +398,9 @@ static void vfp_enable(void *unused)
}
#ifdef CONFIG_PM
#include <linux/sysdev.h>
#include <linux/syscore_ops.h>
static int vfp_pm_suspend(struct sys_device *dev, pm_message_t state)
static int vfp_pm_suspend(void)
{
struct thread_info *ti = current_thread_info();
u32 fpexc = fmrx(FPEXC);
@ -420,34 +420,25 @@ static int vfp_pm_suspend(struct sys_device *dev, pm_message_t state)
return 0;
}
static int vfp_pm_resume(struct sys_device *dev)
static void vfp_pm_resume(void)
{
/* ensure we have access to the vfp */
vfp_enable(NULL);
/* and disable it to ensure the next usage restores the state */
fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
return 0;
}
static struct sysdev_class vfp_pm_sysclass = {
.name = "vfp",
static struct syscore_ops vfp_pm_syscore_ops = {
.suspend = vfp_pm_suspend,
.resume = vfp_pm_resume,
};
static struct sys_device vfp_pm_sysdev = {
.cls = &vfp_pm_sysclass,
};
static void vfp_pm_init(void)
{
sysdev_class_register(&vfp_pm_sysclass);
sysdev_register(&vfp_pm_sysdev);
register_syscore_ops(&vfp_pm_syscore_ops);
}
#else
static inline void vfp_pm_init(void) { }
#endif /* CONFIG_PM */