[PATCH v12 29/86] media: v4l2-mc: Add v4l2_subdev_sensor_fll_llp_set()

Sakari Ailus
2026-04-09T20:15:31Z

Add v4l2_subdev_sensor_fll_llp_set() to facilitate driver implementation
of both blanking and line and frame lenght controls.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
drivers/media/v4l2-core/v4l2-mc.c | 67 +++++++++++++++++++++++++++++++
include/media/v4l2-mc.h | 8 ++++
2 files changed, 75 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-mc.c b/drivers/media/v4l2-core/v4l2-mc.c
index 937d358697e1..2e0be23d7511 100644
--- a/drivers/media/v4l2-core/v4l2-mc.c
+++ b/drivers/media/v4l2-core/v4l2-mc.c
@@ -14,6 +14,7 @@
#include <linux/usb.h>
#include <media/media-device.h>
#include <media/media-entity.h>
+#include <media/v4l2-ctrls.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-mc.h>
#include <media/v4l2-subdev.h>
@@ -427,6 +428,72 @@ int v4l2_create_fwnode_links(struct v4l2_subdev *src_sd,
}
EXPORT_SYMBOL_GPL(v4l2_create_fwnode_links);

+int v4l2_subdev_sensor_fll_llp_set(struct v4l2_ctrl *fll, struct v4l2_ctrl *vblank,
+ struct v4l2_ctrl *llp, struct v4l2_ctrl *hblank,
+ struct v4l2_ctrl *exposure,
+ const struct v4l2_mbus_framefmt *format,
+ struct v4l2_ctrl *src, bool *setting_ctrl,
+ int exposure_margin)
+{
+ struct v4l2_ctrl *dest;
+ s32 val;
+ int ret;
+
+ /* Was setting the control user-initiated or were we called again? */
+ if (*setting_ctrl) {
+ *setting_ctrl = false;
+ return 0;
+ }
+
+ /* Are we being called for writing a value to a register? */
+ if (src->val == src->cur.val)
+ return 0;
+
+ switch (src->id) {
+ case V4L2_CID_FRAME_LENGTH_LINES:
+ dest = vblank;
+ val = src->val - format->height;
+ break;
+ case V4L2_CID_VBLANK:
+ dest = fll;
+ val = src->val + format->height;
+ break;
+ case V4L2_CID_LINE_LENGTH_PIXELS:
+ dest = hblank;
+ val = src->val - format->width;
+ break;
+ case V4L2_CID_HBLANK:
+ dest = llp;
+ val = src->val + format->width;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (val == dest->val)
+ return 0;
+
+ *setting_ctrl = true;
+
+ ret = __v4l2_ctrl_s_ctrl(dest, val);
+ if (ret)
+ return ret;
+
+ /*
+ * Only modify exposure range when setting fll, directly or via vblank.
+ */
+ if (src->id != V4L2_CID_FRAME_LENGTH_LINES &&
+ dest->id != V4L2_CID_FRAME_LENGTH_LINES)
+ return 0;
+
+ int exposure_max = fll->val - exposure_margin;
+
+ return __v4l2_ctrl_modify_range(exposure, exposure->minimum,
+ exposure_max, exposure->step,
+ exposure_max);
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_sensor_fll_llp_set);
+
/* -----------------------------------------------------------------------------
* Pipeline power management
*
diff --git a/include/media/v4l2-mc.h b/include/media/v4l2-mc.h
index 1837c9fd78cf..8618a74e4e0c 100644
--- a/include/media/v4l2-mc.h
+++ b/include/media/v4l2-mc.h
@@ -18,6 +18,7 @@
/* We don't need to include pci.h or usb.h here */
struct pci_dev;
struct usb_device;
+struct v4l2_ctrl;

#ifdef CONFIG_MEDIA_CONTROLLER
/**
@@ -139,6 +140,13 @@ int v4l2_create_fwnode_links_to_pad(struct v4l2_subdev *src_sd,
int v4l2_create_fwnode_links(struct v4l2_subdev *src_sd,
struct v4l2_subdev *sink_sd);

+int v4l2_subdev_sensor_fll_llp_set(struct v4l2_ctrl *fll, struct v4l2_ctrl *vblank,
+ struct v4l2_ctrl *llp, struct v4l2_ctrl *hblank,
+ struct v4l2_ctrl *exposure,
+ const struct v4l2_mbus_framefmt *format,
+ struct v4l2_ctrl *src, bool *setting_ctrl,
+ int exposure_margin);
+
/**
* v4l2_pipeline_pm_get - Increase the use count of a pipeline
* @entity: The root entity of a pipeline
--
2.47.3