* [PATCH v3 0/3] media: i2c: Add OmniVision OG0VA1B camera sensor driver
@ 2026-07-08 14:33 Wenmeng Liu
2026-07-08 14:33 ` [PATCH v3 1/3] dt-bindings: media: i2c: og0ve1b: Add OmniVision OG0VA1B camera sensor Wenmeng Liu
` (3 more replies)
0 siblings, 4 replies; 12+ messages in thread
From: Wenmeng Liu @ 2026-07-08 14:33 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Sakari Ailus, Vladimir Zapolskiy
Cc: linux-media, devicetree, linux-kernel, Wenmeng Liu, Conor Dooley
Add OmniVision OG0VA1B driver support. The OmniVision OG0VA1B is a
1/10-inch monochrome CMOS VGA image sensor. It outputs 10-bit raw (Y10)
frames at up to 640x480 resolution over a single-lane MIPI CSI-2
interface and is controlled via an I2C-compatible SCCB bus.
This driver has been verified(include tpg) on the Purwa EVK.
Signed-off-by: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com>
---
Changes in v3:
- Generalise the binding title and description for both sensors. -- Vladimir
- Keep the cached pre_isp read so the OG0VE1B test pattern still works,
select it via a per-sensor callback. -- Bryan, Vladimir
- Rename the "sensor" field to "data", drop bpp (derive from code) and
add og0ve1b_pixel_rate(). -- Vladimir
- Sort defines, rename the shared CHIP_ID reg to OG0V_ and order
og0va1b_data first. -- Vladimir
- Expose all four OG0VA1B test patterns instead of one.
- Link to v2: https://lore.kernel.org/r/20260702-og0va1b-v2-0-0071442caa2a@oss.qualcomm.com
Changes in v2:
- Integrate OG0VA1B into the existing og0ve1b driver and binding
instead. -- Vladimir
- Link to v1: https://lore.kernel.org/r/20260618-og0va1b-v1-0-dda71bb83009@oss.qualcomm.com
---
Wenmeng Liu (3):
dt-bindings: media: i2c: og0ve1b: Add OmniVision OG0VA1B camera sensor
media: i2c: og0ve1b: Introduce per-sensor data structure
media: i2c: og0ve1b: Add support for OmniVision OG0VA1B
.../bindings/media/i2c/ovti,og0ve1b.yaml | 15 +-
drivers/media/i2c/og0ve1b.c | 375 ++++++++++++++++++---
2 files changed, 344 insertions(+), 46 deletions(-)
---
base-commit: 5c73cd9f0819c1c44e373e3dabb68318b1de1a12
change-id: 20260618-og0va1b-55bbf3cabb0e
Best regards,
--
Wenmeng Liu <wenmeng.liu@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH v3 1/3] dt-bindings: media: i2c: og0ve1b: Add OmniVision OG0VA1B camera sensor 2026-07-08 14:33 [PATCH v3 0/3] media: i2c: Add OmniVision OG0VA1B camera sensor driver Wenmeng Liu @ 2026-07-08 14:33 ` Wenmeng Liu 2026-07-08 14:33 ` [PATCH v3 2/3] media: i2c: og0ve1b: Introduce per-sensor data structure Wenmeng Liu ` (2 subsequent siblings) 3 siblings, 0 replies; 12+ messages in thread From: Wenmeng Liu @ 2026-07-08 14:33 UTC (permalink / raw) To: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sakari Ailus, Vladimir Zapolskiy Cc: linux-media, devicetree, linux-kernel, Wenmeng Liu, Conor Dooley The OmniVision OG0VA1B is a monochrome image sensor closely related to the already supported OG0VE1B. It shares the same SCCB control interface, power supplies and MIPI D-PHY description, but differs in its chip ID, register programming and output format. Generalise the binding title and description to cover both sensors. Acked-by: Conor Dooley <conor.dooley@microchip.com> Reviewed-by: Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org> Signed-off-by: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com> --- .../devicetree/bindings/media/i2c/ovti,og0ve1b.yaml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,og0ve1b.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,og0ve1b.yaml index bd2f1ae23e6547032361924a6953000bab1129df..b6fa9645c7c6cb3fa907478684d02b01d916fea1 100644 --- a/Documentation/devicetree/bindings/media/i2c/ovti,og0ve1b.yaml +++ b/Documentation/devicetree/bindings/media/i2c/ovti,og0ve1b.yaml @@ -4,14 +4,13 @@ $id: http://devicetree.org/schemas/media/i2c/ovti,og0ve1b.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: OmniVision OG0VE1B Image Sensor +title: OmniVision OG0VA1B and OG0VE1B Image Sensors description: - OmniVision OG0VE1B image sensor is a low power consuming monochrome - image sensor. The sensor is controlled over a serial camera control - bus protocol (SCCB), the widest supported image size is 640x480 at - 120 frames per second rate, data output format is 8/10-bit RAW - transferred over one-lane MIPI D-PHY at up to 800 Mbps. + OmniVision OG0VA1B and OG0VE1B are low power consuming monochrome image + sensors. The sensors are controlled over a serial camera control bus + protocol (SCCB), the widest supported image size is 640x480, data output + format is 8/10-bit RAW transferred over one-lane MIPI D-PHY. maintainers: - Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org> @@ -21,7 +20,9 @@ allOf: properties: compatible: - const: ovti,og0ve1b + enum: + - ovti,og0va1b + - ovti,og0ve1b reg: maxItems: 1 -- 2.34.1 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v3 2/3] media: i2c: og0ve1b: Introduce per-sensor data structure 2026-07-08 14:33 [PATCH v3 0/3] media: i2c: Add OmniVision OG0VA1B camera sensor driver Wenmeng Liu 2026-07-08 14:33 ` [PATCH v3 1/3] dt-bindings: media: i2c: og0ve1b: Add OmniVision OG0VA1B camera sensor Wenmeng Liu @ 2026-07-08 14:33 ` Wenmeng Liu 2026-07-08 14:45 ` sashiko-bot 2026-07-23 13:48 ` Vladimir Zapolskiy 2026-07-08 14:33 ` [PATCH v3 3/3] media: i2c: og0ve1b: Add support for OmniVision OG0VA1B Wenmeng Liu 2026-07-23 2:41 ` [PATCH v3 0/3] media: i2c: Add OmniVision OG0VA1B camera sensor driver Wenmeng Liu 3 siblings, 2 replies; 12+ messages in thread From: Wenmeng Liu @ 2026-07-08 14:33 UTC (permalink / raw) To: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sakari Ailus, Vladimir Zapolskiy Cc: linux-media, devicetree, linux-kernel, Wenmeng Liu Refactor the driver to separate sensor-specific data from the common driver code. Introduce a sensor_data structure, populated through i2c_get_match_data(), to hold the chip ID, MCLK frequency, link frequencies and supported modes. Test pattern programming is described by a per-sensor callback, and each mode stores its media bus format code (rather than a bits-per-pixel value) so that sensors with a different output format can be supported. Signed-off-by: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com> --- drivers/media/i2c/og0ve1b.c | 99 ++++++++++++++++++++++++++++++++------------- 1 file changed, 71 insertions(+), 28 deletions(-) diff --git a/drivers/media/i2c/og0ve1b.c b/drivers/media/i2c/og0ve1b.c index 84a28cdcade10f8fbcf945999e88f84641b9bc0d..041342fbe3c822400388f58a03e6057e186f060f 100644 --- a/drivers/media/i2c/og0ve1b.c +++ b/drivers/media/i2c/og0ve1b.c @@ -65,11 +65,23 @@ struct og0ve1b_mode { u32 height; /* Frame height in pixels */ u32 hts; /* Horizontal timing size */ u32 vts; /* Default vertical timing size */ - u32 bpp; /* Bits per pixel */ + u32 code; /* MEDIA_BUS_FMT code */ const struct og0ve1b_reg_list reg_list; /* Sensor register setting */ }; +struct og0ve1b; + +struct og0ve1b_sensor_data { + u64 chip_id; + unsigned long mclk_freq; + int (*enable_test_pattern)(struct og0ve1b *og0ve1b, u32 pattern); + const s64 *link_freq_menu; + int num_link_freqs; + const struct og0ve1b_mode *modes; + int num_modes; +}; + static const char * const og0ve1b_test_pattern_menu[] = { "Disabled", "Vertical Colour Bars", @@ -99,6 +111,8 @@ struct og0ve1b { /* Saved register value */ u64 pre_isp; + + const struct og0ve1b_sensor_data *data; }; static const struct cci_reg_sequence og0ve1b_640x480_120fps_mode[] = { @@ -247,13 +261,13 @@ static const struct cci_reg_sequence og0ve1b_640x480_120fps_mode[] = { { CCI_REG8(0x3f47), 0x35 }, }; -static const struct og0ve1b_mode supported_modes[] = { +static const struct og0ve1b_mode og0ve1b_supported_modes[] = { { .width = 640, .height = 480, .hts = 792, .vts = 568, - .bpp = 8, + .code = MEDIA_BUS_FMT_Y8_1X8, .reg_list = { .regs = og0ve1b_640x480_120fps_mode, .num_regs = ARRAY_SIZE(og0ve1b_640x480_120fps_mode), @@ -273,11 +287,21 @@ static int og0ve1b_enable_test_pattern(struct og0ve1b *og0ve1b, u32 pattern) return cci_write(og0ve1b->regmap, OG0VE1B_REG_PRE_ISP, val, NULL); } +static const struct og0ve1b_sensor_data og0ve1b_data = { + .chip_id = OG0VE1B_CHIP_ID, + .mclk_freq = OG0VE1B_MCLK_FREQ_24MHZ, + .enable_test_pattern = og0ve1b_enable_test_pattern, + .link_freq_menu = og0ve1b_link_freq_menu, + .num_link_freqs = ARRAY_SIZE(og0ve1b_link_freq_menu), + .modes = og0ve1b_supported_modes, + .num_modes = ARRAY_SIZE(og0ve1b_supported_modes), +}; + static int og0ve1b_set_ctrl(struct v4l2_ctrl *ctrl) { struct og0ve1b *og0ve1b = container_of(ctrl->handler, struct og0ve1b, ctrl_handler); - const struct og0ve1b_mode *mode = &supported_modes[0]; + const struct og0ve1b_mode *mode = &og0ve1b->data->modes[0]; s64 exposure_max; int ret; @@ -314,7 +338,7 @@ static int og0ve1b_set_ctrl(struct v4l2_ctrl *ctrl) ctrl->val + mode->height, NULL); break; case V4L2_CID_TEST_PATTERN: - ret = og0ve1b_enable_test_pattern(og0ve1b, ctrl->val); + ret = og0ve1b->data->enable_test_pattern(og0ve1b, ctrl->val); break; default: ret = -EINVAL; @@ -330,10 +354,19 @@ static const struct v4l2_ctrl_ops og0ve1b_ctrl_ops = { .s_ctrl = og0ve1b_set_ctrl, }; +static s64 og0ve1b_pixel_rate(const struct og0ve1b_sensor_data *data) +{ + const struct og0ve1b_mode *mode = &data->modes[0]; + unsigned int bpp = mode->code == MEDIA_BUS_FMT_Y8_1X8 ? 8 : 10; + + return data->link_freq_menu[0] / bpp; +} + static int og0ve1b_init_controls(struct og0ve1b *og0ve1b) { struct v4l2_ctrl_handler *ctrl_hdlr = &og0ve1b->ctrl_handler; - const struct og0ve1b_mode *mode = &supported_modes[0]; + const struct og0ve1b_mode *mode = &og0ve1b->data->modes[0]; + const struct og0ve1b_sensor_data *data = og0ve1b->data; s64 exposure_max, pixel_rate, h_blank, v_blank; struct v4l2_fwnode_device_properties props; struct v4l2_ctrl *ctrl; @@ -343,12 +376,12 @@ static int og0ve1b_init_controls(struct og0ve1b *og0ve1b) ctrl = v4l2_ctrl_new_int_menu(ctrl_hdlr, &og0ve1b_ctrl_ops, V4L2_CID_LINK_FREQ, - ARRAY_SIZE(og0ve1b_link_freq_menu) - 1, - 0, og0ve1b_link_freq_menu); + data->num_link_freqs - 1, + 0, data->link_freq_menu); if (ctrl) ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; - pixel_rate = og0ve1b_link_freq_menu[0] / mode->bpp; + pixel_rate = og0ve1b_pixel_rate(data); v4l2_ctrl_new_std(ctrl_hdlr, &og0ve1b_ctrl_ops, V4L2_CID_PIXEL_RATE, 0, pixel_rate, 1, pixel_rate); @@ -407,7 +440,7 @@ static int og0ve1b_init_controls(struct og0ve1b *og0ve1b) static void og0ve1b_update_pad_format(const struct og0ve1b_mode *mode, struct v4l2_mbus_framefmt *fmt) { - fmt->code = MEDIA_BUS_FMT_Y8_1X8; + fmt->code = mode->code; fmt->width = mode->width; fmt->height = mode->height; fmt->field = V4L2_FIELD_NONE; @@ -421,8 +454,8 @@ static int og0ve1b_enable_streams(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, u32 pad, u64 streams_mask) { - const struct og0ve1b_reg_list *reg_list = &supported_modes[0].reg_list; struct og0ve1b *og0ve1b = to_og0ve1b(sd); + const struct og0ve1b_reg_list *reg_list = &og0ve1b->data->modes[0].reg_list; int ret; ret = pm_runtime_resume_and_get(og0ve1b->dev); @@ -484,13 +517,14 @@ static int og0ve1b_set_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, struct v4l2_subdev_format *fmt) { + struct og0ve1b *og0ve1b = to_og0ve1b(sd); struct v4l2_mbus_framefmt *format; const struct og0ve1b_mode *mode; format = v4l2_subdev_state_get_format(state, 0); - mode = v4l2_find_nearest_size(supported_modes, - ARRAY_SIZE(supported_modes), + mode = v4l2_find_nearest_size(og0ve1b->data->modes, + og0ve1b->data->num_modes, width, height, fmt->format.width, fmt->format.height); @@ -505,10 +539,12 @@ static int og0ve1b_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { + struct og0ve1b *og0ve1b = to_og0ve1b(sd); + if (code->index > 0) return -EINVAL; - code->code = MEDIA_BUS_FMT_Y8_1X8; + code->code = og0ve1b->data->modes[0].code; return 0; } @@ -517,15 +553,18 @@ static int og0ve1b_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_size_enum *fse) { - if (fse->index >= ARRAY_SIZE(supported_modes)) + struct og0ve1b *og0ve1b = to_og0ve1b(sd); + const struct og0ve1b_sensor_data *data = og0ve1b->data; + + if (fse->index >= data->num_modes) return -EINVAL; - if (fse->code != MEDIA_BUS_FMT_Y8_1X8) + if (fse->code != data->modes[fse->index].code) return -EINVAL; - fse->min_width = supported_modes[fse->index].width; + fse->min_width = data->modes[fse->index].width; fse->max_width = fse->min_width; - fse->min_height = supported_modes[fse->index].height; + fse->min_height = data->modes[fse->index].height; fse->max_height = fse->min_height; return 0; @@ -534,13 +573,14 @@ static int og0ve1b_enum_frame_size(struct v4l2_subdev *sd, static int og0ve1b_init_state(struct v4l2_subdev *sd, struct v4l2_subdev_state *state) { + const struct og0ve1b_mode *mode = &to_og0ve1b(sd)->data->modes[0]; struct v4l2_subdev_format fmt = { .which = V4L2_SUBDEV_FORMAT_TRY, .pad = 0, .format = { - .code = MEDIA_BUS_FMT_Y8_1X8, - .width = supported_modes[0].width, - .height = supported_modes[0].height, + .code = mode->code, + .width = mode->width, + .height = mode->height, }, }; @@ -586,9 +626,9 @@ static int og0ve1b_identify_sensor(struct og0ve1b *og0ve1b) return ret; } - if (val != OG0VE1B_CHIP_ID) { - dev_err(og0ve1b->dev, "chip id mismatch: %x!=%llx\n", - OG0VE1B_CHIP_ID, val); + if (val != og0ve1b->data->chip_id) { + dev_err(og0ve1b->dev, "chip id mismatch: %llx!=%llx\n", + og0ve1b->data->chip_id, val); return -ENODEV; } @@ -624,8 +664,8 @@ static int og0ve1b_check_hwcfg(struct og0ve1b *og0ve1b) ret = v4l2_link_freq_to_bitmap(og0ve1b->dev, bus_cfg.link_frequencies, bus_cfg.nr_of_link_frequencies, - og0ve1b_link_freq_menu, - ARRAY_SIZE(og0ve1b_link_freq_menu), + og0ve1b->data->link_freq_menu, + og0ve1b->data->num_link_freqs, &freq_bitmap); v4l2_fwnode_endpoint_free(&bus_cfg); @@ -686,6 +726,9 @@ static int og0ve1b_probe(struct i2c_client *client) return -ENOMEM; og0ve1b->dev = &client->dev; + og0ve1b->data = i2c_get_match_data(client); + if (!og0ve1b->data) + return -ENODEV; v4l2_i2c_subdev_init(&og0ve1b->sd, client, &og0ve1b_subdev_ops); @@ -700,7 +743,7 @@ static int og0ve1b_probe(struct i2c_client *client) "failed to get XVCLK clock\n"); freq = clk_get_rate(og0ve1b->xvclk); - if (freq && freq != OG0VE1B_MCLK_FREQ_24MHZ) + if (freq && freq != og0ve1b->data->mclk_freq) return dev_err_probe(og0ve1b->dev, -EINVAL, "XVCLK clock frequency %lu is not supported\n", freq); @@ -819,7 +862,7 @@ static const struct dev_pm_ops og0ve1b_pm_ops = { }; static const struct of_device_id og0ve1b_of_match[] = { - { .compatible = "ovti,og0ve1b" }, + { .compatible = "ovti,og0ve1b", .data = &og0ve1b_data }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, og0ve1b_of_match); -- 2.34.1 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v3 2/3] media: i2c: og0ve1b: Introduce per-sensor data structure 2026-07-08 14:33 ` [PATCH v3 2/3] media: i2c: og0ve1b: Introduce per-sensor data structure Wenmeng Liu @ 2026-07-08 14:45 ` sashiko-bot 2026-07-23 13:48 ` Vladimir Zapolskiy 1 sibling, 0 replies; 12+ messages in thread From: sashiko-bot @ 2026-07-08 14:45 UTC (permalink / raw) To: Wenmeng Liu; +Cc: conor+dt, devicetree, robh Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: Pre-existing issues: - [High] Incorrect evaluation of pm_runtime_get_if_active() return value leads to unbalanced pm_runtime_put() and usage counter underflow when Runtime PM is disabled. -- --- Patch [2]: [PATCH v3 2/3] media: i2c: og0ve1b: Introduce per-sensor data structure --- commit 7e9c88bb94dde2349f9f1531e2c8f8721c3dd997 Author: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com> media: i2c: og0ve1b: Introduce per-sensor data structure Refactor the driver to separate sensor-specific data from the common driver code. Introduce a sensor_data structure, populated through i2c_get_match_data(), to hold the chip ID, MCLK frequency, link frequencies and supported modes. > diff --git a/drivers/media/i2c/og0ve1b.c b/drivers/media/i2c/og0ve1b.c > index 84a28cdcade10..041342fbe3c82 100644 > --- a/drivers/media/i2c/og0ve1b.c > +++ b/drivers/media/i2c/og0ve1b.c [ ... ] > @@ -273,11 +287,21 @@ static int og0ve1b_enable_test_pattern(struct og0ve1b *og0ve1b, u32 pattern) > return cci_write(og0ve1b->regmap, OG0VE1B_REG_PRE_ISP, val, NULL); > } > > +static const struct og0ve1b_sensor_data og0ve1b_data = { > + .chip_id = OG0VE1B_CHIP_ID, > + .mclk_freq = OG0VE1B_MCLK_FREQ_24MHZ, > + .enable_test_pattern = og0ve1b_enable_test_pattern, > + .link_freq_menu = og0ve1b_link_freq_menu, > + .num_link_freqs = ARRAY_SIZE(og0ve1b_link_freq_menu), > + .modes = og0ve1b_supported_modes, > + .num_modes = ARRAY_SIZE(og0ve1b_supported_modes), > +}; > + > static int og0ve1b_set_ctrl(struct v4l2_ctrl *ctrl) > { > struct og0ve1b *og0ve1b = container_of(ctrl->handler, struct og0ve1b, > ctrl_handler); > - const struct og0ve1b_mode *mode = &supported_modes[0]; > + const struct og0ve1b_mode *mode = &og0ve1b->data->modes[0]; > s64 exposure_max; > int ret; > [Severity: High] This is a pre-existing issue, but does the pm_runtime_get_if_active() check later in og0ve1b_set_ctrl() properly handle negative error codes? The function currently checks the runtime PM state with: if (!pm_runtime_get_if_active(og0ve1b->dev)) return 0; If Runtime PM is disabled, pm_runtime_get_if_active() returns -EINVAL. Since the logical NOT operator evaluates -EINVAL as false, the code bypasses the early return and proceeds to the hardware accesses and the pm_runtime_put() call at the end of the function. Could this lead to usage counter underflows and unpowered hardware accesses when the sensor isn't powered up? Should this be checked as <= 0 instead? -- Sashiko AI review · https://sashiko.dev/#/patchset/20260708-og0va1b-v3-0-de8e44455a42@oss.qualcomm.com?part=2 ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v3 2/3] media: i2c: og0ve1b: Introduce per-sensor data structure 2026-07-08 14:33 ` [PATCH v3 2/3] media: i2c: og0ve1b: Introduce per-sensor data structure Wenmeng Liu 2026-07-08 14:45 ` sashiko-bot @ 2026-07-23 13:48 ` Vladimir Zapolskiy 1 sibling, 0 replies; 12+ messages in thread From: Vladimir Zapolskiy @ 2026-07-23 13:48 UTC (permalink / raw) To: Wenmeng Liu, Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sakari Ailus Cc: linux-media, devicetree, linux-kernel Hi Wenmeng. On 7/8/26 17:33, Wenmeng Liu wrote: > Refactor the driver to separate sensor-specific data from the common > driver code. Introduce a sensor_data structure, populated through > i2c_get_match_data(), to hold the chip ID, MCLK frequency, link > frequencies and supported modes. > > Test pattern programming is described by a per-sensor callback, and each > mode stores its media bus format code (rather than a bits-per-pixel > value) so that sensors with a different output format can be supported. > > Signed-off-by: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com> > --- > drivers/media/i2c/og0ve1b.c | 99 ++++++++++++++++++++++++++++++++------------- > 1 file changed, 71 insertions(+), 28 deletions(-) > > diff --git a/drivers/media/i2c/og0ve1b.c b/drivers/media/i2c/og0ve1b.c > index 84a28cdcade10f8fbcf945999e88f84641b9bc0d..041342fbe3c822400388f58a03e6057e186f060f 100644 > --- a/drivers/media/i2c/og0ve1b.c > +++ b/drivers/media/i2c/og0ve1b.c > @@ -65,11 +65,23 @@ struct og0ve1b_mode { > u32 height; /* Frame height in pixels */ > u32 hts; /* Horizontal timing size */ > u32 vts; /* Default vertical timing size */ > - u32 bpp; /* Bits per pixel */ > + u32 code; /* MEDIA_BUS_FMT code */ > > const struct og0ve1b_reg_list reg_list; /* Sensor register setting */ > }; > > +struct og0ve1b; > + > +struct og0ve1b_sensor_data { > + u64 chip_id; > + unsigned long mclk_freq; > + int (*enable_test_pattern)(struct og0ve1b *og0ve1b, u32 pattern); > + const s64 *link_freq_menu; > + int num_link_freqs; > + const struct og0ve1b_mode *modes; > + int num_modes; > +}; > + > static const char * const og0ve1b_test_pattern_menu[] = { > "Disabled", > "Vertical Colour Bars", > @@ -99,6 +111,8 @@ struct og0ve1b { > > /* Saved register value */ > u64 pre_isp; > + > + const struct og0ve1b_sensor_data *data; > }; > > static const struct cci_reg_sequence og0ve1b_640x480_120fps_mode[] = { > @@ -247,13 +261,13 @@ static const struct cci_reg_sequence og0ve1b_640x480_120fps_mode[] = { > { CCI_REG8(0x3f47), 0x35 }, > }; > > -static const struct og0ve1b_mode supported_modes[] = { > +static const struct og0ve1b_mode og0ve1b_supported_modes[] = { > { > .width = 640, > .height = 480, > .hts = 792, > .vts = 568, > - .bpp = 8, > + .code = MEDIA_BUS_FMT_Y8_1X8, > .reg_list = { > .regs = og0ve1b_640x480_120fps_mode, > .num_regs = ARRAY_SIZE(og0ve1b_640x480_120fps_mode), > @@ -273,11 +287,21 @@ static int og0ve1b_enable_test_pattern(struct og0ve1b *og0ve1b, u32 pattern) > return cci_write(og0ve1b->regmap, OG0VE1B_REG_PRE_ISP, val, NULL); > } > > +static const struct og0ve1b_sensor_data og0ve1b_data = { > + .chip_id = OG0VE1B_CHIP_ID, > + .mclk_freq = OG0VE1B_MCLK_FREQ_24MHZ, > + .enable_test_pattern = og0ve1b_enable_test_pattern, > + .link_freq_menu = og0ve1b_link_freq_menu, > + .num_link_freqs = ARRAY_SIZE(og0ve1b_link_freq_menu), > + .modes = og0ve1b_supported_modes, > + .num_modes = ARRAY_SIZE(og0ve1b_supported_modes), > +}; > + > static int og0ve1b_set_ctrl(struct v4l2_ctrl *ctrl) > { > struct og0ve1b *og0ve1b = container_of(ctrl->handler, struct og0ve1b, > ctrl_handler); > - const struct og0ve1b_mode *mode = &supported_modes[0]; > + const struct og0ve1b_mode *mode = &og0ve1b->data->modes[0]; > s64 exposure_max; > int ret; > > @@ -314,7 +338,7 @@ static int og0ve1b_set_ctrl(struct v4l2_ctrl *ctrl) > ctrl->val + mode->height, NULL); > break; > case V4L2_CID_TEST_PATTERN: > - ret = og0ve1b_enable_test_pattern(og0ve1b, ctrl->val); > + ret = og0ve1b->data->enable_test_pattern(og0ve1b, ctrl->val); > break; > default: > ret = -EINVAL; > @@ -330,10 +354,19 @@ static const struct v4l2_ctrl_ops og0ve1b_ctrl_ops = { > .s_ctrl = og0ve1b_set_ctrl, > }; > > +static s64 og0ve1b_pixel_rate(const struct og0ve1b_sensor_data *data) > +{ > + const struct og0ve1b_mode *mode = &data->modes[0]; > + unsigned int bpp = mode->code == MEDIA_BUS_FMT_Y8_1X8 ? 8 : 10; > + > + return data->link_freq_menu[0] / bpp; > +} > + > static int og0ve1b_init_controls(struct og0ve1b *og0ve1b) > { > struct v4l2_ctrl_handler *ctrl_hdlr = &og0ve1b->ctrl_handler; > - const struct og0ve1b_mode *mode = &supported_modes[0]; > + const struct og0ve1b_mode *mode = &og0ve1b->data->modes[0]; > + const struct og0ve1b_sensor_data *data = og0ve1b->data; > s64 exposure_max, pixel_rate, h_blank, v_blank; > struct v4l2_fwnode_device_properties props; > struct v4l2_ctrl *ctrl; > @@ -343,12 +376,12 @@ static int og0ve1b_init_controls(struct og0ve1b *og0ve1b) > > ctrl = v4l2_ctrl_new_int_menu(ctrl_hdlr, &og0ve1b_ctrl_ops, > V4L2_CID_LINK_FREQ, > - ARRAY_SIZE(og0ve1b_link_freq_menu) - 1, > - 0, og0ve1b_link_freq_menu); > + data->num_link_freqs - 1, > + 0, data->link_freq_menu); > if (ctrl) > ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; > > - pixel_rate = og0ve1b_link_freq_menu[0] / mode->bpp; > + pixel_rate = og0ve1b_pixel_rate(data); > v4l2_ctrl_new_std(ctrl_hdlr, &og0ve1b_ctrl_ops, V4L2_CID_PIXEL_RATE, > 0, pixel_rate, 1, pixel_rate); > > @@ -407,7 +440,7 @@ static int og0ve1b_init_controls(struct og0ve1b *og0ve1b) > static void og0ve1b_update_pad_format(const struct og0ve1b_mode *mode, > struct v4l2_mbus_framefmt *fmt) > { > - fmt->code = MEDIA_BUS_FMT_Y8_1X8; > + fmt->code = mode->code; > fmt->width = mode->width; > fmt->height = mode->height; > fmt->field = V4L2_FIELD_NONE; > @@ -421,8 +454,8 @@ static int og0ve1b_enable_streams(struct v4l2_subdev *sd, > struct v4l2_subdev_state *state, u32 pad, > u64 streams_mask) > { > - const struct og0ve1b_reg_list *reg_list = &supported_modes[0].reg_list; > struct og0ve1b *og0ve1b = to_og0ve1b(sd); > + const struct og0ve1b_reg_list *reg_list = &og0ve1b->data->modes[0].reg_list; > int ret; > > ret = pm_runtime_resume_and_get(og0ve1b->dev); > @@ -484,13 +517,14 @@ static int og0ve1b_set_pad_format(struct v4l2_subdev *sd, > struct v4l2_subdev_state *state, > struct v4l2_subdev_format *fmt) > { > + struct og0ve1b *og0ve1b = to_og0ve1b(sd); > struct v4l2_mbus_framefmt *format; > const struct og0ve1b_mode *mode; > > format = v4l2_subdev_state_get_format(state, 0); > > - mode = v4l2_find_nearest_size(supported_modes, > - ARRAY_SIZE(supported_modes), > + mode = v4l2_find_nearest_size(og0ve1b->data->modes, > + og0ve1b->data->num_modes, > width, height, > fmt->format.width, > fmt->format.height); > @@ -505,10 +539,12 @@ static int og0ve1b_enum_mbus_code(struct v4l2_subdev *sd, > struct v4l2_subdev_state *sd_state, > struct v4l2_subdev_mbus_code_enum *code) > { > + struct og0ve1b *og0ve1b = to_og0ve1b(sd); > + > if (code->index > 0) > return -EINVAL; > > - code->code = MEDIA_BUS_FMT_Y8_1X8; > + code->code = og0ve1b->data->modes[0].code; > > return 0; > } > @@ -517,15 +553,18 @@ static int og0ve1b_enum_frame_size(struct v4l2_subdev *sd, > struct v4l2_subdev_state *sd_state, > struct v4l2_subdev_frame_size_enum *fse) > { > - if (fse->index >= ARRAY_SIZE(supported_modes)) > + struct og0ve1b *og0ve1b = to_og0ve1b(sd); > + const struct og0ve1b_sensor_data *data = og0ve1b->data; > + > + if (fse->index >= data->num_modes) > return -EINVAL; > > - if (fse->code != MEDIA_BUS_FMT_Y8_1X8) > + if (fse->code != data->modes[fse->index].code) > return -EINVAL; > > - fse->min_width = supported_modes[fse->index].width; > + fse->min_width = data->modes[fse->index].width; > fse->max_width = fse->min_width; > - fse->min_height = supported_modes[fse->index].height; > + fse->min_height = data->modes[fse->index].height; > fse->max_height = fse->min_height; > > return 0; > @@ -534,13 +573,14 @@ static int og0ve1b_enum_frame_size(struct v4l2_subdev *sd, > static int og0ve1b_init_state(struct v4l2_subdev *sd, > struct v4l2_subdev_state *state) > { > + const struct og0ve1b_mode *mode = &to_og0ve1b(sd)->data->modes[0]; > struct v4l2_subdev_format fmt = { > .which = V4L2_SUBDEV_FORMAT_TRY, > .pad = 0, > .format = { > - .code = MEDIA_BUS_FMT_Y8_1X8, > - .width = supported_modes[0].width, > - .height = supported_modes[0].height, > + .code = mode->code, > + .width = mode->width, > + .height = mode->height, > }, > }; > > @@ -586,9 +626,9 @@ static int og0ve1b_identify_sensor(struct og0ve1b *og0ve1b) > return ret; > } > > - if (val != OG0VE1B_CHIP_ID) { > - dev_err(og0ve1b->dev, "chip id mismatch: %x!=%llx\n", > - OG0VE1B_CHIP_ID, val); > + if (val != og0ve1b->data->chip_id) { > + dev_err(og0ve1b->dev, "chip id mismatch: %llx!=%llx\n", > + og0ve1b->data->chip_id, val); > return -ENODEV; > } > > @@ -624,8 +664,8 @@ static int og0ve1b_check_hwcfg(struct og0ve1b *og0ve1b) > ret = v4l2_link_freq_to_bitmap(og0ve1b->dev, > bus_cfg.link_frequencies, > bus_cfg.nr_of_link_frequencies, > - og0ve1b_link_freq_menu, > - ARRAY_SIZE(og0ve1b_link_freq_menu), > + og0ve1b->data->link_freq_menu, > + og0ve1b->data->num_link_freqs, > &freq_bitmap); > > v4l2_fwnode_endpoint_free(&bus_cfg); > @@ -686,6 +726,9 @@ static int og0ve1b_probe(struct i2c_client *client) > return -ENOMEM; > > og0ve1b->dev = &client->dev; > + og0ve1b->data = i2c_get_match_data(client); > + if (!og0ve1b->data) > + return -ENODEV; > > v4l2_i2c_subdev_init(&og0ve1b->sd, client, &og0ve1b_subdev_ops); > > @@ -700,7 +743,7 @@ static int og0ve1b_probe(struct i2c_client *client) > "failed to get XVCLK clock\n"); > > freq = clk_get_rate(og0ve1b->xvclk); > - if (freq && freq != OG0VE1B_MCLK_FREQ_24MHZ) > + if (freq && freq != og0ve1b->data->mclk_freq) > return dev_err_probe(og0ve1b->dev, -EINVAL, > "XVCLK clock frequency %lu is not supported\n", > freq); > @@ -819,7 +862,7 @@ static const struct dev_pm_ops og0ve1b_pm_ops = { > }; > > static const struct of_device_id og0ve1b_of_match[] = { > - { .compatible = "ovti,og0ve1b" }, > + { .compatible = "ovti,og0ve1b", .data = &og0ve1b_data }, > { /* sentinel */ } > }; > MODULE_DEVICE_TABLE(of, og0ve1b_of_match); > I'm sorry for a delay in completion of my review and testing. The change is good in my opinion: Reviewed-by: Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org> Tested-by: Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org> -- Best wishes, Vladimir ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v3 3/3] media: i2c: og0ve1b: Add support for OmniVision OG0VA1B 2026-07-08 14:33 [PATCH v3 0/3] media: i2c: Add OmniVision OG0VA1B camera sensor driver Wenmeng Liu 2026-07-08 14:33 ` [PATCH v3 1/3] dt-bindings: media: i2c: og0ve1b: Add OmniVision OG0VA1B camera sensor Wenmeng Liu 2026-07-08 14:33 ` [PATCH v3 2/3] media: i2c: og0ve1b: Introduce per-sensor data structure Wenmeng Liu @ 2026-07-08 14:33 ` Wenmeng Liu 2026-07-23 13:51 ` Vladimir Zapolskiy 2026-07-24 13:35 ` Vladimir Zapolskiy 2026-07-23 2:41 ` [PATCH v3 0/3] media: i2c: Add OmniVision OG0VA1B camera sensor driver Wenmeng Liu 3 siblings, 2 replies; 12+ messages in thread From: Wenmeng Liu @ 2026-07-08 14:33 UTC (permalink / raw) To: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sakari Ailus, Vladimir Zapolskiy Cc: linux-media, devicetree, linux-kernel, Wenmeng Liu The OmniVision OG0VA1B is a monochrome image sensor closely related to the OG0VE1B. It shares the SCCB control interface, power supplies and the single-lane MIPI D-PHY description, and differs in its chip id, the test pattern register, the register programming and the output format (10-bit RAW instead of 8-bit). Add an og0ve1b_sensor_data entry describing the OG0VA1B together with its 640x480 60fps register sequence. Signed-off-by: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com> --- drivers/media/i2c/og0ve1b.c | 278 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 266 insertions(+), 12 deletions(-) diff --git a/drivers/media/i2c/og0ve1b.c b/drivers/media/i2c/og0ve1b.c index 041342fbe3c822400388f58a03e6057e186f060f..c558cdd43314931db35e463641dd28e10b94ec8a 100644 --- a/drivers/media/i2c/og0ve1b.c +++ b/drivers/media/i2c/og0ve1b.c @@ -14,10 +14,14 @@ #include <media/v4l2-device.h> #include <media/v4l2-fwnode.h> +#define OG0VA1B_LINK_FREQ_480MHZ (480 * HZ_PER_MHZ) +#define OG0VA1B_MCLK_FREQ_19_2MHZ (19200 * HZ_PER_KHZ) + #define OG0VE1B_LINK_FREQ_500MHZ (500 * HZ_PER_MHZ) #define OG0VE1B_MCLK_FREQ_24MHZ (24 * HZ_PER_MHZ) -#define OG0VE1B_REG_CHIP_ID CCI_REG24(0x300a) +#define OG0V_REG_CHIP_ID CCI_REG24(0x300a) +#define OG0VA1B_CHIP_ID 0xc75641 #define OG0VE1B_CHIP_ID 0xc75645 #define OG0VE1B_REG_MODE_SELECT CCI_REG8(0x0100) @@ -45,12 +49,18 @@ #define OG0VE1B_REG_VTS CCI_REG16(0x380e) #define OG0VE1B_VTS_MAX 0xffff -/* Test pattern */ +/* Test pattern - OG0VA1B uses 0x5100, OG0VE1B uses 0x5e00 */ +#define OG0VA1B_REG_TEST_PATTERN CCI_REG8(0x5100) +#define OG0VA1B_TEST_PATTERN_BAR_SHIFT 2 #define OG0VE1B_REG_PRE_ISP CCI_REG8(0x5e00) #define OG0VE1B_TEST_PATTERN_ENABLE BIT(7) #define to_og0ve1b(_sd) container_of(_sd, struct og0ve1b, sd) +static const s64 og0va1b_link_freq_menu[] = { + OG0VA1B_LINK_FREQ_480MHZ, +}; + static const s64 og0ve1b_link_freq_menu[] = { OG0VE1B_LINK_FREQ_500MHZ, }; @@ -73,15 +83,31 @@ struct og0ve1b_mode { struct og0ve1b; struct og0ve1b_sensor_data { + const char *name; u64 chip_id; unsigned long mclk_freq; int (*enable_test_pattern)(struct og0ve1b *og0ve1b, u32 pattern); + const char * const *test_pattern_menu; + int num_test_patterns; + bool cache_test_pattern_reg; + /* Exposure register unit: OG0VE1B 1/16 line (4), OG0VA1B whole lines (0). */ + unsigned int exposure_shift; + /* Pixel rate multiplier: OG0VA1B uses CSI-2 DDR (2), OG0VE1B keeps 1. */ + unsigned int pixel_rate_mul; const s64 *link_freq_menu; int num_link_freqs; const struct og0ve1b_mode *modes; int num_modes; }; +static const char * const og0va1b_test_pattern_menu[] = { + "Disabled", + "Standard Color Bar", + "Top-Bottom Darker Color Bar", + "Right-Left Darker Color Bar", + "Bottom-Top Darker Color Bar", +}; + static const char * const og0ve1b_test_pattern_menu[] = { "Disabled", "Vertical Colour Bars", @@ -115,6 +141,196 @@ struct og0ve1b { const struct og0ve1b_sensor_data *data; }; +static const struct cci_reg_sequence og0va1b_640x480_60fps_mode[] = { + { CCI_REG8(0x0302), 0x31 }, + { CCI_REG8(0x0303), 0x02 }, + { CCI_REG8(0x0304), 0x01 }, + { CCI_REG8(0x0305), 0x90 }, + { CCI_REG8(0x0306), 0x00 }, + { CCI_REG8(0x0323), 0x02 }, + { CCI_REG8(0x0325), 0x68 }, + { CCI_REG8(0x0326), 0xd8 }, + { CCI_REG8(0x3006), 0x0e }, + { CCI_REG8(0x300d), 0x08 }, + { CCI_REG8(0x3018), 0xf0 }, + { CCI_REG8(0x301c), 0xf0 }, + { CCI_REG8(0x3020), 0x20 }, + { CCI_REG8(0x3040), 0x0f }, + { CCI_REG8(0x3022), 0x01 }, + { CCI_REG8(0x3107), 0x40 }, + { CCI_REG8(0x3216), 0x01 }, + { CCI_REG8(0x3217), 0x00 }, + { CCI_REG8(0x3218), 0xc0 }, + { CCI_REG8(0x3219), 0x55 }, + { CCI_REG8(0x3506), 0x01 }, + { CCI_REG8(0x3507), 0x50 }, + { CCI_REG8(0x3508), 0x01 }, + { CCI_REG8(0x3509), 0x00 }, + { CCI_REG8(0x350a), 0x01 }, + { CCI_REG8(0x350b), 0x00 }, + { CCI_REG8(0x350c), 0x00 }, + { CCI_REG8(0x3541), 0x00 }, + { CCI_REG8(0x3542), 0x40 }, + { CCI_REG8(0x3605), 0x90 }, + { CCI_REG8(0x3606), 0x41 }, + { CCI_REG8(0x3612), 0x00 }, + { CCI_REG8(0x3620), 0x08 }, + { CCI_REG8(0x3630), 0x17 }, + { CCI_REG8(0x3631), 0x99 }, + { CCI_REG8(0x3639), 0x88 }, + { CCI_REG8(0x3668), 0x00 }, + { CCI_REG8(0x3674), 0x00 }, + { CCI_REG8(0x3677), 0x3f }, + { CCI_REG8(0x368f), 0x06 }, + { CCI_REG8(0x36a2), 0x19 }, + { CCI_REG8(0x36a4), 0xf1 }, + { CCI_REG8(0x36a5), 0x2d }, + { CCI_REG8(0x3706), 0x30 }, + { CCI_REG8(0x370d), 0x72 }, + { CCI_REG8(0x3713), 0x86 }, + { CCI_REG8(0x3715), 0x03 }, + { CCI_REG8(0x3716), 0x00 }, + { CCI_REG8(0x376d), 0x24 }, + { CCI_REG8(0x3770), 0x3a }, + { CCI_REG8(0x3778), 0x00 }, + { CCI_REG8(0x37a8), 0x03 }, + { CCI_REG8(0x37a9), 0x00 }, + { CCI_REG8(0x37df), 0x7d }, + { CCI_REG8(0x3800), 0x00 }, + { CCI_REG8(0x3801), 0x00 }, + { CCI_REG8(0x3802), 0x00 }, + { CCI_REG8(0x3803), 0x00 }, + { CCI_REG8(0x3804), 0x02 }, + { CCI_REG8(0x3805), 0x8f }, + { CCI_REG8(0x3806), 0x01 }, + { CCI_REG8(0x3807), 0xef }, + { CCI_REG8(0x3808), 0x02 }, + { CCI_REG8(0x3809), 0x80 }, + { CCI_REG8(0x380a), 0x01 }, + { CCI_REG8(0x380b), 0xe0 }, + { CCI_REG8(0x380c), 0x01 }, + { CCI_REG8(0x380d), 0x78 }, + { CCI_REG8(0x380e), 0x08 }, + { CCI_REG8(0x380f), 0x30 }, + { CCI_REG8(0x3810), 0x00 }, + { CCI_REG8(0x3811), 0x08 }, + { CCI_REG8(0x3812), 0x00 }, + { CCI_REG8(0x3813), 0x08 }, + { CCI_REG8(0x3814), 0x11 }, + { CCI_REG8(0x3815), 0x11 }, + { CCI_REG8(0x3816), 0x00 }, + { CCI_REG8(0x3817), 0x01 }, + { CCI_REG8(0x3818), 0x00 }, + { CCI_REG8(0x3819), 0x05 }, + { CCI_REG8(0x3820), 0x40 }, + { CCI_REG8(0x3821), 0x04 }, + { CCI_REG8(0x3823), 0x00 }, + { CCI_REG8(0x3826), 0x00 }, + { CCI_REG8(0x3827), 0x00 }, + { CCI_REG8(0x382b), 0x52 }, + { CCI_REG8(0x384a), 0xa2 }, + { CCI_REG8(0x3858), 0x00 }, + { CCI_REG8(0x3859), 0x00 }, + { CCI_REG8(0x3860), 0x00 }, + { CCI_REG8(0x3861), 0x00 }, + { CCI_REG8(0x3866), 0x0c }, + { CCI_REG8(0x3867), 0x07 }, + { CCI_REG8(0x3884), 0x00 }, + { CCI_REG8(0x3885), 0x08 }, + { CCI_REG8(0x3888), 0x50 }, + { CCI_REG8(0x3893), 0x6c }, + { CCI_REG8(0x3898), 0x00 }, + { CCI_REG8(0x389a), 0x04 }, + { CCI_REG8(0x389b), 0x01 }, + { CCI_REG8(0x389c), 0x0b }, + { CCI_REG8(0x389d), 0xdc }, + { CCI_REG8(0x38b1), 0x04 }, + { CCI_REG8(0x38b2), 0x00 }, + { CCI_REG8(0x38b3), 0x08 }, + { CCI_REG8(0x38c1), 0x46 }, + { CCI_REG8(0x38c9), 0x02 }, + { CCI_REG8(0x38d4), 0x06 }, + { CCI_REG8(0x38d5), 0x5a }, + { CCI_REG8(0x38d6), 0x08 }, + { CCI_REG8(0x38d7), 0x3a }, + { CCI_REG8(0x391f), 0x00 }, + { CCI_REG8(0x3920), 0xaa }, + { CCI_REG8(0x3921), 0x00 }, + { CCI_REG8(0x3922), 0x00 }, + { CCI_REG8(0x3923), 0x00 }, + { CCI_REG8(0x3924), 0x00 }, + { CCI_REG8(0x3925), 0x00 }, + { CCI_REG8(0x3926), 0x00 }, + { CCI_REG8(0x3927), 0x00 }, + { CCI_REG8(0x3928), 0x10 }, + { CCI_REG8(0x3929), 0x01 }, + { CCI_REG8(0x392a), 0xb4 }, + { CCI_REG8(0x392b), 0x00 }, + { CCI_REG8(0x392c), 0x10 }, + { CCI_REG8(0x392d), 0x01 }, + { CCI_REG8(0x392e), 0x78 }, + { CCI_REG8(0x392f), 0x4a }, + { CCI_REG8(0x391e), 0x01 }, + { CCI_REG8(0x389f), 0x08 }, + { CCI_REG8(0x38a0), 0x00 }, + { CCI_REG8(0x38a1), 0x00 }, + { CCI_REG8(0x3a06), 0x06 }, + { CCI_REG8(0x3a07), 0x78 }, + { CCI_REG8(0x3a08), 0x08 }, + { CCI_REG8(0x3a09), 0x80 }, + { CCI_REG8(0x3a52), 0x00 }, + { CCI_REG8(0x3a53), 0x01 }, + { CCI_REG8(0x3a54), 0x0c }, + { CCI_REG8(0x3a55), 0x04 }, + { CCI_REG8(0x3a58), 0x0c }, + { CCI_REG8(0x3a59), 0x04 }, + { CCI_REG8(0x4000), 0xcf }, + { CCI_REG8(0x4003), 0x40 }, + { CCI_REG8(0x4008), 0x04 }, + { CCI_REG8(0x4009), 0x13 }, + { CCI_REG8(0x400a), 0x02 }, + { CCI_REG8(0x400b), 0x34 }, + { CCI_REG8(0x4010), 0x71 }, + { CCI_REG8(0x4042), 0xc3 }, + { CCI_REG8(0x4306), 0x04 }, + { CCI_REG8(0x4307), 0x12 }, + { CCI_REG8(0x4500), 0x70 }, + { CCI_REG8(0x4509), 0x00 }, + { CCI_REG8(0x450b), 0x83 }, + { CCI_REG8(0x4604), 0x68 }, + { CCI_REG8(0x481b), 0x44 }, + { CCI_REG8(0x481f), 0x30 }, + { CCI_REG8(0x4823), 0x44 }, + { CCI_REG8(0x4825), 0x35 }, + { CCI_REG8(0x4837), 0x11 }, + { CCI_REG8(0x4f00), 0x04 }, + { CCI_REG8(0x4f10), 0x04 }, + { CCI_REG8(0x4f21), 0x01 }, + { CCI_REG8(0x4f22), 0x00 }, + { CCI_REG8(0x4f23), 0x54 }, + { CCI_REG8(0x4f24), 0x51 }, + { CCI_REG8(0x4f25), 0x41 }, + { CCI_REG8(0x5000), 0x3f }, + { CCI_REG8(0x5001), 0x80 }, + { CCI_REG8(0x500a), 0x00 }, + { CCI_REG8(0x5100), 0x00 }, + { CCI_REG8(0x5111), 0x20 }, +}; + +static const struct og0ve1b_mode og0va1b_supported_modes[] = { + { + .width = 640, + .height = 480, + .hts = 752, + .vts = 2096, + .code = MEDIA_BUS_FMT_Y10_1X10, + .reg_list = { + .regs = og0va1b_640x480_60fps_mode, + .num_regs = ARRAY_SIZE(og0va1b_640x480_60fps_mode), + }, + }, +}; + static const struct cci_reg_sequence og0ve1b_640x480_120fps_mode[] = { { CCI_REG8(0x30a0), 0x02 }, { CCI_REG8(0x30a1), 0x00 }, @@ -275,6 +491,17 @@ static const struct og0ve1b_mode og0ve1b_supported_modes[] = { }, }; +static int og0va1b_enable_test_pattern(struct og0ve1b *og0ve1b, u32 pattern) +{ + u64 val = 0; + + if (pattern) + val = ((pattern - 1) << OG0VA1B_TEST_PATTERN_BAR_SHIFT) | + OG0VE1B_TEST_PATTERN_ENABLE; + + return cci_write(og0ve1b->regmap, OG0VA1B_REG_TEST_PATTERN, val, NULL); +} + static int og0ve1b_enable_test_pattern(struct og0ve1b *og0ve1b, u32 pattern) { u64 val = og0ve1b->pre_isp; @@ -287,10 +514,31 @@ static int og0ve1b_enable_test_pattern(struct og0ve1b *og0ve1b, u32 pattern) return cci_write(og0ve1b->regmap, OG0VE1B_REG_PRE_ISP, val, NULL); } +static const struct og0ve1b_sensor_data og0va1b_data = { + .name = "og0va1b", + .chip_id = OG0VA1B_CHIP_ID, + .mclk_freq = OG0VA1B_MCLK_FREQ_19_2MHZ, + .enable_test_pattern = og0va1b_enable_test_pattern, + .test_pattern_menu = og0va1b_test_pattern_menu, + .num_test_patterns = ARRAY_SIZE(og0va1b_test_pattern_menu), + .exposure_shift = 0, + .pixel_rate_mul = 2, + .link_freq_menu = og0va1b_link_freq_menu, + .num_link_freqs = ARRAY_SIZE(og0va1b_link_freq_menu), + .modes = og0va1b_supported_modes, + .num_modes = ARRAY_SIZE(og0va1b_supported_modes), +}; + static const struct og0ve1b_sensor_data og0ve1b_data = { + .name = "og0ve1b", .chip_id = OG0VE1B_CHIP_ID, .mclk_freq = OG0VE1B_MCLK_FREQ_24MHZ, .enable_test_pattern = og0ve1b_enable_test_pattern, + .test_pattern_menu = og0ve1b_test_pattern_menu, + .num_test_patterns = ARRAY_SIZE(og0ve1b_test_pattern_menu), + .cache_test_pattern_reg = true, + .exposure_shift = 4, + .pixel_rate_mul = 1, .link_freq_menu = og0ve1b_link_freq_menu, .num_link_freqs = ARRAY_SIZE(og0ve1b_link_freq_menu), .modes = og0ve1b_supported_modes, @@ -331,7 +579,8 @@ static int og0ve1b_set_ctrl(struct v4l2_ctrl *ctrl) break; case V4L2_CID_EXPOSURE: ret = cci_write(og0ve1b->regmap, OG0VE1B_REG_EXPOSURE, - ctrl->val << 4, NULL); + ctrl->val << og0ve1b->data->exposure_shift, + NULL); break; case V4L2_CID_VBLANK: ret = cci_write(og0ve1b->regmap, OG0VE1B_REG_VTS, @@ -359,7 +608,7 @@ static s64 og0ve1b_pixel_rate(const struct og0ve1b_sensor_data *data) const struct og0ve1b_mode *mode = &data->modes[0]; unsigned int bpp = mode->code == MEDIA_BUS_FMT_Y8_1X8 ? 8 : 10; - return data->link_freq_menu[0] / bpp; + return data->link_freq_menu[0] * data->pixel_rate_mul / bpp; } static int og0ve1b_init_controls(struct og0ve1b *og0ve1b) @@ -412,8 +661,8 @@ static int og0ve1b_init_controls(struct og0ve1b *og0ve1b) v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &og0ve1b_ctrl_ops, V4L2_CID_TEST_PATTERN, - ARRAY_SIZE(og0ve1b_test_pattern_menu) - 1, - 0, 0, og0ve1b_test_pattern_menu); + data->num_test_patterns - 1, + 0, 0, data->test_pattern_menu); if (ctrl_hdlr->error) return ctrl_hdlr->error; @@ -620,7 +869,7 @@ static int og0ve1b_identify_sensor(struct og0ve1b *og0ve1b) u64 val; int ret; - ret = cci_read(og0ve1b->regmap, OG0VE1B_REG_CHIP_ID, &val, NULL); + ret = cci_read(og0ve1b->regmap, OG0V_REG_CHIP_ID, &val, NULL); if (ret) { dev_err(og0ve1b->dev, "failed to read chip id: %d\n", ret); return ret; @@ -632,10 +881,12 @@ static int og0ve1b_identify_sensor(struct og0ve1b *og0ve1b) return -ENODEV; } - ret = cci_read(og0ve1b->regmap, OG0VE1B_REG_PRE_ISP, - &og0ve1b->pre_isp, NULL); - if (ret) - dev_err(og0ve1b->dev, "failed to read pre_isp: %d\n", ret); + if (og0ve1b->data->cache_test_pattern_reg) { + ret = cci_read(og0ve1b->regmap, OG0VE1B_REG_PRE_ISP, + &og0ve1b->pre_isp, NULL); + if (ret) + dev_err(og0ve1b->dev, "failed to read pre_isp: %d\n", ret); + } return ret; } @@ -731,6 +982,8 @@ static int og0ve1b_probe(struct i2c_client *client) return -ENODEV; v4l2_i2c_subdev_init(&og0ve1b->sd, client, &og0ve1b_subdev_ops); + v4l2_i2c_subdev_set_name(&og0ve1b->sd, client, + og0ve1b->data->name, NULL); og0ve1b->regmap = devm_cci_regmap_init_i2c(client, 16); if (IS_ERR(og0ve1b->regmap)) @@ -862,6 +1115,7 @@ static const struct dev_pm_ops og0ve1b_pm_ops = { }; static const struct of_device_id og0ve1b_of_match[] = { + { .compatible = "ovti,og0va1b", .data = &og0va1b_data }, { .compatible = "ovti,og0ve1b", .data = &og0ve1b_data }, { /* sentinel */ } }; @@ -880,5 +1134,5 @@ static struct i2c_driver og0ve1b_i2c_driver = { module_i2c_driver(og0ve1b_i2c_driver); MODULE_AUTHOR("Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>"); -MODULE_DESCRIPTION("OmniVision OG0VE1B sensor driver"); +MODULE_DESCRIPTION("OmniVision OG0VE1B/OG0VA1B sensor driver"); MODULE_LICENSE("GPL"); -- 2.34.1 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v3 3/3] media: i2c: og0ve1b: Add support for OmniVision OG0VA1B 2026-07-08 14:33 ` [PATCH v3 3/3] media: i2c: og0ve1b: Add support for OmniVision OG0VA1B Wenmeng Liu @ 2026-07-23 13:51 ` Vladimir Zapolskiy 2026-07-24 13:35 ` Vladimir Zapolskiy 1 sibling, 0 replies; 12+ messages in thread From: Vladimir Zapolskiy @ 2026-07-23 13:51 UTC (permalink / raw) To: Wenmeng Liu, Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sakari Ailus Cc: linux-media, devicetree, linux-kernel On 7/8/26 17:33, Wenmeng Liu wrote: > The OmniVision OG0VA1B is a monochrome image sensor closely related to > the OG0VE1B. It shares the SCCB control interface, power supplies and > the single-lane MIPI D-PHY description, and differs in its chip id, the > test pattern register, the register programming and the output format > (10-bit RAW instead of 8-bit). > > Add an og0ve1b_sensor_data entry describing the OG0VA1B together with > its 640x480 60fps register sequence. > > Signed-off-by: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com> Thank you for the change, no more review comments and no regressions to report from my side: Reviewed-by: Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org> Tested-by: Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org> # og0ve1b -- Best wishes, Vladimir ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v3 3/3] media: i2c: og0ve1b: Add support for OmniVision OG0VA1B 2026-07-08 14:33 ` [PATCH v3 3/3] media: i2c: og0ve1b: Add support for OmniVision OG0VA1B Wenmeng Liu 2026-07-23 13:51 ` Vladimir Zapolskiy @ 2026-07-24 13:35 ` Vladimir Zapolskiy 2026-07-27 9:38 ` Wenmeng Liu 1 sibling, 1 reply; 12+ messages in thread From: Vladimir Zapolskiy @ 2026-07-24 13:35 UTC (permalink / raw) To: Wenmeng Liu, Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sakari Ailus Cc: linux-media, devicetree, linux-kernel Hi Wenmeng. On 7/8/26 17:33, Wenmeng Liu wrote: > The OmniVision OG0VA1B is a monochrome image sensor closely related to > the OG0VE1B. It shares the SCCB control interface, power supplies and > the single-lane MIPI D-PHY description, and differs in its chip id, the > test pattern register, the register programming and the output format > (10-bit RAW instead of 8-bit). > > Add an og0ve1b_sensor_data entry describing the OG0VA1B together with > its 640x480 60fps register sequence. > > Signed-off-by: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com> > --- > drivers/media/i2c/og0ve1b.c | 278 ++++++++++++++++++++++++++++++++++++++++++-- > 1 file changed, 266 insertions(+), 12 deletions(-) > > diff --git a/drivers/media/i2c/og0ve1b.c b/drivers/media/i2c/og0ve1b.c > index 041342fbe3c822400388f58a03e6057e186f060f..c558cdd43314931db35e463641dd28e10b94ec8a 100644 > --- a/drivers/media/i2c/og0ve1b.c > +++ b/drivers/media/i2c/og0ve1b.c > @@ -14,10 +14,14 @@ > #include <media/v4l2-device.h> > #include <media/v4l2-fwnode.h> > > +#define OG0VA1B_LINK_FREQ_480MHZ (480 * HZ_PER_MHZ) > +#define OG0VA1B_MCLK_FREQ_19_2MHZ (19200 * HZ_PER_KHZ) > + > #define OG0VE1B_LINK_FREQ_500MHZ (500 * HZ_PER_MHZ) > #define OG0VE1B_MCLK_FREQ_24MHZ (24 * HZ_PER_MHZ) > > -#define OG0VE1B_REG_CHIP_ID CCI_REG24(0x300a) > +#define OG0V_REG_CHIP_ID CCI_REG24(0x300a) > +#define OG0VA1B_CHIP_ID 0xc75641 > #define OG0VE1B_CHIP_ID 0xc75645 > > #define OG0VE1B_REG_MODE_SELECT CCI_REG8(0x0100) > @@ -45,12 +49,18 @@ > #define OG0VE1B_REG_VTS CCI_REG16(0x380e) > #define OG0VE1B_VTS_MAX 0xffff > > -/* Test pattern */ > +/* Test pattern - OG0VA1B uses 0x5100, OG0VE1B uses 0x5e00 */ > +#define OG0VA1B_REG_TEST_PATTERN CCI_REG8(0x5100) > +#define OG0VA1B_TEST_PATTERN_BAR_SHIFT 2 > #define OG0VE1B_REG_PRE_ISP CCI_REG8(0x5e00) > #define OG0VE1B_TEST_PATTERN_ENABLE BIT(7) > > #define to_og0ve1b(_sd) container_of(_sd, struct og0ve1b, sd) > > +static const s64 og0va1b_link_freq_menu[] = { > + OG0VA1B_LINK_FREQ_480MHZ, > +}; > + > static const s64 og0ve1b_link_freq_menu[] = { > OG0VE1B_LINK_FREQ_500MHZ, > }; > @@ -73,15 +83,31 @@ struct og0ve1b_mode { > struct og0ve1b; > > struct og0ve1b_sensor_data { > + const char *name; > u64 chip_id; > unsigned long mclk_freq; > int (*enable_test_pattern)(struct og0ve1b *og0ve1b, u32 pattern); > + const char * const *test_pattern_menu; > + int num_test_patterns; > + bool cache_test_pattern_reg; > + /* Exposure register unit: OG0VE1B 1/16 line (4), OG0VA1B whole lines (0). */ > + unsigned int exposure_shift; > + /* Pixel rate multiplier: OG0VA1B uses CSI-2 DDR (2), OG0VE1B keeps 1. */ > + unsigned int pixel_rate_mul; > const s64 *link_freq_menu; > int num_link_freqs; > const struct og0ve1b_mode *modes; > int num_modes; > }; > > +static const char * const og0va1b_test_pattern_menu[] = { > + "Disabled", > + "Standard Color Bar", > + "Top-Bottom Darker Color Bar", > + "Right-Left Darker Color Bar", > + "Bottom-Top Darker Color Bar", > +}; > + In the original og0ve1b_test_pattern_menu[] I copied a pretty regular test pattern name "Vertical Colour Bars" inapproptiately, and here the references to "Colour Bars" are also present... Due to quite an obvious reason of sensor specifics would you consider to change the test pattern names to something else?.. Sorry for late comment. -- Best wishes, Vladimir ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v3 3/3] media: i2c: og0ve1b: Add support for OmniVision OG0VA1B 2026-07-24 13:35 ` Vladimir Zapolskiy @ 2026-07-27 9:38 ` Wenmeng Liu 2026-07-27 19:05 ` Vladimir Zapolskiy 0 siblings, 1 reply; 12+ messages in thread From: Wenmeng Liu @ 2026-07-27 9:38 UTC (permalink / raw) To: Vladimir Zapolskiy, Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sakari Ailus Cc: linux-media, devicetree, linux-kernel Hi Vladimir, On 7/24/2026 9:35 PM, Vladimir Zapolskiy wrote: > Hi Wenmeng. > > On 7/8/26 17:33, Wenmeng Liu wrote: >> The OmniVision OG0VA1B is a monochrome image sensor closely related to >> the OG0VE1B. It shares the SCCB control interface, power supplies and >> the single-lane MIPI D-PHY description, and differs in its chip id, the >> test pattern register, the register programming and the output format >> (10-bit RAW instead of 8-bit). >> >> Add an og0ve1b_sensor_data entry describing the OG0VA1B together with >> its 640x480 60fps register sequence. >> >> Signed-off-by: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com> >> --- >> drivers/media/i2c/og0ve1b.c | 278 ++++++++++++++++++++++++++++++++++ >> ++++++++-- >> 1 file changed, 266 insertions(+), 12 deletions(-) >> >> diff --git a/drivers/media/i2c/og0ve1b.c b/drivers/media/i2c/og0ve1b.c >> index >> 041342fbe3c822400388f58a03e6057e186f060f..c558cdd43314931db35e463641dd28e10b94ec8a 100644 >> --- a/drivers/media/i2c/og0ve1b.c >> +++ b/drivers/media/i2c/og0ve1b.c >> @@ -14,10 +14,14 @@ >> #include <media/v4l2-device.h> >> #include <media/v4l2-fwnode.h> >> +#define OG0VA1B_LINK_FREQ_480MHZ (480 * HZ_PER_MHZ) >> +#define OG0VA1B_MCLK_FREQ_19_2MHZ (19200 * HZ_PER_KHZ) >> + >> #define OG0VE1B_LINK_FREQ_500MHZ (500 * HZ_PER_MHZ) >> #define OG0VE1B_MCLK_FREQ_24MHZ (24 * HZ_PER_MHZ) >> -#define OG0VE1B_REG_CHIP_ID CCI_REG24(0x300a) >> +#define OG0V_REG_CHIP_ID CCI_REG24(0x300a) >> +#define OG0VA1B_CHIP_ID 0xc75641 >> #define OG0VE1B_CHIP_ID 0xc75645 >> #define OG0VE1B_REG_MODE_SELECT CCI_REG8(0x0100) >> @@ -45,12 +49,18 @@ >> #define OG0VE1B_REG_VTS CCI_REG16(0x380e) >> #define OG0VE1B_VTS_MAX 0xffff >> -/* Test pattern */ >> +/* Test pattern - OG0VA1B uses 0x5100, OG0VE1B uses 0x5e00 */ >> +#define OG0VA1B_REG_TEST_PATTERN CCI_REG8(0x5100) >> +#define OG0VA1B_TEST_PATTERN_BAR_SHIFT 2 >> #define OG0VE1B_REG_PRE_ISP CCI_REG8(0x5e00) >> #define OG0VE1B_TEST_PATTERN_ENABLE BIT(7) >> #define to_og0ve1b(_sd) container_of(_sd, struct og0ve1b, >> sd) >> +static const s64 og0va1b_link_freq_menu[] = { >> + OG0VA1B_LINK_FREQ_480MHZ, >> +}; >> + >> static const s64 og0ve1b_link_freq_menu[] = { >> OG0VE1B_LINK_FREQ_500MHZ, >> }; >> @@ -73,15 +83,31 @@ struct og0ve1b_mode { >> struct og0ve1b; >> struct og0ve1b_sensor_data { >> + const char *name; >> u64 chip_id; >> unsigned long mclk_freq; >> int (*enable_test_pattern)(struct og0ve1b *og0ve1b, u32 pattern); >> + const char * const *test_pattern_menu; >> + int num_test_patterns; >> + bool cache_test_pattern_reg; >> + /* Exposure register unit: OG0VE1B 1/16 line (4), OG0VA1B whole >> lines (0). */ >> + unsigned int exposure_shift; >> + /* Pixel rate multiplier: OG0VA1B uses CSI-2 DDR (2), OG0VE1B >> keeps 1. */ >> + unsigned int pixel_rate_mul; >> const s64 *link_freq_menu; >> int num_link_freqs; >> const struct og0ve1b_mode *modes; >> int num_modes; >> }; >> +static const char * const og0va1b_test_pattern_menu[] = { >> + "Disabled", >> + "Standard Color Bar", >> + "Top-Bottom Darker Color Bar", >> + "Right-Left Darker Color Bar", >> + "Bottom-Top Darker Color Bar", >> +}; >> + > > In the original og0ve1b_test_pattern_menu[] I copied a pretty regular > test pattern name "Vertical Colour Bars" inapproptiately, and here > the references to "Colour Bars" are also present... Due to quite > an obvious reason of sensor specifics would you consider to change > the test pattern names to something else?.. Sorry for late comment. > Thanks for the review, and no worries about the timing. You're right that "Color Bar" is misleading for a monochrome sensor. The OG0VA1B datasheet names these as "Test Bar", so I've aligned with it: "Disabled", "Standard Test Bar", "Top-Bottom Darker Test Bar", "Right-Left Darker Test Bar", "Bottom-Top Darker Test Bar", For OG0VE1B, "Vertical Colour Bars" has the same issue, Would you like me to update it with "Vertical Darker Test Bars"? Best regards, Wenmeng ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v3 3/3] media: i2c: og0ve1b: Add support for OmniVision OG0VA1B 2026-07-27 9:38 ` Wenmeng Liu @ 2026-07-27 19:05 ` Vladimir Zapolskiy 0 siblings, 0 replies; 12+ messages in thread From: Vladimir Zapolskiy @ 2026-07-27 19:05 UTC (permalink / raw) To: Wenmeng Liu, Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sakari Ailus Cc: linux-media, devicetree, linux-kernel Hi Wenmeng, On 7/27/26 12:38, Wenmeng Liu wrote: > Hi Vladimir, > > On 7/24/2026 9:35 PM, Vladimir Zapolskiy wrote: >> Hi Wenmeng. >> >> On 7/8/26 17:33, Wenmeng Liu wrote: >>> The OmniVision OG0VA1B is a monochrome image sensor closely related to >>> the OG0VE1B. It shares the SCCB control interface, power supplies and >>> the single-lane MIPI D-PHY description, and differs in its chip id, the >>> test pattern register, the register programming and the output format >>> (10-bit RAW instead of 8-bit). >>> >>> Add an og0ve1b_sensor_data entry describing the OG0VA1B together with >>> its 640x480 60fps register sequence. >>> >>> Signed-off-by: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com> >>> --- >>> drivers/media/i2c/og0ve1b.c | 278 ++++++++++++++++++++++++++++++++++ >>> ++++++++-- >>> 1 file changed, 266 insertions(+), 12 deletions(-) >>> >>> diff --git a/drivers/media/i2c/og0ve1b.c b/drivers/media/i2c/og0ve1b.c >>> index >>> 041342fbe3c822400388f58a03e6057e186f060f..c558cdd43314931db35e463641dd28e10b94ec8a 100644 >>> --- a/drivers/media/i2c/og0ve1b.c >>> +++ b/drivers/media/i2c/og0ve1b.c >>> @@ -14,10 +14,14 @@ >>> #include <media/v4l2-device.h> >>> #include <media/v4l2-fwnode.h> >>> +#define OG0VA1B_LINK_FREQ_480MHZ (480 * HZ_PER_MHZ) >>> +#define OG0VA1B_MCLK_FREQ_19_2MHZ (19200 * HZ_PER_KHZ) >>> + >>> #define OG0VE1B_LINK_FREQ_500MHZ (500 * HZ_PER_MHZ) >>> #define OG0VE1B_MCLK_FREQ_24MHZ (24 * HZ_PER_MHZ) >>> -#define OG0VE1B_REG_CHIP_ID CCI_REG24(0x300a) >>> +#define OG0V_REG_CHIP_ID CCI_REG24(0x300a) >>> +#define OG0VA1B_CHIP_ID 0xc75641 >>> #define OG0VE1B_CHIP_ID 0xc75645 >>> #define OG0VE1B_REG_MODE_SELECT CCI_REG8(0x0100) >>> @@ -45,12 +49,18 @@ >>> #define OG0VE1B_REG_VTS CCI_REG16(0x380e) >>> #define OG0VE1B_VTS_MAX 0xffff >>> -/* Test pattern */ >>> +/* Test pattern - OG0VA1B uses 0x5100, OG0VE1B uses 0x5e00 */ >>> +#define OG0VA1B_REG_TEST_PATTERN CCI_REG8(0x5100) >>> +#define OG0VA1B_TEST_PATTERN_BAR_SHIFT 2 >>> #define OG0VE1B_REG_PRE_ISP CCI_REG8(0x5e00) >>> #define OG0VE1B_TEST_PATTERN_ENABLE BIT(7) >>> #define to_og0ve1b(_sd) container_of(_sd, struct og0ve1b, >>> sd) >>> +static const s64 og0va1b_link_freq_menu[] = { >>> + OG0VA1B_LINK_FREQ_480MHZ, >>> +}; >>> + >>> static const s64 og0ve1b_link_freq_menu[] = { >>> OG0VE1B_LINK_FREQ_500MHZ, >>> }; >>> @@ -73,15 +83,31 @@ struct og0ve1b_mode { >>> struct og0ve1b; >>> struct og0ve1b_sensor_data { >>> + const char *name; >>> u64 chip_id; >>> unsigned long mclk_freq; >>> int (*enable_test_pattern)(struct og0ve1b *og0ve1b, u32 pattern); >>> + const char * const *test_pattern_menu; >>> + int num_test_patterns; >>> + bool cache_test_pattern_reg; >>> + /* Exposure register unit: OG0VE1B 1/16 line (4), OG0VA1B whole >>> lines (0). */ >>> + unsigned int exposure_shift; >>> + /* Pixel rate multiplier: OG0VA1B uses CSI-2 DDR (2), OG0VE1B >>> keeps 1. */ >>> + unsigned int pixel_rate_mul; >>> const s64 *link_freq_menu; >>> int num_link_freqs; >>> const struct og0ve1b_mode *modes; >>> int num_modes; >>> }; >>> +static const char * const og0va1b_test_pattern_menu[] = { >>> + "Disabled", >>> + "Standard Color Bar", >>> + "Top-Bottom Darker Color Bar", >>> + "Right-Left Darker Color Bar", >>> + "Bottom-Top Darker Color Bar", >>> +}; >>> + >> >> In the original og0ve1b_test_pattern_menu[] I copied a pretty regular >> test pattern name "Vertical Colour Bars" inapproptiately, and here >> the references to "Colour Bars" are also present... Due to quite >> an obvious reason of sensor specifics would you consider to change >> the test pattern names to something else?.. Sorry for late comment. >> > > Thanks for the review, and no worries about the timing. > > You're right that "Color Bar" is misleading for a monochrome sensor. > The OG0VA1B datasheet names these as "Test Bar", so I've aligned with it: > > "Disabled", > "Standard Test Bar", > "Top-Bottom Darker Test Bar", > "Right-Left Darker Test Bar", > "Bottom-Top Darker Test Bar", > > For OG0VE1B, "Vertical Colour Bars" has the same issue, Would you like > me to update it with "Vertical Darker Test Bars"? Sure, and it will be very much appreciated to get it fixed! Likely the same "Standard Test Bar" name will be good for its description. From my POV the driver is mature, feel free to send v4 with the gained tags, but someone else may provide more review comments. -- Best wishes, Vladimir ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v3 0/3] media: i2c: Add OmniVision OG0VA1B camera sensor driver 2026-07-08 14:33 [PATCH v3 0/3] media: i2c: Add OmniVision OG0VA1B camera sensor driver Wenmeng Liu ` (2 preceding siblings ...) 2026-07-08 14:33 ` [PATCH v3 3/3] media: i2c: og0ve1b: Add support for OmniVision OG0VA1B Wenmeng Liu @ 2026-07-23 2:41 ` Wenmeng Liu 2026-07-28 8:27 ` [PATCH v3 0/3] media: i2c: Add OmniVision OG0VA1B camera sensor driver - IPU and ACPI Alain Cousinie 3 siblings, 1 reply; 12+ messages in thread From: Wenmeng Liu @ 2026-07-23 2:41 UTC (permalink / raw) To: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sakari Ailus, Vladimir Zapolskiy Cc: linux-media, devicetree, linux-kernel, Conor Dooley On 7/8/2026 10:33 PM, Wenmeng Liu wrote: > Add OmniVision OG0VA1B driver support. The OmniVision OG0VA1B is a > 1/10-inch monochrome CMOS VGA image sensor. It outputs 10-bit raw (Y10) > frames at up to 640x480 resolution over a single-lane MIPI CSI-2 > interface and is controlled via an I2C-compatible SCCB bus. > > This driver has been verified(include tpg) on the Purwa EVK. > > Signed-off-by: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com> > --- > Changes in v3: > - Generalise the binding title and description for both sensors. -- Vladimir > - Keep the cached pre_isp read so the OG0VE1B test pattern still works, > select it via a per-sensor callback. -- Bryan, Vladimir > - Rename the "sensor" field to "data", drop bpp (derive from code) and > add og0ve1b_pixel_rate(). -- Vladimir > - Sort defines, rename the shared CHIP_ID reg to OG0V_ and order > og0va1b_data first. -- Vladimir > - Expose all four OG0VA1B test patterns instead of one. > - Link to v2: https://lore.kernel.org/r/20260702-og0va1b-v2-0-0071442caa2a@oss.qualcomm.com > > Changes in v2: > - Integrate OG0VA1B into the existing og0ve1b driver and binding > instead. -- Vladimir > - Link to v1: https://lore.kernel.org/r/20260618-og0va1b-v1-0-dda71bb83009@oss.qualcomm.com > > --- > Wenmeng Liu (3): > dt-bindings: media: i2c: og0ve1b: Add OmniVision OG0VA1B camera sensor > media: i2c: og0ve1b: Introduce per-sensor data structure > media: i2c: og0ve1b: Add support for OmniVision OG0VA1B > > .../bindings/media/i2c/ovti,og0ve1b.yaml | 15 +- > drivers/media/i2c/og0ve1b.c | 375 ++++++++++++++++++--- > 2 files changed, 344 insertions(+), 46 deletions(-) > --- > base-commit: 5c73cd9f0819c1c44e373e3dabb68318b1de1a12 > change-id: 20260618-og0va1b-55bbf3cabb0e > > Best regards, Gentle reminder to review this patchset. Thanks, Wenmeng ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v3 0/3] media: i2c: Add OmniVision OG0VA1B camera sensor driver - IPU and ACPI 2026-07-23 2:41 ` [PATCH v3 0/3] media: i2c: Add OmniVision OG0VA1B camera sensor driver Wenmeng Liu @ 2026-07-28 8:27 ` Alain Cousinie 0 siblings, 0 replies; 12+ messages in thread From: Alain Cousinie @ 2026-07-28 8:27 UTC (permalink / raw) To: wenmeng.liu Cc: conor+dt, conor.dooley, devicetree, krzk+dt, linux-kernel, linux-media, mchehab, robh, sakari.ailus, vladimir.zapolskiy Hello, I am a novice when it comes to the Linux kernel. The og0va1b sensor is also used in laptops (HP, Dell, etc.) with IPU6 and ACPI. I tried this on my HP Spectre 14-eu0xxx laptop, and it seems to work (though it isn't fully functional yet, as other elements are missing). I would like to propose adding this configuration for this sensor. So, I added the ACPI ID—OVTI00AB for og0va1b—to the IPU: +++ b/drivers/media/pci/intel/ipu-bridge.c @@ -73,6 +73,8 @@ IPU_SENSOR_CONFIG("INT3537", 1, 437000000), /* Lontium lt6911uxe */ IPU_SENSOR_CONFIG("INTC10C5", 0), + /* Omnivision OG0VA1B */ + IPU_SENSOR_CONFIG("OVTI00AB", 1, 480000000), /* Omnivision OV01A10 / OV01A1S */ IPU_SENSOR_CONFIG("OVTI01A0", 1, 400000000), IPU_SENSOR_CONFIG("OVTI01AS", 1, 400000000), --- Then, I added the ACPI declaration to `ov0ve1b.c`, following the patches for og0va1b: diff --git a/drivers/media/i2c/og0ve1b.c b/drivers/media/i2c/og0ve1b.c --- a/drivers/media/i2c/og0ve1b.c +++ b/drivers/media/i2c/og0ve1b.c @@ -978,8 +978,11 @@ og0ve1b->dev = &client->dev; og0ve1b->data = i2c_get_match_data(client); - if (!og0ve1b->data) - return -ENODEV; + if (!og0ve1b->data) { + og0ve1b->data = device_get_match_data(&client->dev); + if (!og0ve1b->data) + return -ENODEV; + } v4l2_i2c_subdev_init(&og0ve1b->sd, client, &og0ve1b_subdev_ops); v4l2_i2c_subdev_set_name(&og0ve1b->sd, client, @@ -1114,6 +1117,15 @@ SET_RUNTIME_PM_OPS(og0ve1b_power_off, og0ve1b_power_on, NULL) }; +#ifdef CONFIG_ACPI +static const struct acpi_device_id og0ve1b_acpi_ids[] = { + {"OVTI00AB", (uintptr_t)&og0va1b_data}, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(acpi, og0ve1b_acpi_ids); +#endif + static const struct of_device_id og0ve1b_of_match[] = { { .compatible = "ovti,og0va1b", .data = &og0va1b_data }, { .compatible = "ovti,og0ve1b", .data = &og0ve1b_data }, @@ -1126,6 +1138,7 @@ .name = "og0ve1b", .pm = &og0ve1b_pm_ops, .of_match_table = og0ve1b_of_match, + .acpi_match_table = ACPI_PTR(og0ve1b_acpi_ids), }, .probe = og0ve1b_probe, .remove = og0ve1b_remove, --- Here is an example of my tests: `$ cam -c2 -C1 -Ftest.bin` Using camera \_SB_.PC00.LNK1 as cam0 [3:02:57.280464484] [55404] INFO Camera camera.cpp:1216 configuring streams: (0) 640x480-R10/sYCC cam0: Capture 1 frames 10977.366149 (0.00 fps) cam0-stream0 seq: 000000 bytesused: 614400 This produces a raw image file that I can view using various tools, and it appears to correspond to the sensor. Best Regards, Alain > On 23/07/2026 à 04:41, Wenmeng Liu wrote : >> >> >> On 7/8/2026 10:33 PM, Wenmeng Liu wrote: >>> Add OmniVision OG0VA1B driver support. The OmniVision OG0VA1B is a >>> 1/10-inch monochrome CMOS VGA image sensor. It outputs 10-bit raw (Y10) >>> frames at up to 640x480 resolution over a single-lane MIPI CSI-2 >>> interface and is controlled via an I2C-compatible SCCB bus. >>> >>> This driver has been verified(include tpg) on the Purwa EVK. >>> >>> Signed-off-by: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com> >>> --- >>> Changes in v3: >>> - Generalise the binding title and description for both sensors. -- >>> Vladimir >>> - Keep the cached pre_isp read so the OG0VE1B test pattern still works, >>> select it via a per-sensor callback. -- Bryan, Vladimir >>> - Rename the "sensor" field to "data", drop bpp (derive from code) and >>> add og0ve1b_pixel_rate(). -- Vladimir >>> - Sort defines, rename the shared CHIP_ID reg to OG0V_ and order >>> og0va1b_data first. -- Vladimir >>> - Expose all four OG0VA1B test patterns instead of one. >>> - Link to v2: >>> https://lore.kernel.org/r/20260702-og0va1b-v2-0-0071442caa2a@oss.qualcomm.com >>> >>> Changes in v2: >>> - Integrate OG0VA1B into the existing og0ve1b driver and binding >>> instead. -- Vladimir >>> - Link to v1: >>> https://lore.kernel.org/r/20260618-og0va1b-v1-0-dda71bb83009@oss.qualcomm.com >>> >>> --- >>> Wenmeng Liu (3): >>> dt-bindings: media: i2c: og0ve1b: Add OmniVision OG0VA1B >>> camera sensor >>> media: i2c: og0ve1b: Introduce per-sensor data structure >>> media: i2c: og0ve1b: Add support for OmniVision OG0VA1B >>> >>> .../bindings/media/i2c/ovti,og0ve1b.yaml | 15 +- >>> drivers/media/i2c/og0ve1b.c | 375 >>> ++++++++++++++++++--- >>> 2 files changed, 344 insertions(+), 46 deletions(-) >>> --- >>> base-commit: 5c73cd9f0819c1c44e373e3dabb68318b1de1a12 >>> change-id: 20260618-og0va1b-55bbf3cabb0e >>> >>> Best regards, >> >> >> Gentle reminder to review this patchset. >> >> Thanks, >> Wenmeng >> ^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2026-07-28 12:28 UTC | newest] Thread overview: 12+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-07-08 14:33 [PATCH v3 0/3] media: i2c: Add OmniVision OG0VA1B camera sensor driver Wenmeng Liu 2026-07-08 14:33 ` [PATCH v3 1/3] dt-bindings: media: i2c: og0ve1b: Add OmniVision OG0VA1B camera sensor Wenmeng Liu 2026-07-08 14:33 ` [PATCH v3 2/3] media: i2c: og0ve1b: Introduce per-sensor data structure Wenmeng Liu 2026-07-08 14:45 ` sashiko-bot 2026-07-23 13:48 ` Vladimir Zapolskiy 2026-07-08 14:33 ` [PATCH v3 3/3] media: i2c: og0ve1b: Add support for OmniVision OG0VA1B Wenmeng Liu 2026-07-23 13:51 ` Vladimir Zapolskiy 2026-07-24 13:35 ` Vladimir Zapolskiy 2026-07-27 9:38 ` Wenmeng Liu 2026-07-27 19:05 ` Vladimir Zapolskiy 2026-07-23 2:41 ` [PATCH v3 0/3] media: i2c: Add OmniVision OG0VA1B camera sensor driver Wenmeng Liu 2026-07-28 8:27 ` [PATCH v3 0/3] media: i2c: Add OmniVision OG0VA1B camera sensor driver - IPU and ACPI Alain Cousinie
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox