由上一次的分析可知,在suspend_ops->enter(state);中会进行唤醒源的配置。下面分析平台代码:
//位于linux-3.18\arch\arm\plat-samsung\pm.c
static int s3c_pm_enter(suspend_state_t state)
{
int ret;
/* ensure the debug is initialised (if enabled) */
s3c_pm_debug_init();
S3C_PMDBG("%s(%d)\n", __func__, state);
if (pm_cpu_prep == NULL || pm_cpu_sleep == NULL) {
printk(KERN_ERR "%s: error: no cpu sleep function\n", __func__);
return -EINVAL;
}
/*
这里会检查是否配置了唤醒源s3c_irqwake_intmask=0xffffffffL s3c_irqwake_eintmask= 0xffffffff表示无内外唤醒源,如果设置成0xfffffffe表示bit0为内部唤醒源,可以通过调用s3c_irq_wake或s3c_irqext_wake配置哪个引脚是内部或者外部唤醒源
*/
if (!of_have_populated_dt() &&
!any_allowed(s3c_irqwake_intmask, s3c_irqwake_intallow) &&
!any_allowed(s3c_irqwake_eintmask, s3c_irqwake_eintallow)) {
printk(KERN_ERR "%s: No wake-up sources!\n", __func__);
printk(KERN_ERR "%s: Aborting sleep\n", __func__);
return -EINVAL;
}
/* save all necessary core registers not covered by the drivers */
if (!of_have_populated_dt()) {
samsung_pm_save_gpios();
samsung_pm_saved_gpios();
}
s3c_pm_save_uarts();
s3c_pm_save_core();
/*配置外部中断引脚
*/
s3c_pm_configure_extint();
S3C_PMDBG("sleep: irq wakeup masks: %08lx,%08lx\n",
s3c_irqwake_intmask, s3c_irqwake_eintmask);
s3c_pm_arch_prepare_irqs();
/* call cpu specific preparation */
pm_cpu_prep();
/* flush cache back to ram */
flush_cache_all();
s3c_pm_check_store();
/* send the cpu to sleep... */
s3c_pm_arch_stop_clocks();
/* this will also act as our return point from when
* we resume as it saves its own register state and restores it
* during the resume. */
ret = cpu_suspend(0, pm_cpu_sleep);
if (ret)
return ret;
/* restore the system state */
s3c_pm_restore_core();
s3c_pm_restore_uarts();
if (!of_have_populated_dt()) {
samsung_pm_restore_gpios();
s3c_pm_restored_gpios();
}
s3c_pm_debug_init();
/* check what irq (if any) restored the system */
s3c_pm_arch_show_resume_irqs();
S3C_PMDBG("%s: post sleep, preparing to return\n", __func__);
/* LEDs should now be 1110 */
s3c_pm_debug_smdkled(1 << 1, 0);
s3c_pm_check_restore();
/* ok, let's return from sleep */
S3C_PMDBG("S3C PM Resume (post-restore)\n");
return 0;
}
怎样修改内核:
a. 通过调用s3c_irq_wake来修改s3c_irqwake_intmask、s3c_irqwake_eintmask用来表示唤醒源是哪个
b. 需要自己设置GPIO用于中断功能,并设置它的触发方式
s3c2440中可以配置内部唤醒源有:int0,1,2,3
外部中断可以配置唤醒源有eint4,5,…15
在我们的按键驱动中: request_irq之后调用s3c_irq_wake或s3c_irqext_wake
示例代码:
for (i = 0; i < 4; i++)
{
request_irq(pins_desc[i].irq, buttons_irq, (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING), pins_desc[i].name, &pins_desc[i]);
}
/* 指定这些中断可以用于唤醒系统 ,这里指定了IRQ_EINT0,IRQ_EINT2,IRQ_EINT11
irq_set_irq_wake表示
*/
irq_set_irq_wake(IRQ_EINT0, 1);
irq_set_irq_wake(IRQ_EINT2, 1);
irq_set_irq_wake(IRQ_EINT11, 1);