/*++ 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 . WonderMedia Technologies, Inc. 10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C. --*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#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 #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 #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 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);