设置 | 登录 | 注册

目前共有11篇帖子。

Linux內核 Runtime PM

1楼 巨大八爪鱼 2025-12-5 15:14
#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");

2楼 巨大八爪鱼 2025-12-5 15:14

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#

3楼 巨大八爪鱼 2025-12-5 15:15

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#

4楼 巨大八爪鱼 2025-12-5 15:16
參考驅動程序:Luckfox_Nova_SDK_250430/kernel/drivers/input/misc/bma150.c
巨大八爪鱼電源管理入門:驅動Runtime PM管理

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

5楼 巨大八爪鱼 2025-12-5 17:34

ret = pm_runtime_get_sync(&data->pdev->dev);

if (ret != 0) {應該改成if (ret < 0) {才對。

只有<0才是出錯,>=0都是正常狀態。

8楼 巨大八爪鱼 2025-12-5 17:57

【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


int pm_runtime_put_sync_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_runtime_autosuspend(dev) and return its result


void pm_runtime_mark_last_busy(struct device *dev);

set the power.last_busy field to the current time

9楼 巨大八爪鱼 2025-12-5 19:12

在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。

内容转换:

回复帖子
内容:
用户名: 您目前是匿名发表。
验证码:
看不清?换一张