Linux电源管理 — RPM

一. 简介
  • RPM全称Runtime Power Management,即运行时电源管理。主要是用于设备运行时的电源管理,由kernel统一管理。当设备处于空闲状态时,挂起设备;而当设备需要被使用时,使设备恢复进入正常工作状态。
  • 在文件 /include/linux/pm.h 中,dev_pm_ops结构体下有与runtime pm相关的三个回调函数;以及使用rpm_status枚举表示设备的状态。
struct dev_pm_ops {
	......
	int (*runtime_suspend)(struct device *dev);	//挂起
	int (*runtime_resume)(struct device *dev);	//恢复
	int (*runtime_idle)(struct device *dev);	//空闲
};
enum rpm_status {
	RPM_ACTIVE = 0,		//运行状态
	RPM_RESUMING,		//正在恢复成运行状态
	RPM_SUSPENDED,		//挂起状态
	RPM_SUSPENDING,		//正在挂起状态
};
  • runtime pm的相关API接口函数在文件 /include/linux/pm_runtime.h下。
二. 运行机制
  • 每个设备都有一个usage_count变量,记录设备的使用情况。
  • 当该变量大于0时,表示设备正在被使用,处于active状态;当该变量等于0时,表示设备没有被使用,处于suspend状态。
  • 当要使用设备时,使用pm_runtime_get_sync/pm_runtime_get将usage_count变量+1,每次+1都会去根据当前设备状态判断是否需要resume;当需要resume时,就会调用runtime_resume回调函数。
  • 当使用完设备时,使用pm_runtime_put_sync/pm_runtime_put将usage_count变量-1,为0时suspend设备;suspend设备时先调用runtime_idle回调函数,然后在合适时机调用runtime_suspend回调函数。
三. 相关操作
  • 查看当前设备状态
cat /sys/devices/$dev/power/runtime_status
  • 增加/减少设备计数
echo on > /sys/devices/$dev/power/control
echo auto > /sys/devices/$dev/power/control
  • 查看设备在active/suspend状态的时间
cat /sys/devices/$dev/power/runtime_active_time
cat /sys/devices/$dev/power/runtime_suspend_time
四. 伪代码示例
/*Test 驱动模块结构体*/
struct TestDev_t
{
	dev_t dev_num;					//设备号
	struct cdev TestCdev;			//使用Linux内核下cdev结构体,描述一个字符设备
	struct class *TestClass; 		//创建LedClass类指针
	struct device *TestDevice;		//设备节点指针
	struct platform_device *p_dev;  //platform设备指针
};

/*字符设备操作函数*/
static int test_open(struct inode *inode, struct file *filp)
{
	struct TestDev_t *p_TestDev = container_of(inode->i_cdev, struct TestDev_t, TestCdev);
	filp->private_data = p_TestDev;
	pm_runtime_get(&p_TestDev->p_dev->dev);
	return 0;
}

static int test_release(struct inode *inode, struct file *filp)
{
	struct TestDev_t *p_TestDev = (struct TestDev_t *)filp->private_data;
	pm_runtime_put(&p_TestDev->p_dev->dev);
	retuen 0;
}

static struct file_operations TestDevFops = {
	.owner 		= THIS_MODULE,	
	.open 		= test_open,
	.read 		= test_read,
	.write 		= test_write,
	.unlocked_ioctl = test_ioctl,
	.release 	= test_release,
};

/* 当platform设备和驱动match时,就会执行prode函数 */
static int test_probe(struct platform_device *pdev)
{
	struct TestDev_t* p_TestDev = (struct TestDev_t*)kmalloc(sizeof(struct TestDev_t), GFP_KERNEL);
	/*注册设备号*/
	alloc_chrdev_region(TestDev.dev_num, 0, 1, "TestDev");
	/*注册字符设备*/
	cdev_init(&TestDev.TestCdev, &TestDevFops);
	cdev_add(&TestDev.TestCdev, TestDev.dev_num, 1);
	/*创建设备节点文件*/
	TestDev.TestClass = class_create(THIS_MODULE, "TestDev");
	TestDev.TestDevice = device_create(TestDev.TestClass, NULL, TestDev.dev_num, NULL, "TestDev");
	/*使能设备rpm功能*/
	pm_runtime_enable(&pdev->dev);
	/*保存设备驱动结构体*/
	p_TestDev->p_dev = pdev;
	platform_set_drvdata(pdev, p_TestDev);
	return 0;
}

/*卸载platform驱动的时,remove函数会执行*/
static int test_remove(struct platform_device *pdev)
{
	struct TestDev_t* p_TestDev = platform_get_drvdata(pdev);
	/*注销字符设备*/
	cdev_del(&TestDev.TestCdev);
	/*注销设备号*/
	unregister_chrdev_region(TestDev.dev_num, 1);
	/*删除设备节点文件*/
	device_destroy(TestDev.TestClass, TestDev.dev_num);
	class_destroy(TestDev.TestClass);
	/*失能设备rpm功能*/
	pm_runtime_disable(&pdev->dev);
	Kfree(p_TestDev);
	return 0;
}

/* 运行时挂起设备操作 */
static int test_runtime_suspend(struct device *dev)
{
	printk("dev runtime suspend\r\n");
	/*挂起设备的操作*/
	return 0;
}

/* 运行时恢复设备操作 */
static int test_runtime_resume(struct device *dev)
{
	printk("dev runtime resume\r\n");
	/*唤醒设备的操作*/
	return 0;
}

/* 运行时设备空闲时操作 */
static int test_runtime_idle(struct device *dev)
{
	printk("dev runtime idle\r\n");
	return 0;
}

/* 设备runtime的 suspend/resume/idle 操作 */
static const dev_pm_ops test_rpm_ops = {
	SET_RUNTIME_PM_OPS(test_runtime_suspend, test_runtime_resume, test_runtime_idle);
};

/* 匹配列表 */
static const struct of_device_id test_of_match[] = {
	{ .compatible = "xxxxxx" },			/* 表示兼容的设备属性 */
	{  }
};

/* platform驱动结构体 */
static struct platform_driver test_driver = {
	.driver		= {
		.name	= "xxxxxxxxx",			 /* 驱动名字 */
		.of_match_table	= test_of_match, /* 设备树匹配表 , 用于设备匹配 */
		.pm = &test_rpm_ops,			 /* 赋值驱动中的dev_pm_ops结构体 */
	},
	.probe		= test_probe,
	.remove		= test_remove,
};

*模块加载函数*/
static int __init test_init(void)
{
	return platform_driver_register(&test_driver);
}

/*模块卸载函数*/
static void __exit test_exit(void)
{
	platform_driver_unregister(&test_driver);
}

module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");


五. 参考资料
  • 《Linux设备驱动开发详解:基于最新的Linux4.0内核》
  • http://www.wowotech.net

以上是我在学习过程中的总结,不当之处请在评论区指出。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值