[PATCH v5 4/8] media: synopsys: Use V4L2 1-to-1 subdev helpers
Frank.Li at oss.nxp.com
Frank.Li at oss.nxp.com
Wed Jun 17 12:50:14 PDT 2026
From: Frank Li <Frank.Li at nxp.com>
Use the V4L2 1-to-1 subdev infrastructure to simplify the driver.
Replace the local subdev registration and media pad setup code with
media_async_register_subdev_1to1() and struct v4l2_subdev_1to1. Reduce
boilerplate code and aligns the driver with the common pattern used by
simple subdevices that have a single sink and a single source pad.
Signed-off-by: Frank Li <Frank.Li at nxp.com>
---
change in v5
new patch
previous method:
https://lore.kernel.org/imx/20260226-v4l2_init_register-v2-2-902d7140f9fa@nxp.com/
---
drivers/media/platform/synopsys/Kconfig | 1 +
drivers/media/platform/synopsys/dw-mipi-csi2rx.c | 172 ++++-------------------
2 files changed, 28 insertions(+), 145 deletions(-)
diff --git a/drivers/media/platform/synopsys/Kconfig b/drivers/media/platform/synopsys/Kconfig
index b109de2c8111c..8d7aabf93af34 100644
--- a/drivers/media/platform/synopsys/Kconfig
+++ b/drivers/media/platform/synopsys/Kconfig
@@ -10,6 +10,7 @@ config VIDEO_DW_MIPI_CSI2RX
depends on PM && COMMON_CLK
select GENERIC_PHY_MIPI_DPHY
select MEDIA_CONTROLLER
+ select V4L2_1TO1
select V4L2_FWNODE
select VIDEO_V4L2_SUBDEV_API
help
diff --git a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
index f51367409ff46..b70e3783adcd3 100644
--- a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
+++ b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
@@ -22,6 +22,7 @@
#include <media/mipi-csi2.h>
#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device-1to1.h>
#include <media/v4l2-fwnode.h>
#include <media/v4l2-mc.h>
#include <media/v4l2-subdev.h>
@@ -78,12 +79,6 @@ enum dw_mipi_csi2rx_regs_index {
DW_MIPI_CSI2RX_MAX,
};
-enum {
- DW_MIPI_CSI2RX_PAD_SINK,
- DW_MIPI_CSI2RX_PAD_SRC,
- DW_MIPI_CSI2RX_PAD_MAX,
-};
-
struct dw_mipi_csi2rx_device;
struct dw_mipi_csi2rx_drvdata {
@@ -112,12 +107,8 @@ struct dw_mipi_csi2rx_device {
const struct dw_mipi_csi2rx_format *formats;
unsigned int formats_num;
- struct media_pad pads[DW_MIPI_CSI2RX_PAD_MAX];
- struct v4l2_async_notifier notifier;
- struct v4l2_subdev sd;
+ struct v4l2_subdev_1to1 sd_1to1;
- enum v4l2_mbus_type bus_type;
- u32 lanes_num;
u64 enabled_streams;
const struct dw_mipi_csi2rx_drvdata *drvdata;
@@ -294,7 +285,7 @@ static const struct dw_mipi_csi2rx_format formats[] = {
static inline struct dw_mipi_csi2rx_device *to_csi2(struct v4l2_subdev *sd)
{
- return container_of(sd, struct dw_mipi_csi2rx_device, sd);
+ return container_of(sd, struct dw_mipi_csi2rx_device, sd_1to1.sd);
}
static bool dw_mipi_csi2rx_has_reg(struct dw_mipi_csi2rx_device *csi2,
@@ -360,9 +351,9 @@ dw_mipi_csi2rx_find_format(struct dw_mipi_csi2rx_device *csi2, u32 mbus_code)
static int dw_mipi_csi2rx_start(struct dw_mipi_csi2rx_device *csi2)
{
+ u32 lanes = csi2->sd_1to1.vep.bus.mipi_csi2.num_data_lanes;
struct media_pad *source_pad;
union phy_configure_opts opts;
- u32 lanes = csi2->lanes_num;
u32 control = 0;
s64 link_freq;
int ret;
@@ -371,7 +362,7 @@ static int dw_mipi_csi2rx_start(struct dw_mipi_csi2rx_device *csi2)
return -EINVAL;
source_pad = media_pad_remote_pad_unique(
- &csi2->pads[DW_MIPI_CSI2RX_PAD_SINK]);
+ &csi2->sd_1to1.pads[V4L2_SUBDEV_1TO1_PADS_SINK]);
if (IS_ERR(source_pad))
return PTR_ERR(source_pad);
@@ -380,7 +371,7 @@ static int dw_mipi_csi2rx_start(struct dw_mipi_csi2rx_device *csi2)
if (link_freq < 0)
return link_freq;
- switch (csi2->bus_type) {
+ switch (csi2->sd_1to1.vep.bus_type) {
case V4L2_MBUS_CSI2_DPHY:
ret = phy_mipi_dphy_get_default_config_for_hsclk(link_freq * 2,
lanes, &opts.mipi_dphy);
@@ -458,16 +449,16 @@ dw_mipi_csi2rx_enum_mbus_code(struct v4l2_subdev *sd,
struct dw_mipi_csi2rx_device *csi2 = to_csi2(sd);
switch (code->pad) {
- case DW_MIPI_CSI2RX_PAD_SRC:
+ case V4L2_SUBDEV_1TO1_PADS_SOURCE:
if (code->index)
return -EINVAL;
code->code =
v4l2_subdev_state_get_format(sd_state,
- DW_MIPI_CSI2RX_PAD_SINK)->code;
+ V4L2_SUBDEV_1TO1_PADS_SINK)->code;
return 0;
- case DW_MIPI_CSI2RX_PAD_SINK:
+ case V4L2_SUBDEV_1TO1_PADS_SINK:
if (code->index >= csi2->formats_num)
return -EINVAL;
@@ -487,7 +478,7 @@ static int dw_mipi_csi2rx_set_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *sink, *src;
/* the format on the source pad always matches the sink pad */
- if (format->pad == DW_MIPI_CSI2RX_PAD_SRC)
+ if (format->pad == V4L2_SUBDEV_1TO1_PADS_SOURCE)
return v4l2_subdev_get_fmt(sd, state, format);
sink = v4l2_subdev_state_get_format(state, format->pad, format->stream);
@@ -549,12 +540,12 @@ static int dw_mipi_csi2rx_enable_streams(struct v4l2_subdev *sd,
u64 mask;
int ret;
- sink_pad = &sd->entity.pads[DW_MIPI_CSI2RX_PAD_SINK];
+ sink_pad = &sd->entity.pads[V4L2_SUBDEV_1TO1_PADS_SINK];
remote_pad = media_pad_remote_pad_first(sink_pad);
remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
- mask = v4l2_subdev_state_xlate_streams(state, DW_MIPI_CSI2RX_PAD_SINK,
- DW_MIPI_CSI2RX_PAD_SRC,
+ mask = v4l2_subdev_state_xlate_streams(state, V4L2_SUBDEV_1TO1_PADS_SINK,
+ V4L2_SUBDEV_1TO1_PADS_SOURCE,
&streams_mask);
if (!csi2->enabled_streams) {
@@ -608,12 +599,12 @@ static int dw_mipi_csi2rx_disable_streams(struct v4l2_subdev *sd,
u64 mask;
int ret;
- sink_pad = &sd->entity.pads[DW_MIPI_CSI2RX_PAD_SINK];
+ sink_pad = &sd->entity.pads[V4L2_SUBDEV_1TO1_PADS_SINK];
remote_pad = media_pad_remote_pad_first(sink_pad);
remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
- mask = v4l2_subdev_state_xlate_streams(state, DW_MIPI_CSI2RX_PAD_SINK,
- DW_MIPI_CSI2RX_PAD_SRC,
+ mask = v4l2_subdev_state_xlate_streams(state, V4L2_SUBDEV_1TO1_PADS_SINK,
+ V4L2_SUBDEV_1TO1_PADS_SOURCE,
&streams_mask);
ret = v4l2_subdev_disable_streams(remote_sd, remote_pad->index, mask);
@@ -649,9 +640,9 @@ static int dw_mipi_csi2rx_init_state(struct v4l2_subdev *sd,
{
struct v4l2_subdev_route routes[] = {
{
- .sink_pad = DW_MIPI_CSI2RX_PAD_SINK,
+ .sink_pad = V4L2_SUBDEV_1TO1_PADS_SINK,
.sink_stream = 0,
- .source_pad = DW_MIPI_CSI2RX_PAD_SRC,
+ .source_pad = V4L2_SUBDEV_1TO1_PADS_SOURCE,
.source_stream = 0,
.flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
},
@@ -670,91 +661,11 @@ static const struct v4l2_subdev_internal_ops dw_mipi_csi2rx_internal_ops = {
.init_state = dw_mipi_csi2rx_init_state,
};
-static int dw_mipi_csi2rx_notifier_bound(struct v4l2_async_notifier *notifier,
- struct v4l2_subdev *sd,
- struct v4l2_async_connection *asd)
-{
- struct dw_mipi_csi2rx_device *csi2 =
- container_of(notifier, struct dw_mipi_csi2rx_device, notifier);
- struct media_pad *sink_pad = &csi2->pads[DW_MIPI_CSI2RX_PAD_SINK];
- int ret;
-
- ret = v4l2_create_fwnode_links_to_pad(sd, sink_pad,
- MEDIA_LNK_FL_ENABLED);
- if (ret) {
- dev_err(csi2->dev, "failed to link source pad of %s\n",
- sd->name);
- return ret;
- }
-
- return 0;
-}
-
-static const struct v4l2_async_notifier_operations dw_mipi_csi2rx_notifier_ops = {
- .bound = dw_mipi_csi2rx_notifier_bound,
-};
-
-static int dw_mipi_csi2rx_register_notifier(struct dw_mipi_csi2rx_device *csi2)
-{
- struct v4l2_async_connection *asd;
- struct v4l2_async_notifier *ntf = &csi2->notifier;
- struct v4l2_fwnode_endpoint vep;
- struct v4l2_subdev *sd = &csi2->sd;
- struct device *dev = csi2->dev;
- int ret;
-
- struct fwnode_handle *ep __free(fwnode_handle) =
- fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, 0);
- if (!ep)
- return dev_err_probe(dev, -ENODEV, "failed to get endpoint\n");
-
- vep.bus_type = V4L2_MBUS_UNKNOWN;
- ret = v4l2_fwnode_endpoint_parse(ep, &vep);
- if (ret)
- return dev_err_probe(dev, ret, "failed to parse endpoint\n");
-
- if (vep.bus_type != V4L2_MBUS_CSI2_DPHY &&
- vep.bus_type != V4L2_MBUS_CSI2_CPHY)
- return dev_err_probe(dev, -EINVAL,
- "invalid bus type of endpoint\n");
-
- csi2->bus_type = vep.bus_type;
- csi2->lanes_num = vep.bus.mipi_csi2.num_data_lanes;
-
- v4l2_async_subdev_nf_init(ntf, sd);
- ntf->ops = &dw_mipi_csi2rx_notifier_ops;
-
- asd = v4l2_async_nf_add_fwnode_remote(ntf, ep,
- struct v4l2_async_connection);
- if (IS_ERR(asd)) {
- ret = PTR_ERR(asd);
- goto err_nf_cleanup;
- }
-
- ret = v4l2_async_nf_register(ntf);
- if (ret) {
- ret = dev_err_probe(dev, ret, "failed to register notifier\n");
- goto err_nf_cleanup;
- }
-
- return 0;
-
-err_nf_cleanup:
- v4l2_async_nf_cleanup(ntf);
-
- return ret;
-}
-
static int dw_mipi_csi2rx_register(struct dw_mipi_csi2rx_device *csi2)
{
- struct media_pad *pads = csi2->pads;
- struct v4l2_subdev *sd = &csi2->sd;
+ struct v4l2_subdev *sd = &csi2->sd_1to1.sd;
int ret;
- ret = dw_mipi_csi2rx_register_notifier(csi2);
- if (ret)
- goto err;
-
v4l2_subdev_init(sd, &dw_mipi_csi2rx_ops);
sd->dev = csi2->dev;
sd->entity.ops = &dw_mipi_csi2rx_media_ops;
@@ -764,45 +675,15 @@ static int dw_mipi_csi2rx_register(struct dw_mipi_csi2rx_device *csi2)
snprintf(sd->name, sizeof(sd->name), "dw-mipi-csi2rx %s",
dev_name(csi2->dev));
- pads[DW_MIPI_CSI2RX_PAD_SINK].flags = MEDIA_PAD_FL_SINK |
- MEDIA_PAD_FL_MUST_CONNECT;
- pads[DW_MIPI_CSI2RX_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE;
- ret = media_entity_pads_init(&sd->entity, DW_MIPI_CSI2RX_PAD_MAX, pads);
- if (ret)
- goto err_notifier_unregister;
+ csi2->sd_1to1.remote_bustype_cap_mask = BIT(V4L2_MBUS_CSI2_DPHY) |
+ BIT(V4L2_MBUS_CSI2_CPHY);
- ret = v4l2_subdev_init_finalize(sd);
+ ret = media_async_register_subdev_1to1(&csi2->sd_1to1);
if (ret)
- goto err_entity_cleanup;
-
- ret = v4l2_async_register_subdev(sd);
- if (ret) {
- dev_err(sd->dev, "failed to register CSI-2 subdev\n");
- goto err_subdev_cleanup;
- }
+ return dev_err_probe(sd->dev, ret,
+ "failed to register CSI-2 subdev\n");
return 0;
-
-err_subdev_cleanup:
- v4l2_subdev_cleanup(sd);
-err_entity_cleanup:
- media_entity_cleanup(&sd->entity);
-err_notifier_unregister:
- v4l2_async_nf_unregister(&csi2->notifier);
- v4l2_async_nf_cleanup(&csi2->notifier);
-err:
- return ret;
-}
-
-static void dw_mipi_csi2rx_unregister(struct dw_mipi_csi2rx_device *csi2)
-{
- struct v4l2_subdev *sd = &csi2->sd;
-
- v4l2_async_unregister_subdev(sd);
- v4l2_subdev_cleanup(sd);
- media_entity_cleanup(&sd->entity);
- v4l2_async_nf_unregister(&csi2->notifier);
- v4l2_async_nf_cleanup(&csi2->notifier);
}
static void imx93_csi2rx_dphy_assert_reset(struct dw_mipi_csi2rx_device *csi2)
@@ -879,12 +760,13 @@ static void imx93_csi2rx_dphy_ipi_enable(struct dw_mipi_csi2rx_device *csi2)
static int imx93_csi2rx_wait_for_phy_stopstate(struct dw_mipi_csi2rx_device *csi2)
{
+ u32 num_lanes = csi2->sd_1to1.vep.bus.mipi_csi2.num_data_lanes;
struct device *dev = csi2->dev;
u32 stopstate_mask;
u32 val;
int ret;
- stopstate_mask = DPHY_STOPSTATE_CLK_LANE | GENMASK(csi2->lanes_num - 1, 0);
+ stopstate_mask = DPHY_STOPSTATE_CLK_LANE | GENMASK(num_lanes - 1, 0);
ret = read_poll_timeout(dw_mipi_csi2rx_read, val,
(val & stopstate_mask) == stopstate_mask,
@@ -993,7 +875,7 @@ static void dw_mipi_csi2rx_remove(struct platform_device *pdev)
{
struct dw_mipi_csi2rx_device *csi2 = platform_get_drvdata(pdev);
- dw_mipi_csi2rx_unregister(csi2);
+ media_async_subdev_1to1_cleanup(&csi2->sd_1to1);
phy_exit(csi2->phy);
}
--
2.43.0
More information about the linux-arm-kernel
mailing list