
一. 电源管理：在不影响使用电子设备的前提下尽可能让它省电

8051:
无电源管理：灭灯6.1MA 亮灯32.2MA
有电源管理：灭灯0.27uA 亮灯26.7MA
MCU全速运行时耗电6.1ma, led耗电26ma

Linux更加复杂:
1. 硬件更复杂：外接更多设备，这些设备也需要单独供电，休眠前可能需要单独设置
2. 软件更复杂：需要有统一的框架，唤醒后可能需要重新初始化


二. 给u-boot添加suspend命令
u-boot全速运行,耗电83ma
u-boot suspend:耗电33ma ==>外设备没有完全关闭，比如声卡、网卡

进入休眠模式的方法：
    /* 1. 配置GPIO: 比如想维持LED亮或灭, 用于唤醒CPU的引脚要设为中断功能 */
    /* 2. 设置INTMSK屏蔽所有中断: 在sleep模式下,这些引脚只是用于唤醒系统,当CPU正常运行时可以重新设置INTMSK让这些引脚用于中断功能 */ 
    /* 3. 配置唤醒源 */
    /* 4. 设置MISCCR[13:12]=11b, 使得USB模块进入休眠 */
    /* 5. 在GSTATUS[4:3]保存某值, 它们可以在系统被唤醒时使用 */
    /* 6. 设置 MISCCR[1:0] 使能数据总线的上拉电阻 */
    /* 7. 清除 LCDCON1.ENVID 以停止LCD */
    /* 8. 读这2个寄存器: rREFRESH and rCLKCON, 以便填充TLB
     *    如果不使用MMU的话,这个目的可以忽略 
     */
    /* 9. 设置 REFRESH[22]=1b,让SDRAM进入self-refresh mode */
    /* 10. 等待SDRAM成功进入self-refresh mode  */
    /* 11.设置 MISCCR[19:17]=111b以保护SDRAM信号(SCLK0,SCLK1 and SCKE) */
    /* 12. 设置CLKCON的SLEEP位让系统进入sleep mode */   


唤醒系统的方法：
    /* 1. 按下按键 */
    /* 2. 根据 GSTATUS2[1]判断是复位还是唤醒 */ 
    /* 3. 设置 MISCCR[19:17]=000b, 以释放SDRAM信号 */
    /* 4. 配置s3c2440的memory controller */
    /* 5. 等待SDRAM退出self-refresh mode */
    /* 6. 根据GSTATUS[3:4]的值来运行休眠前的函数 */

u-boot-1.1.6_jz2440_suspend.patch


nfs 30000000 192.168.1.124:/work/nfs_root/u-boot.bin;protect off all;erase 0 3ffff;cp.b 30000000 0 40000
nfs 30000000 192.168.1.124:/work/nfs_root/u-boot.bin;nand erase bootloader; nand write.jffs2 30000000 bootloader


三. Linux系统suspend的实现
1. suspend流程
启动 suspend to ram:
echo mem > /sys/power/state

