@@ -533,8 +533,8 @@ static int cal_camerarx_regmap_init(struct cal_dev *cal,
static int cal_camerarx_parse_dt(struct cal_camerarx *phy)
{
struct v4l2_fwnode_endpoint *endpoint = &phy->endpoint;
- struct device_node *ep_node;
char data_lanes[V4L2_FWNODE_CSI2_MAX_DATA_LANES * 2];
+ struct device_node *ep_node;
unsigned int i;
int ret;
@@ -582,9 +582,11 @@ static int cal_camerarx_parse_dt(struct cal_camerarx *phy)
endpoint->bus.mipi_csi2.flags);
/* Retrieve the connected device and store it for later use. */
- phy->sensor_node = of_graph_get_remote_port_parent(ep_node);
+ phy->sensor_ep_node = of_graph_get_remote_endpoint(ep_node);
+ phy->sensor_node = of_graph_get_port_parent(phy->sensor_ep_node);
if (!phy->sensor_node) {
phy_dbg(3, phy, "Can't get remote parent\n");
+ of_node_put(phy->sensor_ep_node);
ret = -EINVAL;
goto done;
}
@@ -596,11 +598,25 @@ static int cal_camerarx_parse_dt(struct cal_camerarx *phy)
return ret;
}
+/* ------------------------------------------------------------------
+ * V4L2 Subdev Operations
+ * ------------------------------------------------------------------
+ */
+
+static const struct v4l2_subdev_ops cal_camerarx_subdev_ops = {
+};
+
+/* ------------------------------------------------------------------
+ * Create and Destroy
+ * ------------------------------------------------------------------
+ */
+
struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal,
unsigned int instance)
{
struct platform_device *pdev = to_platform_device(cal->dev);
struct cal_camerarx *phy;
+ struct v4l2_subdev *sd;
int ret;
phy = kzalloc(sizeof(*phy), GFP_KERNEL);
@@ -632,9 +648,28 @@ struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal,
if (ret)
goto error;
+ /* Initialize the V4L2 subdev and media entity. */
+ sd = &phy->subdev;
+ v4l2_subdev_init(sd, &cal_camerarx_subdev_ops);
+ sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
+ snprintf(sd->name, sizeof(sd->name), "CAMERARX%u", instance);
+ sd->dev = cal->dev;
+
+ phy->pads[CAL_CAMERARX_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ phy->pads[CAL_CAMERARX_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_pads_init(&sd->entity, ARRAY_SIZE(phy->pads),
+ phy->pads);
+ if (ret)
+ goto error;
+
+ ret = v4l2_device_register_subdev(&cal->v4l2_dev, sd);
+ if (ret)
+ goto error;
+
return phy;
error:
+ media_entity_cleanup(&phy->subdev.entity);
kfree(phy);
return ERR_PTR(ret);
}
@@ -644,6 +679,9 @@ void cal_camerarx_destroy(struct cal_camerarx *phy)
if (!phy)
return;
+ v4l2_device_unregister_subdev(&phy->subdev);
+ media_entity_cleanup(&phy->subdev.entity);
+ of_node_put(phy->sensor_ep_node);
of_node_put(phy->sensor_node);
kfree(phy);
}
@@ -809,6 +809,18 @@ int cal_ctx_v4l2_register(struct cal_ctx *ctx)
return ret;
}
+ ret = media_create_pad_link(&ctx->phy->subdev.entity,
+ CAL_CAMERARX_PAD_SOURCE,
+ &vfd->entity, 0,
+ MEDIA_LNK_FL_IMMUTABLE |
+ MEDIA_LNK_FL_ENABLED);
+ if (ret) {
+ ctx_err(ctx, "Failed to create media link for context %u\n",
+ ctx->index);
+ video_unregister_device(vfd);
+ return ret;
+ }
+
ctx_info(ctx, "V4L2 device registered as %s\n",
video_device_node_name(vfd));
@@ -421,6 +421,8 @@ static int cal_async_notifier_bound(struct v4l2_async_notifier *notifier,
struct v4l2_async_subdev *asd)
{
struct cal_camerarx *phy = to_cal_asd(asd)->phy;
+ int pad;
+ int ret;
if (phy->sensor) {
phy_info(phy, "Rejecting subdev %s (Already set!!)",
@@ -431,6 +433,25 @@ static int cal_async_notifier_bound(struct v4l2_async_notifier *notifier,
phy->sensor = subdev;
phy_dbg(1, phy, "Using sensor %s for capture\n", subdev->name);
+ pad = media_entity_get_fwnode_pad(&subdev->entity,
+ of_fwnode_handle(phy->sensor_ep_node),
+ MEDIA_PAD_FL_SOURCE);
+ if (pad < 0) {
+ phy_err(phy, "Sensor %s has no connected source pad\n",
+ subdev->name);
+ return pad;
+ }
+
+ ret = media_create_pad_link(&subdev->entity, pad,
+ &phy->subdev.entity, CAL_CAMERARX_PAD_SINK,
+ MEDIA_LNK_FL_IMMUTABLE |
+ MEDIA_LNK_FL_ENABLED);
+ if (ret) {
+ phy_err(phy, "Failed to create media link for sensor %s\n",
+ subdev->name);
+ return ret;
+ }
+
return 0;
}
@@ -797,6 +818,11 @@ static int cal_probe(struct platform_device *pdev)
cal_get_hwinfo(cal);
pm_runtime_put_sync(&pdev->dev);
+ /* Initialize the media device. */
+ ret = cal_media_init(cal);
+ if (ret < 0)
+ goto error_pm_runtime;
+
/* Create CAMERARX PHYs. */
for (i = 0; i < cal->data->num_csi2_phy; ++i) {
cal->phy[i] = cal_camerarx_create(cal, i);
@@ -816,11 +842,6 @@ static int cal_probe(struct platform_device *pdev)
goto error_camerarx;
}
- /* Initialize the media device. */
- ret = cal_media_init(cal);
- if (ret < 0)
- goto error_camerarx;
-
/* Create contexts. */
for (i = 0; i < cal->data->num_csi2_phy; ++i) {
if (!cal->phy[i]->sensor_node)
@@ -848,12 +869,12 @@ static int cal_probe(struct platform_device *pdev)
cal_ctx_v4l2_cleanup(ctx);
}
- cal_media_cleanup(cal);
-
error_camerarx:
for (i = 0; i < ARRAY_SIZE(cal->phy); i++)
cal_camerarx_destroy(cal->phy[i]);
+ cal_media_cleanup(cal);
+
error_pm_runtime:
pm_runtime_disable(&pdev->dev);
@@ -24,6 +24,7 @@
#include <media/v4l2-dev.h>
#include <media/v4l2-device.h>
#include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
#include <media/videobuf2-v4l2.h>
#define CAL_MODULE_NAME "cal"
@@ -33,12 +34,14 @@
#define MAX_WIDTH_BYTES (8192 * 8)
#define MAX_HEIGHT_LINES 16383
+#define CAL_CAMERARX_PAD_SINK 0
+#define CAL_CAMERARX_PAD_SOURCE 1
+
struct device;
struct device_node;
struct resource;
struct regmap;
struct regmap_fied;
-struct v4l2_subdev;
/* CTRL_CORE_CAMERRX_CONTROL register field id */
enum cal_camerarx_field {
@@ -108,8 +111,12 @@ struct cal_camerarx {
unsigned int instance;
struct v4l2_fwnode_endpoint endpoint;
+ struct device_node *sensor_ep_node;
struct device_node *sensor_node;
struct v4l2_subdev *sensor;
+
+ struct v4l2_subdev subdev;
+ struct media_pad pads[2];
};
struct cal_dev {