电源相关回调函数
2026/7/21 7:47:31 网站建设 项目流程

IMX415 里有两套“电源管理回调”:

  1. Runtime PM 回调:摄像头平时不用时断电,开流时再上电。

  2. System Sleep PM 回调:整个系统执行 suspend/resume 时触发。

它们都先放进struct dev_pm_ops,再绑定到i2c_driver.driver.pm


一、回调在哪里绑定

1. 先定义dev_pm_ops

源码中:

static const struct dev_pm_ops imx415_pm_ops = { SET_RUNTIME_PM_OPS(imx415_runtime_suspend, imx415_runtime_resume, NULL) SET_LATE_SYSTEM_SLEEP_PM_OPS(imx415_suspend, imx415_resume) };

这里包含两组回调。

Runtime PM

SET_RUNTIME_PM_OPS( imx415_runtime_suspend, imx415_runtime_resume, NULL )

大致等价于:

static const struct dev_pm_ops imx415_pm_ops = { .runtime_suspend = imx415_runtime_suspend, .runtime_resume = imx415_runtime_resume, .runtime_idle = NULL, };

系统休眠 PM

SET_LATE_SYSTEM_SLEEP_PM_OPS( imx415_suspend, imx415_resume )

通常会把它们放到系统休眠的 late/early 阶段,例如:

.suspend_late = imx415_suspend; .resume_early = imx415_resume;

同时也可能覆盖 freeze/thaw、poweroff/restore 等系统休眠阶段,具体宏展开与内核版本有关。IMX415 的 Runtime PM 和系统休眠回调都集中注册在imx415_pm_ops中。


2. 再绑定到 I2C 驱动

源码底部:

static struct i2c_driver imx415_i2c_driver = { .driver = { .name = IMX415_NAME, .pm = &imx415_pm_ops, .of_match_table = of_match_ptr(imx415_of_match), }, .probe = &imx415_probe, .remove = &imx415_remove, .id_table = imx415_match_id, };

关键是:

.pm = &imx415_pm_ops,

完整绑定关系:

imx415_i2c_driver │ └── driver │ └── pm │ └── imx415_pm_ops ├── runtime_suspend │ └── imx415_runtime_suspend ├── runtime_resume │ └── imx415_runtime_resume ├── suspend_late │ └── imx415_suspend └── resume_early └── imx415_resume

驱动与 I2C 设备匹配后:

client->dev.driver ↓ &imx415_i2c_driver.driver ↓ dev->driver->pm ↓ &imx415_pm_ops

以后 PM Core 需要挂起或恢复这个设备时,就通过:

dev->driver->pm->runtime_suspend(dev); dev->driver->pm->runtime_resume(dev);

找到 IMX415 的回调。IMX415 的 PM 表最终就是通过i2c_driver.driver.pm绑定给 I2C 设备的。


二、Runtime PM 回调具体做什么

1. Runtime Resume

static int __maybe_unused imx415_runtime_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct v4l2_subdev *sd = i2c_get_clientdata(client); struct imx415 *imx415 = to_imx415(sd); return __imx415_power_on(imx415); }

调用链:

PM Core ↓ imx415_runtime_resume(dev) ↓ device → i2c_client ↓ i2c_client → v4l2_subdev ↓ v4l2_subdev → struct imx415 ↓ __imx415_power_on(imx415)

__imx415_power_on()才是真正操作硬件的函数,通常包括:

选择 default pinctrl 打开 power GPIO 拉 reset 设置并打开 xvclk 打开 dvdd/dovdd/avdd regulator 等待 Sensor 上电稳定 释放 reset

2. Runtime Suspend

static int __maybe_unused imx415_runtime_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct v4l2_subdev *sd = i2c_get_clientdata(client); struct imx415 *imx415 = to_imx415(sd); __imx415_power_off(imx415); return 0; }

调用链:

PM Core ↓ imx415_runtime_suspend(dev) ↓ __imx415_power_off(imx415)

__imx415_power_off()通常执行:

reset GPIO 置为复位状态 关闭 xvclk 切换到 sleep pinctrl 关闭 power GPIO 关闭 regulator

这两个 Runtime PM 回调最终分别调用__imx415_power_on()__imx415_power_off()


三、Runtime PM 是什么时候启用的

imx415_probe()的前半段,驱动为了读取 Chip ID,会先直接上电:

ret = __imx415_power_on(imx415); if (ret) goto err_free_handler; ret = imx415_check_sensor_id(imx415, client); if (ret) goto err_power_off;

注意:

这里第一次上电不是 Runtime PM 回调触发的,而是probe()直接调用__imx415_power_on()

因为这时 Runtime PM 还没启用。

完成 Sensor 注册后,probe()尾部执行:

pm_runtime_set_active(dev); pm_runtime_enable(dev); pm_runtime_idle(dev);

含义分别是:

pm_runtime_set_active(dev)

告诉 PM Core:

设备当前物理状态是上电状态

因为前面已经手动执行了:

__imx415_power_on()

所以软件状态也要标记为 active。