－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－
state_store (kernel/power/main.c)
    pm_suspend (kernel/power/suspend.c)
        enter_state (kernel/power/suspend.c)
            suspend_prepare (kernel/power/suspend.c)
                pm_prepare_console (kernel/power/console.c)
                    pm_notifier_call_chain(PM_SUSPEND_PREPARE); (kernel/power/main.c)  // 通知所有关心"休眠消息"的驱动程序
                    suspend_freeze_processes (kernel/power/power.h) // 冻结APP和内核线程
            suspend_devices_and_enter (kernel/power/suspend.c) // 让设备进入休眠状态
                suspend_ops->begin  // 如果平台相关的代码有begin函数就去调用它          
                suspend_console (kernel/power/suspend.c)
                dpm_suspend_start(PMSG_SUSPEND); (drivers/base/power/main.c)
                    dpm_prepare(state);  (drivers/base/power/main.c)
                        对于dmp_list链表中的每一个设备,都调用device_prepare(dev, state);
                                对于该设备,调用它的dev->pm_domain->ops.prepare 或
                                                   dev->type->pm->prepare       或
                                                   dev->class->pm->prepare      或
                                                   dev->bus->pm->prepare        或
                                                   dev->driver->pm->prepare
                    dpm_suspend(state); (drivers/base/power/main.c)  // 让各类设备休眠
                        对于dpm_prepared_list链表中的每一个设备,都调用device_suspend(dev);
                            __device_suspend(dev, pm_transition, false);
                                对于该设备,调用它的dev->pm_domain->ops.suspend  或
                                                   dev->type->pm->suspend       或
                                                   dev->class->pm->suspend      或
                                                   dev->bus->pm->suspend        或
                                                   dev->driver->pm->suspend

                    suspend_enter(state, &wakeup) (kernel/power/suspend.c)
                        suspend_ops->prepare // 即s3c_pm_prepare
                        dpm_suspend_end(PMSG_SUSPEND);       (drivers/base/power/main.c) 
                            dpm_suspend_late(state); (drivers/base/power/main.c) 
                                对于dpm_suspended_list链表中的每一个设备,都调用device_suspend_late(dev, state);
                                   对于该设备,调用它的dev->pm_domain->ops.suspend_late      或
                                                           dev->type->pm->suspend_late      或
                                                           dev->class->pm->suspend_late     或
                                                           dev->bus->pm->suspend_late       或
                                                           dev->driver->pm->suspend_late
                            dpm_suspend_noirq
                                对于dpm_late_early_list链表中的每一个设备,都调用device_suspend_noirq(dev, state);
                                   对于该设备,调用它的dev->pm_domain->ops.suspend_noirq      或
                                                           dev->type->pm->suspend_noirq      或
                                                           dev->class->pm->suspend_noirq     或
                                                           dev->bus->pm->suspend_noirq       或
                                                           dev->driver->pm->suspend_noirq                                                          
                        suspend_ops->prepare_late() //         
                        disable_nonboot_cpus();     
                        arch_suspend_disable_irqs();
                        syscore_suspend
                        suspend_ops->enter(state);  // s3c_pm_enter (arch\arm\plat-samsung\pm.c)                                                   
                            ......
                            pm_cpu_prep // s3c2410_pm_prepare (arch\arm\mach-s3c24xx\pm-s3c2410.c)
                                GSTATUS3 = s3c_cpu_resume
                                
                            ......  
                            cpu_suspend(0, pm_cpu_sleep); // arch\arm\kernel\sleep.S
                                pm_cpu_sleep (arch\arm\mach-s3c24xx\pm-s3c2410.c) // s3c2410_cpu_suspend
                                    s3c2410_cpu_suspend (arch\arm\mach-s3c24xx\sleep-s3c2410.S)
                            以上是休眠过程      
                            ＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝
                            下面开始唤醒过程
                            按键, 导致u-boot运行, 读取GSTATUS3, 执行s3c_cpu_resume 
                            .....
                            s3c_pm_restore_core
                        syscore_resume
                        arch_suspend_enable_irqs
                        enable_nonboot_cpus
                        suspend_ops->wake
                        dpm_resume_start(PMSG_RESUME);  
                            dpm_resume_noirq(state);
                                对于dpm_noirq_list链表中的每一个设备,调用device_resume_noirq(dev, state);
                                    对于该设备,调用它的dev->pm_domain->ops.resume_noirq      或
                                                           dev->type->pm->resume_noirq       或
                                                           dev->class->pm->resume_noirq      或
                                                           dev->bus->pm->resume_noirq        或
                                                           dev->driver->pm->resume_noirq
                            dpm_resume_early(state);
                                对于dpm_late_early_list链表中的每一个设备,调用device_resume_early(dev, state);
                                    对于该设备,调用它的dev->pm_domain->ops.resume_early      或
                                                           dev->type->pm->resume_early       或
                                                           dev->class->pm->resume_early      或
                                                           dev->bus->pm->resume_early        或
                                                           dev->driver->pm->resume_early
                            suspend_ops->finish()
                                s3c_pm_finish
                                            
                dpm_resume_end(PMSG_RESUME);
                    dpm_resume(state);
                        对于dpm_suspended_list链表中的每一个设备,调用device_resume(dev, state, false);
                            对于该设备,调用它的dev->pm_domain->ops.resume     或
                                                   dev->type->pm->resume       或
                                                   dev->class->pm->resume      或
                                                   dev->bus->pm->resume        或
                                                   dev->driver->pm->resume
                    dpm_complete(state);
                        对于dpm_prepared_list链表中的每一个设备,调用device_complete(dev, state);
                            对于该设备,调用它的dev->pm_domain->ops.complete     或
                                                   dev->type->pm->complete       或
                                                   dev->class->pm->complete      或
                                                   dev->bus->pm->complete        或
                                                   dev->driver->pm->complete
                        
                resume_console();
            suspend_finish();
                suspend_thaw_processes();
                pm_notifier_call_chain(PM_POST_SUSPEND);
                pm_restore_console();
            //返回用户空间  


