diff options
Diffstat (limited to 'drivers/media/platform/renesas-ceu.c')
-rw-r--r-- | drivers/media/platform/renesas-ceu.c | 53 |
1 files changed, 29 insertions, 24 deletions
diff --git a/drivers/media/platform/renesas-ceu.c b/drivers/media/platform/renesas-ceu.c index b7ae820a2ef6..eee4ae7234be 100644 --- a/drivers/media/platform/renesas-ceu.c +++ b/drivers/media/platform/renesas-ceu.c @@ -189,8 +189,6 @@ struct ceu_device { /* async subdev notification helpers */ struct v4l2_async_notifier notifier; - /* pointers to "struct ceu_subdevice -> asd" */ - struct v4l2_async_subdev **asds; /* vb2 queue, capture buffer list and active buffer pointer */ struct vb2_queue vb2_vq; @@ -1482,15 +1480,6 @@ static int ceu_init_async_subdevs(struct ceu_device *ceudev, unsigned int n_sd) if (!ceudev->subdevs) return -ENOMEM; - /* - * Reserve memory for 'n_sd' pointers to async_subdevices. - * ceudev->asds members will point to &ceu_subdev.asd - */ - ceudev->asds = devm_kcalloc(ceudev->dev, n_sd, - sizeof(*ceudev->asds), GFP_KERNEL); - if (!ceudev->asds) - return -ENOMEM; - ceudev->sd = NULL; ceudev->sd_index = 0; ceudev->num_sd = 0; @@ -1518,6 +1507,7 @@ static int ceu_parse_platform_data(struct ceu_device *ceudev, return ret; for (i = 0; i < pdata->num_subdevs; i++) { + /* Setup the ceu subdevice and the async subdevice. */ async_sd = &pdata->subdevs[i]; ceu_sd = &ceudev->subdevs[i]; @@ -1529,7 +1519,12 @@ static int ceu_parse_platform_data(struct ceu_device *ceudev, ceu_sd->asd.match.i2c.adapter_id = async_sd->i2c_adapter_id; ceu_sd->asd.match.i2c.address = async_sd->i2c_address; - ceudev->asds[i] = &ceu_sd->asd; + ret = v4l2_async_notifier_add_subdev(&ceudev->notifier, + &ceu_sd->asd); + if (ret) { + v4l2_async_notifier_cleanup(&ceudev->notifier); + return ret; + } } return pdata->num_subdevs; @@ -1542,8 +1537,8 @@ static int ceu_parse_dt(struct ceu_device *ceudev) { struct device_node *of = ceudev->dev->of_node; struct v4l2_fwnode_endpoint fw_ep; + struct device_node *ep, *remote; struct ceu_subdev *ceu_sd; - struct device_node *ep; unsigned int i; int num_ep; int ret; @@ -1562,40 +1557,46 @@ static int ceu_parse_dt(struct ceu_device *ceudev) dev_err(ceudev->dev, "No subdevice connected on endpoint %u.\n", i); ret = -ENODEV; - goto error_put_node; + goto error_cleanup; } ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &fw_ep); if (ret) { dev_err(ceudev->dev, "Unable to parse endpoint #%u.\n", i); - goto error_put_node; + goto error_cleanup; } if (fw_ep.bus_type != V4L2_MBUS_PARALLEL) { dev_err(ceudev->dev, "Only parallel input supported.\n"); ret = -EINVAL; - goto error_put_node; + goto error_cleanup; } /* Setup the ceu subdevice and the async subdevice. */ ceu_sd = &ceudev->subdevs[i]; INIT_LIST_HEAD(&ceu_sd->asd.list); + remote = of_graph_get_remote_port_parent(ep); ceu_sd->mbus_flags = fw_ep.bus.parallel.flags; ceu_sd->asd.match_type = V4L2_ASYNC_MATCH_FWNODE; - ceu_sd->asd.match.fwnode = - fwnode_graph_get_remote_port_parent( - of_fwnode_handle(ep)); + ceu_sd->asd.match.fwnode = of_fwnode_handle(remote); + + ret = v4l2_async_notifier_add_subdev(&ceudev->notifier, + &ceu_sd->asd); + if (ret) { + of_node_put(remote); + goto error_cleanup; + } - ceudev->asds[i] = &ceu_sd->asd; of_node_put(ep); } return num_ep; -error_put_node: +error_cleanup: + v4l2_async_notifier_cleanup(&ceudev->notifier); of_node_put(ep); return ret; } @@ -1674,6 +1675,8 @@ static int ceu_probe(struct platform_device *pdev) if (ret) goto error_pm_disable; + v4l2_async_notifier_init(&ceudev->notifier); + if (IS_ENABLED(CONFIG_OF) && dev->of_node) { ceu_data = of_match_device(ceu_of_match, dev)->data; num_subdevs = ceu_parse_dt(ceudev); @@ -1693,18 +1696,18 @@ static int ceu_probe(struct platform_device *pdev) ceudev->irq_mask = ceu_data->irq_mask; ceudev->notifier.v4l2_dev = &ceudev->v4l2_dev; - ceudev->notifier.subdevs = ceudev->asds; - ceudev->notifier.num_subdevs = num_subdevs; ceudev->notifier.ops = &ceu_notify_ops; ret = v4l2_async_notifier_register(&ceudev->v4l2_dev, &ceudev->notifier); if (ret) - goto error_v4l2_unregister; + goto error_cleanup; dev_info(dev, "Renesas Capture Engine Unit %s\n", dev_name(dev)); return 0; +error_cleanup: + v4l2_async_notifier_cleanup(&ceudev->notifier); error_v4l2_unregister: v4l2_device_unregister(&ceudev->v4l2_dev); error_pm_disable: @@ -1723,6 +1726,8 @@ static int ceu_remove(struct platform_device *pdev) v4l2_async_notifier_unregister(&ceudev->notifier); + v4l2_async_notifier_cleanup(&ceudev->notifier); + v4l2_device_unregister(&ceudev->v4l2_dev); video_unregister_device(&ceudev->vdev); |