pm_runtime_enable(dev)

正式启用该设备的 Runtime PM。

此后:

pm_runtime_get_xxx() pm_runtime_put_xxx()

才会驱动 active/suspended 状态变化。

pm_runtime_idle(dev)

告诉 PM Core:

probe已经完成,当前没有用户使用设备, 可以检查是否进入Runtime Suspend

如果当前:

usage_count == 0

且没有其他阻止条件,PM Core 就可能调用:

imx415_runtime_suspend(dev)

进而把 probe 阶段临时打开的 Sensor 关闭。

所以 probe 阶段的完整电源流程大致是:

imx415_probe() ↓ __imx415_power_on() // 直接上电 ↓ 读取 Chip ID ↓ 注册 V4L2 subdev ↓ pm_runtime_set_active() ↓ pm_runtime_enable() ↓ pm_runtime_idle() ↓ PM Core判断无人使用 ↓ imx415_runtime_suspend() ↓ __imx415_power_off()

IMX415 在 probe 中先直接上电识别芯片,完成注册后才用pm_runtime_set_active()pm_runtime_enable()pm_runtime_idle()把控制权移交给 Runtime PM。


四、开流时什么时候触发 Runtime Resume

IMX415 的s_stream()中:

static int imx415_s_stream(struct v4l2_subdev *sd, int on) { ... if (on) { ret = pm_runtime_get_sync(&client->dev); if (ret < 0) { pm_runtime_put_noidle(&client->dev); goto unlock_and_return; } ret = __imx415_start_stream(imx415); ... } else { __imx415_stop_stream(imx415); pm_runtime_put(&client->dev); } }

开流

应用执行:

v4l2-ctl -d /dev/video0 --stream-mmap

大致链路:

VIDIOC_STREAMON ↓ RKISP/RKCIF启动pipeline ↓ 调用Sensor subdev的s_stream(1) ↓ imx415_s_stream(sd, 1) ↓ pm_runtime_get_sync(&client->dev)

此时有两种情况。

Sensor 当前已 Runtime Suspend

dev->power.runtime_status == RPM_SUSPENDED

那么:

pm_runtime_get_sync() ↓ usage_count加1 ↓ PM Core发现设备已挂起 ↓ dev->driver->pm->runtime_resume(dev) ↓ imx415_runtime_resume(dev) ↓ __imx415_power_on(imx415)

Sensor 上电后再执行:

__imx415_start_stream(imx415);

最终写寄存器并开启 MIPI 输出。

Sensor 本来就是 Active

这时pm_runtime_get_sync()主要增加引用计数,不会重复调用:

imx415_runtime_resume()

所以:

调用了pm_runtime_get_sync(),不代表每次都会进入runtime_resume();只有设备当前处于 Runtime Suspended 状态时才需要恢复。

回调函数触发入口:

IMX415 的主要 Runtime Resume 触发入口就是s_stream(1)中的pm_runtime_get_sync()


五、停流时什么时候触发 Runtime Suspend

应用执行停止采集:

VIDIOC_STREAMOFF ↓ RKISP/RKCIF停止pipeline ↓ imx415_s_stream(sd, 0)

驱动执行:

__imx415_stop_stream(imx415); pm_runtime_put(&client->dev);

pm_runtime_put()会减少 Runtime PM 使用计数:

usage_count = usage_count - 1

如果减少后:

usage_count == 0

PM Core 会认为设备可能已经无人使用,随后根据 Runtime PM 策略进入 suspend:

pm_runtime_put() ↓ usage_count减到0 ↓ PM Core请求设备空闲 ↓ dev->driver->pm->runtime_suspend(dev) ↓ imx415_runtime_suspend(dev) ↓ __imx415_power_off(imx415)

所以开关流对应关系是:

STREAMON ↓ pm_runtime_get_sync() ↓ runtime_resume ↓ Sensor上电 STREAMOFF ↓ pm_runtime_put() ↓ runtime_suspend ↓ Sensor断电

不过严格来说,pm_runtime_put()是否立即执行 suspend,取决于内核 PM 策略、引用计数和是否启用了 autosuspend。这个驱动片段没有显示设置 autosuspend 延时,因此通常会较快进入 idle/suspend。


六、s_power()也可能触发 Runtime PM

IMX415 还实现了 V4L2 的:

static int imx415_s_power(struct v4l2_subdev *sd, int on)

内部也是:

if (on) { ret = pm_runtime_get_sync(&client->dev); ... } else { pm_runtime_put(&client->dev); }

因此:

V4L2调用s_power(1) ↓ pm_runtime_get_sync() ↓ 可能触发imx415_runtime_resume() V4L2调用s_power(0) ↓ pm_runtime_put() ↓ 可能触发imx415_runtime_suspend()

注意:

imx415_s_power()

本身不是 PM Core 回调,它是:

struct v4l2_subdev_core_ops

中的 V4L2 回调:

static const struct v4l2_subdev_core_ops imx415_core_ops = { .s_power = imx415_s_power, ... };

它只是通过调用 Runtime PM API,间接触发真正的 PM 回调。

