📄 pm.c
字号:
if (mp200_sleep_mode == PM_SLEEP_MODE_NONE) { switch (state) { case PM_SUSPEND_STANDBY: sleep_mode = PM_SLEEP_MODE_S1; break; case PM_SUSPEND_MEM: sleep_mode = PM_SLEEP_MODE_S3; break; default: return; } } else { sleep_mode = mp200_sleep_mode; } printk(KERN_INFO "PM: mp200/%x is entering sleep now ...\n", system_rev); local_irq_disable(); local_fiq_disable();#ifdef CONFIG_MP200_RTC /* * lets figure out the offset of the RTC to our system time. */ memset(&rt, 0, sizeof(struct rtc_time)); get_rtc_time(&rt); mkt = mktime(rt.tm_year + 1900, rt.tm_mon + 1, rt.tm_mday, rt.tm_hour, rt.tm_min, rt.tm_sec); rtc_offset = (long)(xtime.tv_sec - mkt);#endif mp200_pm_intc_mask(PM_INTC_MASK_SAVE_AND_MASK, &intc_state); timer_set_clock(TIMER_SUSPEND); /* if clock is not 12MHz, then make the clock 12MHz */ pll_mode = mp200_pm_get_pll(); if(pll_mode != MP200_PLL_12MHZ) { mp200_pm_full_to_eco(); } mp200_pm_do_suspend(sleep_mode); mp200_pm_do_resume(); if(pll_mode == MP200_PLL_12MHZ) { mp200_pm_full_to_eco(); } else { mp200_pm_eco_to_full(pll_mode); } mp200_pm_update_lpj(); timer_set_clock(TIMER_RESUME); mp200_pm_intc_mask(PM_INTC_MASK_RESTORE, &intc_state);#ifdef CONFIG_MP200_RTC get_rtc_time(&rt); mkt = mktime(rt.tm_year + 1900, rt.tm_mon + 1, rt.tm_mday, rt.tm_hour, rt.tm_min, rt.tm_sec); xtime.tv_sec = mkt + rtc_offset;#endif local_fiq_enable(); local_irq_enable(); printk(KERN_INFO "PM: mp200/%x is re-starting from sleep...\n", system_rev);}static voidmp200_pm_set_poweroff_regs(void){ unsigned int n = 0; /* power OFF */ n += SET_PMU_CMDS(n, pmu_cmds_power_off); if (n >= PMU_CMD_BUF_RAM_SIZE) { printk(KERN_INFO "%s(): PMU command length over. (%d word)\n", __FUNCTION__, n); } /* setting pmu regs. */ /* power off sequence start address */ outl(0, PMU_PC); /* disable watch dog timer */ outl(PMU_WDT_DISABLE, PMU_WDT_COUNT_EN); /* set watch dog timer limit count */ outl(PMU_WDT_MAX_COUNT, PMU_WDT_COUNT_LMT);}static voidmp200_pm_do_poweroff(void){ unsigned int wfi_reg = 0; unsigned int regval; /* LCD panel off */ pwc_write(PWC_IOOUT2, 0x0, MASK_GPIO_LCDPANEL); /* setting pmu registers for poweroff */ mp200_pm_set_poweroff_regs(); /* disable interrupt */ outl(MASK_INTC_ALL, intc[0].ids); outl(MASK_INTC_ALL, intc[1].ids);#if 1 /* mwi APB clock control off */ outl(inl(SMU_APBCLKCTRL) & ~(0x00040000), SMU_APBCLKCTRL);#endif /* disable uwire int */ outl(MWI_ENCLR, MWI_INTENCLR); /* start PMU */ outl(PMU_START_SET, PMU_START); /* wait for pmu_start */ do { regval = inl(PMU_START); } while (regval != PMU_START_SET); /* save PEn regs and wait for interrupt */ __asm__ __volatile__ (" mcr p15, 0, %0, c7, c0, 4"::"r" (wfi_reg)); /* * PEn status moves to WFI, pmu command start at that time. * after warm boot handler done, pc return here */ regval = inl(PMU_START); if ((regval & PMU_START_SET) == PMU_START_SET) { outl(0, PMU_START); printk(KERN_INFO "%s(): PMU not run.\n", __FUNCTION__); }}void mp200_pm_power_off(void){ unsigned long irq_flags; /* int mask */ local_irq_save(irq_flags); /* noneed? */ timer_set_clock(TIMER_SUSPEND); /* if clock is not 12MHz, then make the clock 12MHz */ if (mp200_pm_get_pll() != MP200_PLL_12MHZ) { mp200_pm_full_to_eco(); } /* poweroff setting function*/ mp200_pm_do_poweroff(); printk(KERN_INFO "%s(): AFTER PMU POWER OFF.\n", __FUNCTION__); /* int unmask */ local_irq_restore(irq_flags); /* not call */}void mp200_pm_cache_clean(void){ flush_cache_all();}static int mp200_pm_prepare(suspend_state_t state){ switch (state) { case PM_SUSPEND_STANDBY: case PM_SUSPEND_MEM: break; case PM_SUSPEND_DISK: return -ENOTSUPP; default: return -EINVAL; } return 0;}static int mp200_pm_enter(suspend_state_t state){ switch (state) { case PM_SUSPEND_STANDBY: case PM_SUSPEND_MEM: mp200_pm_suspend(state); break; case PM_SUSPEND_DISK: return -ENOTSUPP; default: return -EINVAL; } return 0;}static int mp200_pm_finish(suspend_state_t state){ return 0;}static struct pm_ops mp200_pm_ops = { .pm_disk_mode = 0, .prepare = mp200_pm_prepare, .enter = mp200_pm_enter, .finish = mp200_pm_finish,};int mp200_pm_sleep(unsigned int mode){ suspend_state_t state; int ret; switch (mode) { case PM_SLEEP_MODE_S1: case PM_SLEEP_MODE_S2: state = PM_SUSPEND_STANDBY; break; case PM_SLEEP_MODE_S3: state = PM_SUSPEND_MEM; break; default: return -EINVAL; } mp200_sleep_mode = mode; ret = pm_suspend(state); mp200_sleep_mode = PM_SLEEP_MODE_NONE; return ret;}#ifdef CONFIG_PROC_FS/* * Writing to /proc/pm puts the CPU in sleep mode */static ssize_t mp200_pm_write_proc(struct file *file, const char *buffer, size_t count, loff_t * ppos){ char *buf; char *tok; char *s; char *str; char *whitespace = " \t\r\n"; int ret = 0; if (current->uid != 0) { return -EPERM; } if (count == 0) { return 0; } buf = kmalloc(count + 1, GFP_KERNEL); if (buf == NULL) { ret = -ENOMEM; goto exit_2; } if (copy_from_user(buf, buffer, count) != 0) { ret = -EFAULT; goto exit_1; } buf[count] = '\0'; s = buf + strspn(buf, whitespace); tok = strsep(&s, whitespace); str = "M248"; if (strnicmp(tok, str, strlen(str) + 1) == 0) { printk("248MHz...\n"); ret = mp200_pm_set_pll(MP200_PLL_248MHZ); goto exit_1; } str = "M164"; if (strnicmp(tok, str, strlen(str) + 1) == 0) { printk("164MHz...\n"); ret = mp200_pm_set_pll(MP200_PLL_164MHZ); goto exit_1; } str = "M124"; if (strnicmp(tok, str, strlen(str) + 1) == 0) { printk("124MHz...\n"); ret = mp200_pm_set_pll(MP200_PLL_124MHZ); goto exit_1; } str = "M83"; if (strnicmp(tok, str, strlen(str) + 1) == 0) { printk("83MHz...\n"); ret = mp200_pm_set_pll(MP200_PLL_83MHZ); goto exit_1; } str = "M50"; if (strnicmp(tok, str, strlen(str) + 1) == 0) { printk("50MHz...\n"); ret = mp200_pm_set_pll(MP200_PLL_50MHZ); goto exit_1; } str = "M12"; if (strnicmp(tok, str, strlen(str) + 1) == 0) { printk("12MHz(OSC)...\n"); ret = mp200_pm_set_pll(MP200_PLL_12MHZ); goto exit_1; } str = "S1"; if (strnicmp(tok, str, strlen(str) + 1) == 0) { ret = mp200_pm_sleep(PM_SLEEP_MODE_S1); goto exit_1; } str = "S2"; if (strnicmp(tok, str, strlen(str) + 1) == 0) { ret = mp200_pm_sleep(PM_SLEEP_MODE_S2); goto exit_1; } str = "S3"; if (strnicmp(tok, str, strlen(str) + 1) == 0) { ret = mp200_pm_sleep(PM_SLEEP_MODE_S3); goto exit_1; } str = "PD"; if (strnicmp(tok, str, strlen(str) + 1) == 0) { printk("MP201 PowerDown...\n"); mp200_pm_power_off(); goto exit_1; } ret = -EINVAL; exit_1: kfree(buf); exit_2: if (ret == 0) { return count; } return ret;}static int mp200_pm_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data){#ifdef PM_DEBUG_REG printk("** SMU registers dump ** \n"); printk("SMU_SMU_RESET_STATE = 0x%08x \n", inl(SMU_SMU_RESET_STATE)); printk("SMU_PLLSEL = 0x%08x \n", inl(SMU_PLLSEL)); printk("SMU_PLLSEL2 = 0x%08x \n", inl(SMU_PLLSEL2)); printk("SMU_LPLL_CTRL1 = 0x%08x \n", inl(SMU_LPLL_CTRL1)); printk("SMU_LPLL_CTRL2 = 0x%08x \n", inl(SMU_LPLL_CTRL2)); printk("SMU_HPLL_CTRL1 = 0x%08x \n", inl(SMU_HPLL_CTRL1)); printk("SMU_HPLL_CTRL2 = 0x%08x \n", inl(SMU_HPLL_CTRL2)); printk("SMU_HPLL_CTRL3 = 0x%08x \n", inl(SMU_HPLL_CTRL3)); printk("SMU_HPLL_CTRL4 = 0x%08x \n", inl(SMU_HPLL_CTRL4)); printk("SMU_CLK_DOMAIN_DIV = 0x%08x \n", inl(SMU_CLK_DOMAIN_DIV)); printk("SMU_OSC_CTRL = 0x%08x \n", inl(SMU_OSC_CTRL)); printk("SMU_AUTO_FRQ_CHANGE = 0x%08x \n", inl(SMU_AUTO_FRQ_CHANGE)); printk("** FIF registers dump ** \n"); printk("FIF_SDRCONFIGA = 0x%08x \n", inl(FIF_SDRCONFIGA)); printk("FIF_SDRCONFIGB = 0x%08x \n", inl(FIF_SDRCONFIGB)); printk("\n"); printk("loops_per_jiffy = 0x%08x \n", (unsigned int)loops_per_jiffy);#endif /* PM_DEBUG_REG */ return 0;}#endif /* CONFIG_PROC_FS */extern void (*mp200_change_pll_on_sram) (struct pll_param *);extern void (*mp200_change_osc_on_sram) (void);static int __init mp200_pm_init(void){#ifdef CONFIG_PROC_FS struct proc_dir_entry *entry;#endif#ifdef PM_POWERIC_ES_SWITCH unsigned int reg = 0;#endif printk(KERN_INFO "Starting pm.\n");#ifdef PM_POWERIC_ES_SWITCH if(pwc_read(PWC_LSIVER, ®) < 0) { return -EIO; } printk(KERN_INFO " RW5T735 LSIVER [%02x]\n", reg); if(reg <= PWC_LSIVER_ES1_1) { lsiver_old = 1; /* ES1.1 or less */ }#endif /* PM_POWERIC_ES_SWITCH */ pm_idle = mp200_pm_idle; /* * copy to SRAM */ if (warmboot_handler_size > (HANDLER_SIZE - 4)) { printk(KERN_INFO "warmboot handler size over. 0x%x\n", warmboot_handler_size); return -ENOMEM; } /* copy warm boot handler to SRAM S/W virtual area */ memcpy((void *)WARMBOOT_ADDR, warmboot_handler, warmboot_handler_size); mp200_change_pll_on_sram = (void (*)(struct pll_param *))(WARMBOOT_ADDR + ((unsigned int)mp200_change_pll - (unsigned int)warmboot_handler)); mp200_change_osc_on_sram = (void (*)(void))(WARMBOOT_ADDR + ((unsigned int)mp200_change_osc - (unsigned int)warmboot_handler));#ifdef PM_DEBUG_REG printk("mp200_change_pll_on_sram = 0x%08x \n", (unsigned int)mp200_change_pll_on_sram); printk("mp200_change_osc_on_sram = 0x%08x \n", (unsigned int)mp200_change_osc_on_sram);#endif /* PM_DEBUG_REG */ pm_set_ops(&mp200_pm_ops);#ifdef CONFIG_PROC_FS entry = create_proc_read_entry("pm", S_IWUSR | S_IRUGO, NULL, mp200_pm_read_proc, 0); if (entry == NULL) { return -ENOENT; } entry->write_proc = (write_proc_t *) mp200_pm_write_proc;#endif /* * set irq type of button (rising edge) */ set_irq_type(INT_PWC_GPIO_KEY_DATA0, IRQT_RISING); set_irq_type(INT_PWC_GPIO_KEY_DATA1, IRQT_HIGH); set_irq_type(INT_PWC_GPIO_KEY_DATA2, IRQT_RISING); set_irq_type(INT_PWC_GPIO_KEY_DATA3, IRQT_RISING); /* button (GPIO0-4) chattering On */ pwc_write(PWC_STATE1, MASK_GPIO_KEYDATA, MASK_GPIO_KEYDATA); /* USBWAK chattering Off */#ifdef PM_POWERIC_ES_SWITCH if(lsiver_old == 0) { pwc_write(PWC_STATE3, 0x00, MASK_USBWAKINT); }#else pwc_write(PWC_STATE3, 0x00, MASK_USBWAKINT);#endif /* !PM_POWERIC_ES_SWITCH */ pm_power_off = mp200_pm_power_off; return 0;}__initcall(mp200_pm_init);EXPORT_SYMBOL(mp200_pm_sleep);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -