diff options
Diffstat (limited to 'arch/arm/mach-wmt/pm.c')
-rwxr-xr-x | arch/arm/mach-wmt/pm.c | 2212 |
1 files changed, 2212 insertions, 0 deletions
diff --git a/arch/arm/mach-wmt/pm.c b/arch/arm/mach-wmt/pm.c new file mode 100755 index 00000000..af516e30 --- /dev/null +++ b/arch/arm/mach-wmt/pm.c @@ -0,0 +1,2212 @@ +/*++ +linux/arch/arm/mach-wmt/pm.c + +Copyright (c) 2008 WonderMedia Technologies, Inc. + +This program is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software Foundation, +either version 2 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. + +WonderMedia Technologies, Inc. +10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C. +--*/ +#include <linux/init.h> +#include <linux/suspend.h> +#include <linux/errno.h> +#include <linux/time.h> +#include <linux/sysctl.h> +#include <linux/interrupt.h> +#include <linux/vmalloc.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/timer.h> +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/proc_fs.h> +#include <linux/cpufreq.h> +#include <linux/reboot.h> +#include <mach/hardware.h> +#include <asm/memory.h> +#include <asm/system.h> +#include <asm/leds.h> +#include <asm/io.h> +#include <linux/rtc.h> + +#include <asm/cacheflush.h> +#include <asm/hardware/cache-l2x0.h> + +#include <mach/wmt_secure.h> + +#include <linux/gpio.h> +#include <mach/wmt_iomux.h> + + + + + +//#define CONFIG_KBDC_WAKEUP +//#define KB_WAKEUP_SUPPORT +//#define MOUSE_WAKEUP_SUPPORT + +#define SOFT_POWER_SUPPORT +#define RTC_WAKEUP_SUPPORT +//#ifdef CONFIG_RMTCTL_WonderMedia //define if CIR menuconfig enable +#define CIR_WAKEUP_SUPPORT +//#endif +#define KEYPAD_POWER_SUPPORT +#define PMWT_C_WAKEUP(src, type) ((type & PMWT_TYPEMASK) << (((src - 24) & PMWT_WAKEUPMASK) * 4)) + +enum wakeup_intr_tri_src_e { + WKS_T_WK0 = 0, /* General Purpose Wakeup Source 0 */ + WKS_T_WK2, /* General Purpose Wakeup Source 1 */ + WKS_T_WK3, /* General Purpose Wakeup Source 2 */ + WKS_T_WK4, /* General Purpose Wakeup Source 3 */ + WKS_T_SUS0, /* General Purpose Wakeup Source 4 */ + WKS_T_SUS1, /* General Purpose Wakeup Source 5 */ + WKS_T_USBATTA0, /* USBATTA0 */ + WKS_T_CIRIN, /* CIRIN */ + WKS_T_USBOC0, /* WKS_USBOC0 as wakeup */ + WKS_T_USBOC1, /* WKS_USBOC0 as wakeup */ + WKS_T_USBOC2, /* WKS_USBOC0 as wakeup */ + WKS_T_USBOC3, /* WKS_USBOC0 as wakeup */ + WKS_T_UHC, /* UHC interrupt as wakeup */ + WKS_T_UDC, /* WKS_UDC interrupt as wakeup */ + WKS_T_CIR, /* CIR interrupt as wakeupr */ + WKS_T_USBSW0, /* USBSW0 interrupt as wakeupr */ + WKS_T_SD3 = 18, /* SD3 interrupt as wakeupr */ + WKS_T_DCDET = 19, /* DCDET interrupt as wakeupr */ + WKS_T_SD2 = 20, /* SD2 interrupt as wakeupr */ + WKS_T_HDMICEC = 21, /* HDMICEC interrupt as wakeupr */ + WKS_T_SD0 = 22, /* SD0 interrupt as wakeupr */ + WKS_T_WK5 = 23, /* Wakeup event number */ + WKS_T_PWRBTN = 24, /* PWRBTN as wakeup */ + WKS_T_RTC = 25, /* RTC as wakeup */ + CA9MP_RST = 26, /* CA9MP_RST */ + SOFT_RST = 27, /* SOFT_RST */ + CORE0_WD_RST = 28, /* CORE0_WD_RST */ + CORE1_WD_RST = 29 /* CORE1_WD_RST */ +}; + +static struct wakeup_source *wmt_ws; + +static struct workqueue_struct *wakeup_queue; +static struct delayed_work wakeupwork; + +static struct { + bool have_switch; + unsigned int gpio_no; + unsigned int wakeup_source; +}hall_switch; + + +#define DRIVER_NAME "PMC" +#if defined(CONFIG_PM_RTC_IS_GMT) && defined(RTC_WAKEUP_SUPPORT) +#include <linux/rtc.h> +#endif + +/* + * Debug macros + */ +#ifdef DEBUG +# define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args) +#else +# define DPRINTK(fmt, args...) +#endif + +/* + * For saving discontinuous registers during hibernation. + */ +#define SAVE(x) (saved[SAVED_##x] = (x##_VAL)) +#define RESTORE(x) ((x##_VAL) = saved[SAVED_##x]) + +enum { + SAVED_SP = 0, + SAVED_OSTW, SAVED_OSTI, + SAVED_PMCEL, SAVED_PMCEU, + SAVED_PMCE2, SAVED_PMCE3, + /* SAVED_ATAUDMA, */ + SAVED_SIZE +}; + +struct apm_dev_s { + char id; +}; + + +extern unsigned int wmt_read_oscr(void); +extern void wmt_read_rtc(unsigned int *date, unsigned int *time); +extern void wmt_serial_set_reg(void); + +/* Hibernation entry table physical address */ +#define LOADER_ADDR 0xffff0000 +#define HIBERNATION_ENTER_EXIT_CODE_BASE_ADDR 0xFFFFFFC0 +#define DO_POWER_ON_SLEEP (HIBERNATION_ENTER_EXIT_CODE_BASE_ADDR + 0x00) +#define DO_POWER_OFF_SUSPEND (HIBERNATION_ENTER_EXIT_CODE_BASE_ADDR + 0x04) +#define DO_WM_IO_SET (HIBERNATION_ENTER_EXIT_CODE_BASE_ADDR + 0x34) + +static unsigned int exec_at = (unsigned int)-1; + +/*from = 4 high memory*/ +static void (*theKernel)(int from); +//static void (*theKernel_io)(int from); + +#if defined(SOFT_POWER_SUPPORT) && defined(CONFIG_PROC_FS) +//static struct proc_dir_entry *proc_softpower; +static unsigned int softpower_data; +#endif + +static long rtc2sys; + +struct work_struct PMC_shutdown; +struct work_struct PMC_sync; + + +extern int wmt_getsyspara(char *varname, char *varval, int *varlen); +static int power_on_debounce_value = 100; /*power button debounce time when power on state*/ +static int resume_debounce_value = 2000; /*power button debounce time when press button to resume system*/ +static int power_up_debounce_value = 2000; /*power button debounce time when press button to power up*/ +#define min_debounce_value 0 +#define max_debounce_value 4000 + +char hotplug_path[256] = "/sbin/hotplug"; +static int sync_counter = 0; +static unsigned int time1, time2; + +#define REG_VAL(addr) (*((volatile unsigned int *)(addr))) + + +#ifdef KEYPAD_POWER_SUPPORT +#include <linux/input.h> +#define KPAD_POWER_FUNCTION_NUM 1 +#define power_button_timeout (HZ/10) +static struct input_dev *kpadPower_dev; +static unsigned int kpadPower_codes[KPAD_POWER_FUNCTION_NUM] = { + [0] = KEY_POWER +}; +static unsigned int powerKey_is_pressed; +static unsigned int pressed_jiffies; +static struct timer_list kpadPower_timer; +static spinlock_t kpadPower_lock; +#endif + +#ifdef CONFIG_BATTERY_WMT +static unsigned int battery_used; +#endif + +#ifdef CONFIG_CACHE_L2X0 +unsigned int l2x0_onoff; +unsigned int l2x0_aux; +unsigned int l2x0_prefetch_ctrl; +unsigned int en_static_address_filtering = 0; +unsigned int address_filtering_start = 0xD8000000; +unsigned int address_filtering_end = 0xD9000000; +static volatile unsigned int l2x0_base; +unsigned int cpu_trustzone_enabled = 0; +#endif + +//gri +static unsigned int var_fake_power_button=0; +static unsigned int var_wake_type2=0; +static unsigned int var_wake_type=0; +static unsigned int var_wake_param=0; +static unsigned int var_wake_en=0; +static unsigned int var_1st_flag=0; + +volatile unsigned int Wake_up_sts_mask = 0;// all static we add pwbn +static unsigned int dynamic_wakeup = 0; +static unsigned int dynamic_pmc_intr = 0; + +static unsigned int pmlock_1st_flag=0; +static unsigned int pmlock_intr_1st_flag=0; + +spinlock_t wmt_pm_lock; +spinlock_t wmt_pm_intr_lock; + +unsigned int WMT_WAKE_UP_EVENT;//for printing wakeup event + +/* wmt_pwrbtn_debounce_value() + * + * Entry to set the power button debounce value, the time unit is ms. + */ +static void wmt_pwrbtn_debounce_value(unsigned int time) +{ + volatile unsigned long debounce_value = 0 ; + unsigned long pmpb_value = 0; + + /*add a delay to wait pmc & rtc sync*/ + udelay(130); + + /*Debounce value unit is 1024 * RTC period ,RTC is 32KHz so the unit is ~ 32ms*/ + if (time % 32) + debounce_value = (time / 32) + 1; + else + debounce_value = (time / 32); + + pmpb_value = PMPB_VAL; + pmpb_value &= ~ PMPB_DEBOUNCE(0xff); + pmpb_value |= PMPB_DEBOUNCE(debounce_value); + + PMPB_VAL = pmpb_value; + //udelay(100); + DPRINTK("[%s] PMPB_VAL = 0x%.8X \n",__func__,PMPB_VAL); +} + +/* wmt_power_up_debounce_value() + * + * Entry to set the power button debounce value, the time unit is ms. + */ +void wmt_power_up_debounce_value(void) { + + //printk("[%s] power_up_debounce_value = %d \n",__func__,power_up_debounce_value); + wmt_pwrbtn_debounce_value(power_up_debounce_value); + +} + +static void run_sync(struct work_struct *work) +{ + int ret; + char *argv[] = { "/system/etc/wmt/script/force.sh", "PMC", NULL }; + char *envp_shutdown[] = + { "HOME=/", "PATH=/sbin:/bin:/usr/sbin:/usr/bin", "", NULL }; + + wmt_pwrbtn_debounce_value(power_up_debounce_value); + DPRINTK("[%s] start\n",__func__); + ret = call_usermodehelper(argv[0], argv, envp_shutdown, 0); + DPRINTK("[%s] sync end\n",__func__); +} + +static void run_shutdown(struct work_struct *work) +{ + int ret; + char *argv[] = { hotplug_path, "PMC", NULL }; + char *envp_shutdown[] = + { "HOME=/", "PATH=/sbin:/bin:/usr/sbin:/usr/bin", "ACTION=shutdown", NULL }; + DPRINTK("[%s] \n",__func__); + + wmt_pwrbtn_debounce_value(power_up_debounce_value); + ret = call_usermodehelper(argv[0], argv, envp_shutdown, 0); +} + +//kevin add support wakeup3/wakeup0 to wakeup ap +#include <mach/viatel.h> +irqreturn_t viatelcom_irq_cp_wake_ap(int irq, void *data); +extern int gpio_viatel_4wire[4]; + +void pmc_enable_wakeup_isr(enum wakeup_src_e wakeup_event, unsigned int type) +{ + unsigned long pm_lock_flags; + unsigned int wakeup_event_bit, wakeup_event_type; + unsigned int wakeup_event_temp; + + if (type > 4) + type = 4; + + if (! pmlock_intr_1st_flag) { + pmlock_intr_1st_flag = 1; + spin_lock_init(&wmt_pm_intr_lock); + } + + spin_lock_irqsave(&wmt_pm_intr_lock, pm_lock_flags); + switch (wakeup_event) { + case WKS_WK0: + wakeup_event_bit = (INT_TRG_EN_VAL | (1 << WKS_T_WK0)); + wakeup_event_type = ((INT_TYPE0_VAL & (~(0xf << (WKS_T_WK0 << 2)))) | (type << (WKS_T_WK0 << 2))); + do { + INT_TYPE0_VAL = wakeup_event_type; + } while(INT_TYPE0_VAL != wakeup_event_type); + break; + case WKS_WK2: + wakeup_event_bit = (INT_TRG_EN_VAL | (1 << WKS_T_WK2)); + wakeup_event_type = ((INT_TYPE0_VAL & (~(0xf << (WKS_T_WK2 << 2)))) | (type << (WKS_T_WK2 << 2))); + do { + INT_TYPE0_VAL = wakeup_event_type; + } while(INT_TYPE0_VAL != wakeup_event_type); + break; + case WKS_WK3: + wakeup_event_bit = (INT_TRG_EN_VAL | (1 << WKS_T_WK3)); + wakeup_event_type = ((INT_TYPE0_VAL & (~(0xf << (WKS_T_WK3 << 2)))) | (type << (WKS_T_WK3 << 2))); + do { + INT_TYPE0_VAL = wakeup_event_type; + } while(INT_TYPE0_VAL != wakeup_event_type); + break; + case WKS_WK4: + wakeup_event_bit = (INT_TRG_EN_VAL | (1 << WKS_T_WK4)); + wakeup_event_type = ((INT_TYPE0_VAL & (~(0xf << (WKS_T_WK4 << 2)))) | (type << (WKS_T_WK4 << 2))); + do { + INT_TYPE0_VAL = wakeup_event_type; + } while(INT_TYPE0_VAL != wakeup_event_type); + break; + case WKS_SUS0: + wakeup_event_bit = (INT_TRG_EN_VAL | (1 << WKS_T_SUS0)); + wakeup_event_type = ((INT_TYPE0_VAL & (~(0xf << (WKS_T_SUS0 << 2)))) | (type << (WKS_T_SUS0 << 2))); + do { + INT_TYPE0_VAL = wakeup_event_type; + } while(INT_TYPE0_VAL != wakeup_event_type); + break; + case WKS_SUS1: + wakeup_event_bit = (INT_TRG_EN_VAL | (1 << WKS_T_SUS1)); + wakeup_event_type = ((INT_TYPE0_VAL & (~(0xf << (WKS_T_SUS1 << 2)))) | (type << (WKS_T_SUS1 << 2))); + do { + INT_TYPE0_VAL = wakeup_event_type; + } while(INT_TYPE0_VAL != wakeup_event_type); + break; + case WKS_USBATTA0: + wakeup_event_bit = (INT_TRG_EN_VAL | (1 << WKS_T_USBATTA0)); + wakeup_event_type = ((INT_TYPE0_VAL & (~(0xf << (WKS_T_USBATTA0 << 2)))) | (type << (WKS_T_USBATTA0 << 2))); + do { + INT_TYPE0_VAL = wakeup_event_type; + } while(INT_TYPE0_VAL != wakeup_event_type); + break; + case WKS_CIRIN: + wakeup_event_bit = (INT_TRG_EN_VAL | (1 << WKS_T_CIRIN)); + wakeup_event_type = ((INT_TYPE0_VAL & (~(0xf << (WKS_T_CIRIN << 2)))) | (type << (WKS_T_CIRIN << 2))); + do { + INT_TYPE0_VAL = wakeup_event_type; + } while(INT_TYPE0_VAL != wakeup_event_type); + break; + case WKS_PWRBTN: + wakeup_event_bit = (INT_TRG_EN_VAL | (1 << WKS_T_PWRBTN)); + break; + case WKS_RTC: + wakeup_event_bit = (INT_TRG_EN_VAL | (1 << WKS_T_RTC)); + break; + case WKS_USBOC0: + wakeup_event_bit = (INT_TRG_EN_VAL | (1 << WKS_T_USBOC0)); + wakeup_event_temp = WKS_USBOC0 - WKS_USBOC0; + wakeup_event_type = ((INT_TYPE2_VAL & (~(0xf << (wakeup_event_temp << 2)))) | (type << (wakeup_event_temp << 2))); + do { + INT_TYPE2_VAL = wakeup_event_type; + } while(INT_TYPE2_VAL != wakeup_event_type); + break; + case WKS_USBOC1: + wakeup_event_bit = (INT_TRG_EN_VAL | (1 << WKS_T_USBOC1)); + wakeup_event_temp = WKS_USBOC1 - WKS_USBOC0; + wakeup_event_type = ((INT_TYPE2_VAL & (~(0xf << (wakeup_event_temp << 2)))) | (type << (wakeup_event_temp << 2))); + do { + INT_TYPE2_VAL = wakeup_event_type; + } while(INT_TYPE2_VAL != wakeup_event_type); + break; + case WKS_USBOC2: + wakeup_event_bit = (INT_TRG_EN_VAL | (1 << WKS_T_USBOC2)); + wakeup_event_temp = WKS_USBOC2 - WKS_USBOC0; + wakeup_event_type = ((INT_TYPE2_VAL & (~(0xf << (wakeup_event_temp << 2)))) | (type << (wakeup_event_temp << 2))); + do { + INT_TYPE2_VAL = wakeup_event_type; + } while(INT_TYPE2_VAL != wakeup_event_type); + break; + case WKS_USBOC3: + wakeup_event_bit = (INT_TRG_EN_VAL | (1 << WKS_T_USBOC3)); + wakeup_event_temp = WKS_USBOC3 - WKS_USBOC0; + wakeup_event_type = ((INT_TYPE2_VAL & (~(0xf << (wakeup_event_temp << 2)))) | (type << (wakeup_event_temp << 2))); + do { + INT_TYPE2_VAL = wakeup_event_type; + } while(INT_TYPE2_VAL != wakeup_event_type); + break; + case WKS_UHC: + wakeup_event_bit = (INT_TRG_EN_VAL | (1 << WKS_T_UHC)); + wakeup_event_temp = WKS_UHC - WKS_USBOC0; + wakeup_event_type = ((INT_TYPE2_VAL & (~(0xf << (wakeup_event_temp << 2)))) | (type << (wakeup_event_temp << 2))); + do { + INT_TYPE2_VAL = wakeup_event_type; + } while(INT_TYPE2_VAL != wakeup_event_type); + break; + case WKS_UDC: + wakeup_event_bit = (INT_TRG_EN_VAL | (1 << WKS_T_UDC)); + wakeup_event_temp = WKS_UDC - WKS_USBOC0; + wakeup_event_type = ((INT_TYPE2_VAL & (~(0xf << (wakeup_event_temp << 2)))) | (type << (wakeup_event_temp << 2))); + do { + INT_TYPE2_VAL = wakeup_event_type; + } while(INT_TYPE2_VAL != wakeup_event_type); + break; + case WKS_CIR: + wakeup_event_bit = (INT_TRG_EN_VAL | (1 << WKS_T_CIR)); + wakeup_event_temp = WKS_CIR - WKS_USBOC0; + wakeup_event_type = ((INT_TYPE2_VAL & (~(0xf << (wakeup_event_temp << 2)))) | (type << (wakeup_event_temp << 2))); + do { + INT_TYPE2_VAL = wakeup_event_type; + } while(INT_TYPE2_VAL != wakeup_event_type); + break; + case WKS_USBSW0: + wakeup_event_bit = (INT_TRG_EN_VAL | (1 << WKS_T_USBSW0)); + wakeup_event_temp = WKS_USBSW0 - WKS_USBOC0; + wakeup_event_type = ((INT_TYPE2_VAL & (~(0xf << (wakeup_event_temp << 2)))) | (type << (wakeup_event_temp << 2))); + do { + INT_TYPE2_VAL = wakeup_event_type; + } while(INT_TYPE2_VAL != wakeup_event_type); + break; + case WKS_SD3: + wakeup_event_bit = (INT_TRG_EN_VAL | (1 << WKS_T_SD3)); + wakeup_event_temp = WKS_SD3 - WKS_SD3 + 2; + wakeup_event_type = ((INT_TYPE1_VAL & (~(0xf << (wakeup_event_temp << 2)))) | (type << (wakeup_event_temp << 2))); + do { + INT_TYPE1_VAL = wakeup_event_type; + } while(INT_TYPE1_VAL != wakeup_event_type); + break; + case WKS_DCDET: + wakeup_event_bit = (INT_TRG_EN_VAL | (1 << WKS_T_DCDET)); + wakeup_event_temp = WKS_DCDET - WKS_SD3 + 2; + wakeup_event_type = ((INT_TYPE1_VAL & (~(0xf << (wakeup_event_temp << 2)))) | (type << (wakeup_event_temp << 2))); + do { + INT_TYPE1_VAL = wakeup_event_type; + } while(INT_TYPE1_VAL != wakeup_event_type); + break; + case WKS_SD2: + wakeup_event_bit = (INT_TRG_EN_VAL | (1 << WKS_T_SD2)); + wakeup_event_temp = WKS_SD2 - WKS_SD3 + 2; + wakeup_event_type = ((INT_TYPE1_VAL & (~(0xf << (wakeup_event_temp << 2)))) | (type << (wakeup_event_temp << 2))); + do { + INT_TYPE1_VAL = wakeup_event_type; + } while(INT_TYPE1_VAL != wakeup_event_type); + break; + case WKS_HDMICEC: + wakeup_event_bit = (INT_TRG_EN_VAL | (1 << WKS_T_HDMICEC)); + wakeup_event_temp = WKS_HDMICEC - WKS_SD3 + 2; + wakeup_event_type = ((INT_TYPE1_VAL & (~(0xf << (wakeup_event_temp << 2)))) | (type << (wakeup_event_temp << 2))); + do { + INT_TYPE1_VAL = wakeup_event_type; + } while(INT_TYPE1_VAL != wakeup_event_type); + break; + case WKS_SD0: + wakeup_event_bit = (INT_TRG_EN_VAL | (1 << WKS_T_SD0)); + wakeup_event_temp = WKS_SD0 - WKS_SD3 + 2; + wakeup_event_type = ((INT_TYPE1_VAL & (~(0xf << (wakeup_event_temp << 2)))) | (type << (wakeup_event_temp << 2))); + do { + INT_TYPE1_VAL = wakeup_event_type; + } while(INT_TYPE1_VAL != wakeup_event_type); + break; + case WKS_WK5: + wakeup_event_bit = (INT_TRG_EN_VAL | (1 << WKS_T_WK5)); + wakeup_event_temp = WKS_WK5 - WKS_SD3 + 2; + wakeup_event_type = ((INT_TYPE1_VAL & (~(0xf << (wakeup_event_temp << 2)))) | (type << (wakeup_event_temp << 2))); + do { + INT_TYPE1_VAL = wakeup_event_type; + } while(INT_TYPE1_VAL != wakeup_event_type); + break; + default: + goto pmc_enable_wakeup_isr_error; + break; + } + + while (PMCIS_VAL & (1 << wakeup_event)) { + PMCIS_VAL = (1 << wakeup_event); + } + + do { + INT_TRG_EN_VAL = wakeup_event_bit; + } while(INT_TRG_EN_VAL != wakeup_event_bit); + dynamic_pmc_intr = INT_TRG_EN_VAL; + +pmc_enable_wakeup_isr_error: + spin_unlock_irqrestore(&wmt_pm_intr_lock, pm_lock_flags); + +} +EXPORT_SYMBOL(pmc_enable_wakeup_isr); + +void pmc_disable_wakeup_isr(enum wakeup_src_e wakeup_event) +{ + + unsigned long pm_lock_flags; + unsigned int wakeup_event_bit; + + if (! pmlock_intr_1st_flag) { + pmlock_intr_1st_flag = 1; + spin_lock_init(&wmt_pm_intr_lock); + } + + spin_lock_irqsave(&wmt_pm_intr_lock, pm_lock_flags); + switch (wakeup_event) { + case WKS_WK0: + wakeup_event_bit = (INT_TRG_EN_VAL & (~(1 << WKS_T_WK0))); + break; + case WKS_WK2: + wakeup_event_bit = (INT_TRG_EN_VAL & (~(1 << WKS_T_WK2))); + break; + case WKS_WK3: + wakeup_event_bit = (INT_TRG_EN_VAL & (~(1 << WKS_T_WK3))); + break; + case WKS_WK4: + wakeup_event_bit = (INT_TRG_EN_VAL & (~(1 << WKS_T_WK4))); + break; + case WKS_SUS0: + wakeup_event_bit = (INT_TRG_EN_VAL & (~(1 << WKS_T_SUS0))); + break; + case WKS_SUS1: + wakeup_event_bit = (INT_TRG_EN_VAL & (~(1 << WKS_T_SUS1))); + break; + case WKS_USBATTA0: + wakeup_event_bit = (INT_TRG_EN_VAL & (~(1 << WKS_T_USBATTA0))); + break; + case WKS_CIRIN: + wakeup_event_bit = (INT_TRG_EN_VAL & (~(1 << WKS_T_CIRIN))); + break; + case WKS_PWRBTN: + wakeup_event_bit = (INT_TRG_EN_VAL & (~(1 << WKS_T_PWRBTN))); + break; + case WKS_RTC: + wakeup_event_bit = (INT_TRG_EN_VAL & (~(1 << WKS_T_RTC))); + break; + case WKS_USBOC0: + wakeup_event_bit = (INT_TRG_EN_VAL & (~(1 << WKS_T_USBOC0))); + break; + case WKS_USBOC1: + wakeup_event_bit = (INT_TRG_EN_VAL & (~(1 << WKS_T_USBOC1))); + break; + case WKS_USBOC2: + wakeup_event_bit = (INT_TRG_EN_VAL & (~(1 << WKS_T_USBOC2))); + break; + case WKS_USBOC3: + wakeup_event_bit = (INT_TRG_EN_VAL & (~(1 << WKS_T_USBOC3))); + break; + case WKS_UHC: + wakeup_event_bit = (INT_TRG_EN_VAL & (~(1 << WKS_T_UHC))); + break; + case WKS_UDC: + wakeup_event_bit = (INT_TRG_EN_VAL & (~(1 << WKS_T_UDC))); + break; + case WKS_CIR: + wakeup_event_bit = (INT_TRG_EN_VAL & (~(1 << WKS_T_CIR))); + break; + case WKS_USBSW0: + wakeup_event_bit = (INT_TRG_EN_VAL & (~(1 << WKS_T_USBSW0))); + break; + case WKS_SD3: + wakeup_event_bit = (INT_TRG_EN_VAL & (~(1 << WKS_T_SD3))); + break; + case WKS_DCDET: + wakeup_event_bit = (INT_TRG_EN_VAL & (~(1 << WKS_T_DCDET))); + break; + case WKS_SD2: + wakeup_event_bit = (INT_TRG_EN_VAL & (~(1 << WKS_T_SD2))); + break; + case WKS_HDMICEC: + wakeup_event_bit = (INT_TRG_EN_VAL & (~(1 << WKS_T_HDMICEC))); + break; + case WKS_SD0: + wakeup_event_bit = (INT_TRG_EN_VAL & (~(1 << WKS_T_SD0))); + break; + case WKS_WK5: + wakeup_event_bit = (INT_TRG_EN_VAL & (~(1 << WKS_T_WK5))); + break; + default: + goto pmc_disable_wakeup_isr_error; + break; + } + + do { + INT_TRG_EN_VAL = wakeup_event_bit; + } while(INT_TRG_EN_VAL != wakeup_event_bit); + dynamic_pmc_intr = INT_TRG_EN_VAL; + +pmc_disable_wakeup_isr_error: + spin_unlock_irqrestore(&wmt_pm_intr_lock, pm_lock_flags); + +} +EXPORT_SYMBOL(pmc_disable_wakeup_isr); + +void pmc_clear_intr_status(enum wakeup_src_e wakeup_event) +{ + unsigned long pm_lock_flags; + unsigned int wakeup_event_bit; + + if (! pmlock_intr_1st_flag) { + pmlock_intr_1st_flag = 1; + spin_lock_init(&wmt_pm_intr_lock); + } + + wakeup_event_bit = (1 << wakeup_event); + + spin_lock_irqsave(&wmt_pm_intr_lock, pm_lock_flags); + + while (PMCIS_VAL & wakeup_event_bit) { + PMCIS_VAL = wakeup_event_bit; + } + + spin_unlock_irqrestore(&wmt_pm_intr_lock, pm_lock_flags); +} +EXPORT_SYMBOL(pmc_clear_intr_status); + +void pmc_clear_wakeup_status(enum wakeup_src_e wakeup_event) +{ + unsigned long pm_lock_flags; + unsigned int wakeup_event_bit; + + if (! pmlock_1st_flag) { + pmlock_1st_flag = 1; + spin_lock_init(&wmt_pm_lock); + } + + wakeup_event_bit = (1 << wakeup_event); + + spin_lock_irqsave(&wmt_pm_lock, pm_lock_flags); + + while (PMWS_VAL & wakeup_event_bit) { + PMWS_VAL = wakeup_event_bit; + } + + spin_unlock_irqrestore(&wmt_pm_lock, pm_lock_flags); +} +EXPORT_SYMBOL(pmc_clear_wakeup_status); + +void pmc_enable_wakeup_event(enum wakeup_src_e wakeup_event, unsigned int type) +{ + unsigned int which_bit; + unsigned ori_type = 0; + unsigned long pm_lock_flags; + + if ((wakeup_event > WKS_CIRIN) && (wakeup_event < WKS_PWRBTN)) + return; + + if ((wakeup_event > WKS_USBSW0) && (wakeup_event < WKS_SD3)) + return; + + if (type > 4) + return; + + if (! pmlock_1st_flag) { + pmlock_1st_flag = 1; + spin_lock_init(&wmt_pm_lock); + } + + which_bit = (1 << wakeup_event); + + spin_lock_irqsave(&wmt_pm_lock, pm_lock_flags); + if (which_bit < 0x100) { + + ori_type = PMWT_VAL; + ori_type &= (~(0xf << (wakeup_event << 2))); + ori_type |= (type << (wakeup_event << 2)); + do { + PMWT_VAL = ori_type; + } while(PMWT_VAL != ori_type); + } else if (which_bit >= 0x1000000) { + unsigned int temp; + + temp = wakeup_event - 24; + + ori_type = PMWTC_VAL; + ori_type &= (~(0xf << (temp << 2))); + ori_type |= (type << (temp << 2)); + do { + PMWTC_VAL = ori_type; + } while(PMWTC_VAL != ori_type); + } else if (which_bit >= 0x10000) { + unsigned int temp; + temp = wakeup_event - 16; + + ori_type = WK_EVT_TYPE_VAL; + ori_type &= (~(0xf << (temp << 2))); + ori_type |= (type << (temp << 2)); + do { + WK_EVT_TYPE_VAL = ori_type; + } while(WK_EVT_TYPE_VAL != ori_type); + } + dynamic_wakeup |= (1 << wakeup_event); + + spin_unlock_irqrestore(&wmt_pm_lock, pm_lock_flags); +} +EXPORT_SYMBOL(pmc_enable_wakeup_event); + +void pmc_disable_wakeup_event(enum wakeup_src_e wakeup_event) +{ + + if (! pmlock_1st_flag) { + pmlock_1st_flag = 1; + spin_lock_init(&wmt_pm_lock); + } + + dynamic_wakeup &= (~(1 << wakeup_event)); + +} +EXPORT_SYMBOL(pmc_disable_wakeup_event); + + +static void wakeup_func(struct work_struct *work) +{ + struct file *fp; + mm_segment_t fs; + loff_t pos=0; + unsigned long flags; + char buf[3]; + + fp = filp_open("/sys/class/backlight/pwm-backlight.0/brightness", O_RDWR, 0777); + + if (IS_ERR(fp)) { + printk(KERN_ERR"open file error\n"); + return; + } + + fs = get_fs(); + set_fs(KERNEL_DS); + vfs_read(fp, buf, sizeof(buf), &pos); + filp_close(fp, NULL); + set_fs(fs); + //printk(KERN_ERR"%s buf %s\n",__FUNCTION__,buf); + if(gpio_get_value(hall_switch.gpio_no)){ + if(strncmp(buf,"0",1)) + { + return; + } + + } + else{ + if(!strncmp(buf,"0",1)) + { + return; + } + } + +#ifdef KEYPAD_POWER_SUPPORT + if(kpadPower_dev) { + + spin_lock_irqsave(&kpadPower_lock, flags); + if(!powerKey_is_pressed) { + powerKey_is_pressed = 1; + input_report_key(kpadPower_dev, KEY_POWER, 1); //power key is pressed + input_sync(kpadPower_dev); + pressed_jiffies = jiffies; + wmt_pwrbtn_debounce_value(power_up_debounce_value); + DPRINTK("\n[%s]power key pressed -->\n",__func__); + time1 = jiffies_to_msecs(jiffies); + __pm_wakeup_event(wmt_ws, (MSEC_PER_SEC >> 4)); + } + //disable_irq(IRQ_PMC_WAKEUP); + spin_unlock_irqrestore(&kpadPower_lock, flags); + mod_timer(&kpadPower_timer, jiffies + power_button_timeout); + } + #endif +} + +static irqreturn_t pmc_wakeup_isr(int this_irq, void *dev_id) +{ + unsigned int status_i; + unsigned long flags; + + status_i = PMCIS_VAL; + + rmb(); + + + //kevin add for wakeup3 to wakeup ap + if(status_i & (gpio_viatel_4wire[GPIO_VIATEL_USB_MDM_WAKE_AP]==149?BIT0:BIT2)){ + //printk("call viatelcom_irq_cp_wake_ap\n"); + viatelcom_irq_cp_wake_ap(this_irq,dev_id); + PMCIS_VAL |= (gpio_viatel_4wire[GPIO_VIATEL_USB_MDM_WAKE_AP]==149?BIT0:BIT2); + + } + + /* + * TODO : wakeup event and interrupt event share the same interrupt + * source IRQ_PMC. we should make a mechanism like 'request_irq' to + * register interrupt event callback function, and call the right + * function here. + */ + /* DCDET interrupt */ + //if (status_i & BIT27) { + // extern void dcdet_isr_callback(void); + // dcdet_isr_callback(); + // PMCIS_VAL |= BIT0; + //} + + if(hall_switch.have_switch && (status_i & (1<<(hall_switch.wakeup_source)))){ + //printk(KERN_ERR"call wakeup0\n"); + queue_delayed_work(wakeup_queue, &wakeupwork, msecs_to_jiffies(50)); + pmc_clear_intr_status(hall_switch.wakeup_source); + } + + if (status_i & BIT14) { + + pmc_clear_intr_status(WKS_PWRBTN); + #ifdef KEYPAD_POWER_SUPPORT + if(kpadPower_dev) { + + spin_lock_irqsave(&kpadPower_lock, flags); + if(!powerKey_is_pressed) { + powerKey_is_pressed = 1; + input_report_key(kpadPower_dev, KEY_POWER, 1); //power key is pressed + input_sync(kpadPower_dev); + pressed_jiffies = jiffies; + wmt_pwrbtn_debounce_value(power_up_debounce_value); + DPRINTK("\n[%s]power key pressed -->\n",__func__); + time1 = jiffies_to_msecs(jiffies); + __pm_wakeup_event(wmt_ws, (MSEC_PER_SEC >> 4)); + } + //disable_irq(IRQ_PMC_WAKEUP); + spin_unlock_irqrestore(&kpadPower_lock, flags); + mod_timer(&kpadPower_timer, jiffies + power_button_timeout); + } + #endif + + #if defined(SOFT_POWER_SUPPORT) && defined(CONFIG_PROC_FS) + softpower_data = 1; + #endif + + } + + return IRQ_HANDLED; +} + +extern int PM_device_PostSuspend(void); +extern int PM_device_PreResume(void); + +void check_pmc_busy(void) +{ + while (PMCS2_VAL&0x3F0038) + ; +} +void save_plla_speed(unsigned int *plla_div) +{ + plla_div[0] = PMARM_VAL;/*arm_div*/ + check_pmc_busy(); + plla_div[1]= PML2C_VAL;;/*l2c_div*/ + check_pmc_busy(); + plla_div[2] = PML2CTAG_VAL;/*l2c_tag_div*/ + check_pmc_busy(); + plla_div[3] = PML2CDATA_VAL;/*l2c_data_div*/ + check_pmc_busy(); + plla_div[4] = PML2CAXI_VAL;/*axi_l2c_div*/ + check_pmc_busy(); + plla_div[5] = PMDBGAPB_VAL;/*dbg_apb_div*/ + check_pmc_busy(); + plla_div[6] = PMPMA_VAL; + check_pmc_busy(); + +} + +void save_pllb_speed(unsigned int *pllb_div) +{ + check_pmc_busy(); + pllb_div[0] = PMPWM_VAL; + check_pmc_busy(); + pllb_div[1] = PMSDMMC_VAL; + check_pmc_busy(); + pllb_div[2] = PMSDMMC1_VAL; + check_pmc_busy(); + pllb_div[3] = PMSDMMC2_VAL; + check_pmc_busy(); + pllb_div[4] = PMI2C0_VAL; + check_pmc_busy(); + pllb_div[5] = PMI2C1_VAL; + check_pmc_busy(); + pllb_div[6] = PMI2C2_VAL; + check_pmc_busy(); + pllb_div[7] = PMI2C3_VAL; + check_pmc_busy(); + pllb_div[8] = PMI2C4_VAL; + check_pmc_busy(); + pllb_div[9] = PMSF_VAL; + check_pmc_busy(); + pllb_div[10] = PMSPI_VAL; + check_pmc_busy(); + pllb_div[11] = PMSPI1_VAL; + check_pmc_busy(); + pllb_div[12] = PMNAND_VAL; + check_pmc_busy(); + pllb_div[13] = PMNA12_VAL; + check_pmc_busy(); + pllb_div[14] = PMADC_VAL; + check_pmc_busy(); + pllb_div[15] = PMCSI0_VAL; + check_pmc_busy(); + pllb_div[16] = PMCSI1_VAL; + check_pmc_busy(); + pllb_div[17] = PMMALI_VAL; + check_pmc_busy(); + pllb_div[18] = PMPAXI_VAL; + check_pmc_busy(); + pllb_div[19] = PMSE_VAL; + check_pmc_busy(); + pllb_div[20] = PMPCM0_VAL; + check_pmc_busy(); + pllb_div[21] = PMPCM1_VAL; + check_pmc_busy(); + pllb_div[22] = PMAHB_VAL; + check_pmc_busy(); + pllb_div[23] = PMAPB0_VAL; + check_pmc_busy(); + pllb_div[24] = PMPMB_VAL; + check_pmc_busy(); + +} + +void save_plld_speed(unsigned int *plld_div) +{ + check_pmc_busy(); + plld_div[0] = PMWMTVDU_VAL;/*vdu_div*/ + check_pmc_busy(); + plld_div[1]= PMCNMVDU_VAL;;/*cnm_div*/ + check_pmc_busy(); + plld_div[2] = PMWMTNA_VAL;/*na_vdu_div*/ + check_pmc_busy(); + plld_div[3] = PMCNMNA_VAL;/*na_cnm_div*/ + check_pmc_busy(); +} + + +void restore_plla_speed(unsigned int *plla_div) +{ + + auto_pll_divisor(DEV_ARM, SET_PLLDIV, 2, 300); + PMARM_VAL = plla_div[0];/*arm_div*/ + wmb(); + check_pmc_busy(); + PML2C_VAL = plla_div[1];/*l2c_div*/ + wmb(); + check_pmc_busy(); + PML2CTAG_VAL = plla_div[2];/*l2c_tag_div*/ + wmb(); + check_pmc_busy(); + PML2CDATA_VAL = plla_div[3];/*l2c_data_div*/ + wmb(); + check_pmc_busy(); + PML2CAXI_VAL = plla_div[4];/*l2c_axi_div*/ + wmb(); + check_pmc_busy(); + PMDBGAPB_VAL = plla_div[5];/*dbg_apb_div*/ + wmb(); + check_pmc_busy(); + PMPMA_VAL = plla_div[6]; + wmb(); + check_pmc_busy(); +} + +void restore_pllb_speed(unsigned int *pllb_div) +{ + check_pmc_busy(); + PMPWM_VAL = pllb_div[0]; + wmb(); + check_pmc_busy(); +#if 0 + PMSDMMC_VAL = pllb_div[1]; + wmb(); + check_pmc_busy(); + PMSDMMC1_VAL = pllb_div[2]; + wmb(); + check_pmc_busy(); + PMSDMMC2_VAL = pllb_div[3]; + wmb(); + check_pmc_busy(); +#endif + PMI2C0_VAL = pllb_div[4]; + wmb(); + check_pmc_busy(); + PMI2C1_VAL = pllb_div[5]; + wmb(); + check_pmc_busy(); + PMI2C2_VAL = pllb_div[6]; + wmb(); + check_pmc_busy(); + PMI2C3_VAL = pllb_div[7]; + wmb(); + check_pmc_busy(); + PMI2C4_VAL = pllb_div[8]; + wmb(); + check_pmc_busy(); + PMSF_VAL = pllb_div[9]; + wmb(); + check_pmc_busy(); + PMSPI_VAL = pllb_div[10]; + wmb(); + check_pmc_busy(); + PMSPI1_VAL = pllb_div[11]; + wmb(); + check_pmc_busy(); + PMNAND_VAL = pllb_div[12]; + wmb(); + check_pmc_busy(); + PMNA12_VAL = pllb_div[13]; + wmb(); + check_pmc_busy(); + PMADC_VAL = pllb_div[14]; + wmb(); + check_pmc_busy(); + PMCSI0_VAL = pllb_div[15]; + wmb(); + check_pmc_busy(); + PMCSI1_VAL = pllb_div[16]; + wmb(); + check_pmc_busy(); + PMMALI_VAL = pllb_div[17]; + wmb(); + check_pmc_busy(); + PMPAXI_VAL = pllb_div[18]; + wmb(); + check_pmc_busy(); + PMSE_VAL = pllb_div[19]; + wmb(); + check_pmc_busy(); + PMPCM0_VAL = pllb_div[20]; + wmb(); + check_pmc_busy(); + PMPCM1_VAL = pllb_div[21]; + wmb(); + check_pmc_busy(); + PMAHB_VAL = pllb_div[22]; + wmb(); + check_pmc_busy(); + PMAPB0_VAL = pllb_div[23]; + wmb(); + check_pmc_busy(); + PMPMB_VAL = pllb_div[24]; + wmb(); + check_pmc_busy(); + +} + +void restore_plld_speed(unsigned int *plld_div) +{ + check_pmc_busy(); + PMWMTVDU_VAL = plld_div[0]; /*vdu_div*/ + wmb(); + check_pmc_busy(); + PMCNMVDU_VAL = plld_div[1]; /*cnm_div*/ + wmb(); + check_pmc_busy(); + PMWMTNA_VAL = plld_div[2]; /*na_vdu_div*/ + wmb(); + check_pmc_busy(); + PMCNMNA_VAL = plld_div[3]; /*na_cnm_div*/ + wmb(); + check_pmc_busy(); +} + + +/* wmt_pm_standby() + * + * Entry to the power-on sleep hibernation mode. + */ +static void wmt_pm_standby(void) +{ + volatile unsigned int hib_phy_addr = 0,base = 0; + +#ifdef CONFIG_CACHE_L2X0 + __u32 power_ctrl; + + if( l2x0_onoff == 1) + { + outer_cache.flush_all(); + outer_cache.disable(); + outer_cache.inv_all(); + } +#endif + + /* Get standby virtual address entry point */ + base = (unsigned int)ioremap_nocache(LOADER_ADDR, 0x10000); + + exec_at = base + (DO_POWER_ON_SLEEP - LOADER_ADDR); + hib_phy_addr = *(unsigned int *) exec_at; + exec_at = base + (hib_phy_addr - LOADER_ADDR); + + //led_light(3); + theKernel = (void (*)(int))exec_at; /* set rom address */ + theKernel(4); /* jump to rom */ + //led_light(3); + + iounmap((void __iomem *)base); + +#ifdef CONFIG_CACHE_L2X0 + if( l2x0_onoff == 1) + { + if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & 1)) + { + if(cpu_trustzone_enabled == 0) + { + /* l2x0 controller is disabled */ + writel_relaxed(l2x0_aux, l2x0_base + L2X0_AUX_CTRL); + + if( en_static_address_filtering == 1 ) + { + writel_relaxed(address_filtering_end, l2x0_base + 0xC04); + writel_relaxed((address_filtering_start | 0x01), l2x0_base + 0xC00); + } + + writel_relaxed(0x110, l2x0_base + L2X0_TAG_LATENCY_CTRL); + writel_relaxed(0x110, l2x0_base + L2X0_DATA_LATENCY_CTRL); + power_ctrl = readl_relaxed(l2x0_base + L2X0_POWER_CTRL) | L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN; + writel_relaxed(power_ctrl, l2x0_base + L2X0_POWER_CTRL); + + writel_relaxed(l2x0_prefetch_ctrl, l2x0_base + L2X0_PREFETCH_CTRL); + + outer_cache.inv_all(); + + /* enable L2X0 */ + writel_relaxed(1, l2x0_base + L2X0_CTRL); + } + else + { + /* l2x0 controller is disabled */ + wmt_smc(WMT_SMC_CMD_PL310AUX, l2x0_aux); + + if( en_static_address_filtering == 1 ) + { + wmt_smc(WMT_SMC_CMD_PL310FILTER_END, address_filtering_end); + wmt_smc(WMT_SMC_CMD_PL310FILTER_START, (address_filtering_start | 0x01)); + } + + wmt_smc(WMT_SMC_CMD_PL310TAG_LATENCY, 0x110); + wmt_smc(WMT_SMC_CMD_PL310DATA_LATENCY, 0x110); + power_ctrl = readl_relaxed(l2x0_base + L2X0_POWER_CTRL) | L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN; + wmt_smc(WMT_SMC_CMD_PL310POWER, power_ctrl); + + wmt_smc(WMT_SMC_CMD_PL310PREFETCH, l2x0_prefetch_ctrl); + + outer_cache.inv_all(); + + /* enable L2X0 */ + wmt_smc(WMT_SMC_CMD_PL310CTRL, 1); + } + + } + + } +#endif +} + +extern void wmt_assem_suspend(void); +extern void wmt_assem_secure_suspend(void); + +extern char use_dvfs; +/* wmt_pm_suspend() + * + * Entry to the power-off suspend hibernation mode. + */ + +static void wmt_pm_suspend(void) +{ + unsigned int saved[SAVED_SIZE]; + int result; + unsigned int plla_div[7]; + + unsigned int pllb_div[25]; + + unsigned int plld_div[4]; + + +#ifdef CONFIG_CACHE_L2X0 + __u32 power_ctrl; +#endif + +/* FIXME */ +#if 1 + result = PM_device_PostSuspend(); + if (result) + printk("PM_device_PostSuspend fail\n"); +#endif + +#ifdef CONFIG_CACHE_L2X0 + if( l2x0_onoff == 1) + { + outer_cache.flush_all(); + outer_cache.disable(); + outer_cache.inv_all(); + } +#endif + + SAVE(OSTW); /* save vital registers */ + SAVE(OSTI); + SAVE(PMCEL); /* save clock gating */ + SAVE(PMCEU); + SAVE(PMCE2); + SAVE(PMCE3); + + *(volatile unsigned int *)0xfe018008 |= 0x03030303; //scu output pm + + //for single core +#ifndef CONFIG_SMP + HSP7_VAL = 0xffffffb8; + while(HSP7_VAL != 0xffffffb8); + asm("sev" : : "r" (0)); +#endif + save_plld_speed(plld_div); /*save plld clock register*/ + + save_pllb_speed(pllb_div); /*save pllb clock register*/ + if (!use_dvfs) + save_plla_speed(plla_div); + //led_light(2); + + if(cpu_trustzone_enabled == 1) + wmt_assem_secure_suspend(); + else + wmt_assem_suspend(); + + RESTORE(PMCE3); + RESTORE(PMCE2); + RESTORE(PMCEU); /* restore clock gating */ + RESTORE(PMCEL); + RESTORE(OSTI); /* restore vital registers */ + RESTORE(OSTW); + wmt_serial_set_reg(); + + if (!use_dvfs) + restore_plla_speed(plla_div); /* restore plla clock register */ + + restore_pllb_speed(pllb_div); /* restore pllb clock register */ + + restore_plld_speed(plld_div); /* restore plld clock register */ + + PMPB_VAL |= 1; /* enable soft power */ + + //* ((volatile unsigned int *)0xfe140054) = 0x0; + +#ifdef CONFIG_CACHE_L2X0 + if( l2x0_onoff == 1) + { + if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & 1)) + { + if(cpu_trustzone_enabled == 0) + { + /* l2x0 controller is disabled */ + writel_relaxed(l2x0_aux, l2x0_base + L2X0_AUX_CTRL); + + if( en_static_address_filtering == 1 ) + { + writel_relaxed(address_filtering_end, l2x0_base + 0xC04); + writel_relaxed((address_filtering_start | 0x01), l2x0_base + 0xC00); + } + + writel_relaxed(0x110, l2x0_base + L2X0_TAG_LATENCY_CTRL); + writel_relaxed(0x110, l2x0_base + L2X0_DATA_LATENCY_CTRL); + power_ctrl = readl_relaxed(l2x0_base + L2X0_POWER_CTRL) | L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN; + writel_relaxed(power_ctrl, l2x0_base + L2X0_POWER_CTRL); + + writel_relaxed(l2x0_prefetch_ctrl, l2x0_base + L2X0_PREFETCH_CTRL); + + outer_cache.inv_all(); + + /* enable L2X0 */ + writel_relaxed(1, l2x0_base + L2X0_CTRL); + } + else + { + /* l2x0 controller is disabled */ + wmt_smc(WMT_SMC_CMD_PL310AUX, l2x0_aux); + + if( en_static_address_filtering == 1 ) + { + wmt_smc(WMT_SMC_CMD_PL310FILTER_END, address_filtering_end); + wmt_smc(WMT_SMC_CMD_PL310FILTER_START, (address_filtering_start | 0x01)); + } + + wmt_smc(WMT_SMC_CMD_PL310TAG_LATENCY, 0x110); + wmt_smc(WMT_SMC_CMD_PL310DATA_LATENCY, 0x110); + power_ctrl = readl_relaxed(l2x0_base + L2X0_POWER_CTRL) | L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN; + wmt_smc(WMT_SMC_CMD_PL310POWER, power_ctrl); + + wmt_smc(WMT_SMC_CMD_PL310PREFETCH, l2x0_prefetch_ctrl); + + outer_cache.inv_all(); + + /* enable L2X0 */ + wmt_smc(WMT_SMC_CMD_PL310CTRL, 1); + } + } + } +#endif + + result = PM_device_PreResume(); + if (result != 0) + printk("PM_device_PreResume fail\n"); +} + +/* wmt_pm_enter() + * + * To Finally enter the sleep state. + * + * Note: Only support PM_SUSPEND_STANDBY and PM_SUSPEND_MEM + */ +int wmt_trigger_resume_kpad = 0; +int wmt_trigger_resume_notify = 0; + +void wmt_resume_kpad(void) +{ + DPRINTK(KERN_ALERT "\n[%s]power key pressed\n",__func__); + powerKey_is_pressed = 1; + input_report_key(kpadPower_dev, KEY_POWER, 1); /*power key is pressed*/ + input_sync(kpadPower_dev); + pressed_jiffies = jiffies; + mod_timer(&kpadPower_timer, jiffies + power_button_timeout); +} + +void wmt_resume_notify(void) +{ + input_report_key(kpadPower_dev, KEY_POWER, 1); /*power key is pressed*/ + input_sync(kpadPower_dev); + input_report_key(kpadPower_dev, KEY_POWER, 0); //power key is released + input_sync(kpadPower_dev); +} + +static int wmt_pm_enter(suspend_state_t state) +{ + unsigned int status, status_i; +// unsigned int wakeup_notify; + + int notify_framwork = 0; + + if (!((state == PM_SUSPEND_STANDBY) || (state == PM_SUSPEND_MEM))) { + printk(KERN_ALERT "%s, Only support PM_SUSPEND_STANDBY and PM_SUSPEND_MEM\n", DRIVER_NAME); + return -EINVAL; + } + + /* only enable fiq in normal operation */ + //local_fiq_disable(); + //local_irq_disable(); + /* disable system OS timer */ + OSTC_VAL &= ~OSTC_ENABLE; + + + /* FIXME, 2009/09/15 */ + //PMCDS_VAL = PMCDS_VAL; + + WMT_WAKE_UP_EVENT = 0; + /*set power button debounce value*/ + wmt_pwrbtn_debounce_value(resume_debounce_value); + + /* + * We use pm_standby as apm_standby for power-on hibernation. + * but we still suspend memory in both case. + */ + + if (state == PM_SUSPEND_STANDBY) + wmt_pm_standby(); /* Go to standby mode*/ + else + wmt_pm_suspend(); /* Go to suspend mode*/ + + /*set power button debounce value*/ + wmt_pwrbtn_debounce_value(power_on_debounce_value); + + /* + * Clean wakeup source + */ + + status = PMWS_VAL; + status_i = PMCIS_VAL; + WMT_WAKE_UP_EVENT = (PMWS_VAL & (WK_TRG_EN_VAL | 0x4000));//wmt_pm_enter + status = (status & Wake_up_sts_mask); + + PMCIS_VAL = PMCIS_VAL; + + //notify_framwork=1; + +#ifdef KEYPAD_POWER_SUPPORT + if (status & (1 << WKS_PWRBTN)) { + wmt_trigger_resume_kpad = 1; + } +#endif + + if (status & (1 << WKS_WK5)){ + DPRINTK(KERN_ALERT "\n[%s]WK5 event\n",__func__); + if (var_fake_power_button & (1 << WKS_WK5)) + notify_framwork=1; + } + + if (status & (1 << WKS_SD0)){ + DPRINTK(KERN_ALERT "\n[%s]SD0 event\n",__func__); + if (var_fake_power_button & (1 << WKS_SD0)) + notify_framwork=1; + } + + if (status & (1 << WKS_HDMICEC)){ + DPRINTK(KERN_ALERT "\n[%s]HDMICEC event\n",__func__); + if (var_fake_power_button & (1 << WKS_HDMICEC)) + notify_framwork=1; + } + + if (status & (1 << WKS_SD2)){ + DPRINTK(KERN_ALERT "\n[%s]SD2 event\n",__func__); + if (var_fake_power_button & (1 << WKS_SD2)) + notify_framwork=1; + } + + if (status & (1 << WKS_DCDET)){ + DPRINTK(KERN_ALERT "\n[%s]DCDET event\n",__func__); + if (var_fake_power_button & (1 << WKS_DCDET)) + notify_framwork=1; + } + + if (status & (1 << WKS_SD3)){ + DPRINTK(KERN_ALERT "\n[%s]SD3 event\n",__func__); + if (var_fake_power_button & (1 << WKS_SD3)) + notify_framwork=1; + } + + if (status & (1 << WKS_USBSW0)){ + DPRINTK(KERN_ALERT "\n[%s]USBSW0 event\n",__func__); + if (var_fake_power_button & (1 << WKS_USBSW0)) + notify_framwork=1; + } + +#ifdef CIR_WAKEUP_SUPPORT + if (status & (1 << WKS_CIR)){ + DPRINTK(KERN_ALERT "\n[%s]CIR event\n",__func__); + if (var_fake_power_button & (1 << WKS_CIR)) + notify_framwork=1; + } +#endif + +#ifdef CONFIG_USB_GADGET_WMT +/*UDC wake up source*/ + if (status & (1 << WKS_UDC)){ + DPRINTK(KERN_ALERT "\n[%s]UDC event\n",__func__); + if (var_fake_power_button & (1 << WKS_UDC)) + notify_framwork=1; + } +#endif + +#ifdef CONFIG_USB +//UHC + if (status & (1 << WKS_UHC)){ + DPRINTK(KERN_ALERT "\n[%s]UHC event\n",__func__); + if (var_fake_power_button & (1 << WKS_UHC)) + notify_framwork=1; + } + + if (status & (1 << WKS_USBOC3)){ + DPRINTK(KERN_ALERT "\n[%s]USBOC3 event\n",__func__); + if (var_fake_power_button & (1 << WKS_USBOC3)) + notify_framwork=1; + } + + if (status & (1 << WKS_USBOC2)){ + DPRINTK(KERN_ALERT "\n[%s]USBOC2 event\n",__func__); + if (var_fake_power_button & (1 << WKS_USBOC2)) + notify_framwork=1; + } + + if (status & (1 << WKS_USBOC1)){ + DPRINTK(KERN_ALERT "\n[%s]USBOC1 event\n",__func__); + if (var_fake_power_button & (1 << WKS_USBOC1)) + notify_framwork=1; + } + + if (status & (1 << WKS_USBOC0)){ + DPRINTK(KERN_ALERT "\n[%s]USBOC0 event\n",__func__); + if (var_fake_power_button & (1 << WKS_USBOC0)) + notify_framwork=1; + } +#endif + +#ifdef RTC_WAKEUP_SUPPORT + if (status & (1 << WKS_RTC)){ + DPRINTK(KERN_ALERT "\n[%s]RTC event\n",__func__); + if (var_fake_power_button & (1 << WKS_RTC)) + notify_framwork=1; + } +#endif + + if (status & (1 << WKS_CIRIN)){ + DPRINTK(KERN_ALERT "\n[%s]CIRIN event\n",__func__); + if (var_fake_power_button & (1 << WKS_CIRIN)) + notify_framwork=1; + } + +#ifdef CONFIG_USB_GADGET_WMT + /*UDC2 wake up source*/ + if (status & (1 << WKS_USBATTA0)){ + DPRINTK(KERN_ALERT "\n[%s]UDCATTA0 event\n",__func__); + if (var_fake_power_button & (1 << WKS_USBATTA0)) + notify_framwork=1; + } +#endif + + if(status & (1 << WKS_SUS1)){ + DPRINTK(KERN_ALERT "\n[%s]SUS1 event\n",__func__); + if (var_fake_power_button & (1 << WKS_SUS1)) + notify_framwork=1; + } + + if(status & (1 << WKS_SUS0)){ + DPRINTK(KERN_ALERT "\n[%s]SUS0 event\n",__func__); + if (var_fake_power_button & (1 << WKS_SUS0)) + notify_framwork=1; + } + + if(status & (1 << WKS_WK4)){ + DPRINTK(KERN_ALERT "\n[%s]WK4 event\n",__func__); + if (var_fake_power_button & (1 << WKS_WK4)) + notify_framwork=1; + } + + if (status & (1 << WKS_WK3)){ + DPRINTK(KERN_ALERT "\n[%s]WK3 event\n",__func__); + if (var_fake_power_button & (1 << WKS_WK3)) + notify_framwork=1; + } + + if (status & (1 << WKS_WK2)){ + DPRINTK(KERN_ALERT "\n[%s]WK2 event\n",__func__); + if (var_fake_power_button & (1 << WKS_WK2)) + notify_framwork=1; + } + + if (status & (1 << WKS_WK0)){ + DPRINTK(KERN_ALERT "\n[%s]WK0 event\n",__func__); + if (var_fake_power_button & (1 << WKS_WK0)) + notify_framwork=1; + } + + if (notify_framwork) { + wmt_trigger_resume_notify = 1; + } + +#ifdef RTC_WAKEUP_SUPPORT + RTAS_VAL = 0x0; /* Disable RTC alarm */ +#endif + + /* + * Force to do once CPR for system. + */ + OSM1_VAL = wmt_read_oscr() + LATCH; + OSTC_VAL |= OSTC_ENABLE; + + //udelay(200); /* delay for resume not complete */ + + /* + * disable trigger wakeup event + */ + do { + WK_TRG_EN_VAL = 0x4000; + } while(WK_TRG_EN_VAL != 0x4000); + + return 0; +} + + +/* wmt_pm_prepare() + * + * Called after processes are frozen, but before we shut down devices. + */ +static int wmt_pm_prepare(void) +{ + unsigned int date, time; + struct timeval tv; + + /* + * Estimate time zone so that wmt_pm_finish can update the GMT time + */ + + rtc2sys = 0; + + if ((*(volatile unsigned int *)SYSTEM_CFG_CTRL_BASE_ADDR)>0x34260102) { + wmt_read_rtc(&date, &time); + } + + do_gettimeofday(&tv); + + rtc2sys = mktime(RTCD_YEAR(date) + ((RTCD_CENT(date) * 100) + 2000), + RTCD_MON(date), + RTCD_MDAY(date), + RTCT_HOUR(time), + RTCT_MIN(time), + RTCT_SEC(time)); + rtc2sys = rtc2sys-tv.tv_sec; + if (rtc2sys > 0) + rtc2sys += 10; + else + rtc2sys -= 10; + rtc2sys = rtc2sys/60/60; + rtc2sys = rtc2sys*60*60; + + return 0; +} + +/* wmt_pm_finish() + * + * Called after devices are re-setup, but before processes are thawed. + */ +static void wmt_pm_finish(void) +{ + unsigned int date, time; + struct timespec tv; + +#if 0 + struct rtc_time tm; + unsigned long tmp = 0; + struct timeval tv1; +#endif + /* FIXME: + * There are a warning when call iounmap here, + * please iounmap the mapped virtual ram later */ + // iounmap((void *)exec_at); + + /* + * Update kernel time spec. + */ + if ((*(volatile unsigned int *)SYSTEM_CFG_CTRL_BASE_ADDR)>0x34260102) { + wmt_read_rtc(&date, &time); + } + + tv.tv_nsec = 0; + tv.tv_sec = mktime(RTCD_YEAR(date) + ((RTCD_CENT(date) * 100) + 2000), + RTCD_MON(date), + RTCD_MDAY(date), + RTCT_HOUR(time), + RTCT_MIN(time), + RTCT_SEC(time)); + /* RTC stores local time, adjust GMT time, tv */ + tv.tv_sec = tv.tv_sec-rtc2sys; + do_settimeofday(&tv); + +} + +static int wmt_pm_valid(suspend_state_t state) +{ + switch (state) { + case PM_SUSPEND_STANDBY: + case PM_SUSPEND_MEM: + return 1; + default: + return 0; + } +} + +static struct platform_suspend_ops wmt_pm_ops = { + .valid = wmt_pm_valid, + .prepare = wmt_pm_prepare, + .enter = wmt_pm_enter, + .finish = wmt_pm_finish, +}; + +#if 0 +#if defined(SOFT_POWER_SUPPORT) && defined(CONFIG_PROC_FS) + +static int procfile_read(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + int len = 0; + len = sprintf(page, "%d\n", softpower_data); + return len; +} + + +static int procfile_write(struct file *file, const char *buffer, unsigned long count, void *data) +{ + char *endp; + + softpower_data = simple_strtoul(buffer, &endp, 0); + + if (softpower_data != 0) + softpower_data = 1; + +/* printk("%s: %s, softpower_data=[0x%X]\n", DRIVER_NAME, __FUNCTION__, softpower_data );*/ +/* printk("%s: return [%d]\n", DRIVER_NAME, (count + endp - buffer ) );*/ + + return (count + endp - buffer); +} + +#endif /* defined(SOFT_POWER_SUPPORT) && defined(CONFIG_PROC_FS)*/ +#endif + +#ifdef KEYPAD_POWER_SUPPORT +static inline void kpadPower_timeout(unsigned long fcontext) +{ + + struct input_dev *dev = (struct input_dev *) fcontext; + //printk("-------------------------> kpadPower time out\n"); + time2 = jiffies_to_msecs(jiffies); + if ((time2 - time1) > 2000 && sync_counter > 4) { //2000 msec + schedule_work(&PMC_sync); + //DPRINTK("1[%s]dannier count=%d jiffies=%lu, %d\n",__func__, sync_counter, jiffies,jiffies_to_msecs(jiffies)); + } //else + //DPRINTK("0[%s]dannier count=%d jiffies=%lu, %d\n",__func__, sync_counter, jiffies,jiffies_to_msecs(jiffies)); + DPRINTK(KERN_ALERT "\n[%s]kpadPower time out GPIO_ID_GPIO_VAL = %x\n",__func__,GPIO_ID_GPIO_VAL); + if(!kpadPower_dev) + return; + + spin_lock_irq(&kpadPower_lock); + + if(!(PMPB_VAL & BIT24)) { + input_report_key(dev, KEY_POWER, 0); //power key is released + input_sync(dev); + powerKey_is_pressed = 0; + wmt_pwrbtn_debounce_value(power_on_debounce_value); + DPRINTK("[%s]power key released\n",__func__); + sync_counter = 0; + }else { + DPRINTK("[%s]power key not released\n",__func__); + mod_timer(&kpadPower_timer, jiffies + power_button_timeout); + sync_counter++; + } + + spin_unlock_irq(&kpadPower_lock); + +} +#endif + +static int wmt_wakeup_pm_notify(struct notifier_block *nb, unsigned long event, + void *dummy) +{ + unsigned long pm_lock_flags; + + spin_lock_irqsave(&wmt_pm_lock, pm_lock_flags); + if (event == PM_SUSPEND_PREPARE) { + dynamic_pmc_intr = INT_TRG_EN_VAL; + do { + INT_TRG_EN_VAL = 0; + } while (INT_TRG_EN_VAL != 0); + + PMWS_VAL = PMWS_VAL; + + do { + WK_TRG_EN_VAL = (Wake_up_sts_mask | dynamic_wakeup); + } while (WK_TRG_EN_VAL != (Wake_up_sts_mask | dynamic_wakeup)); + + } else if (event == PM_POST_SUSPEND) { + do { + INT_TRG_EN_VAL = dynamic_pmc_intr; + } while (INT_TRG_EN_VAL != dynamic_pmc_intr); + + do { + WK_TRG_EN_VAL = 0x4000; + } while (WK_TRG_EN_VAL != 0x4000); + + } + spin_unlock_irqrestore(&wmt_pm_lock, pm_lock_flags); + return NOTIFY_OK; +} + +static struct notifier_block wmt_pmc_pm_notify = { + .notifier_call = wmt_wakeup_pm_notify, +}; +#ifdef CONFIG_HIBERNATION +static int wmt_hibernation_begin(void) +{ + printk("\n!!! %s:Enter\n",__FUNCTION__); + disable_hlt(); + return 0; +} +unsigned int saved[SAVED_SIZE]; +unsigned int plla_div[7]; +unsigned int pllb_div[25]; +unsigned int plld_div[4]; +#ifdef CONFIG_CACHE_L2X0 + __u32 power_cntrl; +#endif + +static int wmt_hibernation_pre_snapshot(void) +{ + int result; +#ifdef CONFIG_CACHE_L2X0 + volatile unsigned int l2x0_base; +#endif + printk("\n!!! %s:Enter\n",__FUNCTION__); +#if 1 + result = PM_device_PostSuspend(); + if (result) + printk("\n %s : PM_device_PostSuspend fail\n", __FUNCTION__); +#endif +#ifdef CONFIG_CACHE_L2X0 + if( l2x0_onoff == 1) + { + l2x0_base = (volatile unsigned int) ioremap(0xD9000000, SZ_4K); + outer_cache.flush_all(); + outer_cache.disable(); + outer_cache.inv_all(); + } +#endif + SAVE(OSTW); /* save vital registers */ + SAVE(OSTI); + SAVE(PMCEL); /* save clock gating */ + SAVE(PMCEU); + SAVE(PMCE2); + SAVE(PMCE3); + //for single core, sev to make cpu1 out of wfe. + #ifndef CONFIG_SMP + HSP7_VAL = 0xffffffb8; + while(HSP7_VAL != 0xffffffb8); + asm("sev" : : "r" (0)); + #endif + save_plld_speed(plld_div); /*save plld clock register*/ + save_pllb_speed(pllb_div); /*save pllb clock register*/ + if (!use_dvfs) + save_plla_speed(plla_div); + return 0; +} +static void wmt_hibernation_leave(void) +{ +int result; +#ifdef CONFIG_CACHE_L2X0 + volatile unsigned int l2x0_base; +#endif + printk("\n!!! %s:Enter\n",__FUNCTION__); + RESTORE(PMCE3); + RESTORE(PMCE2); + RESTORE(PMCEU); /* restore clock gating */ + RESTORE(PMCEL); + RESTORE(OSTI); /* restore vital registers */ + RESTORE(OSTW); + wmt_serial_set_reg(); + if (!use_dvfs) + restore_plla_speed(plla_div); /* restore plla clock register */ + restore_pllb_speed(pllb_div); /* restore pllb clock register */ + restore_plld_speed(plld_div); /* restore plld clock register */ + PMPB_VAL |= 1; /* enable soft power */ +#ifdef CONFIG_CACHE_L2X0 + if( l2x0_onoff == 1) + { + l2x0_base = (volatile unsigned int) ioremap(0xD9000000, SZ_4K); + if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & 1)) + { + writel_relaxed(l2x0_aux, l2x0_base + L2X0_AUX_CTRL); + if( en_static_address_filtering == 1 ) + { + writel_relaxed(address_filtering_end, l2x0_base + 0xC04); + writel_relaxed((address_filtering_start | 0x01), l2x0_base + 0xC00); + } + writel_relaxed(0x110, l2x0_base + L2X0_TAG_LATENCY_CTRL); + writel_relaxed(0x110, l2x0_base + L2X0_DATA_LATENCY_CTRL); + power_cntrl = readl_relaxed(l2x0_base + L2X0_POWER_CTRL) | L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN; + writel_relaxed(power_cntrl, l2x0_base + L2X0_POWER_CTRL); + writel_relaxed(l2x0_prefetch_ctrl, l2x0_base + L2X0_PREFETCH_CTRL); + outer_cache.inv_all(); + writel_relaxed(1, l2x0_base + L2X0_CTRL); + } + iounmap((void __iomem *)l2x0_base); + } +#endif + result = PM_device_PreResume(); + if (!result) + printk("PM_device_PreResume fail\n"); +} +static void wmt_hibernation_finish(void) +{ + extern int env_cache_flush(void); + int ret; + printk("\n!!! %s:Enter\n",__FUNCTION__); + ret = env_cache_flush(); + if(!ret) + printk("env_cache_flush success.\n"); +} +static void wmt_hibernation_end(void) +{ + printk("\n!!! %s:Enter\n",__FUNCTION__); + enable_hlt(); +} +static int wmt_hibernation_prepare(void) +{ + printk("\n!!! %s:Enter\n",__FUNCTION__); + return 0; +} +static int wmt_hibernation_enter(void) +{ + int std_stress_test = 0; + int ret; + char buf_env[80]; + int varlen = sizeof(buf_env); + printk("\n!!! %s:Enter\n",__FUNCTION__); + ret = wmt_getsyspara("wmt.std.stress", buf_env, &varlen); + if (ret == 0) + sscanf(buf_env, "%d", &std_stress_test); + if(std_stress_test) { + printk(KERN_CRIT "\n Do STD Stress Test \n"); + machine_restart(NULL); + }else{ + printk(KERN_CRIT "\n No Stress Test \n"); + machine_power_off(); + } + return 0; +} +static int wmt_hibernation_pre_restore(void) +{ + printk("\n!!! %s:Enter\n",__FUNCTION__); + return 0; +} +static void wmt_hibernation_restore_cleanup(void) +{ + printk("\n!!! %s:Enter\n",__FUNCTION__); +} +static const struct platform_hibernation_ops wmt_hibernation_ops = { + .begin = wmt_hibernation_begin, + .end = wmt_hibernation_end, + .pre_snapshot = wmt_hibernation_pre_snapshot, + .finish = wmt_hibernation_finish, + .prepare = wmt_hibernation_prepare, + .enter = wmt_hibernation_enter, + .leave = wmt_hibernation_leave, + .pre_restore = wmt_hibernation_pre_restore, + .restore_cleanup = wmt_hibernation_restore_cleanup, +}; +#endif +/* + * Initialize power management interface + */ +static int __init wmt_pm_init(void) +{ + struct apm_dev_s *pm_dev; + char buf[256]; + char varname[] = "wmt.pwbn.param"; + int varlen = 256; + char wake_buf[100]; + char wake_varname[] = "wmt.pmc.param"; + int wake_varlen = 100; +#ifdef CONFIG_BATTERY_WMT + char bat_varname[] = "wmt.io.bat"; +#endif + +#ifdef KEYPAD_POWER_SUPPORT + int i; + + kpadPower_dev = input_allocate_device(); + if(kpadPower_dev) { + //Initial the static variable + spin_lock_init(&kpadPower_lock); + powerKey_is_pressed = 0; + pressed_jiffies = 0; + init_timer(&kpadPower_timer); + kpadPower_timer.function = kpadPower_timeout; + kpadPower_timer.data = (unsigned long)kpadPower_dev; + + /* Register an input event device. */ + set_bit(EV_KEY,kpadPower_dev->evbit); + for (i = 0; i < KPAD_POWER_FUNCTION_NUM; i++) + set_bit(kpadPower_codes[i], kpadPower_dev->keybit); + + kpadPower_dev->name = "kpadPower", + kpadPower_dev->phys = "kpadPower", + + + kpadPower_dev->keycode = kpadPower_codes; + kpadPower_dev->keycodesize = sizeof(unsigned int); + kpadPower_dev->keycodemax = KPAD_POWER_FUNCTION_NUM; + + /* + * For better view of /proc/bus/input/devices + */ + kpadPower_dev->id.bustype = 0; + kpadPower_dev->id.vendor = 0; + kpadPower_dev->id.product = 0; + kpadPower_dev->id.version = 0; + input_register_device(kpadPower_dev); + } else + printk("[wmt_pm_init]Error: No memory for registering Kpad Power\n"); +#endif + + register_pm_notifier(&wmt_pmc_pm_notify); + +//gri + if (! pmlock_1st_flag) { + pmlock_1st_flag = 1; + spin_lock_init(&wmt_pm_lock); + } + if (! pmlock_intr_1st_flag) { + pmlock_intr_1st_flag = 1; + spin_lock_init(&wmt_pm_intr_lock); + } + + if (wmt_getsyspara(wake_varname, wake_buf, &wake_varlen) == 0) { + sscanf(wake_buf,"%x:%x:%x:%x:%x", + &var_wake_en, + &var_wake_param, + &var_wake_type, + &var_wake_type2, + &var_fake_power_button); + } + else { + var_wake_en = 1; + var_wake_param = 0x0040C080; //cir rtc pwrbtn dcdet(cirin) + var_wake_type = 0x40000000; + var_wake_type2 = 0x0; + var_fake_power_button = 0x00400080; + } + + Wake_up_sts_mask = (var_wake_param | BIT14); // add power button + + var_1st_flag = 1; + + printk("[%s] var define var_wake_en=%x var_wake_param=%x var_wake_type=%x var_wake_type2=%x var_fake_power_button=%x\n", + __func__, var_wake_en, var_wake_param, var_wake_type, var_wake_type2, var_fake_power_button); + +#if 0//test pmc_enable_wakeup_event + do { + WK_EVT_TYPE_VAL = 0x33333333; + } while (WK_EVT_TYPE_VAL != 0x33333333); + + { + unsigned int i_temp, en_temp, en_type; + i_temp = 0; + en_type = 0; + do { + en_temp = (var_wake_param & (1 << i_temp)); + if (en_temp) { + if (en_temp < 0x100) + en_type = ((var_wake_type >> (i_temp << 2)) & 0xf); + else if(en_temp >= 0x1000000) + en_type = ((var_wake_type2 >> ((i_temp - 24) << 2)) & 0xf); + else if(en_temp == 0x200000) + en_type = ((var_wake_type >> 24) & 0xf); + else + en_type = 3; + printk("en_temp 0x%x en_type 0x%x\n",i_temp,en_type); + pmc_enable_wakeup_event(i_temp, en_type); + } + i_temp++; + } while (i_temp < 32); + } +#else + { + unsigned int i_temp; + do { + PMWT_VAL = var_wake_type; + } while(PMWT_VAL != var_wake_type); + do { + PMWTC_VAL = var_wake_type2; + } while(PMWTC_VAL != var_wake_type2); + + if (var_wake_param & BIT21) + i_temp = 0x33433333; + else + i_temp = 0x33333333; + do { + WK_EVT_TYPE_VAL = i_temp; + } while(WK_EVT_TYPE_VAL != i_temp); + } +#endif + + printk("[%s] WK_TRG_EN_VAL=0x%x PMWT_VAL=0x%x PMWTC_VAL=0x%x WK_EVT_TYPE_VAL=0x%x\n", + __func__, WK_TRG_EN_VAL, PMWT_VAL, PMWTC_VAL, WK_EVT_TYPE_VAL); + +#ifdef CONFIG_BATTERY_WMT + if (wmt_getsyspara(bat_varname, buf, &varlen) == 0) { + sscanf(buf,"%x", &battery_used); + } + printk("[%s] battery_used = %x\n",__func__, battery_used); +#endif + +#ifdef CONFIG_CACHE_L2X0 + if(wmt_getsyspara("wmt.l2c.param",buf,&varlen) == 0) + sscanf(buf,"%d:%x:%x:%d:%x:%x",&l2x0_onoff, &l2x0_aux, &l2x0_prefetch_ctrl, &en_static_address_filtering, &address_filtering_start, &address_filtering_end); + if( l2x0_onoff == 1) + l2x0_base = (volatile unsigned int) ioremap(0xD9000000, SZ_4K); + + if (wmt_getsyspara("wmt.secure.param",buf,&varlen) == 0) + sscanf(buf,"%d",&cpu_trustzone_enabled); + if(cpu_trustzone_enabled != 1) + cpu_trustzone_enabled = 0; +#endif + + /* Press power button (either hard-power or soft-power) will trigger a power button wakeup interrupt*/ + /* Press reset button will not trigger any PMC wakeup interrupt*/ + /* Hence, force write clear all PMC wakeup interrupts before request PMC wakeup IRQ*/ + + //move to wload + //PMWS_VAL = PMWS_VAL; + //PMCIS_VAL = PMCIS_VAL; + + INIT_WORK(&PMC_shutdown, run_shutdown); + INIT_WORK(&PMC_sync, run_sync); + + /* + * set interrupt service routine + */ +// if (request_irq(IRQ_PMC_WAKEUP, &pmc_wakeup_isr, IRQF_DISABLED, "pmc", &pm_dev) < 0) + if (request_irq(IRQ_PMC_WAKEUP, &pmc_wakeup_isr, IRQF_SHARED, "pmc", &pm_dev) < 0) + printk(KERN_ALERT "%s: [Wondermedia_pm_init] Failed to register pmc wakeup irq \n" + , DRIVER_NAME); + + irq_set_irq_wake(IRQ_PMC_WAKEUP, 1); + +#ifndef CONFIG_SKIP_DRIVER_MSG + /* + * Plan to remove it to recude core size in the future. + */ + printk(KERN_INFO "%s: WonderMedia Power Management driver\n", DRIVER_NAME); +#endif + + /* + * Setup PM core driver into kernel. + */ + suspend_set_ops(&wmt_pm_ops); + +#ifdef CONFIG_HIBERNATION + hibernation_set_ops(&wmt_hibernation_ops);//support hibernation platform mode +#endif /* CONFIG_HIBERNATION */ +#if defined(SOFT_POWER_SUPPORT) && defined(CONFIG_PROC_FS) + + /* Power button is configured as soft power*/ + printk("%s: Power button is configured as soft power\n", DRIVER_NAME); + PMPB_VAL |= PMPB_SOFTPWR; + +#if 0 + /* Create proc entry*/ + proc_softpower = create_proc_entry("softpower", 0644, &proc_root); + proc_softpower->data = &softpower_data; + proc_softpower->read_proc = procfile_read; + proc_softpower->write_proc = procfile_write; +#endif + +#else + /* Power button is configured as hard power*/ + printk("%s: Power button is configured as hard power\n", DRIVER_NAME); + PMPB_VAL = 0; + +#endif /* defined(SOFT_POWER_SUPPORT) && defined(CONFIG_PROC_FS)*/ + + /*read power button debounce value*/ + if (wmt_getsyspara(varname, buf, &varlen) == 0){ + sscanf(buf,"%d:%d:%d", + &power_on_debounce_value, + &resume_debounce_value, + &power_up_debounce_value); + + if (power_on_debounce_value < min_debounce_value) + power_on_debounce_value = min_debounce_value; + if (power_on_debounce_value > max_debounce_value) + power_on_debounce_value = max_debounce_value; + + if (resume_debounce_value < min_debounce_value) + resume_debounce_value = min_debounce_value; + if (resume_debounce_value > max_debounce_value) + resume_debounce_value = max_debounce_value; + + if (power_up_debounce_value < min_debounce_value) + power_up_debounce_value = min_debounce_value; + if (power_up_debounce_value > max_debounce_value) + power_up_debounce_value = max_debounce_value; + } + + + /*set power button debounce value*/ + printk("[%s] power_on = %d resume = %d power_up = %d\n", + __func__,power_on_debounce_value, resume_debounce_value, power_up_debounce_value); + wmt_pwrbtn_debounce_value(power_on_debounce_value); + + wmt_ws = wakeup_source_register("wmt_pwbn"); + + //enable power button intr + pmc_enable_wakeup_isr(WKS_PWRBTN, 0); + + memset(buf ,0, sizeof(buf)); + varlen = sizeof(buf); + if ((wmt_getsyspara("wmt.gpo.hall_switch", buf, &varlen) == 0)) { + int ret = sscanf(buf, "%d:%d", + &hall_switch.gpio_no, + &hall_switch.wakeup_source + ); + + //printk(KERN_ERR"hall_switch gpiono:%d ws:%d\n",hall_switch.gpio_no,hall_switch.wakeup_source); + ret = gpio_request(hall_switch.gpio_no, "hall_switch"); + if(ret < 0) { + printk(KERN_ERR"gpio request fail for hall_switch\n"); + goto hswitch_done; + } + + gpio_direction_input(hall_switch.gpio_no); + wmt_gpio_setpull(hall_switch.gpio_no, WMT_GPIO_PULL_UP); + + pmc_enable_wakeup_isr(hall_switch.wakeup_source,4); + wakeup_queue=create_workqueue("wakeup0"); + INIT_DELAYED_WORK(&wakeupwork, wakeup_func); + hall_switch.have_switch = 1; + } + +hswitch_done: + + + + return 0; +} + +late_initcall(wmt_pm_init); |