关于2440的电源管理调试出现过的问题以及解决方法:
1、系统睡眠与唤醒,拿到普通的代码,出现的问题经常是进入睡眠后,GPIO唤醒总是导致系统重新启动,其实这是因为没有设置CPU的运行模式,而这运行模式是通过设置GPG13,GPG14,GPG15来进行的。所以就要想唤醒后恢复到睡眠之前的状态,则要在进入睡眠前设置这三个GPIO的模式,可以在arch/arm/plat-s3c24xx/pm.c文件中的s3c2410_pm_enter()中在进入谁面前,也就是执行__raw_writel(0x00, S3C2410_CLKCON)前加入如下三条语句:
__raw_writel(__raw_readl(S3C2410_EINTPEND), S3C2410_EINTPEND);
__raw_writel(__raw_readl(S3C2410_INTPND), S3C2410_INTPND);
__raw_writel(__raw_readl(S3C2410_SRCPND), S3C2410_SRCPND);
即可使系统恢复正常。
附:
我修改的s3c2410_pm_enter函数如下:
static int s3c2410_pm_enter(suspend_state_t state)
{
unsigned long regs_save[16];
int tmp;
/* ensure the debug is initialised (if enabled) */
s3c2410_pm_debug_init();
DBG("s3c2410_pm_enter(%d)\n", state);
/* our board doesn't support hard disk.*/
if (state != PM_SUSPEND_MEM) {
printk(KERN_ERR PFX "error: only PM_SUSPEND_MEM supported\n");
return -EINVAL;
}
if (pm_cpu_prep == NULL || pm_cpu_sleep == NULL) {
printk(KERN_ERR PFX "error: no cpu sleep functions set\n");
return -EINVAL;
}
/* configure pin GPF4 for wake-up */
// enable_irq_wake(IRQ_EINT4);
// s3c2410_gpio_cfgpin(S3C2410_GPF4,S3C2410_GPF4_EINT4);
// set_irq_type(IRQ_EINT4, IRQT_BOTHEDGE);
tmp = __raw_readl(S3C2410_EINTMASK);
tmp &= ~(1UL<<4);
__raw_writel(tmp,S3C2410_EINTMASK);
s3c2410_gpio_cfgpin(S3C2410_GPG13,S3C2410_GPG13_INP);//tfirst
s3c2410_gpio_cfgpin(S3C2410_GPG14,S3C2410_GPG14_INP);//tfirst
s3c2410_gpio_cfgpin(S3C2410_GPG15,S3C2410_GPG15_INP);//tfirst
/* check if we have anything to wake-up with... bad things seem
* to happen if you suspend with no wakeup (system will often
* require a full power-cycle)
*/
if (!any_allowed(s3c_irqwake_intmask, s3c_irqwake_intallow) &&
!any_allowed(s3c_irqwake_eintmask, s3c_irqwake_eintallow)) {
printk(KERN_ERR PFX "No sources enabled for wake-up!\n");
printk(KERN_ERR PFX "Aborting sleep\n");
return -EINVAL;
}
/* prepare check area if configured */
s3c2410_pm_check_prepare();
/* set USB pad as suspend mode ,tfirst add ,2009-05-27 */
__raw_writel(__raw_readl(S3C2410_MISCCR) | (3<<12),S3C2410_MISCCR);
/* store the physical address of the register recovery block */
s3c2410_sleep_save_phys = virt_to_phys(regs_save);
DBG("s3c2410_sleep_save_phys=0x%08lx\n", s3c2410_sleep_save_phys);
/* save resume address */
__raw_writel(virt_to_phys(s3c2410_cpu_resume), S3C2410_GSTATUS3);
/*clear the General Status Registers reg 2*/
__raw_writel(0xff,S3C2410_GSTATUS2);
/* save all necessary core registers not covered by the drivers */
s3c2410_pm_do_save(misc_save, ARRAY_SIZE(misc_save));
s3c2410_pm_do_save(gpio_save, ARRAY_SIZE(gpio_save));
s3c2410_pm_do_save(core_save, ARRAY_SIZE(core_save));
s3c2410_pm_do_save(uart_save, ARRAY_SIZE(uart_save));
/* set the irq configuration for wake */
s3c2410_pm_configure_extint();
DBG("sleep: irq wakeup masks: %08lx,%08lx\n",
s3c_irqwake_intmask, s3c_irqwake_eintmask);
__raw_writel(s3c_irqwake_intmask, S3C2410_INTMSK);
__raw_writel(s3c_irqwake_eintmask, S3C2410_EINTMASK);
/* ack any outstanding external interrupts before we go to sleep */
__raw_writel(__raw_readl(S3C2410_EINTPEND), S3C2410_EINTPEND);
__raw_writel(__raw_readl(S3C2410_INTPND), S3C2410_INTPND);
__raw_writel(__raw_readl(S3C2410_SRCPND), S3C2410_SRCPND); |