Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

greybus: camera: add runtime pm support

Add runtime pm support to camera protocol device class driver.

Testing Done:
- Make sure white camera module is able to runtime suspend and resume
when the camera is being used

Signed-off-by: David Lin <dtwlin@google.com>
Signed-off-by: Axel Haslam <ahaslam@baylibre.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@linaro.org>
Signed-off-by: Alex Elder <elder@linaro.org>

authored by

David Lin and committed by
Alex Elder
211634f2 6ba7fad4

+81
+81
drivers/staging/greybus/camera.c
··· 333 333 struct gb_operation *op = NULL; 334 334 int ret; 335 335 336 + ret = gb_pm_runtime_get_sync(gcam->bundle); 337 + if (ret) 338 + return ret; 339 + 336 340 mutex_lock(&gcam->mutex); 337 341 338 342 if (!gcam->connection) { ··· 366 362 mutex_unlock(&gcam->mutex); 367 363 if (op) 368 364 gb_operation_put(op); 365 + 366 + gb_pm_runtime_put_autosuspend(gcam->bundle); 367 + 369 368 return ret; 370 369 } 371 370 ··· 414 407 } 415 408 416 409 mutex_lock(&gcam->mutex); 410 + 411 + ret = gb_pm_runtime_get_sync(gcam->bundle); 412 + if (ret) 413 + goto done_skip_pm_put; 417 414 418 415 if (!gcam->connection) { 419 416 ret = -EINVAL; ··· 471 460 if (gcam->state == GB_CAMERA_STATE_CONFIGURED) { 472 461 gb_camera_teardown_data_connection(gcam); 473 462 gcam->state = GB_CAMERA_STATE_UNCONFIGURED; 463 + 464 + /* 465 + * When unconfiguring streams release the PM runtime reference 466 + * that was acquired when streams were configured. The bundle 467 + * won't be suspended until the PM runtime reference acquired at 468 + * the beginning of this function gets released right before 469 + * returning. 470 + */ 471 + gb_pm_runtime_put_noidle(gcam->bundle); 474 472 } 475 473 476 474 if (resp->num_streams) { 475 + /* 476 + * Make sure the bundle won't be suspended until streams get 477 + * unconfigured after the stream is configured successfully 478 + */ 479 + gb_pm_runtime_get_noresume(gcam->bundle); 480 + 477 481 ret = gb_camera_setup_data_connection(gcam, resp, csi_params); 478 482 if (ret < 0) { 479 483 memset(req, 0, sizeof(*req)); ··· 498 472 resp, sizeof(*resp)); 499 473 *flags = 0; 500 474 *num_streams = 0; 475 + gb_pm_runtime_put_noidle(gcam->bundle); 501 476 goto done; 502 477 } 503 478 ··· 506 479 } 507 480 508 481 done: 482 + gb_pm_runtime_put_autosuspend(gcam->bundle); 483 + 484 + done_skip_pm_put: 509 485 mutex_unlock(&gcam->mutex); 510 486 kfree(req); 511 487 kfree(resp); ··· 1180 1150 1181 1151 greybus_set_drvdata(bundle, gcam); 1182 1152 1153 + gb_pm_runtime_put_autosuspend(gcam->bundle); 1154 + 1183 1155 return 0; 1184 1156 1185 1157 error: ··· 1193 1161 static void gb_camera_disconnect(struct gb_bundle *bundle) 1194 1162 { 1195 1163 struct gb_camera *gcam = greybus_get_drvdata(bundle); 1164 + int ret; 1165 + 1166 + ret = gb_pm_runtime_get_sync(bundle); 1167 + if (ret) 1168 + gb_pm_runtime_get_noresume(bundle); 1196 1169 1197 1170 gb_camera_cleanup(gcam); 1198 1171 gb_camera_unregister(&gcam->module); ··· 1208 1171 { }, 1209 1172 }; 1210 1173 1174 + #ifdef CONFIG_PM_RUNTIME 1175 + static int gb_camera_suspend(struct device *dev) 1176 + { 1177 + struct gb_bundle *bundle = to_gb_bundle(dev); 1178 + struct gb_camera *gcam = greybus_get_drvdata(bundle); 1179 + 1180 + if (gcam->data_connection) 1181 + gb_connection_disable(gcam->data_connection); 1182 + 1183 + gb_connection_disable(gcam->connection); 1184 + 1185 + return 0; 1186 + } 1187 + 1188 + static int gb_camera_resume(struct device *dev) 1189 + { 1190 + struct gb_bundle *bundle = to_gb_bundle(dev); 1191 + struct gb_camera *gcam = greybus_get_drvdata(bundle); 1192 + int ret; 1193 + 1194 + ret = gb_connection_enable(gcam->connection); 1195 + if (ret) { 1196 + gcam_err(gcam, "failed to enable connection: %d\n", ret); 1197 + return ret; 1198 + } 1199 + 1200 + if (gcam->data_connection) { 1201 + ret = gb_connection_enable(gcam->data_connection); 1202 + if (ret) { 1203 + gcam_err(gcam, 1204 + "failed to enable data connection: %d\n", ret); 1205 + return ret; 1206 + } 1207 + } 1208 + 1209 + return 0; 1210 + } 1211 + #endif 1212 + 1213 + static const struct dev_pm_ops gb_camera_pm_ops = { 1214 + SET_RUNTIME_PM_OPS(gb_camera_suspend, gb_camera_resume, NULL) 1215 + }; 1216 + 1211 1217 static struct greybus_driver gb_camera_driver = { 1212 1218 .name = "camera", 1213 1219 .probe = gb_camera_probe, 1214 1220 .disconnect = gb_camera_disconnect, 1215 1221 .id_table = gb_camera_id_table, 1222 + .driver.pm = &gb_camera_pm_ops, 1216 1223 }; 1217 1224 1218 1225 module_greybus_driver(gb_camera_driver);