便携嵌入式设备电源管理解决方案
的寄存器值保存到内存中,并将SDRAM设置为自刷新模式,以保持SDRAM中的数据。当SA -1110 收到硬件中断等唤醒源退出Sleep模式后不会接着执行先前未执行的指令,而是回到初始状态去执行启动代码。因此为了让CPU在唤醒后能够持续的工作,需要将返回代码的地址保存到PowerManager Scratch Pad Register ( PSPR)寄存器中,使得启动代码能让CPU重新跳到返回代码的地址处,执行返回代码从而回到睡眠前的工作。
SA - 1110进入Sleep模式的代码片断如下:
extern void cpu_sa1110_resume ( voi
d) ; /3 SA - 1110返回函数3 /
extern int cpu_sa1110_do_suspend ( void) ; /3 SA - 1110睡眠函数3 /
int sa1110_suspend ( void)
{
. . .
cli ( ) ; /3 关闭中断3 /
sys_ctx. osmr0 = OSMR0; /3 保存重要的寄存器3 /
. . .
sys_ctx. p sdr = PSDR;
. . .
PSPR = virt_to_phys ( cpu_sa1100_resume) ; /3 设置返回函数地址3 /
cpu_sa1110_do_suspend ( ) ; /3 进入睡眠3 //3 退出睡眠3 /
GPDR = sys_ctx. gpdr; /3 恢复寄存器3 /
GRER = sys_ctx. grer;
GFER = sys_ctx. gfer;
GAFR = sys_ctx. gafr;
. . .
sti ( ) ; /3 启动中断3 /
return 0;
}
(2)实现各个外设的电源管理代码
利用Linux内核提供电源管理子系统,可以将iPAQ中的每个需要实现电源管理的外部设备纳入统一的管理。这需要在各个设备的驱动程序中使用电源管理子系统的接口函数(如2. 1所描述)和实际的硬件操作代码,这里将以显示设备为例:
/3 SA - 1110 frame buffer电源管理请求处理函数3 /
static int sa1110fb_pm_callback ( struct pm_dev 3 pm_dev, pm
_request_t req, void
3 data)
{
struct sa1110fb_info 3 fbi = pm_dev - > data;
if ( req = = PM_SUSPEND | | req = = PM_RESUME) {
int state = ( int) data;
if ( state = = 0) {
set_ctrlr_ state ( fbi, C_ENABLE) ; /3 进入D0 模式,开启LCD控制器3 /
} else {
set_ctrlr_state ( fbi, C_D ISABLE) ; /3 进入D1 - D3模式关闭LCD 控制器. 3 /
} }
return 0;
}
/3 SA - 1110 frAME buffer驱动初始化函数3 /
int __init sa1110fb_init ( void)
{
struct sa1110fb_info 3 fbi;
int ret;
. . .
/3 在电源管理子系统中注册3 /
fbi - > pm = pm _ register ( PM _SYS_DEV, PM _SYS_VGA,
sa1110fb_pm_callback) ;
if ( fbi - > pm)
fbi - > pm - > data = fbi; /3 设置私有数据3 / . . .
return ret;
}
3)实现电源管理设备
这个设备实际是用于接受用户空间程序的控制所用,所以只需要简单的实现“ioctl”调用就可以了。
/3 ioctl调用方法3 /
static int do_ioctl ( struct inode 3 inode, struct file 3 filp, u_int
cmd, u_long arg)
{ . . .
switch ( cmd) {
case APM_ IOC_STANDBY: {
pm_send_all ( PM_SUSPEND, ( void 3 ) 2) ; /3 外设挂起3 /
; } break;
case APM_ IOC_RESUME: {
pm_send_all ( PM_RESUME, ( void 3 ) 0) ; /3 外设唤醒3 /
} break;
case APM_ IOC_SUSPEND: {
pm_send_all ( PM_SUSPEND, ( void 3 ) 2) ; /3 外设挂起3 /
sa1110_suspend ( ) ; /3 CPU进入休眠模式3 /
/3 CP
U醒来,继续执行3 /
pm_send_all ( PM_RESUME, ( void 3 ) 0) ; /3 唤醒外设3 /
} break;
default:
return - EINVAL;
}
return 0;
}
最后,使用命令“mknod /dev/ apm c 254 0”,可以在文件系统中建立起该设备的访问节点。该节点名为/dev/ apm,是一个字符设备(c) ,主设备号为254,此设备号为0。
(4)编写用户空间电源管理程序
用户可以在适当的时候选择是否改变CPU的时钟频率和显示刷新率,是否关闭某些外部设备,是否使整个系统进入睡眠模式等等。这只需要使用系统调用“ioctl”对电源管理设备( /dev/ apm)发送命令就可以了。
int fd;
. . .
fd = open ( /dev/ apm , O_RDONLY) ; /3 打开电源管理设备3 /
ioctl ( fd, APM_ IOC_SUSPEND,NULL) ; /3 发送电源管理命令3 /
close ( fd) ; /3 关闭电源管理设备3 /
实现iPAQ电源管理前后耗电量比较
实现电源管理以前:开启LCD, CPU 处于空闲状态,大多数其他芯片关闭,功耗为470mW。实现电源管理以后:在电源管理前的基础上开启SDRAM 的自动节能模式,功耗下降到280mW。然后降低LCD刷新率到30Hz, 功耗下降到238mW。再把CPU频率降低到57. 3MHz,功耗下降到172mW。最后关闭LCD,功耗下降到98m
- 利用udev在/dev下动态生成/移除设备文件(04-21)
- Linux内存使用的体会 (04-23)
- 无线动物识别和跟踪管理系统的设计(02-14)
- 嵌入式操作系统uCLinux详解(03-19)
- 微控制器省电管理方法(05-04)
- Linux 时钟管理(06-13)