Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2c933466 authored by Sakari Ailus's avatar Sakari Ailus Committed by Mauro Carvalho Chehab
Browse files

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: default avatarSakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: default avatarJacopo Mondi <jacopo+renesas@jmondi.org>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+samsung@kernel.org>
parent 706c0cff
Loading
Loading
Loading
Loading
+50 −43
Original line number Original line Diff line number Diff line
@@ -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 =
	unsigned int i;
			container_of(asd, struct sensor_async_subdev, asd);
	int ret;


	if (vep->bus_type != V4L2_MBUS_CSI2_DPHY) {
	for (i = 0; i < CIO2_NUM_PORTS; i++) {
		dev_err(dev, "Only CSI2 bus type is currently supported\n");
		struct v4l2_fwnode_endpoint vep = {
		return -EINVAL;
			.bus_type = V4L2_MBUS_CSI2_DPHY
	}
		};
		struct sensor_async_subdev *s_asd = NULL;
		struct fwnode_handle *ep;


	s_asd->csi2.port = vep->base.port;
		ep = fwnode_graph_get_endpoint_by_id(
	s_asd->csi2.lanes = vep->bus.mipi_csi2.num_data_lanes;
			dev_fwnode(&cio2->pci_dev->dev), i, 0,
			FWNODE_GRAPH_ENDPOINT_NEXT);


	return 0;
		if (!ep)
			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;
		}
		}


static int cio2_notifier_init(struct cio2_device *cio2)
		s_asd->csi2.port = vep.base.port;
{
		s_asd->csi2.lanes = vep.bus.mipi_csi2.num_data_lanes;
	int ret;


	v4l2_async_notifier_init(&cio2->notifier);
		ret = v4l2_async_notifier_add_fwnode_remote_subdev(
			&cio2->notifier, ep, &s_asd->asd);
		if (ret)
			goto err_parse;


	ret = v4l2_async_notifier_parse_fwnode_endpoints(
		fwnode_handle_put(ep);
		&cio2->pci_dev->dev, &cio2->notifier,

		sizeof(struct sensor_async_subdev),
		continue;
		cio2_fwnode_parse);

	if (ret < 0)
err_parse:
		goto out;
		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);