static void scal_volt_func(struct work_struct *work) { int ret = 0; ret = regulator_set_voltage(regulator, volt, volt); if (ret) { PM_ERR("regulator_set_voltage failed!\n"); PM_ERR("stop!\n"); return; } else PM_DBG("regulator_set_voltage: %d(uV)\n",volt); if (volt_direction == VOLT_DOWN) { volt = volt - volt_step; if(volt < stop_volt) { PM_DBG("stop!\n"); return; } } else if (volt_direction == VOLT_UP) { volt = volt + volt_step; if (volt > stop_volt) { PM_DBG("stop!\n"); return; } } queue_delayed_work(scal_volt_wq, &scal_volt_work, msecs_to_jiffies(timer_tick*1000)); }
void parse_dpm_list(struct list_head *head, unsigned int idx) { struct list_head *list; struct soc_device *dev; PM_DBG("(%p)", head); list_for_each(list, head) { dev = to_device(list, idx); PM_DBG("-->%s(%p)", dev->name, dev); }
ssize_t clk_rate_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t n) { struct dvfs_node *clk_dvfs_node = NULL; char cmd[20], clk_name[20], msg[50]; int rate; printk("%s: %s\n", __func__, buf); sscanf(buf, "%s %s %d", cmd, clk_name, &rate); clk_dvfs_node = clk_get_dvfs_node(clk_name); if (!clk_dvfs_node) { PM_ERR("%s: clk(%s) get dvfs node error\n", __func__, clk_name); return n; } if (0 == strncmp(cmd, "set", strlen("set"))) { PM_DBG("Get command set %s %dHz\n", clk_name, rate); if (file_read(FILE_GOV_MODE, msg) != 0) { PM_ERR("read current governor error\n"); return n; } else { PM_DBG("current governor = %s\n", msg); } strcpy(msg, "userspace"); if (file_write(FILE_GOV_MODE, msg) != 0) { PM_ERR("set current governor error\n"); return n; } dvfs_clk_enable_limit(clk_dvfs_node, rate, rate); dvfs_clk_set_rate(clk_dvfs_node, rate); } else if (0 == strncmp(cmd, "reset", strlen("reset"))) { PM_DBG("Get command reset %s\n", clk_name); if (file_read(FILE_GOV_MODE, msg) != 0) { PM_ERR("read current governor error\n"); return n; } else { PM_DBG("current governor = %s\n", msg); } strcpy(msg, "interactive"); if (file_write(FILE_GOV_MODE, msg) != 0) { PM_ERR("set current governor error\n"); return n; } dvfs_clk_disable_limit(clk_dvfs_node); } return n; }
int aw_pm_begin(suspend_state_t state) { struct cpufreq_policy *policy; PM_DBG("%d state begin:%d\n", state,debug_mask); //set freq max #ifdef CONFIG_CPU_FREQ_USR_EVNT_NOTIFY //cpufreq_user_event_notify(); #endif backup_max_freq = 0; backup_min_freq = 0; policy = cpufreq_cpu_get(0); if (!policy) { PM_DBG("line:%d cpufreq_cpu_get failed!\n", __LINE__); goto out; } backup_max_freq = policy->max; backup_min_freq = policy->min; policy->user_policy.max= suspend_freq; policy->user_policy.min = suspend_freq; cpufreq_cpu_put(policy); cpufreq_update_policy(0); /*must init perfcounter, because delay_us and delay_ms is depandant perf counter*/ #ifndef GET_CYCLE_CNT backup_perfcounter(); init_perfcounters (1, 0); #endif if(unlikely(debug_mask&PM_STANDBY_PRINT_REG)){ printk("before dev suspend , line:%d\n", __LINE__); show_reg(SW_VA_CCM_IO_BASE, (CCU_REG_LENGTH)*4, "ccu"); show_reg(SW_VA_PORTC_IO_BASE, GPIO_REG_LENGTH*4, "gpio"); show_reg(SW_VA_TIMERC_IO_BASE, TMR_REG_LENGTH*4, "timer"); show_reg(SW_VA_TWI0_IO_BASE, TWI0_REG_LENGTH*4, "twi0"); show_reg(SW_VA_SRAM_IO_BASE, SRAM_REG_LENGTH*4, "sram"); if (userdef_reg_addr != 0 && userdef_reg_size != 0) { show_reg(userdef_reg_addr, userdef_reg_size*4, "user defined"); } } return 0; out: return -1; }
static void arm_mode_timer_handler(unsigned long data) { int i; PM_DBG("enter %s\n", __func__); if (cpu_usage_run == 0) { PM_DBG("STOP\n"); return ; } arm_mode_timer.expires = jiffies + msecs_to_jiffies(ARM_MODE_TIMER_MSEC); add_timer(&arm_mode_timer); for(i = 0; i < cpu_usage_percent; i++) { mdelay(1); } }
ssize_t cpu_usage_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t n) { struct workqueue_struct *workqueue; struct work_struct *work; char cmd[20]; int usage = 0; int cpu; sscanf(buf, "%s %d", cmd, &usage); if((!strncmp(cmd, "start", strlen("start")))) { PM_DBG("get cmd start\n"); cpu_usage_run = 1; cpu_usage_percent = (ARM_MODE_TIMER_MSEC * usage) / 100; for_each_online_cpu(cpu){ work = &per_cpu(work_cpu_usage, cpu); workqueue = per_cpu(workqueue_cpu_usage, cpu); if (!work || !workqueue){ PM_ERR("work or workqueue NULL\n"); return n; } queue_work_on(cpu, workqueue, work); } #if 0 del_timer(&arm_mode_timer); arm_mode_timer.expires = jiffies + msecs_to_jiffies(ARM_MODE_TIMER_MSEC); add_timer(&arm_mode_timer); #endif } else if (!strncmp(cmd, "stop", strlen("stop"))) {
int aw_pm_begin(suspend_state_t state) { PM_DBG("%d state begin:%d\n", state,debug_mask); //set freq max #ifdef CONFIG_CPU_FREQ_USR_EVNT_NOTIFY //cpufreq_user_event_notify(); #endif /*must init perfcounter, because delay_us and delay_ms is depandant perf counter*/ #ifndef GET_CYCLE_CNT backup_perfcounter(); init_perfcounters (1, 0); #endif if(unlikely(debug_mask&PM_STANDBY_PRINT_REG)){ printk("before dev suspend , line:%d\n", __LINE__); show_reg(SW_VA_CCM_IO_BASE, (CCU_REG_LENGTH)*4, "ccu"); show_reg(SW_VA_PORTC_IO_BASE, GPIO_REG_LENGTH*4, "gpio"); show_reg(SW_VA_TIMERC_IO_BASE, TMR_REG_LENGTH*4, "timer"); show_reg(SW_VA_TWI0_IO_BASE, TWI0_REG_LENGTH*4, "twi0"); show_reg(SW_VA_SRAM_IO_BASE, SRAM_REG_LENGTH*4, "sram"); if (userdef_reg_addr != 0 && userdef_reg_size != 0) { show_reg(userdef_reg_addr, userdef_reg_size*4, "user defined"); } } return 0; }
static int file_write(char *file_path, char *buf) { struct file *file = NULL; mm_segment_t old_fs; loff_t offset = 0; PM_DBG("write %s %s size = %d\n", file_path, buf, strlen(buf)); file = filp_open(file_path, O_RDWR, 0); if (IS_ERR(file)) { PM_ERR("%s error open file %s\n", __func__, file_path); return -1; } old_fs = get_fs(); set_fs(KERNEL_DS); file->f_op->write(file, (char *)buf, strlen(buf), &offset); set_fs(old_fs); filp_close(file, NULL); file = NULL; return 0; }
static int file_read(char *file_path, char *buf) { struct file *file = NULL; mm_segment_t old_fs; loff_t offset = 0; PM_DBG("read %s\n", file_path); file = filp_open(file_path, O_RDONLY, 0); if (IS_ERR(file)) { PM_ERR("%s error open file %s\n", __func__, file_path); return -1; } old_fs = get_fs(); set_fs(KERNEL_DS); file->f_op->read(file, (char *)buf, 32, &offset); sscanf(buf, "%s", buf); set_fs(old_fs); filp_close(file, NULL); file = NULL; return 0; }
/* ********************************************************************************************************* * aw_pm_init * *Description: initial pm sub-system for platform; * *Arguments : none; * *Return : result; * *Notes : * ********************************************************************************************************* */ static int __init aw_pm_init(void) { script_item_u item; script_item_u *list = NULL; int cpu0_en = 0; int dram_selfresh_en = 0; int wakeup_src_cnt = 0; PM_DBG("aw_pm_init!\n"); if (fetch_dram_para(&standby_info.dram_para) != 0) { memset(&standby_info.dram_para, 0, sizeof(standby_info.dram_para)); pr_err("%s: fetch_dram_para err. \n", __func__); } memcpy(&mem_para_info.dram_para, &standby_info.dram_para, sizeof(standby_info.dram_para)); //get standby_mode. if(SCIRPT_ITEM_VALUE_TYPE_INT != script_get_item("pm_para", "standby_mode", &item)){ pr_err("%s: script_parser_fetch err. \n", __func__); standby_mode = 0; //standby_mode = 1; pr_err("notice: standby_mode = %d.\n", standby_mode); }else{ standby_mode = item.val; pr_info("standby_mode = %d. \n", standby_mode); if(1 != standby_mode){ pr_err("%s: not support super standby. \n", __func__); } } //get wakeup_src_para cpu_en if(SCIRPT_ITEM_VALUE_TYPE_INT != script_get_item("wakeup_src_para", "cpu_en", &item)){ cpu0_en = 0; }else{ cpu0_en = item.val; } pr_info("cpu0_en = %d.\n", cpu0_en); //get dram_selfresh en if(SCIRPT_ITEM_VALUE_TYPE_INT != script_get_item("wakeup_src_para", "dram_selfresh_en", &item)){ dram_selfresh_en = 1; }else{ dram_selfresh_en = item.val; } pr_info("dram_selfresh_en = %d.\n", dram_selfresh_en); if(0 == dram_selfresh_en && 0 == cpu0_en){ pr_err("Notice: if u don't want the dram enter selfresh mode,\n \ make sure the cpu0 is not allowed to be powered off.\n"); goto script_para_err; }else{
ssize_t clk_rate_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t n) { struct dvfs_node *clk_dvfs_node = NULL; struct clk *clk; char cmd[20], clk_name[20]; unsigned long rate=0; int ret=0; sscanf(buf, "%s %s %lu", cmd, clk_name, &rate); PM_DBG("%s: cmd(%s), clk_name(%s), rate(%lu)\n", __func__, cmd, clk_name, rate); if (!strncmp(cmd, "set", strlen("set"))) { clk_dvfs_node = clk_get_dvfs_node(clk_name); if (!clk_dvfs_node) { PM_ERR("%s: clk(%s) get dvfs node error\n", __func__, clk_name); return n; } if (!strncmp(clk_name, "clk_core", strlen("clk_core"))) { if (file_write(FILE_GOV_MODE, "userspace") != 0) { PM_ERR("%s: set current governor error\n", __func__); return n; } } ret = dvfs_clk_enable_limit(clk_dvfs_node, rate, rate); } else { clk = clk_get(NULL, clk_name); if (IS_ERR_OR_NULL(clk)) { PM_ERR("%s: get clk(%s) err(%ld)\n", __func__, clk_name, PTR_ERR(clk)); return n; } if (!strncmp(cmd, "rawset", strlen("rawset"))) { ret = clk_set_rate(clk, rate); } else if (!strncmp(cmd, "open", strlen("open"))) { ret = clk_prepare_enable(clk); } else if (!strncmp(cmd, "close", strlen("close"))) { clk_disable_unprepare(clk); } } if (ret) { PM_ERR("%s: set rate err(%d)", __func__, ret); } return n; }
/* ********************************************************************************************************* * aw_pm_end * *Description: Notify the platform that system is in work mode now. * *Arguments : none * *Return : none * *Notes : This function is called by the PM core right after resuming devices, to indicate to * the platform that the system has returned to the working state or * the transition to the sleep state has been aborted. This function is opposited to * aw_pm_begin function. ********************************************************************************************************* */ void aw_pm_end(void) { struct cpufreq_policy *policy; #ifndef GET_CYCLE_CNT #ifndef IO_MEASURE restore_perfcounter(); #endif #endif pm_disable_watchdog(dogMode); if (backup_max_freq != 0 && backup_min_freq != 0) { policy = cpufreq_cpu_get(0); if (!policy) { printk("cpufreq_cpu_get err! check it! aw_pm_end:%d\n", __LINE__); return; } policy->user_policy.max = backup_max_freq; policy->user_policy.min = backup_min_freq; cpufreq_cpu_put(policy); cpufreq_update_policy(0); } if(unlikely(debug_mask&PM_STANDBY_PRINT_REG)){ printk("after dev suspend, line:%d\n", __LINE__); show_reg(SW_VA_CCM_IO_BASE, (CCU_REG_LENGTH)*4, "ccu"); show_reg(SW_VA_PORTC_IO_BASE, GPIO_REG_LENGTH*4, "gpio"); show_reg(SW_VA_TIMERC_IO_BASE, TMR_REG_LENGTH*4, "timer"); show_reg(SW_VA_TWI0_IO_BASE, TWI0_REG_LENGTH*4, "twi0"); show_reg(SW_VA_SRAM_IO_BASE, SRAM_REG_LENGTH*4, "sram"); if (userdef_reg_addr != 0 && userdef_reg_size != 0) { show_reg(userdef_reg_addr, userdef_reg_size*4, "user defined"); } } PM_DBG("aw_pm_end!\n"); }
/* ********************************************************************************************************* * aw_pm_end * *Description: Notify the platform that system is in work mode now. * *Arguments : none * *Return : none * *Notes : This function is called by the PM core right after resuming devices, to indicate to * the platform that the system has returned to the working state or * the transition to the sleep state has been aborted. This function is opposited to * aw_pm_begin function. ********************************************************************************************************* */ void aw_pm_end(void) { #ifndef GET_CYCLE_CNT #ifndef IO_MEASURE restore_perfcounter(); #endif #endif pm_disable_watchdog(0); if(unlikely(debug_mask&PM_STANDBY_PRINT_REG)){ printk("after dev suspend, line:%d\n", __LINE__); show_reg(SW_VA_CCM_IO_BASE, (CCU_REG_LENGTH)*4, "ccu"); show_reg(SW_VA_PORTC_IO_BASE, GPIO_REG_LENGTH*4, "gpio"); show_reg(SW_VA_TIMERC_IO_BASE, TMR_REG_LENGTH*4, "timer"); show_reg(SW_VA_TWI0_IO_BASE, TWI0_REG_LENGTH*4, "twi0"); show_reg(SW_VA_SRAM_IO_BASE, SRAM_REG_LENGTH*4, "sram"); if (userdef_reg_addr != 0 && userdef_reg_size != 0) { show_reg(userdef_reg_addr, userdef_reg_size*4, "user defined"); } } PM_DBG("aw_pm_end!\n"); }
/* ********************************************************************************************************* * aw_pm_wake * *Description: platform wakeup; * *Arguments : none; * *Return : none; * *Notes : This function called when the system has just left a sleep state, right after * the nonboot CPUs have been enabled and before device drivers' early resume * callbacks are executed. This function is opposited to the aw_pm_prepare_late; ********************************************************************************************************* */ static void aw_pm_wake(void) { PM_DBG("platform wakeup, wakesource is:0x%x\n", standby_info.standby_para.event); }
ssize_t clk_auto_volt_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t n) { char cmd[10]; char volt_flag[10]; char regulator_name[20]; sscanf(buf, "%s %s %s %u %u %u %u", cmd, volt_flag, regulator_name, &begin_volt, &stop_volt, &volt_step, &timer_tick); if (0 == strncmp(cmd, "start", strlen("start"))) { if (0 == strncmp(volt_flag, "up", strlen("up"))) { if (begin_volt >= stop_volt) { PM_ERR("wrong! begin_volt >= stop_volt!\n"); return -EINVAL; } volt_direction = VOLT_UP; } else if (0 == strncmp(volt_flag, "down", strlen("down"))) { if (begin_volt <= stop_volt) { PM_ERR("wrong! begin_volt <= stop_volt!\n"); return -EINVAL; } volt_direction = VOLT_DOWN; } else { PM_ERR("argument %s is invalid!\n",volt_flag); return -EINVAL; } regulator = dvfs_get_regulator(regulator_name); if (IS_ERR_OR_NULL(regulator)) { PM_ERR("%s get dvfs_regulator %s error\n", __func__, regulator_name); return -ENOMEM; } if (wq_is_run == 1) { cancel_delayed_work(&scal_volt_work); flush_workqueue(scal_volt_wq); //destroy_workqueue(scal_volt_wq); wq_is_run = 0; } PM_DBG("begin!\n"); volt = begin_volt; scal_volt_wq = create_workqueue("scal volt wq"); INIT_DELAYED_WORK(&scal_volt_work, scal_volt_func); queue_delayed_work(scal_volt_wq, &scal_volt_work, msecs_to_jiffies(timer_tick*1000)); wq_is_run = 1; } else if (0 == strncmp(cmd, "stop", strlen("stop"))) { if (wq_is_run == 1) { cancel_delayed_work(&scal_volt_work); flush_workqueue(scal_volt_wq); //destroy_workqueue(scal_volt_wq); wq_is_run = 0; } } else { PM_ERR("argument %s is invalid!\n", cmd); return -EINVAL; } return n; }
static int aw_pm_valid(suspend_state_t state) { #ifdef CHECK_IC_VERSION enum sw_ic_ver version = MAGIC_VER_NULL; #endif PM_DBG("valid\n"); console_suspend_enabled = 0; if(!((state > PM_SUSPEND_ON) && (state < PM_SUSPEND_MAX))){ PM_DBG("state (%d) invalid!\n", state); return 0; } #ifdef CHECK_IC_VERSION if(1 == standby_mode){ version = sw_get_ic_ver(); if(!(MAGIC_VER_A13B == version || MAGIC_VER_A12B == version || MAGIC_VER_A10SB == version)){ pr_info("ic version: %d not support super standby. \n", version); standby_mode = 0; } } #endif //if 1 == standby_mode, actually, mean mem corresponding with super standby if(PM_SUSPEND_STANDBY == state){ if(1 == standby_mode){ standby_type = NORMAL_STANDBY; }else{ standby_type = SUPER_STANDBY; } printk("standby_mode:%d, standby_type:%d, line:%d\n",standby_mode, standby_type, __LINE__); }else if(PM_SUSPEND_MEM == state || PM_SUSPEND_BOOTFAST == state){ if(1 == standby_mode){ standby_type = SUPER_STANDBY; }else{ standby_type = NORMAL_STANDBY; } printk("standby_mode:%d, standby_type:%d, line:%d\n",standby_mode, standby_type, __LINE__); } //allocat space for backup dram data if(SUPER_STANDBY == standby_type){ if((DRAM_BACKUP_SIZE) < ((int)&resume0_bin_end - (int)&resume0_bin_start) ){ //judge the reserved space for resume0 is enough or not. pr_info("Notice: reserved space(%d) for resume is not enough(%d). \n", DRAM_BACKUP_SIZE,((int)&resume0_bin_end - (int)&resume0_bin_start)); return 0; } memcpy((void *)DRAM_BACKUP_BASE_ADDR, (void *)&resume0_bin_start, (int)&resume0_bin_end - (int)&resume0_bin_start); dmac_flush_range((void *)DRAM_BACKUP_BASE_ADDR, (void *)(DRAM_BACKUP_BASE_ADDR + DRAM_BACKUP_SIZE -1) ); } #ifdef GET_CYCLE_CNT // init counters: init_perfcounters (1, 0); #endif return 1; }
/* ********************************************************************************************************* * aw_pm_recover * *Description: Recover platform from a suspend failure; * *Arguments : none * *Return : none * *Notes : This function alled by the PM core if the suspending of devices fails. * This callback is optional and should only be implemented by platforms * which require special recovery actions in that situation. ********************************************************************************************************* */ void aw_pm_recover(void) { PM_DBG("aw_pm_recover\n"); }
/* ********************************************************************************************************* * aw_pm_finish * *Description: Finish wake-up of the platform; * *Arguments : none * *Return : none * *Notes : This function is called right prior to calling device drivers' regular suspend * callbacks. This function is opposited to the aw_pm_prepare function. ********************************************************************************************************* */ void aw_pm_finish(void) { PM_DBG("platform wakeup finish\n"); }
/* ********************************************************************************************************* * aw_pm_enter * *Description: Enter the system sleep state; * *Arguments : state system sleep state; * *Return : return 0 is process successed; * *Notes : this function is the core function for platform sleep. ********************************************************************************************************* */ static int aw_pm_enter(suspend_state_t state) { // asm volatile ("stmfd sp!, {r1-r12, lr}" ); normal_standby_func standby; PM_DBG("enter state %d\n", state); if(unlikely(debug_mask&PM_STANDBY_PRINT_REG)){ printk("after cpu suspend , line:%d\n", __LINE__); show_reg(SW_VA_CCM_IO_BASE, (CCU_REG_LENGTH)*4, "ccu"); show_reg(SW_VA_PORTC_IO_BASE, GPIO_REG_LENGTH*4, "gpio"); show_reg(SW_VA_TIMERC_IO_BASE, TMR_REG_LENGTH*4, "timer"); show_reg(SW_VA_TWI0_IO_BASE, TWI0_REG_LENGTH*4, "twi0"); show_reg(SW_VA_SRAM_IO_BASE, SRAM_REG_LENGTH*4, "sram"); if (userdef_reg_addr != 0 && userdef_reg_size != 0) { show_reg(userdef_reg_addr, userdef_reg_size*4, "user defined"); } } standby_info.standby_para.axp_enable = standby_axp_enable; if(NORMAL_STANDBY== standby_type){ standby = (int (*)(struct aw_pm_info *arg))SRAM_FUNC_START; //move standby code to sram memcpy((void *)SRAM_FUNC_START, (void *)&standby_bin_start, (int)&standby_bin_end - (int)&standby_bin_start); /* config system wakeup evetn type */ if(PM_SUSPEND_MEM == state || PM_SUSPEND_STANDBY == state){ standby_info.standby_para.axp_src = AXP_MEM_WAKEUP; }else if(PM_SUSPEND_BOOTFAST == state){ standby_info.standby_para.axp_src = AXP_BOOTFAST_WAKEUP; } standby_info.standby_para.event_enable = (SUSPEND_WAKEUP_SRC_EXINT | SUSPEND_WAKEUP_SRC_ALARM); if (standby_timeout != 0) { standby_info.standby_para.event_enable |= (SUSPEND_WAKEUP_SRC_TIMEOFF); standby_info.standby_para.time_off = standby_timeout; } /* goto sram and run */ printk("standby_mode:%d, standby_type:%d, line:%d\n",standby_mode, standby_type, __LINE__); standby(&standby_info); printk("standby_mode:%d, standby_type:%d, line:%d\n",standby_mode, standby_type, __LINE__); }else if(SUPER_STANDBY == standby_type){ printk("standby_mode:%d, standby_type:%d, line:%d\n",standby_mode, standby_type, __LINE__); print_call_info(); aw_super_standby(state); } pm_enable_watchdog(); print_call_info(); if(unlikely(debug_mask&PM_STANDBY_PRINT_REG)){ printk("after cpu suspend , line:%d\n", __LINE__); show_reg(SW_VA_CCM_IO_BASE, (CCU_REG_LENGTH)*4, "ccu"); show_reg(SW_VA_PORTC_IO_BASE, GPIO_REG_LENGTH*4, "gpio"); show_reg(SW_VA_TIMERC_IO_BASE, TMR_REG_LENGTH*4, "timer"); show_reg(SW_VA_TWI0_IO_BASE, TWI0_REG_LENGTH*4, "twi0"); show_reg(SW_VA_SRAM_IO_BASE, SRAM_REG_LENGTH*4, "sram"); if (userdef_reg_addr != 0 && userdef_reg_size != 0) { show_reg(userdef_reg_addr, userdef_reg_size*4, "user defined"); } } // asm volatile ("ldmfd sp!, {r1-r12, lr}" ); return 0; }
/* ********************************************************************************************************* * aw_pm_prepare_late * *Description: Finish preparing the platform for entering the system sleep state. * *Arguments : none; * *Return : return 0 for process successed, and negative code for error; * *Notes : this is a call-back function, registered into PM core. * prepare_late is called before disabling nonboot CPUs and after * device drivers' late suspend callbacks have been executed; ********************************************************************************************************* */ int aw_pm_prepare_late(void) { PM_DBG("prepare_late\n"); return 0; }