/*++ linux/arch/arm/mach-wmt/wmt_cpuidle.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 //#define DEBUG #ifdef DEBUG static int dbg_mask = 0; module_param(dbg_mask, int, S_IRUGO | S_IWUSR); #define id_dbg(fmt, args...) \ do {\ if (dbg_mask) \ printk(KERN_ERR "[%s]_%d: " fmt, __func__ , __LINE__, ## args);\ } while(0) #define id_trace() \ do {\ if (dbg_mask) \ printk(KERN_ERR "trace in %s %d\n", __func__, __LINE__);\ } while(0) #else #define id_dbg(fmt, args...) #define id_trace() #endif #define WMT_CPU_IDLE_MAX_STATES 2 extern int wmt_setsyspara(char *varname, unsigned char *varval); extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlenex); /* Actual code that puts the SoC in different idle states */ static int wmt_enter_idle(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { cpu_do_idle(); return index; } static struct cpuidle_driver wmt_cpuidle_driver = { .name = "wmt_cpuidle", .owner = THIS_MODULE, .en_core_tk_irqen = 1, /* ARM Wait for interrupt state */ .states[0] = ARM_CPUIDLE_WFI_STATE, /* Wait for interrupt and DDR self refresh state */ .states[1] = { .enter = wmt_enter_idle, .exit_latency = 10, .target_residency = 100000, .flags = CPUIDLE_FLAG_TIME_VALID, .name = "ZAC_OFF", .desc = "WFI and disable ZAC clock", }, .state_count = WMT_CPU_IDLE_MAX_STATES, }; static int __init wmt_cpuidle_check_env(void) { int ret = 0; int varlen = 128; unsigned int drv_en = 0; unsigned char buf[128] = {0}; /* uboot env name is: wmt.cpuidle.param/wmt.dvfs.param */ ret = wmt_getsyspara("wmt.cpuidle.param", buf, &varlen); if (ret) { printk(KERN_INFO "Can not find uboot env wmt.cpuidle.param\n"); ret = -ENODATA; goto out; } id_dbg("wmt.cpuidle.param:%s\n", buf); sscanf(buf, "%d", &drv_en); if (!drv_en) { printk(KERN_INFO "wmt cpuidle driver disaled\n"); ret = -ENODEV; goto out; } out: return ret; } static DEFINE_PER_CPU(struct cpuidle_device, wmt_cpuidle_device); static int __init wmt_cpuidle_driver_init(void) { struct cpuidle_device *device = NULL; if (wmt_cpuidle_check_env()) { printk(KERN_WARNING "wmt_cpuidle check env failed!\n"); return -EINVAL; } device = &per_cpu(wmt_cpuidle_device, smp_processor_id()); device->state_count = WMT_CPU_IDLE_MAX_STATES; cpuidle_register_driver(&wmt_cpuidle_driver); if (cpuidle_register_device(device)) { printk(KERN_ERR "wmt_cpuidle_driver_init: Failed registering\n"); return -EIO; } printk(KERN_INFO "WMT cpuidle driver register\n"); return 0; } module_init(wmt_cpuidle_driver_init); MODULE_AUTHOR("WonderMedia Technologies, Inc"); MODULE_DESCRIPTION("WMT CPU idle driver"); MODULE_LICENSE("Dual BSD/GPL");