mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-13 14:04:05 +08:00
media: ipu3-cio2: Parse information from firmware without using callbacks
Instead of using the convenience function v4l2_async_notifier_parse_fwnode_endpoints(), parse the endpoints and set up the async sub-devices without using callbacks. While this adds a little bit of code, it makes parsing the endpoints quite a bit more simple and gives more control to the driver over the process. The parsing assumes D-PHY instead of letting the V4L2 fwnode framework guess it. Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com> Reviewed-by: Jacopo Mondi <jacopo+renesas@jmondi.org> Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
This commit is contained in:
parent
706c0cffaf
commit
2c93346698
@ -1475,36 +1475,52 @@ static const struct v4l2_async_notifier_operations cio2_async_ops = {
|
|||||||
.complete = cio2_notifier_complete,
|
.complete = cio2_notifier_complete,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int cio2_fwnode_parse(struct device *dev,
|
static int cio2_parse_firmware(struct cio2_device *cio2)
|
||||||
struct v4l2_fwnode_endpoint *vep,
|
|
||||||
struct v4l2_async_subdev *asd)
|
|
||||||
{
|
|
||||||
struct sensor_async_subdev *s_asd =
|
|
||||||
container_of(asd, struct sensor_async_subdev, asd);
|
|
||||||
|
|
||||||
if (vep->bus_type != V4L2_MBUS_CSI2_DPHY) {
|
|
||||||
dev_err(dev, "Only CSI2 bus type is currently supported\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
s_asd->csi2.port = vep->base.port;
|
|
||||||
s_asd->csi2.lanes = vep->bus.mipi_csi2.num_data_lanes;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cio2_notifier_init(struct cio2_device *cio2)
|
|
||||||
{
|
{
|
||||||
|
unsigned int i;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
v4l2_async_notifier_init(&cio2->notifier);
|
for (i = 0; i < CIO2_NUM_PORTS; i++) {
|
||||||
|
struct v4l2_fwnode_endpoint vep = {
|
||||||
|
.bus_type = V4L2_MBUS_CSI2_DPHY
|
||||||
|
};
|
||||||
|
struct sensor_async_subdev *s_asd = NULL;
|
||||||
|
struct fwnode_handle *ep;
|
||||||
|
|
||||||
ret = v4l2_async_notifier_parse_fwnode_endpoints(
|
ep = fwnode_graph_get_endpoint_by_id(
|
||||||
&cio2->pci_dev->dev, &cio2->notifier,
|
dev_fwnode(&cio2->pci_dev->dev), i, 0,
|
||||||
sizeof(struct sensor_async_subdev),
|
FWNODE_GRAPH_ENDPOINT_NEXT);
|
||||||
cio2_fwnode_parse);
|
|
||||||
if (ret < 0)
|
if (!ep)
|
||||||
goto out;
|
continue;
|
||||||
|
|
||||||
|
ret = v4l2_fwnode_endpoint_parse(ep, &vep);
|
||||||
|
if (ret)
|
||||||
|
goto err_parse;
|
||||||
|
|
||||||
|
s_asd = kzalloc(sizeof(*s_asd), GFP_KERNEL);
|
||||||
|
if (!s_asd) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto err_parse;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_asd->csi2.port = vep.base.port;
|
||||||
|
s_asd->csi2.lanes = vep.bus.mipi_csi2.num_data_lanes;
|
||||||
|
|
||||||
|
ret = v4l2_async_notifier_add_fwnode_remote_subdev(
|
||||||
|
&cio2->notifier, ep, &s_asd->asd);
|
||||||
|
if (ret)
|
||||||
|
goto err_parse;
|
||||||
|
|
||||||
|
fwnode_handle_put(ep);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
|
||||||
|
err_parse:
|
||||||
|
fwnode_handle_put(ep);
|
||||||
|
kfree(s_asd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Proceed even without sensors connected to allow the device to
|
* Proceed even without sensors connected to allow the device to
|
||||||
@ -1512,25 +1528,13 @@ static int cio2_notifier_init(struct cio2_device *cio2)
|
|||||||
*/
|
*/
|
||||||
cio2->notifier.ops = &cio2_async_ops;
|
cio2->notifier.ops = &cio2_async_ops;
|
||||||
ret = v4l2_async_notifier_register(&cio2->v4l2_dev, &cio2->notifier);
|
ret = v4l2_async_notifier_register(&cio2->v4l2_dev, &cio2->notifier);
|
||||||
if (ret) {
|
if (ret)
|
||||||
dev_err(&cio2->pci_dev->dev,
|
dev_err(&cio2->pci_dev->dev,
|
||||||
"failed to register async notifier : %d\n", ret);
|
"failed to register async notifier : %d\n", ret);
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
if (ret)
|
|
||||||
v4l2_async_notifier_cleanup(&cio2->notifier);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cio2_notifier_exit(struct cio2_device *cio2)
|
|
||||||
{
|
|
||||||
v4l2_async_notifier_unregister(&cio2->notifier);
|
|
||||||
v4l2_async_notifier_cleanup(&cio2->notifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**************** Queue initialization ****************/
|
/**************** Queue initialization ****************/
|
||||||
static const struct media_entity_operations cio2_media_ops = {
|
static const struct media_entity_operations cio2_media_ops = {
|
||||||
.link_validate = v4l2_subdev_link_validate,
|
.link_validate = v4l2_subdev_link_validate,
|
||||||
@ -1814,16 +1818,18 @@ static int cio2_pci_probe(struct pci_dev *pci_dev,
|
|||||||
if (r)
|
if (r)
|
||||||
goto fail_v4l2_device_unregister;
|
goto fail_v4l2_device_unregister;
|
||||||
|
|
||||||
|
v4l2_async_notifier_init(&cio2->notifier);
|
||||||
|
|
||||||
/* Register notifier for subdevices we care */
|
/* Register notifier for subdevices we care */
|
||||||
r = cio2_notifier_init(cio2);
|
r = cio2_parse_firmware(cio2);
|
||||||
if (r)
|
if (r)
|
||||||
goto fail_cio2_queue_exit;
|
goto fail_clean_notifier;
|
||||||
|
|
||||||
r = devm_request_irq(&pci_dev->dev, pci_dev->irq, cio2_irq,
|
r = devm_request_irq(&pci_dev->dev, pci_dev->irq, cio2_irq,
|
||||||
IRQF_SHARED, CIO2_NAME, cio2);
|
IRQF_SHARED, CIO2_NAME, cio2);
|
||||||
if (r) {
|
if (r) {
|
||||||
dev_err(&pci_dev->dev, "failed to request IRQ (%d)\n", r);
|
dev_err(&pci_dev->dev, "failed to request IRQ (%d)\n", r);
|
||||||
goto fail;
|
goto fail_clean_notifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
pm_runtime_put_noidle(&pci_dev->dev);
|
pm_runtime_put_noidle(&pci_dev->dev);
|
||||||
@ -1831,9 +1837,9 @@ static int cio2_pci_probe(struct pci_dev *pci_dev,
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail:
|
fail_clean_notifier:
|
||||||
cio2_notifier_exit(cio2);
|
v4l2_async_notifier_unregister(&cio2->notifier);
|
||||||
fail_cio2_queue_exit:
|
v4l2_async_notifier_cleanup(&cio2->notifier);
|
||||||
cio2_queues_exit(cio2);
|
cio2_queues_exit(cio2);
|
||||||
fail_v4l2_device_unregister:
|
fail_v4l2_device_unregister:
|
||||||
v4l2_device_unregister(&cio2->v4l2_dev);
|
v4l2_device_unregister(&cio2->v4l2_dev);
|
||||||
@ -1852,7 +1858,8 @@ static void cio2_pci_remove(struct pci_dev *pci_dev)
|
|||||||
struct cio2_device *cio2 = pci_get_drvdata(pci_dev);
|
struct cio2_device *cio2 = pci_get_drvdata(pci_dev);
|
||||||
|
|
||||||
media_device_unregister(&cio2->media_dev);
|
media_device_unregister(&cio2->media_dev);
|
||||||
cio2_notifier_exit(cio2);
|
v4l2_async_notifier_unregister(&cio2->notifier);
|
||||||
|
v4l2_async_notifier_cleanup(&cio2->notifier);
|
||||||
cio2_queues_exit(cio2);
|
cio2_queues_exit(cio2);
|
||||||
cio2_fbpt_exit_dummy(cio2);
|
cio2_fbpt_exit_dummy(cio2);
|
||||||
v4l2_device_unregister(&cio2->v4l2_dev);
|
v4l2_device_unregister(&cio2->v4l2_dev);
|
||||||
|
Loading…
Reference in New Issue
Block a user