当前位置:嗨网首页>书籍在线阅读

13-设备驱动中的电源管理

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

12.4 设备驱动中的电源管理

一个真实生活中的设备驱动除了要处理设备的基本功能以外,还需要处理电源管理,主要提供挂起和恢复用的suspend()、resume()两个函数,对于platform_driver而言,该结构体已经包含了这两个成员函数,包含suspend()、resume()入口的platform_driver一般形如代码清单12.19。

代码清单12.19 包含suspend/resume的platform.driver

1 #ifdef CONFIG_PM

2 static int xxx_suspend(struct platform_device *pdev, pm_message_t state)

3 {

4 ...

5 return 0;

6 }

7

8 static int xxx_resume(struct platform_device *pdev)

9 {

10 ...

11 return 0;

12 }

13 #else

14 #define xxx_suspend NULL

15 #define xxx_resume NULL

16 #endif

17

18 static struct platform_driver xxx_driver = {

19 .probe = xxx_probe,

20 .remove = xxx_remove,

21 .suspend = xxx_suspend,

22 .resume = xxx_resume,

23 .driver = {

24 .name = "xxx",

25 .owner = THIS_MODULE,

26 },

27 };

上述代码清单中,对于suspend()、resume()进行了CONFIG_PM宏的检查,也就是说内核配置了电源管理的情况下,才定义suspend()、resume()的实体,否则将它们定义为NULL。

通常而言,在suspend()函数里面会停止设备,并关闭给它提供的时钟,所以在suspend()函数里面经常看见这样的语句:

clk_disable(xxx->clk);

而在resume()函数中,进行相反的操作:

clk_enable(xxx->clk);

clk_disable()、clk_enable()的具体实现直接依赖于SoC的类型,实际上,在BSP内为SoC内的各个PLL、分频器和时钟gate建立了一颗树,并提供了一组操作时钟的通用API。因此,在具体的设备驱动中,最好不要直接去修改寄存器来操作时钟,而应该用如下API:

/ 获得、释放时钟 /

struct clk clk_get(struct device dev, const char *id);

void clk_put(struct clk *clk);

/ 使能、禁止时钟 /

int clk_enable(struct clk *clk);

void clk_disable(struct clk *clk);

/ 获得、试探和设置频率 /

unsigned long clk_get_rate(struct clk *clk);

long clk_round_rate(struct clk *clk, unsigned long rate);

int clk_set_rate(struct clk *clk, unsigned long rate);

/ 设置、获得父时钟 /

int clk_set_parent(struct clk clk, struct clk parent);

struct clk clk_get_parent(struct clk clk);

从代码清单12.2中platform_driver结构体的定义可知,它除了包含suspend()和resume()入口以外,还包含如下两个入口:

int (suspend_late)(struct platform_device , pm_message_t state);

int (resume_early)(struct platform_device );

suspend_late()与suspend()的区别在于,suspend_late()工作于中断都被禁止的情况下,而且仅有一个CPU是活跃的。相似的,resume_early()也工作于中断都被禁止的情况下。绝大多数情况下,设备驱动不提供suspend_late()和resume_early()入口。