关系是:

V4L2回调 imx415_s_power() ↓ pm_runtime_get_sync / put ↓ PM Core ↓ Runtime PM回调 imx415_runtime_resume / suspend

IMX415 的s_stream()s_power()都通过 Runtime PM API维护使用计数。


七、imx415_set_ctrl()会不会触发上电回调

代码中一般是:

if (!pm_runtime_get_if_in_use(&client->dev)) return 0;

这里使用的是:

pm_runtime_get_if_in_use()

它与:

pm_runtime_get_sync()

不同。

pm_runtime_get_sync()

设备如果已经休眠,会主动唤醒:

可能触发 runtime_resume

pm_runtime_get_if_in_use()

只在设备本来就在使用中时增加引用:

设备Active且正在使用 → 增加引用 → 可以写寄存器 设备已经Suspended → 返回0 → 不唤醒设备 → 不触发runtime_resume

因此:

单独设置曝光时,如果 Sensor 已经断电,imx415_set_ctrl()不会为了写曝光而把 Sensor 重新上电。

它只保存 Control 值,等开流时:

s_stream(1) ↓ pm_runtime_get_sync() ↓ runtime_resume ↓ __v4l2_ctrl_handler_setup() ↓ imx415_set_ctrl() ↓ 真正写曝光寄存器

八、系统休眠回调什么时候触发

这一组:

SET_LATE_SYSTEM_SLEEP_PM_OPS(imx415_suspend, imx415_resume)

不是开关摄像头流时触发,而是在整个 Linux 系统执行休眠/唤醒时触发。

例如:

echo mem > /sys/power/state

或者:

systemctl suspend

系统进入 suspend:

用户执行system suspend ↓ Linux PM Core遍历所有设备 ↓ 进入设备suspend late阶段 ↓ dev->driver->pm->suspend_late(dev) ↓ imx415_suspend(dev)

系统唤醒:

系统开始resume ↓ 进入设备resume early阶段 ↓ dev->driver->pm->resume_early(dev) ↓ imx415_resume(dev)

你的 IMX415 中,这两个函数只有在:

CONFIG_VIDEO_CAM_SLEEP_WAKEUP

可用时才真正存在:

#if IS_REACHABLE(CONFIG_VIDEO_CAM_SLEEP_WAKEUP) static int imx415_suspend(struct device *dev) { ... cam_sw_prepare_sleep(...); return 0; } static int imx415_resume(struct device *dev) { ... cam_sw_prepare_wakeup(...); cam_sw_write_array(...); __v4l2_ctrl_handler_setup(...); return 0; } #else #define imx415_resume NULL #define imx415_suspend NULL #endif

也就是说,如果没有开启该配置:

系统休眠回调实际是NULL

但 Runtime PM 回调仍然存在。系统 resume 时还会重新写模式寄存器和 Control 值。


九、四种电源相关函数不要混淆

函数类型谁调用
imx415_s_power()V4L2 subdev回调V4L2框架或上游驱动
imx415_runtime_resume()Runtime PM回调Linux PM Core
imx415_runtime_suspend()Runtime PM回调Linux PM Core
__imx415_power_on()内部硬件函数probe或runtime_resume
__imx415_power_off()内部硬件函数remove或runtime_suspend
imx415_suspend()系统休眠回调系统PM Core
imx415_resume()系统唤醒回调系统PM Core

最重要的分层是:

上层业务回调 s_stream / s_power ↓ Runtime PM接口 pm_runtime_get_sync / pm_runtime_put ↓ Linux PM Core ↓ PM回调 runtime_resume / runtime_suspend ↓ 真正硬件操作 __power_on / __power_off

十、整条开流上电流程

应用层 v4l2-ctl --stream-mmap ↓ VIDIOC_STREAMON ↓ RKISP/RKCIF启动Media Pipeline ↓ 调用IMX415 subdev imx415_s_stream(sd, 1) ↓ pm_runtime_get_sync(&client->dev) ↓ Runtime PM检查设备状态 ├── 已Active:只增加usage_count └── 已Suspended: ↓ dev->driver->pm ↓ imx415_pm_ops.runtime_resume ↓ imx415_runtime_resume(dev) ↓ __imx415_power_on(imx415) ↓ regulator、GPIO、clock、reset上电 ↓ __imx415_start_stream() ↓ 写Sensor寄存器 ↓ Sensor输出MIPI数据

停流则相反:

VIDIOC_STREAMOFF ↓ imx415_s_stream(sd, 0) ↓ __imx415_stop_stream() ↓ pm_runtime_put() ↓ usage_count降为0 ↓ imx415_runtime_suspend() ↓ __imx415_power_off()

一句话概括:

电源管理回调通过imx415_i2c_driver.driver.pm = &imx415_pm_ops绑定给 I2C 设备;Runtime PM 回调主要由s_stream()s_power()中的pm_runtime_get_sync()pm_runtime_put()间接触发,而系统suspend/resume回调由整个 Linux 系统进入休眠和唤醒过程触发。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询