驱动程序里相关的电源管理函数的调用过程:
休眠: prepare—>suspend—>suspend_late—>suspend_noirq
唤醒: resume_noirq—>resume_early—>resume-->complete

    
参考文章:
实现流程: Linux电源管理(6)_Generic PM之Suspend功能 
http://www.wowotech.net/linux_kenrel/suspend_and_resume.html

驱动所涉及的接口: Linux电源管理(4)_Power Management Interface
http://www.wowotech.net/linux_kenrel/pm_interface.html
        
                    
                                

power_attr(state);

static struct kobj_attribute state_attr = { \
    .attr   = {             \
        .name = __stringify("state"),   \
        .mode = 0644,           \
    },                  \
    .show   = state_show,           \
    .store  =state_store,       \
}



arch\arm\plat-samsung\pm.c
s3c_pm_init
    suspend_set_ops(&s3c_pm_ops);
        suspend_ops = ops   


2. 修改内核或驱动以使用suspend功能
设置唤醒源: 配置GPIO引脚工作于中断功能, 设置它的触发方式

怎样修改内核:
a. 通过调用s3c_irq_wake来修改s3c_irqwake_intmask、s3c_irqwake_eintmask用来表示唤醒源是哪个
b. 需要自己设置GPIO用于中断功能,并设置它的触发方式

int0,1,2,3
eint4,5,...15

在我们的按键驱动中: request_irq之后调用s3c_irq_wake或s3c_irqext_wake

2.1 直接修改内核: s3c_irqwake_intmask、s3c_irqwake_eintmask, 并且配置GPIO
或
2.2 修改按键驱动,在request_irq之后调用irq_set_irq_wake

2.1
解压新工具链并设置PATH
sudo tar xjf arm-linux-gcc-4.3.2.tar.bz2 -C /
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/opt/usr/local/arm/4.3.2/bin

编译内核:
tar xjf linux-3.4.2.tar.bz2 
cd linux-3.4.2
patch -p1 < ../linux-3.4.2_alsa_wm8976_uda1341_jz2440_mini2440_tq2440.patch
cp config_wm8976_jz2440 .config
make menuconfig

修改arch\arm\plat-samsung\pm.c

unsigned long s3c_irqwake_intmask   = 0xfffffffa;
unsigned long s3c_irqwake_eintmask  = 0xfffff7ff;

