static struct rdev_sysfs_entry rdev_state =
__ATTR(state, S_IRUGO|S_IWUSR, state_show, state_store);
static ssize_t
state_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t n)
+-- pm_suspend(state);
+-- enter_state(state);
+-- suspend_prepare();
+-- suspend_test(TEST_FREEZER);
+-- suspend_devices_and_enter(state);//...
+-- suspend_finish();
int suspend_devices_and_enter(suspend_state_t state)
+-- trace_machine_suspend(state);
+-- suspend_console();
+-- dpm_suspend_start(PMSG_SUSPEND);
//调用每个设备的power.prepare()函数,然后将其移入dpm_prepared_list列表中
+-- dpm_prepare(state); //...
+-- while (!list_empty(&dpm_list)) {
struct device *dev = to_device(dpm_list.next);
device_prepare(dev, state);
dev->power.is_prepared = true;
if (!list_empty(&dev->power.entry))
list_move_tail(&dev->power.entry, &dpm_prepared_list);
}
+-- dpm_suspend(state);
//对"dpm_prepared_list"中的每个设备调用device_suspend()函数,然后将其移入
//dpm_suspended_list列表中
+-- while (!list_empty(&dpm_prepared_list)) {
struct device *dev = to_device(dpm_prepared_list.prev);
device_suspend(dev);
if (!list_empty(&dev->power.entry))
list_move(&dev->power.entry, &dpm_suspended_list);
}
+-- suspend_test(TEST_DEVICES)
+-- suspend_enter(state, &wakeup);
+-- suspend_ops->prepare();
+-- dpm_suspend_end(PMSG_SUSPEND); //这里应该调用唤醒各个设备的函数?
+-- suspend_ops->prepare_late();
+-- suspend_test(TEST_PLATFORM)
+-- disable_nonboot_cpus();
+-- arch_suspend_disable_irqs();
+-- irqs_disabled()
+-- syscore_suspend();
+-- *wakeup = pm_wakeup_pending();
+-- suspend_ops->enter(state); //最终在这里挂起...?
+-- syscore_resume();
+-- arch_suspend_enable_irqs();
+-- irqs_disabled()
+-- enable_nonboot_cpus();
+-- suspend_ops->wake();
+-- dpm_resume_start(PMSG_RESUME);
+-- suspend_ops->finish();
+-- suspend_test_start();
+-- dpm_resume_end(PMSG_RESUME);
+-- resume_console();
+-- suspend_ops->end();
+-- suspend_ops->recover();
device_initcall(pxa_pm_init);
static int __init pxa_pm_init(void)
+-- suspend_set_ops(&pxa_pm_ops);
+-- suspend_ops = ops;
static const struct platform_suspend_ops pxa_pm_ops = {
.valid = pxa_pm_valid,
.enter = pxa_pm_enter,
.prepare = pxa_pm_prepare,
.finish = pxa_pm_finish,
};
int device_register(struct device *dev)
+-- device_initialize(dev);
+-- device_pm_init(dev);
+-- pm_runtime_init(dev);
+-- device_add(dev);
//pm_runtime_init()对dev->power的相关属性进行了初始化(每个设备在想系统注册的时候)
void pm_runtime_init(struct device *dev)
{
dev->power.runtime_status = RPM_SUSPENDED;
dev->power.idle_notification = false;
dev->power.disable_depth = 1;
atomic_set(&dev->power.usage_count, 0);
dev->power.runtime_error = 0;
atomic_set(&dev->power.child_count, 0);
pm_suspend_ignore_children(dev, false);
dev->power.runtime_auto = true;
dev->power.request_pending = false;
dev->power.request = RPM_REQ_NONE;
dev->power.deferred_resume = false;
dev->power.accounting_timestamp = jiffies;
INIT_WORK(&dev->power.work, pm_runtime_work);
dev->power.timer_expires = 0;
setup_timer(&dev->power.suspend_timer, pm_suspend_timer_fn,
(unsigned long)dev);
dev->power.suspend_time = ktime_set(0, 0);
dev->power.max_time_suspended_ns = -1;
init_waitqueue_head(&dev->power.wait_queue);
}
int device_add(struct device *dev)
+-- device_add_attrs(dev);
+-- bus_add_device(dev);
+-- dpm_sysfs_add(dev);
+-- device_pm_add(dev);
//所有的设备都被链接到一个名为dpm_list的链表
+-- list_add_tail(&dev->power.entry, &dpm_list); //dpm_list...
+-- dev_pm_qos_constraints_init(dev);
+-- ...
static int
device_resume(struct device *dev, pm_message_t state, bool async)
+-- callback = pm_op(&dev->pm_domain->ops, state);
...
+-- callback = pm_op(dev->driver->pm, state); //优先级最高
+-- dpm_run_callback(callback, dev, state, info);
+-- calltime = initcall_debug_start(dev);
+-- cb(dev); //pm_op()选中的函数callback()在此处被回调
+-- initcall_debug_report(dev, calltime, error);
+-- complete_all(&dev->power.completion);
+-- if (put)
pm_runtime_put_sync(dev);
//__device_suspend()对于回调函数的选择过程与device_resume()类似
static int
device_suspend(struct device *dev)
+-- async_schedule(async_suspend, dev);
+-- __device_suspend(dev, pm_transition, false);
+-- __device_suspend(dev, pm_transition, false);
+-- dpm_wait_for_children(dev, async);
+-- callback = pm_op(&dev->pm_domain->ops, state);
...
//根据state从dev->driver->pm里面选出一个function()
+-- callback = pm_op(dev->driver->pm, state);
+-- dpm_run_callback(callback, dev, state, info);
+-- calltime = initcall_debug_start(dev);
+-- cb(dev); //pm_op()选中的函数callback()在此处被回调;
+-- initcall_debug_report(dev, calltime, error);
+-- complete_all(&dev->power.completion);
+-- __pm_runtime_disable(dev, false);
//pm_op()根据state指定的状态来选择调用dev_pm_ops中的那个函数
//而dev_pm_ops按优先级从高到低分别可能是
//driver->pm,bus->pm,class->pm,type->pm,pm_domain->ops
//优先级高者存在则用之,否则落入下一优先级
static pm_callback_t
pm_op(const struct dev_pm_ops *ops, pm_message_t state)
{
switch (state.event) {
#ifdef CONFIG_SUSPEND
case PM_EVENT_SUSPEND:
return ops->suspend;
case PM_EVENT_RESUME:
return ops->resume;
#endif /* CONFIG_SUSPEND */
#ifdef CONFIG_HIBERNATE_CALLBACKS
case PM_EVENT_FREEZE:
case PM_EVENT_QUIESCE:
return ops->freeze;
case PM_EVENT_HIBERNATE:
return ops->poweroff;
case PM_EVENT_THAW:
case PM_EVENT_RECOVER:
return ops->thaw;
break;
case PM_EVENT_RESTORE:
return ops->restore;
#endif /* CONFIG_HIBERNATE_CALLBACKS */
}
return NULL;
}
//以platform_driver为例:
static const struct dev_pm_ops atmel_trng_pm_ops = {
.suspend = atmel_trng_suspend,
.resume = atmel_trng_resume,
};
static struct platform_driver atmel_trng_driver = {
.probe = atmel_trng_probe,
.remove = __devexit_p(atmel_trng_remove),
//driver->pm->suspend()
//driver->pm->resume()
.driver = {
.name = "atmel-trng",
.owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &atmel_trng_pm_ops, //电源管理相关的操作在这里初始化...
#endif /* CONFIG_PM */
},
};
module_platform_driver(atmel_trng_driver);
//#define module_platform_driver(__platform_driver) \
// module_driver(__platform_driver, platform_driver_register, \
// platform_driver_unregister)
//#define module_driver(__driver, __register, __unregister, ...) \
//static int __init __driver##_init(void) \
//{ \
// return __register(&(__driver) , ##__VA_ARGS__); \
//} \
//module_init(__driver##_init); \
//static void __exit __driver##_exit(void) \
//{ \
// __unregister(&(__driver) , ##__VA_ARGS__); \
//} \
//module_exit(__driver##_exit);
int platform_driver_register(struct platform_driver *drv)
+-- driver_register(&drv->driver);
+-- bus_add_driver(drv);
+-- driver_attach(drv);
唤醒源的设置
void __init pxa3xx_init_irq(void)
+-- pxa_init_irq(56, pxa3xx_set_wake);
+-- pxa_init_ext_wakeup_irq(pxa3xx_set_wake);
+-- for (irq = IRQ_WAKEUP0; irq <= IRQ_WAKEUP1; irq++) {
//pxa_ext_wakeup_chip...
irq_set_chip_and_handler(irq, &pxa_ext_wakeup_chip, handle_edge_irq);
set_irq_flags(irq, IRQF_VALID);
}
+-- pxa_ext_wakeup_chip.irq_set_wake = fn; //pxa_ext_wakeup_chip.irq_set_wake ...
static int pxa3xx_set_wake(struct irq_data *d, unsigned int on)
{
unsigned long flags, mask = 0;
switch (d->irq) {
case IRQ_SSP3:
mask = ADXER_MFP_WSSP3;
break;
case IRQ_MSL:
mask = ADXER_WMSL0;
break;
……
}
local_irq_save(flags);
if (on)
wakeup_src |= mask;
else
wakeup_src &= ~mask; // wakeup_src...
local_irq_restore(flags);
return 0;
}
//NOTE: currently, the OBM (OEM Boot Module) binary comes along with
//PXA3xx development kits assumes that the resuming process continues
//with the address stored within the first 4 bytes of SDRAM. The PSPR
//register is used privately by BootROM and OBM, and _must_ be set to
//0x5c014000 for the moment.
static void pxa3xx_cpu_pm_suspend(void)
{
volatile unsigned long *p = (volatile void *)0xc0000000;
unsigned long saved_data = *p;
extern int pxa3xx_finish_suspend(unsigned long);
/* resuming from D2 requires the HSIO2/BOOT/TPM clocks enabled */
CKENA |= (1 << CKEN_BOOT) | (1 << CKEN_TPM);
CKENB |= 1 << (CKEN_HSIO2 & 0x1f);
/* clear and setup wakeup source */
AD3SR = ~0;
AD3ER = wakeup_src; //这里用到了wakeup_src...
ASCR = ASCR;
ARSR = ARSR;
PCFR |= (1u << 13); /* L1_DIS */
PCFR &= ~((1u << 12) | (1u << 1)); /* L0_EN | SL_ROD */
PSPR = 0x5c014000;
/* overwrite with the resume address */
*p = virt_to_phys(cpu_resume);
//extern int __cpu_suspend(unsigned long, int (*)(unsigned long));
//__cpu_suspend()和pxa3xx_finish_suspend()都是汇编实现的
cpu_suspend(0, pxa3xx_finish_suspend);
//+-- ret = __cpu_suspend(arg, fn);
//+-- if (ret == 0) {
// cpu_switch_mm(mm->pgd, mm);
// local_flush_tlb_all();
// }
//__cpu_suspend()@sleep.S
//./arch/arm/kernel/sleep.S:16:ENTRY(__cpu_suspend)
//./arch/arm/kernel/sleep.S:38: bl __cpu_suspend_save
//./arch/arm/kernel/sleep.S:41:ENDPROC(__cpu_suspend)
//pxa3xx_finish_suspend()@sleep.S
//./arch/arm/mach-pxa/sleep.S:29:ENTRY(pxa3xx_finish_suspend)
*p = saved_data;
AD3ER = 0;
}
//###########唤醒源设置函数@kernel/irq/manage.c#################
//irq_set_irq_wake - control irq power management wakeup
//@irq: interrupt to control
//@on: enable/disable power management wakeup
//Enable/disable power management wakeup mode, which is
//disabled by default. Enables and disables must match,
//just as they match for non-wakeup mode support.
//Wakeup mode lets this IRQ wake the system from sleep
//states like "suspend to RAM".
int irq_set_irq_wake(unsigned int irq, unsigned int on)
{
unsigned long flags;
struct irq_desc *desc = irq_get_desc_buslock(irq,&flags,
IRQ_GET_DESC_CHECK_GLOBAL);
int ret = 0;
if (!desc)
return -EINVAL;
if (on) {
if (desc->wake_depth++ == 0) {
ret = set_irq_wake_real(irq, on);
if (ret) desc->wake_depth = 0;
else irqd_set(&desc->irq_data, IRQD_WAKEUP_STATE);
}
} else {
if (desc->wake_depth == 0) {
WARN(1, "Unbalanced IRQ %d wake disable\n", irq);
} else if (--desc->wake_depth == 0) {
ret = set_irq_wake_real(irq, on);
if (ret) desc->wake_depth = 1;
else irqd_clear(&desc->irq_data, IRQD_WAKEUP_STATE);
}
}
irq_put_desc_busunlock(desc, flags);
return ret;
}
EXPORT_SYMBOL(irq_set_irq_wake);
//使用的时候只要调用该函数将具体的中断号设置为唤醒源即可。例如:
//static void __init cm_x300_init_da9030(void)
//+-- irq_set_irq_wake(IRQ_WAKEUP0, 1);
//即将中断号为IRQ_WAKEUP0的中断设为唤醒源。
int irq_set_irq_wake(unsigned int irq, unsigned int on)
+-- set_irq_wake_real(irq, on);
+-- struct irq_desc *desc = irq_to_desc(irq);
+-- if (desc->irq_data.chip->irq_set_wake)
ret = desc->irq_data.chip->irq_set_wake(&desc->irq_data, on);