void spm_go_to_vcore_dvfs(u32 spm_flags, u32 spm_data)
{
	struct pcm_desc *pcmdesc = __spm_vcore_dvfs.pcmdesc;
	struct pwr_ctrl *pwrctrl = __spm_vcore_dvfs.pwrctrl;
	unsigned long flags;

	spin_lock_irqsave(&__spm_lock, flags);

	mt_cpufreq_set_pmic_phase(PMIC_WRAP_PHASE_NORMAL);

	set_pwrctrl_pcm_flags(pwrctrl, spm_flags);

	__spm_reset_and_init_pcm(pcmdesc);

	__spm_kick_im_to_fetch(pcmdesc);

	__spm_init_pcm_register();

	__spm_init_event_vector(pcmdesc);

	__spm_set_power_control(pwrctrl);

	__spm_set_wakeup_event(pwrctrl);

	__spm_kick_pcm_to_run(pwrctrl);

	spin_unlock_irqrestore(&__spm_lock, flags);
}
static void spm_sodi_post_process(void)
{
    __spm_dpidle_sodi_restore_pmic_setting(vsram_vosel_on_lb);
    
    /* set PMIC WRAP table for normal power control */
    mt_cpufreq_set_pmic_phase(PMIC_WRAP_PHASE_NORMAL);
}
static void spm_sodi_pre_process(void)
{
    /* set PMIC WRAP table for deepidle power control */
    mt_cpufreq_set_pmic_phase(PMIC_WRAP_PHASE_DEEPIDLE);	

    vsram_vosel_on_lb = __spm_dpidle_sodi_set_pmic_setting();
}
static void spm_dpidle_pre_process(void)
{
    //spm_i2c_control(I2C_CHANNEL, 1);

    /* set PMIC WRAP table for deepidle power control */
    mt_cpufreq_set_pmic_phase(PMIC_WRAP_PHASE_DEEPIDLE);
}
static void spm_sodi_post_process(void)
{
    pmic_set_register_value(PMIC_VSRAM_VOSEL_ON_LB,vsram_vosel_on_lb);  
    
    /* set PMIC WRAP table for normal power control */
    mt_cpufreq_set_pmic_phase(PMIC_WRAP_PHASE_NORMAL);
}
static void spm_sodi_pre_process(void)
{
    /* set PMIC WRAP table for deepidle power control */
    mt_cpufreq_set_pmic_phase(PMIC_WRAP_PHASE_DEEPIDLE);
/* [521562] merge ALPS02212031(For_JHZ6735M_65C_L_ALPS.L1.MP3.V1_P82) patch by liming.zhu at 20150818 bigen*/
    vsram_vosel_on_lb = __spm_dpidle_sodi_set_pmic_setting();
	/* [521562] merge ALPS02212031(For_JHZ6735M_65C_L_ALPS.L1.MP3.V1_P82) patch by liming.zhu at 20150818 end*/
}
static void spm_dpidle_post_process(void)
{
    /*   //TODO
        spm_i2c_control(I2C_CHANNEL, 0);
    */
    /* set PMIC WRAP table for normal power control */
    mt_cpufreq_set_pmic_phase(PMIC_WRAP_PHASE_NORMAL);
}
static void spm_sodi_pre_process(void)
{
    /* set PMIC WRAP table for deepidle power control */
    mt_cpufreq_set_pmic_phase(PMIC_WRAP_PHASE_DEEPIDLE);	

    vsram_vosel_on_lb = pmic_get_register_value(PMIC_VSRAM_VOSEL_ON_LB);
    spm_write(SPM_PCM_RESERVE3,(pmic_get_register_value(PMIC_VSRAM_VOSEL_OFFSET)<<8)|pmic_get_register_value(PMIC_VSRAM_VOSEL_DELTA));//delta = 0v
    pmic_set_register_value(PMIC_VSRAM_VOSEL_ON_LB,(vsram_vosel_on_lb&0xff80)|0x28);//0.85v
}
static void spm_sodi_post_process(void)
{
/* [521562] merge ALPS02212031(For_JHZ6735M_65C_L_ALPS.L1.MP3.V1_P82) patch by liming.zhu at 20150818 bigen*/
    __spm_dpidle_sodi_restore_pmic_setting(vsram_vosel_on_lb);
	/* [521562] merge ALPS02212031(For_JHZ6735M_65C_L_ALPS.L1.MP3.V1_P82) patch by liming.zhu at 20150818 end*/

    /* set PMIC WRAP table for normal power control */
    mt_cpufreq_set_pmic_phase(PMIC_WRAP_PHASE_NORMAL);
}
static void spm_dpidle_post_process(void)
{
/*   //TODO
    spm_i2c_control(I2C_CHANNEL, 0);
    spm_write(0xF0001070 , g_bus_ctrl); //26:26 enable 
*/
    pmic_set_register_value(PMIC_VSRAM_VOSEL_ON_LB,vsram_vosel_on_lb); 
    /* set PMIC WRAP table for normal power control */
    mt_cpufreq_set_pmic_phase(PMIC_WRAP_PHASE_NORMAL);       
}
static void spm_dpidle_post_process(void)
{
/*   //TODO
    spm_i2c_control(I2C_CHANNEL, 0);
    spm_write(0xF0001070 , g_bus_ctrl); //26:26 enable 
*/
/* [521562] merge ALPS02212031(For_JHZ6735M_65C_L_ALPS.L1.MP3.V1_P82) patch by liming.zhu at 20150818 bigen*/
	__spm_dpidle_sodi_restore_pmic_setting(vsram_vosel_on_lb);
	/* [521562] merge ALPS02212031(For_JHZ6735M_65C_L_ALPS.L1.MP3.V1_P82) patch by liming.zhu at 20150818 end*/
    /* set PMIC WRAP table for normal power control */
    mt_cpufreq_set_pmic_phase(PMIC_WRAP_PHASE_NORMAL);       
}
void spm_go_to_vcore_dvfs(u32 spm_flags, u32 spm_data)
{
	unsigned long flags;

	spin_lock_irqsave(&__spm_lock, flags);

	mt_cpufreq_set_pmic_phase(PMIC_WRAP_PHASE_NORMAL);

	__go_to_vcore_dvfs(spm_flags, 0, 0);

	spm_crit("[VcoreFS] STA: 0x%x, REQ: 0x%x\n", spm_read(SPM_SLEEP_DVFS_STA), spm_read(SPM_PCM_SRC_REQ));

	spin_unlock_irqrestore(&__spm_lock, flags);
}
static void spm_dpidle_pre_process(void)
{
/*  //TODO
    spm_i2c_control(I2C_CHANNEL, 1);//D1,D2 no ext bulk
    g_bus_ctrl=spm_read(0xF0001070);
    spm_write(0xF0001070 , g_bus_ctrl | (1 << 21)); //bus dcm disable
    g_sys_ck_sel = spm_read(0xF0001108);
    //spm_write(0xF0001108 , g_sys_ck_sel &~ (1<<1) );
    spm_write(0xF0001108 , 0x0);
    spm_write(0xF0000204 , spm_read(0xF0000204) | (1 << 0));  // BUS 26MHz enable 
*/
    /* set PMIC WRAP table for deepidle power control */
    mt_cpufreq_set_pmic_phase(PMIC_WRAP_PHASE_DEEPIDLE);
	/* [521562] merge ALPS02212031(For_JHZ6735M_65C_L_ALPS.L1.MP3.V1_P82) patch by liming.zhu at 20150818 bigen*/
	vsram_vosel_on_lb = __spm_dpidle_sodi_set_pmic_setting();
	/* [521562] merge ALPS02212031(For_JHZ6735M_65C_L_ALPS.L1.MP3.V1_P82) patch by liming.zhu at 20150818 end*/
}
static void spm_dpidle_pre_process(void)
{
/*  //TODO
    spm_i2c_control(I2C_CHANNEL, 1);//D1,D2 no ext bulk
    g_bus_ctrl=spm_read(0xF0001070);
    spm_write(0xF0001070 , g_bus_ctrl | (1 << 21)); //bus dcm disable
    g_sys_ck_sel = spm_read(0xF0001108);
    //spm_write(0xF0001108 , g_sys_ck_sel &~ (1<<1) );
    spm_write(0xF0001108 , 0x0);
    spm_write(0xF0000204 , spm_read(0xF0000204) | (1 << 0));  // BUS 26MHz enable 
*/
    /* set PMIC WRAP table for deepidle power control */
    mt_cpufreq_set_pmic_phase(PMIC_WRAP_PHASE_DEEPIDLE);
    
    vsram_vosel_on_lb = pmic_get_register_value(PMIC_VSRAM_VOSEL_ON_LB);
    spm_write(SPM_PCM_RESERVE3,(pmic_get_register_value(PMIC_VSRAM_VOSEL_OFFSET)<<8)|pmic_get_register_value(PMIC_VSRAM_VOSEL_DELTA));//delta = 0v
    pmic_set_register_value(PMIC_VSRAM_VOSEL_ON_LB,(vsram_vosel_on_lb&0xff80)|0x28);//0.85v
}
static void spm_suspend_pre_process(struct pwr_ctrl *pwrctrl)
{
    /* set PMIC WRAP table for suspend power control */
    mt_cpufreq_set_pmic_phase(PMIC_WRAP_PHASE_SUSPEND);
    
    // FIXME: wait for dual-vcore suspend test finish.
    #if 1 
    if (is_dualvcore_pdn(pwrctrl->pcm_flags))
    {
        /* set LTE pd mode to avoid LTE power on after dual-vcore resume */
        //spm_write(AP_PLL_CON7, spm_read(AP_PLL_CON7) | 0xF);  // set before dual-vcore suspend
        mt_cpufreq_apply_pmic_cmd(IDX_SP_VCORE_PDN_EN_HW_MODE); // if dual-vcore suspend enable, set VCORE_PND_EN to HW mode
        //mt6331_upmu_set_rg_int_en_chrdet(0); // disable charger detection to avoid abnormal EINT.
        //mt6331_upmu_set_rg_int_en_rtc(0); // mask rtc to avoid abnormal EINT.
    }
    else
    #endif
        mt_cpufreq_apply_pmic_cmd(IDX_SP_VCORE_PDN_EN_SW_MODE); // if dual-vcore suspend disable, set VCORE_PND_EN to SW mode

    spm_i2c_control(I2C_CHANNEL, 1);
}
/*
static bool spm_set_suspend_pcm_ver(u32 *suspend_flags)
{
    u32 flag;

    flag = *suspend_flags;

    if(mt_get_clk_mem_sel()==MEMPLL3PLL)
    {
        __spm_suspend.pcmdesc = &suspend_pcm_3pll;
        flag |= SPM_VCORE_DVS_DIS;
    }
    else if(mt_get_clk_mem_sel()==MEMPLL1PLL)

    {
        __spm_suspend.pcmdesc = &suspend_pcm_1pll;
        flag &= ~SPM_VCORE_DVS_DIS;
    }
    else
        return false;

    *suspend_flags = flag;
    return true;

}
*/
static void spm_suspend_pre_process(struct pwr_ctrl *pwrctrl)
{
#if 0
    u32 rdata1 = 0, rdata2 = 0;
#endif

    /* set PMIC WRAP table for suspend power control */
    mt_cpufreq_set_pmic_phase(PMIC_WRAP_PHASE_SUSPEND);
    
    spm_i2c_control(I2C_CHANNEL, 1);

#if 0
    /* for infra pdn (emi driving) */
    spm_write(0xF0004000, spm_read(0xF0004000) | (1 << 24));

    /* MEMPLL control for SPM */
    spm_write(0xF000F5C8, 0x3010F030);
    spm_write(0xF000F5CC, 0x50101010);
#endif
    //spm_write(0xF0001070 , spm_read(0xF0001070) | (1 << 21)); // 26:26 enable 
    //spm_write(0xF0000204 , spm_read(0xF0000204) | (1 << 0));  // BUS 26MHz enable 
    //spm_write(0xF0001108 , 0x0);

#ifdef CONFIG_MD32_SUPPORT
    //spm_write(MD32_BASE+0x2C, (spm_read(MD32_BASE+0x2C) & ~0xFFFF) | 0xcafe);
#endif

#if 0    
    pwrap_read(0x2c2, &rdata1);
    pwrap_write(0x2c2, 0x0123);
    pwrap_read(0x2c2, &rdata2);
    if(rdata2 != 0x0123)
    {
        spm_crit2("suspend pmic wrapper 0x2c2, rdata1 = 0x%x, rdata2 = 0x%x\n", rdata1, rdata2);
        BUG();
    }
#endif
}
static void spm_suspend_post_process(struct pwr_ctrl *pwrctrl)
{
#if 0
    u32 rdata1 = 0, rdata2 = 0;
          
    pwrap_read(0x2c2, &rdata1);
    pwrap_write(0x2c2, 0x3210);
    pwrap_read(0x2c2, &rdata2);
    if(rdata2 != 0x3210)
    {
        spm_crit2("resume pmic wrapper 0x2c2, rdata1 = 0x%x, rdata2 = 0x%x\n", rdata1, rdata2);
        BUG();
    }
#endif

#ifdef CONFIG_MD32_SUPPORT
    //spm_write(MD32_BASE+0x2C, spm_read(MD32_BASE+0x2C) & ~0xFFFF);
#endif

    /* set PMIC WRAP table for normal power control */
    mt_cpufreq_set_pmic_phase(PMIC_WRAP_PHASE_NORMAL);

    spm_i2c_control(I2C_CHANNEL, 0);
}
static void spm_suspend_post_process(struct pwr_ctrl *pwrctrl)
{
    // FIXME: wait for dual-vcore suspend test finish.
    #if 1 
    if (is_dualvcore_pdn(pwrctrl->pcm_flags))
    {
        /* restore LTE pd mode after dual-vcore resume */
        //spm_write(AP_PLL_CON7, spm_read(AP_PLL_CON7) & ~0xF); // set after dual-vcore resume

        /* enable charger detection */
        //mt6331_upmu_set_rg_int_en_chrdet(1);
        /* enable rtc */
        //mt6331_upmu_set_rg_int_en_rtc(1);

        /* set VCORE_PND_EN to SW mode */
        mt_cpufreq_apply_pmic_cmd(IDX_SP_VCORE_PDN_EN_SW_MODE);
    }
    #endif

    /* set PMIC WRAP table for normal power control */
    mt_cpufreq_set_pmic_phase(PMIC_WRAP_PHASE_NORMAL);

    spm_i2c_control(I2C_CHANNEL, 0);
}
wake_reason_t spm_go_to_dpidle(u32 spm_flags, u32 spm_data)
{
    struct wake_status wakesta;
    unsigned long flags;
    struct mtk_irq_mask mask;
    wake_reason_t wr = WR_NONE;
    struct pcm_desc *pcmdesc = __spm_dpidle.pcmdesc;
    struct pwr_ctrl *pwrctrl = __spm_dpidle.pwrctrl;
    struct spm_lp_scen *lpscen;

    lpscen = spm_check_talking_get_lpscen(&__spm_dpidle, &spm_flags);
    pcmdesc = lpscen->pcmdesc;
    pwrctrl = lpscen->pwrctrl;

    set_pwrctrl_pcm_flags(pwrctrl, spm_flags);
	
    /* set PMIC WRAP table for deepidle power control */
    mt_cpufreq_set_pmic_phase(PMIC_WRAP_PHASE_DEEPIDLE);

    spin_lock_irqsave(&__spm_lock, flags);

    mt_irq_mask_all(&mask);
    mt_irq_unmask_for_sleep(MT_SPM_IRQ_ID);
    mt_cirq_clone_gic();
    mt_cirq_enable();

    if (request_uart_to_sleep()) {
        wr = WR_UART_BUSY;
        goto RESTORE_IRQ;
    }
	
    __spm_reset_and_init_pcm(pcmdesc);

    __spm_kick_im_to_fetch(pcmdesc);
	
    __spm_init_pcm_register();

    __spm_init_event_vector(pcmdesc);

    __spm_set_power_control(pwrctrl);

    __spm_set_wakeup_event(pwrctrl);

    __spm_kick_pcm_to_run(pwrctrl);

    spm_dpidle_before_wfi();

    spm_trigger_wfi_for_dpidle(pwrctrl);

    spm_dpidle_after_wfi();

    __spm_get_wakeup_status(&wakesta);

    __spm_clean_after_wakeup();

    request_uart_to_wakeup();

    wr = __spm_output_wake_reason(&wakesta, pcmdesc, false);

RESTORE_IRQ:
    mt_cirq_flush();
    mt_cirq_disable();
    mt_irq_mask_restore(&mask);

    spin_unlock_irqrestore(&__spm_lock, flags);
    /* set PMIC WRAP table for normal power control */
    mt_cpufreq_set_pmic_phase(PMIC_WRAP_PHASE_NORMAL);

    return wr;
}
/*
 * cpu_pdn:
 *    true  = CPU dormant
 *    false = CPU standby
 * pwrlevel:
 *    0 = AXI is off
 *    1 = AXI is 26M
 * pwake_time:
 *    >= 0  = specific wakeup period
 */
