diff --git a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c index 295fb8ad4281af..6bda6515714fd1 100644 --- a/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c +++ b/drivers/media/platform/raspberrypi/rp1_cfe/cfe.c @@ -1915,6 +1915,13 @@ static int cfe_register_node(struct cfe_device *cfe, int id) struct cfe_node *node = &cfe->node[id]; int ret; + /* + * The node may be re-registered after the source subdev has been + * unbound and rebound. The embedded video_device must be reset before + * being re-registered. + */ + memset(&node->video_dev, 0, sizeof(node->video_dev)); + node->cfe = cfe; node->id = id; @@ -2038,6 +2045,7 @@ static void cfe_unregister_nodes(struct cfe_device *cfe) if (check_state(cfe, NODE_REGISTERED, i)) { clear_state(cfe, NODE_REGISTERED, i); video_unregister_device(&node->video_dev); + vb2_queue_release(&node->buffer_queue); } } } @@ -2168,6 +2176,22 @@ static int cfe_async_bound(struct v4l2_async_notifier *notifier, return 0; } +static void cfe_async_unbind(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_connection *asd) +{ + struct cfe_device *cfe = to_cfe_device(notifier->v4l2_dev); + + if (cfe->sensor != subdev) + return; + + cfe_unregister_nodes(cfe); + media_entity_remove_links(&cfe->csi2.sd.entity); + media_entity_remove_links(&cfe->fe.sd.entity); + + cfe->sensor = NULL; +} + static int cfe_async_complete(struct v4l2_async_notifier *notifier) { struct cfe_device *cfe = to_cfe_device(notifier->v4l2_dev); @@ -2177,6 +2201,7 @@ static int cfe_async_complete(struct v4l2_async_notifier *notifier) static const struct v4l2_async_notifier_operations cfe_async_ops = { .bound = cfe_async_bound, + .unbind = cfe_async_unbind, .complete = cfe_async_complete, };