修改arch\arm\plat-s3c24xx\pm.c  /* 实验发现不修改这个文件也成功,原因在于UBOOT已经配置了GPIO,设置了中断触发类型 */
    if (!irqstate) {
        if (pinstate == S3C2410_GPIO_IRQ)
            S3C_PMDBG("Leaving IRQ %d (pin %d) as is\n", irq, pin);
+       else{           
+           s3c_gpio_cfgpin(pin, S3C2410_GPIO_IRQ);
+       }
        /* 配置触发方式 */
    } else {

make uImage && cp arch/arm/boot/uImage /work/nfs_root

sudo tar xjf fs_mini_mdev_new.tar.bz2 -C /work/nfs_root/

使用新内核启动
set bootcmd 'nfs 30000000 192.168.1.124:/work/nfs_root/uImage; bootm 30000000'
set bootargs console=ttySAC0,115200 root=/dev/nfs nfsroot=192.168.1.124:/work/nfs_root/fs_mini_mdev_new ip=192.168.1.17

测试：
cat /sys/power/state
echo mem > /sys/power/state
按键换醒


2.2 在驱动程序中, request_irq后调用irq_set_irq_wake来指定唤醒源

3. 修改驱动程序支持电源管理
a. 通知notifier:
在冻结APP之前,使用pm_notifier_call_chain(PM_SUSPEND_PREPARE)来通知驱动程序
在重启APP之后,使用pm_notifier_call_chain(PM_POST_SUSPEND)来通知驱动程序

如果驱动程序有事情在上述时机要处理,可以使用register_pm_notifier注册一个notifier

b. 添加suspend, resume函数
b.1 添加一个同名platform_device, platform_driver
b.2 老方法:在platform_driver里实现suspend,resume成员
    新方法:在platform_driver里的driver里的pm结构体, 实现suspend,resume成员

对于LCD, 配置内核去掉 CONFIG_FRAMEBUFFER_CONSOLE, 可以在休眠-唤醒后保留LCD上的图像
应该也可以通过APP禁止Framebuffer用作console 

系统处于运行状态并且LCD打开时, 耗电240mA
休眠时, 耗电50mA



两篇文章:
http://blog.csdn.net/bingqingsuimeng/article/details/7935414
http://www.wowotech.net/linux_kenrel/suspend_and_resume.html


四. runtime PM (Runtime Power Management)
1. runtime PM流程
怎样动态地打开或关闭设备的电源?最简单的方法:
在驱动程序里,在open函数中打开电源,在close函数中关闭电源

上述方法有一个缺点: 多个APP使用该设备时可能造成干扰
解决方法：给驱动添加使用计数值: 当该计数大于0时打开电源, 等于0时关闭电源

ioctl: alsa

runtime PM只是提供辅助函数, 比如:
1. 增加计数/减少计数
2. 使能runtime pm

内核驱动示例: drivers\input\misc\bma150.c
pm_runtime_enable / pm_runtime_disable    : 使能/禁止runtime PM, 修改disable_depth变量
pm_runtime_get_sync / pm_runtime_put_sync : 增加/减小计数值, 并且让设备处于resume或suspend状态

在dev_pm_ops里提供3个回调函数: runtime_suspend, runtime_resume, runtime_idle

流程分析:
pm_runtime_get_sync
    __pm_runtime_resume(dev, RPM_GET_PUT);
        atomic_inc(&dev->power.usage_count);  // 增加使用计数
        rpm_resume(dev, rpmflags);            // resume设备
            if (dev->power.disable_depth > 0) retval = -EACCES; // 该变量初值为1,要使用runtime PM, 要先pm_runtime_enable
            
            if (!dev->power.timer_autosuspends) // 为防止设备频繁地开关,可以设置timer_autosuspends
                    pm_runtime_deactivate_timer(dev);
            
            if (dev->power.runtime_status == RPM_ACTIVE) { // 如果设备已经是RPM_ACTIVE,就没必要再次resume,直接返回
            
            // 如果设备处于RPM_RESUMING/RPM_SUSPENDING, 等待该操作完成
            
            // Increment the parent's usage counter and resume it if necessary
            
            // resume设备本身: 前面4个函数被称为 subsystem-level callback
            callback = dev->pm_domain->ops.runtime_resume; 或
            callback = dev->type->pm->runtime_resume;      或
            callback = dev->class->pm->runtime_resume;     或
            callback = dev->bus->pm->runtime_resume;       或
            
            callback = dev->driver->pm->runtime_resume;
            
            retval = rpm_callback(callback, dev);
            
            // 成功时,给父亲的child_count加1
            if (parent)
                atomic_inc(&parent->power.child_count);
            
            // 唤醒其他进程
            wake_up_all(&dev->power.wait_queue);
            
            // 如果resume失败, 让设备进入idle状态
            if (!retval)
                rpm_idle(dev, RPM_ASYNC);
            
pm_runtime_put_sync
    __pm_runtime_idle(dev, RPM_GET_PUT);
        atomic_dec_and_test(&dev->power.usage_count)  // 减小使用计数
        rpm_idle(dev, rpmflags);                      // 让设备进入idle状态
            rpm_check_suspend_allowed(dev);   // 检查是否允许设备进入suspend状态
                if (dev->power.disable_depth > 0) //失败
                if (atomic_read(&dev->power.usage_count) > 0) // 当前的使用计数不是0,失败
                if (!pm_children_suspended(dev))   // 如果的孩子不全部处于suspended, 失败
        if (dev->power.runtime_status != RPM_ACTIVE) // 如果设备本来就不处于RPM_ACTIVE,直接返回
        
        // 调用idle回调函数: 前4个是subsystem-level callback
        callback = dev->pm_domain->ops.runtime_idle; 或
        callback = dev->type->pm->runtime_idle;      或
        callback = dev->class->pm->runtime_idle;     或
        callback = dev->bus->pm->runtime_idle;       或
        
        callback = dev->driver->pm->runtime_idle;
        
        __rpm_callback(callback, dev);
        
        wake_up_all(&dev->power.wait_queue);

bma150.c : i2c_bus_type -> pm_generic_runtime_idle -> pm_runtime_suspend -> __pm_runtime_suspend(dev, 0);
           -> rpm_suspend(dev, rpmflags);
如果设备不提供runtime_idle, 则最终会调用runtime_suspend

如何使用runtime PM:
1. 驱动程序提供接口, APP来调用
2. echo on >  /sys/devices/.../power/control   // 导致control_store -> pm_runtime_forbid(dev); :
                                                      atomic_inc(&dev->power.usage_count);
                                                      rpm_resume(dev, 0);
                                                      
   echo auto >  /sys/devices/.../power/control // 导致control_store -> pm_runtime_allow(dev); :
                                                     atomic_dec_and_test(&dev->power.usage_count)
                                                     rpm_idle(dev, RPM_AUTO);

2. 修改驱动程序和使用
怎么修改?
参考内核驱动示例: drivers\input\misc\bma150.c
2.1 在dev_pm_ops里提供3个回调函数: runtime_suspend, runtime_resume, runtime_idle
2.2 对于runtime PM,默认状态下设备的状态是suspended, 如果硬件上它是运行状态,需要调用pm_runtime_set_active()来修改它的状态
    然后调用pm_runtime_enable()来使能runtime PM    
    一般是在probe函数里调用上述函数
2.3 在对应的系统调用接口里调用: pm_runtime_get_sync / pm_runtime_put_sync : 增加/减小计数值, 并且让设备处于resume或suspend状态
2.4 在remove函数里调用pm_runtime_disable()

前提: 配置内核支持runtime PM
make menuconfig
Power management options  --->
	[*] Run-time PM core functionality


使用:
1. 
echo on >  /sys/devices/platform/mylcd/power/control
echo auto >  /sys/devices/platform/mylcd/power/control

2. 在对应的系统调用接口里调用: pm_runtime_get_sync / pm_runtime_put_sync 


3. autosuspend: 如果不想让设备频繁地开、关,可以使用autosuspend功能
驱动里: 执行pm_runtime_use_autosuspend来设置启动autosuspend功能,
        put设备时, 执行这2个函数:
	pm_runtime_mark_last_busy(&lcd_dev.dev);
	pm_runtime_put_sync_autosuspend(&lcd_dev.dev);

用户空间, 执行以下命令设置时间值:      
echo 2000 > /sys/devices/platform/mylcd/power/autosuspend_delay_ms


五. regulator系统
概念:
Regulator   : 电源芯片, 比如电压转换芯片
Consumer    : 消费者,使用电源的部件, Regulator是给Consumer供电的
machine     : 单板,上面焊接有Regulator和Consumer
Constraints : 约束, 比如某个电源管理芯片输出的电压范围
Supply      : 提供电源的部件, Regulator就是一个Supply; Regulator A可以给Regulator B供电, 那么Regulator B的Supply就是A

写驱动程序:
1. regulator:
   注册一个platform_driver: 在它的probe函数里分配、设置、注册一个regulator
   "设置"里要做的事情: 实现regulator的操作, 比如enable, disable, set_voltage
2. machine:
   注册一个platform_device: 在它的私有数据里指定regulator和consume的对应关系(这个电源芯片给哪一个部件供电)
                            指定约束条件(比如电压范围)
3. consumer: 使用即可: regulator_get, regulator_enable, regulator_disable, regulator_set_voltage....


regulator_register流程分析:
	// 分配regulator_dev
	rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL);
	
	/* set regulator constraints */
	set_machine_constraints
	add_regulator_attributes
	
	/* add consumers devices */
	set_consumer_device_supply
		在regulator_map_list链表里生成一项regulator_map: 它里面有dev_name(consumer的名字),supply(cosumer的电源引脚名字)

	// 把regulator_dev放入regulator_list
	list_add(&rdev->list, &regulator_list);		
	
编译测试:
1. make menuconfig
Device Drivers  --->
	[*] Voltage and Current Regulator Support  --->

修改 drivers/video/Makefile把原来的LCD驱动去掉
#obj-$(CONFIG_FB_S3C2410)         += lcd_4.3.o

    make uImage

2. 编译驱动
3. 使用新内核启动
4. 安装驱动:
   insmod regulator.ko    
   insmod machine.ko    
   insmod consumer_lcd_4.3.ko    
       

六. 编写支持电源管理的应用程序
1. 修改数码相框以自动关闭LCD
关闭LCD : 在读取触摸屏的函数中,判断: 如果15S内无数据,执行: echo auto >  /sys/devices/platform/mylcd/power/control
打开LCD : 如果有触触摸屏动作发生, 执行: echo on >  /sys/devices/platform/mylcd/power/control

alarm(second) : 若干秒后,内核会发出SIGALRM给APP, APP可以提供信号处理函数
思路:
a. 注册信号处理: signal(SIGALRM, function);
   该函数用来关闭LCD
b. 在读取输入事件的进程里, 执行: alarm(15)
c. 如果一直没有读到触摸屏的数据, 定时器就会超时导致function被调用从而关闭LCD
d. 如果读到触摸屏数据, 再次执行alarm(15), 会更新超时时间为当前之后的15S
   如果之前关闭过LCD, 还需要执行: 打开LCD
   
http://blog.csdn.net/dsg333/article/details/4870639

配置内核添加驱动:
a. drivers/input/touchscreen/Makefile
#obj-$(CONFIG_TOUCHSCREEN_S3C2410)      += s3c2410_ts.o
obj-$(CONFIG_TOUCHSCREEN_S3C2410)       += s3c_ts.o

make menuconfig :
Device Drivers  ---> 
	Input device support  ---> 
		[*]   Touchscreens  --->
			<*>   Samsung S3C2410/generic touchscreen input driver

b. drivers/video/Makefile
obj-$(CONFIG_FB_S3C2410)          += lcd_4.3.o

make uImage
			
echo auto >  /sys/devices/platform/mylcd/power/control 无法使用,
因为dev->power.runtime_auto初始值是1, 

成功使用echo auto >  /sys/devices/platform/mylcd/power/control命令来关LCD的前提是dev->power.runtime_auto等于0
可以执行: echo on >  /sys/devices/platform/mylcd/power/control  使得它等于0
但是也不适用于我们的情况，因为：
open(/dev/fb0)会让LCD的使用计数加1
再 echo on会让LCD的使用计数也加1
然后执行echo auto只能让使用计数减1变为

要再次修改驱动




2. 编写支持开关机(suspend)的应用程序
思路: 
读按键, 得到某个值就执行 echo mem > /sys/power/state


七. 从系统角度考虑电源管理,我们要学习更多
1. 软件
内核/驱动:
APP: cache


http://www.wowotech.net/pm_architecture.html

2. 硬件
a. 如果芯片有省电模式，尽量用起来
b. 如果芯片能够关闭, 给它提供开关(比如单独供电)
c. 使用效率高的电源芯片
d. 如果可以，就使用PMU(它集成了若干个DC/DC或LDO, 可以给芯片单独供电并有单独的开关, 甚至可以调整电压电流)


LDO  : 输入电压和输出电压相差不大, 外围器件比较少，干扰小，效率低
DCDC : 输入电压和输出电压可以相差很大, 外围器件比较多，干扰大，效率高




手机电路图大全: http://pan.baidu.com/s/1sjJgK0H






资料:
http://blog.csdn.net/bingqingsuimeng/article/category/1228414
http://os.chinaunix.net/a2006/0519/1002/000001002210.shtml
http://www.ednchina.com/ART_44010_29_0_TA_eeda337e_3.HTM?jumpto=view_welcomead_1408610592294

好文：
http://blog.csdn.net/bingqingsuimeng/article/details/7935414
http://blog.csdn.net/bingqingsuimeng/article/details/8197912
http://blog.sina.com.cn/s/blog_a6559d920101i52j.html

Linux电源管理(1)_整体架构
http://www.wowotech.net/linux_kenrel/pm_architecture.html

Linux电源管理(4)_Power Management Interface
http://www.wowotech.net/linux_kenrel/pm_interface.html

Linux电源管理(6)_Generic PM之Suspend功能
http://www.wowotech.net/linux_kenrel/suspend_and_resume.html


Linux运行时IO设备电源管理框架---PM  (runtime power manager)
http://blog.sina.com.cn/s/blog_533074eb0101dnm2.html


Run-time PM 详解
http://blog.csdn.net/bingqingsuimeng/article/details/7935440

电源管理之regulator机制流程 
http://blog.csdn.net/bingqingsuimeng/article/details/8216782


linux内核对S3C2410睡眠模式的支持 (讲得很好!)
http://blog.csdn.net/hongtao_liu/article/details/4208988

s3c2440 省电模式开发详解(讲得很好!)
http://blog.chinaunix.net/uid-517401-id-1641576.html

http://www.linuxforum.net/forum/showflat.php?Board=embedded&Number=725416

 s3c2440 省电模式开发详解
http://blog.chinaunix.net/uid-517401-id-1641576.html





e:\kernel_projects\linux-3.4.2\linux-3.4.2\drivers\input\misc\Bma150.c



e:\kernel_projects\linux-3.4.2\linux-3.4.2\drivers\input\misc\Mpu3050.c


pm_runtime_set_active
pm_runtime_enable

pm_runtime_set_autosuspend_delay

pm_runtime_get
pm_runtime_put

pm_runtime_disable
pm_runtime_set_suspended

struct dev_pm_info:

pm_runtime_allow/pm_runtime_forbid 用来设置runtime_auto

  unsigned int runtime_auto;
    - if set, indicates that the user space has allowed the device driver to
      power manage the device at run time via the /sys/devices/.../power/control
      interface; it may only be modified with the help of the pm_runtime_allow()
      and pm_runtime_forbid() helper functions

The user space can effectively disallow the driver of the device to power manage
it at run time by changing the value of its /sys/devices/.../power/control
attribute to "on", which causes pm_runtime_forbid() to be called.  In principle,
this mechanism may also be used by the driver to effectively turn off the
runtime power management of the device until the user space turns it on.
Namely, during the initialization the driver can make sure that the runtime PM
status of the device is 'active' and call pm_runtime_forbid().  It should be
noted, however, that if the user space has already intentionally changed the
value of /sys/devices/.../power/control to "auto" to allow the driver to power
manage the device at run time, the driver may confuse it by using
pm_runtime_forbid() this way.

      