目前共有11篇帖子。
![]() |
#include <linux/miscdevice.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> struct data { struct platform_device *pdev; struct miscdevice miscdevice; bool miscdevice_registered; }; static int hello_remove(struct platform_device *pdev); static int hello_open(struct inode *inode, struct file *file) { int ret; struct miscdevice *miscdevice = file->private_data; struct data *data = container_of(miscdevice, struct data, miscdevice); printk("%s\n", __func__); ret = pm_runtime_get_sync(&data->pdev->dev); if (ret != 0) { dev_err(&data->pdev->dev, "pm_runtime_get_sync() failed: ret=%d\n", ret); return ret; } return 0; } static ssize_t hello_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { printk("%s\n", __func__); return count; } static ssize_t hello_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { printk("%s\n", __func__); return count; } static int hello_release(struct inode *inode, struct file *file) { struct miscdevice *miscdevice = file->private_data; struct data *data = container_of(miscdevice, struct data, miscdevice); printk("%s\n", __func__); pm_runtime_put_sync(&data->pdev->dev); return 0; } static const struct file_operations hello_fops = { .owner = THIS_MODULE, .open = hello_open, .read = hello_read, .write = hello_write, .release = hello_release }; static int hello_probe(struct platform_device *pdev) { int ret; struct data *data; printk("%s\n", __func__); data = devm_kzalloc(&pdev->dev, sizeof(struct data), GFP_KERNEL); if (data == NULL) return -ENOMEM; data->pdev = pdev; platform_set_drvdata(pdev, data); data->miscdevice.minor = MISC_DYNAMIC_MINOR; data->miscdevice.name = "hello_file"; data->miscdevice.fops = &hello_fops; data->miscdevice.mode = 0666; ret = misc_register(&data->miscdevice); if (ret != 0) { dev_err(&pdev->dev, "failed to register miscdevice\n"); hello_remove(pdev); return ret; } data->miscdevice_registered = true; //pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); return 0; } static int hello_remove(struct platform_device *pdev) { struct data *data = platform_get_drvdata(pdev); printk("%s\n", __func__); if (data->miscdevice_registered) { misc_deregister(&data->miscdevice); data->miscdevice_registered = false; } printk("---disable begin---\n"); pm_runtime_disable(&pdev->dev); printk("---disable end---\n"); return 0; } static int hello_suspend(struct device *dev) { printk("%s\n", __func__); return 0; } static int hello_resume(struct device *dev) { printk("%s\n", __func__); return 0; } static UNIVERSAL_DEV_PM_OPS(hello_pm, hello_suspend, hello_resume, NULL); static struct platform_driver hello_driver = { .probe = hello_probe, .remove = hello_remove, .driver = { .name = "my_hello", .pm = &hello_pm } }; static void hello_device_release(struct device *dev) { printk("%s\n", __func__); } static struct platform_device hello_device = { .name = "my_hello", .id = -1, .dev = { .release = hello_device_release } }; static int __init hello_init(void) { printk("%s\n", __func__); platform_driver_register(&hello_driver); platform_device_register(&hello_device); return 0; } static void __exit hello_exit(void) { printk("%s\n", __func__); platform_device_unregister(&hello_device); platform_driver_unregister(&hello_driver); } module_init(hello_init); module_exit(hello_exit); MODULE_AUTHOR("Oct1158"); MODULE_LICENSE("GPL"); |
![]() |
root@rk3308b-buildroot:/root# insmod platform_test.ko [23420.584047] hello_init [23420.585266] hello_probe root@rk3308b-buildroot:/root# rmmod platform_test.ko [23423.727269] hello_exit [23423.727619] hello_resume [23423.727689] hello_suspend [23423.727727] hello_remove [23423.728393] ---disable begin--- [23423.728455] ---disable end--- [23423.728656] hello_device_release root@rk3308b-buildroot:/root# |
![]() |
root@rk3308b-buildroot:/root# insmod platform_test.ko [23438.316540] hello_init [23438.317773] hello_probe root@rk3308b-buildroot:/root# echo "shujen" > /dev/hello_file [23459.941964] hello_open [23459.942049] hello_resume [23459.942181] hello_write [23459.942238] hello_release root@rk3308b-buildroot:/root# [23459.942273] hello_suspend root@rk3308b-buildroot:/root# rmmod platform_test.ko [23464.348851] hello_exit [23464.349162] hello_resume [23464.349233] hello_suspend [23464.349269] hello_remove [23464.349984] ---disable begin--- [23464.350030] ---disable end--- [23464.350216] hello_device_release root@rk3308b-buildroot:/root# |
![]() |
参考驱动程序:Luckfox_Nova_SDK_250430/kernel/drivers/input/misc/bma150.c
|
![]() |
ret = pm_runtime_get_sync(&data->pdev->dev); if (ret != 0) {应该改成if (ret < 0) {才对。 只有<0才是出错,>=0都是正常状态。 |
![]() |
【autosuspend功能的使用】 static int hello_open(struct inode *inode, struct file *file) { ... ret = pm_runtime_get_sync(&data->pdev->dev); if (ret < 0) { // 这里应该是<0才对 dev_err(&data->pdev->dev, "pm_runtime_get_sync() failed: ret=%d\n", ret); return ret; } return 0; } static int hello_release(struct inode *inode, struct file *file) { ... pm_runtime_mark_last_busy(&data->pdev->dev); pm_runtime_put_sync_autosuspend(&data->pdev->dev); return 0; } static int hello_probe(struct platform_device *pdev) { ... pm_runtime_set_autosuspend_delay(&pdev->dev, 2000); // 设置超时时间为2秒 pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_enable(&pdev->dev); return 0; } 实测发现pm_runtime_mark_last_busy函数是必须要手动调用的,否则设备关闭的时间是以第一次关闭设备文件的时间为准,而不是最后一次关闭设备文件的时间。 pm_runtime_put_sync_autosuspend函数也可以换成pm_runtime_put_autosuspend函数。 以下是这三个函数的介绍: https://docs.kernel.org/power/runtime_pm.html int pm_runtime_put_autosuspend(struct device *dev); set the power.last_busy field to the current time and decrement the device’s usage counter; if the result is 0 then run pm_request_autosuspend(dev) and return its result set the power.last_busy field to the current time and decrement the device’s usage counter; if the result is 0 then run pm_runtime_autosuspend(dev) and return its result set the power.last_busy field to the current time |
![]() |
在remove函数中,pm_runtime_disable前必须还要调用pm_runtime_dont_use_autosuspend,否则rmmod的时候有可能不会suspend设备。 static int hello_remove(struct platform_device *pdev) { struct data *data = platform_get_drvdata(pdev);
printk("%s\n", __func__);
if (data->miscdevice_registered) { misc_deregister(&data->miscdevice); data->miscdevice_registered = false; }
printk("---disable begin---\n"); pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_disable(&pdev->dev); printk("---disable end---\n"); return 0; } root@rk3308b-buildroot:/root# echo "xxx" > /dev/hello_file [ 1852.244258] hello_open [ 1852.244513] hello_write [ 1852.244578] hello_release root@rk3308b-buildroot:/root# rmmod platform_test [ 1852.618912] hello_exit [ 1852.619244] hello_remove [ 1852.620159] ---disable begin--- [ 1852.620229] hello_suspend [ 1852.620265] ---disable end--- [ 1852.620552] hello_device_release root@rk3308b-buildroot:/root# 巨大八爪鱼:
suspend后再rmmod的打印:会先resume再suspend [ 2098.009571] hello_release root@rk3308b-buildroot:/root# echo "xxx" > /dev/hello_file [ 2098.397681] hello_open [ 2098.397854] hello_write [ 2098.397914] hello_release root@rk3308b-buildroot:/root# [ 2100.898057] hello_suspend root@rk3308b-buildroot:/root# root@rk3308b-buildroot:/root# rmmod platform_test [ 2107.616929] hello_exit [ 2107.617241] hello_resume [ 2107.617319] hello_remove [ 2107.617991] ---disable begin--- [ 2107.618048] hello_suspend [ 2107.618083] ---disable end--- [ 2107.618313] hello_device_release root@rk3308b-buildroot:/root# 巨大八爪鱼:有了pm_runtime_dont_use_autosuspend函数,只要rmmod就一定会suspend。
如果之前suspend了才rmmod,那么先resume再suspend。 如果之前没有suspend就rmmod,那么直接suspend。
[查看详情]
|
https://www.elecfans.com/d/2327034.html
如果不想让设备频繁地开、关,可以使用autosuspend功能
驱动里: 执行pm_runtime_use_autosuspend来设置启动autosuspend功能,
put设备时, 执行这2个函数:
pm_runtime_mark_last_busy(&lcd_dev.dev);(更新power.last_busy的状态)
pm_runtime_put_sync_autosuspend(&lcd_dev.dev);(根据power.last_busy的状态启动定时器,一段时间后如果没有再次打开动作才休眠)
(pm_runtime_get_sync不需要改,open的时候应该马上上电运行)
https://www.cnblogs.com/liusiluandzhangkun/p/8977059.html