电源相关回调函数 IMX415 里有两套“电源管理回调”Runtime PM 回调摄像头平时不用时断电开流时再上电。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 PMSET_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, };系统休眠 PMSET_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 Resumestatic 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 上电稳定 释放 reset2. Runtime Suspendstatic 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 Coreprobe已经完成当前没有用户使用设备 可以检查是否进入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 ResumeIMX415 的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 Suspenddev-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 0PM Core 会认为设备可能已经无人使用随后根据 Runtime PM 策略进入 suspendpm_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 PMIMX415 还实现了 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 / suspendIMX415 的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_resumepm_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 Coreimx415_runtime_suspend()Runtime PM回调Linux PM Core__imx415_power_on()内部硬件函数probe或runtime_resume__imx415_power_off()内部硬件函数remove或runtime_suspendimx415_suspend()系统休眠回调系统PM Coreimx415_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 系统进入休眠和唤醒过程触发。