From: Felipe Calliari <calliarifelipe@gmail.com>
To: linux-media@vger.kernel.org
Cc: Sakari Ailus <sakari.ailus@linux.intel.com>,
Hans de Goede <hansg@kernel.org>,
Bryan O'Donoghue <bod@kernel.org>,
Mauro Carvalho Chehab <mchehab@kernel.org>,
linux-kernel@vger.kernel.org,
Felipe Calliari <calliarifelipe@gmail.com>
Subject: [PATCH 3/3] media: ov02c10: Accept a 26 MHz external clock
Date: Sat, 5 Sep 2026 00:07:32 -0300 [thread overview]
Message-ID: <20260905030732.39196-3-calliarifelipe@gmail.com> (raw)
In-Reply-To: <20260905030732.39196-1-calliarifelipe@gmail.com>
Several Meteor Lake / Lunar Lake designs (e.g. the Samsung Galaxy Book3/4
series) wire the OV02C10 to a 26 MHz external clock instead of the
19.2 MHz assumed so far. The IPU6 ipu-bridge forwards the rate from the
ACPI SSDB verbatim as the "clock-frequency" property, so probe() just
rejects it today:
ov02c10 i2c-OVTI02C1:00: external clock 26000000 is not supported
Rename OV02C10_MCLK to OV02C10_MCLK_19_2MHZ, add OV02C10_MCLK_26MHZ and
accept both.
The PLL register tables are the 19.2 MHz ones; OmniVision's 26 MHz PLL
programming is not publicly available. With a 26 MHz input the same
dividers make every internal clock, and therefore the MIPI link, run
26/19.2 = 1.3542x faster: a ~541.7 MHz link and ~40 fps instead of the
nominal 400 MHz / 30 fps. Rather than leave link-frequency and
pixel-rate describing the 19.2 MHz case, add a second
V4L2_CID_LINK_FREQ menu entry (400 MHz * 26 / 19.2) and select it when
the external clock is 26 MHz. pixel-rate is derived from the link
frequency and scales with it, so the frame rate and exposure times
reported to userspace match the hardware, and the IPU6 CSI-2 receiver
programs its D-PHY high-speed frequency range and bandwidth budget for
the rate the sensor actually transmits.
The ipu-bridge fwnode only lists the nominal 400 MHz link frequency
(keyed by ACPI HID, not by clock rate), so v4l2_link_freq_to_bitmap()
still matches on the 400 MHz entry and the 541.7 MHz index is selected
explicitly for the 26 MHz case.
On a Meteor Lake test machine a single CSI-2 "frame sync error" may
still be logged by the IPU6 receiver at stream start, after which
capture runs cleanly; this looks like a sensor PLL settling transient
and is not addressed here.
While touching the clock check, terminate its error string with a
newline.
Signed-off-by: Felipe Calliari <calliarifelipe@gmail.com>
---
drivers/media/i2c/ov02c10.c | 45 ++++++++++++++++++++++++++++++++-----
1 file changed, 40 insertions(+), 5 deletions(-)
diff --git a/drivers/media/i2c/ov02c10.c b/drivers/media/i2c/ov02c10.c
index 114db38c0..5184eb1cc 100644
--- a/drivers/media/i2c/ov02c10.c
+++ b/drivers/media/i2c/ov02c10.c
@@ -16,7 +16,16 @@
#include <media/v4l2-fwnode.h>
#define OV02C10_LINK_FREQ_400MHZ 400000000ULL
-#define OV02C10_MCLK 19200000
+/*
+ * The PLL register tables target a 19.2 MHz input clock. On boards that
+ * clock the sensor at 26 MHz the same dividers yield a 26/19.2 = 1.3542x
+ * faster MIPI link (and frame rate). OmniVision's 26 MHz PLL values are
+ * not public, so rather than re-normalise the link the driver advertises
+ * the real, scaled link frequency: 400 MHz * 26 / 19.2 = 541.667 MHz.
+ */
+#define OV02C10_LINK_FREQ_541MHZ 541666667ULL
+#define OV02C10_MCLK_19_2MHZ 19200000
+#define OV02C10_MCLK_26MHZ 26000000
#define OV02C10_RGB_DEPTH 10
#define OV02C10_NATIVE_WIDTH 1928
@@ -345,8 +354,14 @@ static const char * const ov02c10_test_pattern_menu[] = {
"Color Bar type 4",
};
+enum {
+ OV02C10_LINK_FREQ_400MHZ_IDX, /* 19.2 MHz external clock */
+ OV02C10_LINK_FREQ_541MHZ_IDX, /* 26 MHz external clock */
+};
+
static const s64 link_freq_menu_items[] = {
- OV02C10_LINK_FREQ_400MHZ,
+ [OV02C10_LINK_FREQ_400MHZ_IDX] = OV02C10_LINK_FREQ_400MHZ,
+ [OV02C10_LINK_FREQ_541MHZ_IDX] = OV02C10_LINK_FREQ_541MHZ,
};
static const struct ov02c10_mode supported_modes[] = {
@@ -396,6 +411,9 @@ struct ov02c10 {
/* MIPI lane info */
u32 link_freq_index;
u8 mipi_lanes;
+
+ /* External (sensor) clock rate, Hz */
+ u32 xvclk_freq;
};
static inline struct ov02c10 *to_ov02c10(struct v4l2_subdev *subdev)
@@ -507,7 +525,8 @@ static int ov02c10_init_controls(struct ov02c10 *ov02c10)
ov02c10->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr,
&ov02c10_ctrl_ops,
V4L2_CID_LINK_FREQ,
- ov02c10->link_freq_index, 0,
+ ov02c10->link_freq_index,
+ ov02c10->link_freq_index,
link_freq_menu_items);
if (ov02c10->link_freq)
ov02c10->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
@@ -875,6 +894,21 @@ static int ov02c10_check_hwcfg(struct ov02c10 *ov02c10)
/* v4l2_link_freq_to_bitmap() guarantees at least 1 bit is set */
ov02c10->link_freq_index = ffs(link_freq_bitmap) - 1;
+ /*
+ * The IPU6 ipu-bridge always describes the nominal 19.2 MHz link
+ * (400 MHz) in the fwnode, keyed by ACPI HID, even on boards that
+ * clock the sensor at 26 MHz. There the real link frequency is
+ * 26/19.2 higher; advertise it so the CSI-2 receiver programs its
+ * D-PHY frequency band and bandwidth budget for the rate the sensor
+ * actually transmits.
+ */
+ if (ov02c10->xvclk_freq == OV02C10_MCLK_26MHZ)
+ ov02c10->link_freq_index = OV02C10_LINK_FREQ_541MHZ_IDX;
+
+ dev_dbg(dev, "%u Hz external clock, link freq %lld Hz\n",
+ ov02c10->xvclk_freq,
+ link_freq_menu_items[ov02c10->link_freq_index]);
+
if (bus_cfg.bus.mipi_csi2.num_data_lanes != 1 &&
bus_cfg.bus.mipi_csi2.num_data_lanes != 2) {
ret = dev_err_probe(dev, -EINVAL,
@@ -924,10 +958,11 @@ static int ov02c10_probe(struct i2c_client *client)
"failed to get imaging clock\n");
freq = clk_get_rate(ov02c10->img_clk);
- if (freq != OV02C10_MCLK)
+ if (freq != OV02C10_MCLK_19_2MHZ && freq != OV02C10_MCLK_26MHZ)
return dev_err_probe(ov02c10->dev, -EINVAL,
- "external clock %lu is not supported",
+ "external clock %lu is not supported\n",
freq);
+ ov02c10->xvclk_freq = freq;
v4l2_i2c_subdev_init(&ov02c10->sd, client, &ov02c10_subdev_ops);
--
2.55.0
next prev parent reply other threads:[~2026-09-05 3:08 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <Tms-fUHfw0sPf1-YX_rgSNq7z1MNyvtfCImHXhxAUQAoTq-fwKvZF-p8a3ozCxAJ7kJCo-lKEU_JSkfUJy6oIA==@protonmail.internalid>
2026-09-05 3:07 ` [PATCH 1/3] media: ov02c10: Drop duplicate register write Felipe Calliari
2026-09-05 3:07 ` [PATCH 2/3] media: ov02c10: Implement get_selection Felipe Calliari
2026-09-08 9:07 ` Bryan O'Donoghue
2026-09-05 3:07 ` Felipe Calliari [this message]
2026-09-08 8:06 ` [PATCH 3/3] media: ov02c10: Accept a 26 MHz external clock Sakari Ailus
2026-09-09 2:55 ` Felipe Calliari
2026-09-08 9:21 ` Bryan O'Donoghue
2026-09-08 9:04 ` [PATCH 1/3] media: ov02c10: Drop duplicate register write Bryan O'Donoghue
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260905030732.39196-3-calliarifelipe@gmail.com \
--to=calliarifelipe@gmail.com \
--cc=bod@kernel.org \
--cc=hansg@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-media@vger.kernel.org \
--cc=mchehab@kernel.org \
--cc=sakari.ailus@linux.intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.