wake_reason_t spm_go_to_sleep_dpidle(u32 spm_flags, u32 spm_data)
{
    u32 sec = 0;
    u32 dpidle_timer_val = 0;
    u32 dpidle_wake_src = 0;
    int wd_ret;
    struct wake_status wakesta;
    unsigned long flags;
    struct mtk_irq_mask mask;
    struct wd_api *wd_api;
    static wake_reason_t last_wr = WR_NONE;
    struct pcm_desc *pcmdesc = __spm_dpidle.pcmdesc;
    struct pwr_ctrl *pwrctrl = __spm_dpidle.pwrctrl;

	/* backup original dpidle setting */
	dpidle_timer_val = pwrctrl->timer_val;
	dpidle_wake_src = pwrctrl->wake_src;

    set_pwrctrl_pcm_flags(pwrctrl, spm_flags);

#if SPM_PWAKE_EN
    sec = spm_get_wake_period(-1 /* FIXME */, last_wr);
#endif
    pwrctrl->timer_val = sec * 32768;

    pwrctrl->wake_src = spm_get_sleep_wakesrc();

    wd_ret = get_wd_api(&wd_api);
    if (!wd_ret)
        wd_api->wd_suspend_notify();

    spin_lock_irqsave(&__spm_lock, flags);

    mt_irq_mask_all(&mask);
    mt_irq_unmask_for_sleep(SPM_IRQ0_ID);
	
    mt_cirq_clone_gic();
    mt_cirq_enable();

    /* set PMIC WRAP table for deepidle power control */
    mt_cpufreq_set_pmic_phase(PMIC_WRAP_PHASE_DEEPIDLE);

    spm_crit2("sleep_deepidle, sec = %u, wakesrc = 0x%x [%u]\n",
              sec, pwrctrl->wake_src, is_cpu_pdn(pwrctrl->pcm_flags));

    __spm_reset_and_init_pcm(pcmdesc);

    __spm_kick_im_to_fetch(pcmdesc);

    if (request_uart_to_sleep()) {
        last_wr = WR_UART_BUSY;
        goto RESTORE_IRQ;
    }

    __spm_init_pcm_register();

    __spm_init_event_vector(pcmdesc);

    __spm_set_power_control(pwrctrl);

    __spm_set_wakeup_event(pwrctrl);

    __spm_kick_pcm_to_run(pwrctrl);

    spm_dpidle_pre_process();

    spm_trigger_wfi_for_dpidle(pwrctrl);

    spm_dpidle_post_process();    

    __spm_get_wakeup_status(&wakesta);

    __spm_clean_after_wakeup();

    request_uart_to_wakeup();

    last_wr = __spm_output_wake_reason(&wakesta, pcmdesc, true);

RESTORE_IRQ:

    /* set PMIC WRAP table for normal power control */
    mt_cpufreq_set_pmic_phase(PMIC_WRAP_PHASE_NORMAL);

    mt_cirq_flush();
    mt_cirq_disable();

    mt_irq_mask_restore(&mask);

    spin_unlock_irqrestore(&__spm_lock, flags);

    if (!wd_ret)
        wd_api->wd_resume_notify();

	/* restore original dpidle setting */
	pwrctrl->timer_val = dpidle_timer_val;
	pwrctrl->wake_src = dpidle_wake_src;

    return last_wr;  
}
void spm_go_to_sodi(u32 spm_flags, u32 spm_data)
{
    struct wake_status wakesta;
    unsigned long flags;
    struct mtk_irq_mask mask;
    wake_reason_t wr = WR_NONE;
    struct pcm_desc *pcmdesc = __spm_sodi.pcmdesc;
    struct pwr_ctrl *pwrctrl = __spm_sodi.pwrctrl;

#if SPM_AEE_RR_REC
    aee_rr_rec_sodi_val(1<<SPM_SODI_ENTER);
#endif 

    set_pwrctrl_pcm_flags(pwrctrl, spm_flags);

    /* set PMIC WRAP table for deepidle power control */
    mt_cpufreq_set_pmic_phase(PMIC_WRAP_PHASE_SODI);	

    soidle_before_wfi(0);
    lockdep_off(); 
    spin_lock_irqsave(&__spm_lock, flags);

    mt_irq_mask_all(&mask);
    mt_irq_unmask_for_sleep(SPM_IRQ0_ID/*MT_SPM_IRQ_ID*/);
    mt_cirq_clone_gic();
    mt_cirq_enable();

#if SPM_AEE_RR_REC
    aee_rr_rec_sodi_val(aee_rr_curr_sodi_val()|(1<<SPM_SODI_ENTER_SPM_FLOW));
#endif   

    __spm_reset_and_init_pcm(pcmdesc);
#if 0
    /* 0: mempll shutdown mode; 1: cg mode */
    gSpm_SODI_mempll_pwr_mode ? (pwrctrl->pcm_flags |= SPM_MEMPLL_CPU) :
				(pwrctrl->pcm_flags &= ~SPM_MEMPLL_CPU);
#endif

    __spm_kick_im_to_fetch(pcmdesc);

    __spm_init_pcm_register();

    __spm_init_event_vector(pcmdesc);

    /* set pcm_apsrc_req to be 1 if 10006b0c[0] is 1 */
    if ((spm_read(SPM_PCM_SRC_REQ) & 1) || pwrctrl->pcm_apsrc_req)
        pwrctrl->pcm_apsrc_req = 1;
    else
        pwrctrl->pcm_apsrc_req = 0;

    __spm_set_power_control(pwrctrl);

    __spm_set_wakeup_event(pwrctrl);

    /* set pcm_flags[18] to be 1 if 10006b08[7] is 1 */
    if ((spm_read(SPM_PCM_FLAGS) & SPM_MEMPLL_RESET) ||
        gSpm_SODI_mempll_pwr_mode ||
        (pwrctrl->pcm_flags_cust & SPM_MEMPLL_CPU))
        pwrctrl->pcm_flags |= SPM_MEMPLL_CPU;
    else
        pwrctrl->pcm_flags &= ~SPM_MEMPLL_CPU;

    __spm_kick_pcm_to_run(pwrctrl);

#if SPM_AEE_RR_REC
    aee_rr_rec_sodi_val(aee_rr_curr_sodi_val()|(1<<SPM_SODI_ENTER_WFI));
#endif

    spm_trigger_wfi_for_sodi(pwrctrl);

#if SPM_AEE_RR_REC
    aee_rr_rec_sodi_val(aee_rr_curr_sodi_val()|(1<<SPM_SODI_LEAVE_WFI));
#endif  

    __spm_get_wakeup_status(&wakesta);

    __spm_clean_after_wakeup();	

    wr = __spm_output_wake_reason(&wakesta, pcmdesc, false);
    /* for test */
    /* wr = __spm_output_wake_reason(&wakesta, pcmdesc, true); */

#if SPM_AEE_RR_REC
    aee_rr_rec_sodi_val(aee_rr_curr_sodi_val()|(1<<SPM_SODI_LEAVE_SPM_FLOW));
#endif  

    mt_cirq_flush();
    mt_cirq_disable();
    mt_irq_mask_restore(&mask);

    spin_unlock_irqrestore(&__spm_lock, flags);
    lockdep_on();
    soidle_after_wfi(0);
	
     /* set PMIC WRAP table for normal power control */
    mt_cpufreq_set_pmic_phase(PMIC_WRAP_PHASE_NORMAL);  

#if SPM_AEE_RR_REC
    aee_rr_rec_sodi_val(0);
#endif 
    //return wr;

}