* [PATCH 0/2] media: i2c: Add OmniVision OG0VA1B camera sensor driver
@ 2026-06-18 10:37 Wenmeng Liu
2026-06-18 10:37 ` [PATCH 1/2] dt-bindings: media: i2c: Add OmniVision OG0VA1B Wenmeng Liu
2026-06-18 10:37 ` [PATCH 2/2] media: i2c: og0va1b: Add OmniVision OG0VA1B camera sensor Wenmeng Liu
0 siblings, 2 replies; 11+ messages in thread
From: Wenmeng Liu @ 2026-06-18 10:37 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Sakari Ailus
Cc: linux-media, devicetree, linux-kernel, Wenmeng Liu
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 on the Purwa EVK.
Signed-off-by: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com>
---
Wenmeng Liu (2):
dt-bindings: media: i2c: Add OmniVision OG0VA1B
media: i2c: og0va1b: Add OmniVision OG0VA1B camera sensor
.../bindings/media/i2c/ovti,og0va1b.yaml | 104 +++
MAINTAINERS | 7 +
drivers/media/i2c/Kconfig | 10 +
drivers/media/i2c/Makefile | 1 +
drivers/media/i2c/og0va1b.c | 867 +++++++++++++++++++++
5 files changed, 989 insertions(+)
---
base-commit: 4fa3f5fabb30bf00d7475d5a33459ea83d639bf9
change-id: 20260618-og0va1b-55bbf3cabb0e
Best regards,
--
Wenmeng Liu <wenmeng.liu@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 1/2] dt-bindings: media: i2c: Add OmniVision OG0VA1B
2026-06-18 10:37 [PATCH 0/2] media: i2c: Add OmniVision OG0VA1B camera sensor driver Wenmeng Liu
@ 2026-06-18 10:37 ` Wenmeng Liu
2026-06-18 10:55 ` Vladimir Zapolskiy
2026-06-18 10:37 ` [PATCH 2/2] media: i2c: og0va1b: Add OmniVision OG0VA1B camera sensor Wenmeng Liu
1 sibling, 1 reply; 11+ messages in thread
From: Wenmeng Liu @ 2026-06-18 10:37 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Sakari Ailus
Cc: linux-media, devicetree, linux-kernel, Wenmeng Liu
Add devicetree binding for OmniVision OG0VA1B image sensor.
OmniVision OG0VA1B is an image sensor, which produces frames in 10-bit
raw output format (Y10) over a 1-lane MIPI CSI-2 interface and supports
the 640x480 (VGA) resolution.
Signed-off-by: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com>
---
.../bindings/media/i2c/ovti,og0va1b.yaml | 104 +++++++++++++++++++++
MAINTAINERS | 6 ++
2 files changed, 110 insertions(+)
diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,og0va1b.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,og0va1b.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..302afc41bb776f75c08b26ac2f04014f8cbea4fa
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/ovti,og0va1b.yaml
@@ -0,0 +1,104 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/ovti,og0va1b.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: OmniVision OG0VA1B Image Sensor
+
+maintainers:
+ - Wenmeng Liu <wenmeng.liu@oss.qualcomm.com>
+
+description:
+ The OmniVision OG0VA1B is a 1/10-inch black and white CMOS VGA (640x480)
+ image sensor. It is controlled over an I2C-compatible SCCB bus and transmits
+ images on a 1-lane MIPI CSI-2 output interface.
+
+allOf:
+ - $ref: /schemas/media/video-interface-devices.yaml#
+
+properties:
+ compatible:
+ const: ovti,og0va1b
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ reset-gpios:
+ description: Active low GPIO connected to XSHUTDN pad of the sensor.
+ maxItems: 1
+
+ avdd-supply:
+ description: Analogue circuit voltage supply.
+
+ dovdd-supply:
+ description: I/O circuit voltage supply.
+
+ dvdd-supply:
+ description: Digital circuit voltage supply.
+
+ port:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ additionalProperties: false
+ description:
+ Output port node, single endpoint describing the CSI-2 transmitter.
+
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+ unevaluatedProperties: false
+
+ properties:
+ data-lanes:
+ description: OG0VA1B supports a single MIPI CSI-2 data lane only.
+ items:
+ - const: 1
+
+ link-frequencies: true
+
+ required:
+ - data-lanes
+ - link-frequencies
+
+ required:
+ - endpoint
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - port
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sensor@36 {
+ compatible = "ovti,og0va1b";
+ reg = <0x36>;
+ clocks = <&clk 0>;
+ reset-gpios = <&gpio 42 GPIO_ACTIVE_LOW>;
+ avdd-supply = <&vreg_2v8>;
+ dovdd-supply = <&vreg_1v8>;
+ dvdd-supply = <&vreg_1v2>;
+
+ port {
+ og0va1b_ep: endpoint {
+ remote-endpoint = <&csiphy_ep>;
+ data-lanes = <1>;
+ link-frequencies = /bits/ 64 <480000000>;
+ };
+ };
+ };
+ };
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index 069b4aa6b523c72b661418d8f37cd214a061f9af..5aa846c8479b20651291d5bd2e316308310f826c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -19886,6 +19886,12 @@ S: Maintained
F: Documentation/devicetree/bindings/media/i2c/ovti,og01a1b.yaml
F: drivers/media/i2c/og01a1b.c
+OMNIVISION OG0VA1B SENSOR DRIVER
+M: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com>
+L: linux-media@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/media/i2c/ovti,og0va1b.yaml
+
OMNIVISION OG0VE1B SENSOR DRIVER
M: Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
L: linux-media@vger.kernel.org
--
2.34.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 2/2] media: i2c: og0va1b: Add OmniVision OG0VA1B camera sensor
2026-06-18 10:37 [PATCH 0/2] media: i2c: Add OmniVision OG0VA1B camera sensor driver Wenmeng Liu
2026-06-18 10:37 ` [PATCH 1/2] dt-bindings: media: i2c: Add OmniVision OG0VA1B Wenmeng Liu
@ 2026-06-18 10:37 ` Wenmeng Liu
2026-06-18 10:47 ` sashiko-bot
` (2 more replies)
1 sibling, 3 replies; 11+ messages in thread
From: Wenmeng Liu @ 2026-06-18 10:37 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Sakari Ailus
Cc: linux-media, devicetree, linux-kernel, Wenmeng Liu
Add V4L2 sub device driver for OmniVision OG0VA1B image sensor.
OmniVision OG0VA1B is an image sensor, which produces frames in 10-bit
raw output format (Y10) over a 1-lane MIPI CSI-2 interface and supports
the 640x480 (VGA) resolution.
Signed-off-by: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com>
---
MAINTAINERS | 1 +
drivers/media/i2c/Kconfig | 10 +
drivers/media/i2c/Makefile | 1 +
drivers/media/i2c/og0va1b.c | 867 ++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 879 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 5aa846c8479b20651291d5bd2e316308310f826c..85a06eb9eacc410a565b80d56979eaa565515d0e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -19891,6 +19891,7 @@ M: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com>
L: linux-media@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/media/i2c/ovti,og0va1b.yaml
+F: drivers/media/i2c/og0va1b.c
OMNIVISION OG0VE1B SENSOR DRIVER
M: Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 5d173e0ecf424f2f204f8d426be818e44357f8e4..56680772f5f47b4629c4e17f5a5feba08b1d94fc 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -363,6 +363,16 @@ config VIDEO_OG01A1B
To compile this driver as a module, choose M here: the
module will be called og01a1b.
+config VIDEO_OG0VA1B
+ tristate "OmniVision OG0VA1B sensor support"
+ select V4L2_CCI_I2C
+ help
+ This is a Video4Linux2 sensor driver for the OmniVision
+ OG0VA1B camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called og0va1b.
+
config VIDEO_OG0VE1B
tristate "OmniVision OG0VE1B sensor support"
select V4L2_CCI_I2C
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index e45359efe0e41e13e3c0869e5ead7d6cf4aca3a7..c60851c7fe07e3bdc511c5f482525ba7a044f48e 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -83,6 +83,7 @@ obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o
obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o
obj-$(CONFIG_VIDEO_MT9V111) += mt9v111.o
obj-$(CONFIG_VIDEO_OG01A1B) += og01a1b.o
+obj-$(CONFIG_VIDEO_OG0VA1B) += og0va1b.o
obj-$(CONFIG_VIDEO_OG0VE1B) += og0ve1b.o
obj-$(CONFIG_VIDEO_OS05B10) += os05b10.o
obj-$(CONFIG_VIDEO_OV01A10) += ov01a10.o
diff --git a/drivers/media/i2c/og0va1b.c b/drivers/media/i2c/og0va1b.c
new file mode 100644
index 0000000000000000000000000000000000000000..f0505b7ba7f329ad57ffafa8f90a24204f002d3c
--- /dev/null
+++ b/drivers/media/i2c/og0va1b.c
@@ -0,0 +1,867 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * OmniVision OG0VA1B Camera Sensor Driver
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+
+#include <media/v4l2-cci.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
+
+#define OG0VA1B_REG_CHIP_ID CCI_REG16(0x300a)
+#define OG0VA1B_CHIP_ID 0xC756
+
+#define OG0VA1B_REG_SW_RESET CCI_REG8(0x103)
+#define OG0VA1B_SW_RESET BIT(0)
+
+#define OG0VA1B_REG_STREAMING CCI_REG8(0x100)
+#define OG0VA1B_STREAMING_ON BIT(0)
+
+/* Exposure: 16-bit coarse integration time at 0x3501/0x3502 */
+#define OG0VA1B_REG_EXPOSURE CCI_REG16(0x3501)
+#define OG0VA1B_EXPOSURE_MIN 1
+#define OG0VA1B_EXPOSURE_STEP 1
+#define OG0VA1B_EXPOSURE_DEFAULT 0x100
+
+#define OG0VA1B_REG_GAIN_H CCI_REG8(0x3508)
+#define OG0VA1B_REG_GAIN_L CCI_REG8(0x3509)
+#define OG0VA1B_GAIN_MIN 0x10
+#define OG0VA1B_GAIN_MAX 0x1ff
+#define OG0VA1B_GAIN_STEP 1
+#define OG0VA1B_GAIN_DEFAULT 0x10
+
+#define OG0VA1B_REG_VTS CCI_REG16(0x380e)
+
+/* Test pattern: register 0x5100, BIT(7) = enable, BIT[3:2] = bar style */
+#define OG0VA1B_REG_TEST_PATTERN CCI_REG8(0x5100)
+#define OG0VA1B_TEST_PATTERN_EN BIT(7)
+#define OG0VA1B_TEST_PATTERN_BAR_SHIFT 2
+
+#define OG0VA1B_EXPOSURE_MARGIN 14
+#define OG0VA1B_VBLANK_MIN OG0VA1B_EXPOSURE_MARGIN
+
+#define OG0VA1B_XVCLK_RATE 19200000UL
+
+#define OG0VA1B_AUTOSUSPEND_DELAY_MS 1000
+
+static const s64 og0va1b_link_freqs[] = {
+ 480000000,
+};
+
+#define OG0VA1B_PIXEL_RATE 48000000UL
+#define OG0VA1B_LINK_FREQ_INDEX 0
+
+#define OG0VA1B_DATA_LANES 1
+
+static const char * const og0va1b_supply_names[] = {
+ "avdd", /* VANA */
+ "dovdd", /* VIO */
+ "dvdd", /* VDIG */
+};
+
+#define OG0VA1B_NUM_SUPPLIES ARRAY_SIZE(og0va1b_supply_names)
+
+struct og0va1b_mode {
+ u32 width;
+ u32 height;
+ u32 hts;
+ u32 vts;
+ u32 num_regs;
+ const struct cci_reg_sequence *regs;
+};
+
+/* VGA 640x480 @ 60 fps */
+static const struct cci_reg_sequence og0va1b_vga_60fps_regs[] = {
+ { 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(0x3022), 0x01 },
+ { CCI_REG8(0x3040), 0x0f },
+ { CCI_REG8(0x3107), 0x40 },
+ { CCI_REG8(0x3216), 0x01 },
+ { CCI_REG8(0x3217), 0x00 },
+ { CCI_REG8(0x3218), 0xc0 },
+ { CCI_REG8(0x3219), 0x55 },
+ { CCI_REG8(0x3500), 0x00 },
+ { CCI_REG8(0x3501), 0x00 },
+ { CCI_REG8(0x3502), 0x01 },
+ { 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(0x389f), 0x08 },
+ { CCI_REG8(0x38a0), 0x00 },
+ { CCI_REG8(0x38a1), 0x00 },
+ { 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(0x391e), 0x01 },
+ { 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(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(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 },
+ { CCI_REG8(0x481b), 0x44 },
+ { CCI_REG8(0x481f), 0x30 },
+ { CCI_REG8(0x4823), 0x44 },
+ { CCI_REG8(0x4825), 0x35 },
+ { CCI_REG8(0x4837), 0x11 },
+};
+
+static const struct og0va1b_mode og0va1b_modes[] = {
+ {
+ .width = 640,
+ .height = 480,
+ .hts = 376,
+ .vts = 2096,
+ .num_regs = ARRAY_SIZE(og0va1b_vga_60fps_regs),
+ .regs = og0va1b_vga_60fps_regs,
+ },
+};
+
+struct og0va1b {
+ struct v4l2_subdev sd;
+ struct media_pad pad;
+ struct regmap *regmap;
+ struct clk *inclk;
+ struct gpio_desc *reset_gpio;
+ struct regulator_bulk_data supplies[OG0VA1B_NUM_SUPPLIES];
+
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct v4l2_ctrl *link_freq;
+ struct v4l2_ctrl *pixel_rate;
+ struct v4l2_ctrl *vblank;
+ struct v4l2_ctrl *hblank;
+ struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *gain;
+ struct v4l2_ctrl *test_pattern;
+};
+
+static inline struct og0va1b *sd_to_og0va1b(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct og0va1b, sd);
+}
+
+static int og0va1b_power_on(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct og0va1b *og0va1b = sd_to_og0va1b(sd);
+ int ret;
+
+ ret = regulator_bulk_enable(OG0VA1B_NUM_SUPPLIES, og0va1b->supplies);
+ if (ret) {
+ dev_err(dev, "failed to enable regulators: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(og0va1b->inclk);
+ if (ret) {
+ dev_err(dev, "failed to enable clock: %d\n", ret);
+ goto err_regulators;
+ }
+
+ gpiod_set_value_cansleep(og0va1b->reset_gpio, 0);
+
+ usleep_range(18000, 20000);
+
+ return 0;
+
+err_regulators:
+ regulator_bulk_disable(OG0VA1B_NUM_SUPPLIES, og0va1b->supplies);
+ return ret;
+}
+
+static int og0va1b_power_off(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct og0va1b *og0va1b = sd_to_og0va1b(sd);
+
+ clk_disable_unprepare(og0va1b->inclk);
+ gpiod_set_value_cansleep(og0va1b->reset_gpio, 1);
+ regulator_bulk_disable(OG0VA1B_NUM_SUPPLIES, og0va1b->supplies);
+
+ return 0;
+}
+
+static int og0va1b_check_id(struct og0va1b *og0va1b)
+{
+ struct device *dev = og0va1b->sd.dev;
+ u64 chip_id;
+ int ret;
+
+ ret = cci_read(og0va1b->regmap, OG0VA1B_REG_CHIP_ID, &chip_id, NULL);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to read chip ID\n");
+
+ if (chip_id != OG0VA1B_CHIP_ID)
+ return dev_err_probe(dev, -ENODEV,
+ "unexpected chip ID 0x%04llx (expected 0x%04x)\n",
+ chip_id, OG0VA1B_CHIP_ID);
+
+ return 0;
+}
+
+static int og0va1b_check_hwcfg(struct device *dev)
+{
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
+ struct v4l2_fwnode_endpoint bus_cfg = {
+ .bus_type = V4L2_MBUS_CSI2_DPHY,
+ };
+ struct fwnode_handle *ep;
+ unsigned int i;
+ int ret;
+
+ if (!fwnode)
+ return -ENXIO;
+
+ ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
+ if (!ep)
+ return dev_err_probe(dev, -ENXIO, "no endpoint found\n");
+
+ ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
+ fwnode_handle_put(ep);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to parse endpoint\n");
+
+ if (bus_cfg.bus.mipi_csi2.num_data_lanes != OG0VA1B_DATA_LANES) {
+ ret = dev_err_probe(dev, -EINVAL,
+ "unsupported number of CSI2 data lanes %u\n",
+ bus_cfg.bus.mipi_csi2.num_data_lanes);
+ goto err_free;
+ }
+
+ if (!bus_cfg.nr_of_link_frequencies) {
+ ret = dev_err_probe(dev, -EINVAL,
+ "no link frequencies defined\n");
+ goto err_free;
+ }
+
+ for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++)
+ if (bus_cfg.link_frequencies[i] ==
+ og0va1b_link_freqs[OG0VA1B_LINK_FREQ_INDEX])
+ break;
+
+ if (i == bus_cfg.nr_of_link_frequencies)
+ ret = dev_err_probe(dev, -EINVAL,
+ "no supported link frequency %lld found\n",
+ og0va1b_link_freqs[OG0VA1B_LINK_FREQ_INDEX]);
+
+err_free:
+ v4l2_fwnode_endpoint_free(&bus_cfg);
+
+ return ret;
+}
+
+static int og0va1b_init(struct og0va1b *og0va1b,
+ const struct og0va1b_mode *mode)
+{
+ int ret;
+
+ ret = cci_write(og0va1b->regmap, OG0VA1B_REG_SW_RESET,
+ OG0VA1B_SW_RESET, NULL);
+ if (ret)
+ return ret;
+
+ usleep_range(5000, 6000);
+
+ return cci_multi_reg_write(og0va1b->regmap, mode->regs, mode->num_regs,
+ NULL);
+}
+
+static int og0va1b_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct og0va1b *og0va1b =
+ container_of(ctrl->handler, struct og0va1b, ctrl_handler);
+ const struct og0va1b_mode *mode = &og0va1b_modes[0];
+ int ret = 0;
+
+ if (ctrl->id == V4L2_CID_VBLANK) {
+ int exp_max = mode->height + ctrl->val - OG0VA1B_EXPOSURE_MARGIN;
+
+ ret = __v4l2_ctrl_modify_range(og0va1b->exposure,
+ og0va1b->exposure->minimum,
+ exp_max,
+ og0va1b->exposure->step,
+ min(og0va1b->exposure->val, exp_max));
+ if (ret)
+ return ret;
+ }
+
+ if (!pm_runtime_get_if_active(og0va1b->sd.dev))
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE:
+ ret = cci_write(og0va1b->regmap, OG0VA1B_REG_EXPOSURE,
+ ctrl->val, NULL);
+ break;
+
+ case V4L2_CID_ANALOGUE_GAIN:
+ ret = cci_write(og0va1b->regmap, OG0VA1B_REG_GAIN_H,
+ (ctrl->val >> 4) & 0x1f, NULL);
+ if (!ret)
+ ret = cci_write(og0va1b->regmap, OG0VA1B_REG_GAIN_L,
+ (ctrl->val & 0xf) << 4, NULL);
+ break;
+
+ case V4L2_CID_VBLANK:
+ ret = cci_write(og0va1b->regmap, OG0VA1B_REG_VTS,
+ mode->height + ctrl->val, NULL);
+ break;
+
+ case V4L2_CID_TEST_PATTERN:
+ if (ctrl->val)
+ ret = cci_write(og0va1b->regmap,
+ OG0VA1B_REG_TEST_PATTERN,
+ (ctrl->val - 1) << OG0VA1B_TEST_PATTERN_BAR_SHIFT |
+ OG0VA1B_TEST_PATTERN_EN, NULL);
+ else
+ ret = cci_write(og0va1b->regmap,
+ OG0VA1B_REG_TEST_PATTERN, 0, NULL);
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ pm_runtime_put_autosuspend(og0va1b->sd.dev);
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops og0va1b_ctrl_ops = {
+ .s_ctrl = og0va1b_s_ctrl,
+};
+
+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 void og0va1b_fill_format(const struct og0va1b_mode *mode,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ fmt->width = mode->width;
+ fmt->height = mode->height;
+ fmt->code = MEDIA_BUS_FMT_Y10_1X10;
+ fmt->field = V4L2_FIELD_NONE;
+ fmt->colorspace = V4L2_COLORSPACE_RAW;
+ fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ fmt->quantization = V4L2_QUANTIZATION_DEFAULT;
+ fmt->xfer_func = V4L2_XFER_FUNC_NONE;
+}
+
+static int og0va1b_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index != 0)
+ return -EINVAL;
+
+ code->code = MEDIA_BUS_FMT_Y10_1X10;
+ return 0;
+}
+
+static int og0va1b_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ if (fse->code != MEDIA_BUS_FMT_Y10_1X10 ||
+ fse->index >= ARRAY_SIZE(og0va1b_modes))
+ return -EINVAL;
+
+ fse->min_width = og0va1b_modes[fse->index].width;
+ fse->max_width = og0va1b_modes[fse->index].width;
+ fse->min_height = og0va1b_modes[fse->index].height;
+ fse->max_height = og0va1b_modes[fse->index].height;
+ return 0;
+}
+
+static int og0va1b_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *fmt)
+{
+ const struct og0va1b_mode *mode;
+ struct v4l2_mbus_framefmt *format;
+
+ mode = v4l2_find_nearest_size(og0va1b_modes,
+ ARRAY_SIZE(og0va1b_modes),
+ width, height,
+ fmt->format.width, fmt->format.height);
+
+ og0va1b_fill_format(mode, &fmt->format);
+
+ format = v4l2_subdev_state_get_format(state, 0);
+ *format = fmt->format;
+
+ return 0;
+}
+
+static int og0va1b_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ struct v4l2_mbus_framefmt *fmt =
+ v4l2_subdev_state_get_format(state, 0);
+
+ og0va1b_fill_format(&og0va1b_modes[0], fmt);
+ return 0;
+}
+
+static int og0va1b_enable_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ u32 pad, u64 streams_mask)
+{
+ struct og0va1b *og0va1b = sd_to_og0va1b(sd);
+ const struct og0va1b_mode *mode = &og0va1b_modes[0];
+ int ret;
+
+ ret = pm_runtime_resume_and_get(og0va1b->sd.dev);
+ if (ret < 0)
+ return ret;
+
+ ret = og0va1b_init(og0va1b, mode);
+ if (ret)
+ goto err_pm;
+
+ ret = __v4l2_ctrl_handler_setup(&og0va1b->ctrl_handler);
+ if (ret)
+ goto err_pm;
+
+ ret = cci_write(og0va1b->regmap, OG0VA1B_REG_STREAMING,
+ OG0VA1B_STREAMING_ON, NULL);
+ if (ret)
+ goto err_pm;
+
+ return 0;
+
+err_pm:
+ pm_runtime_put_autosuspend(og0va1b->sd.dev);
+ return ret;
+}
+
+static int og0va1b_disable_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ u32 pad, u64 streams_mask)
+{
+ struct og0va1b *og0va1b = sd_to_og0va1b(sd);
+ int ret;
+
+ ret = cci_write(og0va1b->regmap, OG0VA1B_REG_STREAMING, 0, NULL);
+ if (ret)
+ dev_warn(og0va1b->sd.dev,
+ "failed to stop streaming: %d\n", ret);
+
+ usleep_range(5000, 6000);
+ pm_runtime_put_autosuspend(og0va1b->sd.dev);
+
+ return 0;
+}
+
+static const struct dev_pm_ops og0va1b_pm_ops = {
+ SET_RUNTIME_PM_OPS(og0va1b_power_off, og0va1b_power_on, NULL)
+};
+
+static const struct v4l2_subdev_video_ops og0va1b_video_ops = {
+ .s_stream = v4l2_subdev_s_stream_helper,
+};
+
+static const struct v4l2_subdev_pad_ops og0va1b_pad_ops = {
+ .enum_mbus_code = og0va1b_enum_mbus_code,
+ .enum_frame_size = og0va1b_enum_frame_size,
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = og0va1b_set_fmt,
+ .enable_streams = og0va1b_enable_streams,
+ .disable_streams = og0va1b_disable_streams,
+};
+
+static const struct v4l2_subdev_ops og0va1b_subdev_ops = {
+ .video = &og0va1b_video_ops,
+ .pad = &og0va1b_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops og0va1b_internal_ops = {
+ .init_state = og0va1b_init_state,
+};
+
+static const struct media_entity_operations og0va1b_entity_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+static int og0va1b_init_controls(struct og0va1b *og0va1b)
+{
+ struct v4l2_ctrl_handler *hdl = &og0va1b->ctrl_handler;
+ const struct og0va1b_mode *mode = &og0va1b_modes[0];
+ struct v4l2_fwnode_device_properties props;
+ int vblank_def = mode->vts - mode->height;
+ int vblank_max = 0xffff - mode->height;
+ int hblank_val = mode->hts - mode->width;
+ int ret;
+
+ v4l2_ctrl_handler_init(hdl, 9);
+
+ og0va1b->link_freq =
+ v4l2_ctrl_new_int_menu(hdl, NULL, V4L2_CID_LINK_FREQ,
+ ARRAY_SIZE(og0va1b_link_freqs) - 1, 0,
+ og0va1b_link_freqs);
+ if (og0va1b->link_freq)
+ og0va1b->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ og0va1b->pixel_rate =
+ v4l2_ctrl_new_std(hdl, NULL, V4L2_CID_PIXEL_RATE,
+ OG0VA1B_PIXEL_RATE, OG0VA1B_PIXEL_RATE, 1,
+ OG0VA1B_PIXEL_RATE);
+
+ og0va1b->vblank =
+ v4l2_ctrl_new_std(hdl, &og0va1b_ctrl_ops, V4L2_CID_VBLANK,
+ OG0VA1B_VBLANK_MIN, vblank_max, 1, vblank_def);
+
+ og0va1b->hblank =
+ v4l2_ctrl_new_std(hdl, NULL, V4L2_CID_HBLANK,
+ hblank_val, hblank_val, 1, hblank_val);
+ if (og0va1b->hblank)
+ og0va1b->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ og0va1b->exposure =
+ v4l2_ctrl_new_std(hdl, &og0va1b_ctrl_ops, V4L2_CID_EXPOSURE,
+ OG0VA1B_EXPOSURE_MIN,
+ mode->vts - OG0VA1B_EXPOSURE_MARGIN,
+ OG0VA1B_EXPOSURE_STEP,
+ OG0VA1B_EXPOSURE_DEFAULT);
+
+ og0va1b->gain =
+ v4l2_ctrl_new_std(hdl, &og0va1b_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
+ OG0VA1B_GAIN_MIN, OG0VA1B_GAIN_MAX,
+ OG0VA1B_GAIN_STEP, OG0VA1B_GAIN_DEFAULT);
+
+ og0va1b->test_pattern =
+ v4l2_ctrl_new_std_menu_items(hdl, &og0va1b_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(og0va1b_test_pattern_menu) - 1,
+ 0, 0, og0va1b_test_pattern_menu);
+
+ ret = v4l2_fwnode_device_parse(og0va1b->sd.dev, &props);
+ if (ret)
+ goto err_free;
+
+ ret = v4l2_ctrl_new_fwnode_properties(hdl, &og0va1b_ctrl_ops, &props);
+ if (ret)
+ goto err_free;
+
+ if (hdl->error) {
+ ret = hdl->error;
+ goto err_free;
+ }
+
+ og0va1b->sd.ctrl_handler = hdl;
+ return 0;
+
+err_free:
+ v4l2_ctrl_handler_free(hdl);
+ return ret;
+}
+
+static int og0va1b_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct og0va1b *og0va1b;
+ unsigned long clk_rate;
+ unsigned int i;
+ int ret;
+
+ og0va1b = devm_kzalloc(dev, sizeof(*og0va1b), GFP_KERNEL);
+ if (!og0va1b)
+ return -ENOMEM;
+
+ v4l2_i2c_subdev_init(&og0va1b->sd, client, &og0va1b_subdev_ops);
+ og0va1b->sd.internal_ops = &og0va1b_internal_ops;
+ og0va1b->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ og0va1b->inclk = devm_v4l2_sensor_clk_get(dev, NULL);
+ if (IS_ERR(og0va1b->inclk))
+ return dev_err_probe(dev, PTR_ERR(og0va1b->inclk),
+ "failed to get clock\n");
+
+ clk_rate = clk_get_rate(og0va1b->inclk);
+ if (clk_rate != OG0VA1B_XVCLK_RATE)
+ return dev_err_probe(dev, -EINVAL,
+ "clock rate %lu Hz != required %lu Hz\n",
+ clk_rate, OG0VA1B_XVCLK_RATE);
+
+ ret = og0va1b_check_hwcfg(dev);
+ if (ret)
+ return ret;
+
+ og0va1b->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(og0va1b->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(og0va1b->reset_gpio),
+ "failed to get reset GPIO\n");
+
+ for (i = 0; i < OG0VA1B_NUM_SUPPLIES; i++)
+ og0va1b->supplies[i].supply = og0va1b_supply_names[i];
+
+ ret = devm_regulator_bulk_get(dev, OG0VA1B_NUM_SUPPLIES,
+ og0va1b->supplies);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to get regulators\n");
+
+ og0va1b->regmap = devm_cci_regmap_init_i2c(client, 16);
+ if (IS_ERR(og0va1b->regmap))
+ return dev_err_probe(dev, PTR_ERR(og0va1b->regmap),
+ "failed to init CCI regmap\n");
+
+ ret = og0va1b_power_on(dev);
+ if (ret)
+ return ret;
+
+ ret = og0va1b_check_id(og0va1b);
+ if (ret)
+ goto err_power_off;
+
+ ret = og0va1b_init_controls(og0va1b);
+ if (ret)
+ goto err_power_off;
+
+ og0va1b->sd.entity.ops = &og0va1b_entity_ops;
+ og0va1b->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+ og0va1b->pad.flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_pads_init(&og0va1b->sd.entity, 1, &og0va1b->pad);
+ if (ret)
+ goto err_controls;
+
+ og0va1b->sd.state_lock = og0va1b->ctrl_handler.lock;
+ ret = v4l2_subdev_init_finalize(&og0va1b->sd);
+ if (ret)
+ goto err_entity;
+
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ ret = v4l2_async_register_subdev_sensor(&og0va1b->sd);
+ if (ret)
+ goto err_pm;
+
+ pm_runtime_set_autosuspend_delay(dev, OG0VA1B_AUTOSUSPEND_DELAY_MS);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_idle(dev);
+
+ return 0;
+
+err_pm:
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+err_entity:
+ v4l2_subdev_cleanup(&og0va1b->sd);
+ media_entity_cleanup(&og0va1b->sd.entity);
+err_controls:
+ v4l2_ctrl_handler_free(&og0va1b->ctrl_handler);
+err_power_off:
+ og0va1b_power_off(dev);
+
+ return ret;
+}
+
+static void og0va1b_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct device *dev = &client->dev;
+
+ v4l2_async_unregister_subdev(sd);
+ v4l2_subdev_cleanup(sd);
+ v4l2_ctrl_handler_free(sd->ctrl_handler);
+ media_entity_cleanup(&sd->entity);
+
+ pm_runtime_dont_use_autosuspend(dev);
+ pm_runtime_disable(dev);
+
+ if (!pm_runtime_status_suspended(dev))
+ og0va1b_power_off(dev);
+
+ pm_runtime_set_suspended(dev);
+}
+
+static const struct i2c_device_id og0va1b_id[] = {
+ { "og0va1b" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, og0va1b_id);
+
+static const struct of_device_id og0va1b_of_match[] = {
+ { .compatible = "ovti,og0va1b" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, og0va1b_of_match);
+
+static struct i2c_driver og0va1b_i2c_driver = {
+ .driver = {
+ .name = "og0va1b",
+ .of_match_table = og0va1b_of_match,
+ .pm = pm_ptr(&og0va1b_pm_ops),
+ },
+ .probe = og0va1b_probe,
+ .remove = og0va1b_remove,
+ .id_table = og0va1b_id,
+};
+module_i2c_driver(og0va1b_i2c_driver);
+
+MODULE_AUTHOR("Wenmeng Liu <wenmeng.liu@oss.qualcomm.com>");
+MODULE_DESCRIPTION("OmniVision OG0VA1B sensor driver");
+MODULE_LICENSE("GPL");
--
2.34.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH 2/2] media: i2c: og0va1b: Add OmniVision OG0VA1B camera sensor
2026-06-18 10:37 ` [PATCH 2/2] media: i2c: og0va1b: Add OmniVision OG0VA1B camera sensor Wenmeng Liu
@ 2026-06-18 10:47 ` sashiko-bot
2026-06-18 10:50 ` Vladimir Zapolskiy
2026-06-18 17:27 ` Uwe Kleine-König
2 siblings, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-06-18 10:47 UTC (permalink / raw)
To: Wenmeng Liu; +Cc: robh, conor+dt, devicetree
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] The driver calculates V4L2_CID_HBLANK as a physically impossible negative value and underreports V4L2_CID_PIXEL_RATE.
- [Medium] Missing `pm_runtime_mark_last_busy()` defeats the configured autosuspend delay.
- [Medium] The power-off sequence incorrectly disables the clock before asserting reset.
--
commit fdebdbb98b4ed425fa89fd8e9a84a3dd03b711db
Author: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com>
media: i2c: og0va1b: Add OmniVision OG0VA1B camera sensor
Add V4L2 sub device driver for OmniVision OG0VA1B image sensor.
OmniVision OG0VA1B is an image sensor, which produces frames in 10-bit
raw output format (Y10) over a 1-lane MIPI CSI-2 interface and supports
the 640x480 (VGA) resolution.
> diff --git a/drivers/media/i2c/og0va1b.c b/drivers/media/i2c/og0va1b.c
> new file mode 100644
> index 0000000000000..f0505b7ba7f32
> --- /dev/null
> +++ b/drivers/media/i2c/og0va1b.c
[ ... ]
> +static const struct og0va1b_mode og0va1b_modes[] = {
> + {
> + .width = 640,
> + .height = 480,
> + .hts = 376,
> + .vts = 2096,
[Severity: High]
Does this code underreport the pixel rate and result in a physically
impossible negative value for the horizontal blanking?
Looking at og0va1b_modes, hts is 376 and width is 640. Later in
og0va1b_init_controls(), hblank_val is calculated as hts - width, which
equals -264:
og0va1b_init_controls() {
...
int hblank_val = mode->hts - mode->width;
...
og0va1b->hblank =
v4l2_ctrl_new_std(hdl, NULL, V4L2_CID_HBLANK,
hblank_val, hblank_val, 1, hblank_val);
}
Could the 376 value represent clock cycles rather than pixels, where the
sensor outputs 2 pixels per clock? If so, should hts be defined in pixels
(752) and the V4L2_CID_PIXEL_RATE be set to 96 MHz (for 10-bit raw over a
480 MHz link) to comply with V4L2 standards?
[ ... ]
> +static int og0va1b_power_off(struct device *dev)
> +{
> + struct v4l2_subdev *sd = dev_get_drvdata(dev);
> + struct og0va1b *og0va1b = sd_to_og0va1b(sd);
> +
> + clk_disable_unprepare(og0va1b->inclk);
> + gpiod_set_value_cansleep(og0va1b->reset_gpio, 1);
[Severity: Medium]
Does this sequence leave the sensor in a dangling state?
The power-off sequence disables the input clock before asserting the hardware
reset GPIO. To ensure the sensor's internal state machine enters reset cleanly,
should the reset line be asserted while the clock is still running?
[ ... ]
> +static int og0va1b_s_ctrl(struct v4l2_ctrl *ctrl)
> +{
[ ... ]
> + switch (ctrl->id) {
> + case V4L2_CID_EXPOSURE:
[ ... ]
> + default:
> + ret = -EINVAL;
> + break;
> + }
> +
> + pm_runtime_put_autosuspend(og0va1b->sd.dev);
> + return ret;
> +}
[Severity: Medium]
Will this defeat the configured autosuspend delay?
The driver explicitly configures an autosuspend delay of 1000ms in probe(),
but calls pm_runtime_put_autosuspend() here without first updating the
last_busy timestamp via pm_runtime_mark_last_busy().
Without the updated timestamp, the runtime PM core might evaluate the
autosuspend timer as already expired, causing the device to power off
synchronously.
[ ... ]
> +static int og0va1b_disable_streams(struct v4l2_subdev *sd,
> + struct v4l2_subdev_state *state,
> + u32 pad, u64 streams_mask)
> +{
> + struct og0va1b *og0va1b = sd_to_og0va1b(sd);
> + int ret;
> +
> + ret = cci_write(og0va1b->regmap, OG0VA1B_REG_STREAMING, 0, NULL);
> + if (ret)
> + dev_warn(og0va1b->sd.dev,
> + "failed to stop streaming: %d\n", ret);
> +
> + usleep_range(5000, 6000);
> + pm_runtime_put_autosuspend(og0va1b->sd.dev);
> +
> + return 0;
> +}
[Severity: Medium]
Similarly, does the missing pm_runtime_mark_last_busy() call before
pm_runtime_put_autosuspend() here cause immediate device suspend, defeating
the autosuspend timer?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260618-og0va1b-v1-0-dda71bb83009@oss.qualcomm.com?part=2
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 2/2] media: i2c: og0va1b: Add OmniVision OG0VA1B camera sensor
2026-06-18 10:37 ` [PATCH 2/2] media: i2c: og0va1b: Add OmniVision OG0VA1B camera sensor Wenmeng Liu
2026-06-18 10:47 ` sashiko-bot
@ 2026-06-18 10:50 ` Vladimir Zapolskiy
2026-06-18 12:36 ` Wenmeng Liu
2026-06-18 17:27 ` Uwe Kleine-König
2 siblings, 1 reply; 11+ messages in thread
From: Vladimir Zapolskiy @ 2026-06-18 10:50 UTC (permalink / raw)
To: Wenmeng Liu, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sakari Ailus
Cc: linux-media, devicetree, linux-kernel
Hello Wenmeng.
On 6/18/26 13:37, Wenmeng Liu wrote:
> Add V4L2 sub device driver for OmniVision OG0VA1B image sensor.
> OmniVision OG0VA1B is an image sensor, which produces frames in 10-bit
> raw output format (Y10) over a 1-lane MIPI CSI-2 interface and supports
> the 640x480 (VGA) resolution.
>
> Signed-off-by: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com>
> ---
> MAINTAINERS | 1 +
> drivers/media/i2c/Kconfig | 10 +
> drivers/media/i2c/Makefile | 1 +
> drivers/media/i2c/og0va1b.c | 867 ++++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 879 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 5aa846c8479b20651291d5bd2e316308310f826c..85a06eb9eacc410a565b80d56979eaa565515d0e 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -19891,6 +19891,7 @@ M: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com>
> L: linux-media@vger.kernel.org
> S: Maintained
> F: Documentation/devicetree/bindings/media/i2c/ovti,og0va1b.yaml
> +F: drivers/media/i2c/og0va1b.c
>
> OMNIVISION OG0VE1B SENSOR DRIVER
> M: Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
> diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
> index 5d173e0ecf424f2f204f8d426be818e44357f8e4..56680772f5f47b4629c4e17f5a5feba08b1d94fc 100644
> --- a/drivers/media/i2c/Kconfig
> +++ b/drivers/media/i2c/Kconfig
> @@ -363,6 +363,16 @@ config VIDEO_OG01A1B
> To compile this driver as a module, choose M here: the
> module will be called og01a1b.
>
> +config VIDEO_OG0VA1B
> + tristate "OmniVision OG0VA1B sensor support"
> + select V4L2_CCI_I2C
> + help
> + This is a Video4Linux2 sensor driver for the OmniVision
> + OG0VA1B camera.
> +
> + To compile this driver as a module, choose M here: the
> + module will be called og0va1b.
> +
> config VIDEO_OG0VE1B
> tristate "OmniVision OG0VE1B sensor support"
> select V4L2_CCI_I2C
> diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
> index e45359efe0e41e13e3c0869e5ead7d6cf4aca3a7..c60851c7fe07e3bdc511c5f482525ba7a044f48e 100644
> --- a/drivers/media/i2c/Makefile
> +++ b/drivers/media/i2c/Makefile
> @@ -83,6 +83,7 @@ obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o
> obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o
> obj-$(CONFIG_VIDEO_MT9V111) += mt9v111.o
> obj-$(CONFIG_VIDEO_OG01A1B) += og01a1b.o
> +obj-$(CONFIG_VIDEO_OG0VA1B) += og0va1b.o
> obj-$(CONFIG_VIDEO_OG0VE1B) += og0ve1b.o
> obj-$(CONFIG_VIDEO_OS05B10) += os05b10.o
> obj-$(CONFIG_VIDEO_OV01A10) += ov01a10.o
> diff --git a/drivers/media/i2c/og0va1b.c b/drivers/media/i2c/og0va1b.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..f0505b7ba7f329ad57ffafa8f90a24204f002d3c
> --- /dev/null
> +++ b/drivers/media/i2c/og0va1b.c
> @@ -0,0 +1,867 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * OmniVision OG0VA1B Camera Sensor Driver
> + *
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/i2c.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/regulator/consumer.h>
> +
> +#include <media/v4l2-cci.h>
> +#include <media/v4l2-ctrls.h>
> +#include <media/v4l2-device.h>
> +#include <media/v4l2-fwnode.h>
> +#include <media/v4l2-subdev.h>
> +
> +#define OG0VA1B_REG_CHIP_ID CCI_REG16(0x300a)
> +#define OG0VA1B_CHIP_ID 0xC756
This is the same chip id as of the OG0VE1B sensor device.
What's the difference between these two sensors, and do you find it possible
to add support of OG0VA1B sensor/modes into OG0VE1B sensor driver? Or is
it just the same device?
Hardware specifics described in dt changes also does not show a difference
in comparison to ovti,og0ve1b.yaml.
--
Best wishes,
Vladimir
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/2] dt-bindings: media: i2c: Add OmniVision OG0VA1B
2026-06-18 10:37 ` [PATCH 1/2] dt-bindings: media: i2c: Add OmniVision OG0VA1B Wenmeng Liu
@ 2026-06-18 10:55 ` Vladimir Zapolskiy
0 siblings, 0 replies; 11+ messages in thread
From: Vladimir Zapolskiy @ 2026-06-18 10:55 UTC (permalink / raw)
To: Wenmeng Liu, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sakari Ailus
Cc: linux-media, devicetree, linux-kernel
Hello Wenmeng.
On 6/18/26 13:37, Wenmeng Liu wrote:
> Add devicetree binding for OmniVision OG0VA1B image sensor.
> OmniVision OG0VA1B is an image sensor, which produces frames in 10-bit
> raw output format (Y10) over a 1-lane MIPI CSI-2 interface and supports
> the 640x480 (VGA) resolution.
>
> Signed-off-by: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com>
> ---
> .../bindings/media/i2c/ovti,og0va1b.yaml | 104 +++++++++++++++++++++
> MAINTAINERS | 6 ++
> 2 files changed, 110 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,og0va1b.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,og0va1b.yaml
> new file mode 100644
> index 0000000000000000000000000000000000000000..302afc41bb776f75c08b26ac2f04014f8cbea4fa
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/i2c/ovti,og0va1b.yaml
> @@ -0,0 +1,104 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/media/i2c/ovti,og0va1b.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: OmniVision OG0VA1B Image Sensor
> +
> +maintainers:
> + - Wenmeng Liu <wenmeng.liu@oss.qualcomm.com>
> +
> +description:
> + The OmniVision OG0VA1B is a 1/10-inch black and white CMOS VGA (640x480)
> + image sensor. It is controlled over an I2C-compatible SCCB bus and transmits
> + images on a 1-lane MIPI CSI-2 output interface.
> +
> +allOf:
> + - $ref: /schemas/media/video-interface-devices.yaml#
> +
> +properties:
> + compatible:
> + const: ovti,og0va1b
So far I don't see a difference from the neighbouring ovti,og0ve1b.yaml,
most likely it is just the same device, and even if it is not, it'd make
sense to consider and add OG0VE1B support into the existing dt binding
documentation.
--
Best wishes,
Vladimir
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 2/2] media: i2c: og0va1b: Add OmniVision OG0VA1B camera sensor
2026-06-18 10:50 ` Vladimir Zapolskiy
@ 2026-06-18 12:36 ` Wenmeng Liu
2026-06-18 13:04 ` Vladimir Zapolskiy
2026-06-18 13:15 ` Kieran Bingham
0 siblings, 2 replies; 11+ messages in thread
From: Wenmeng Liu @ 2026-06-18 12:36 UTC (permalink / raw)
To: Vladimir Zapolskiy, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sakari Ailus
Cc: linux-media, devicetree, linux-kernel
On 6/18/2026 6:50 PM, Vladimir Zapolskiy wrote:
> Hello Wenmeng.
>
> On 6/18/26 13:37, Wenmeng Liu wrote:
>> Add V4L2 sub device driver for OmniVision OG0VA1B image sensor.
>> OmniVision OG0VA1B is an image sensor, which produces frames in 10-bit
>> raw output format (Y10) over a 1-lane MIPI CSI-2 interface and supports
>> the 640x480 (VGA) resolution.
>>
>> Signed-off-by: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com>
>> ---
>> MAINTAINERS | 1 +
>> drivers/media/i2c/Kconfig | 10 +
>> drivers/media/i2c/Makefile | 1 +
>> drivers/media/i2c/og0va1b.c | 867 ++++++++++++++++++++++++++++++++++
>> ++++++++++
>> 4 files changed, 879 insertions(+)
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index
>> 5aa846c8479b20651291d5bd2e316308310f826c..85a06eb9eacc410a565b80d56979eaa565515d0e 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -19891,6 +19891,7 @@ M: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com>
>> L: linux-media@vger.kernel.org
>> S: Maintained
>> F: Documentation/devicetree/bindings/media/i2c/ovti,og0va1b.yaml
>> +F: drivers/media/i2c/og0va1b.c
>> OMNIVISION OG0VE1B SENSOR DRIVER
>> M: Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
>> diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
>> index
>> 5d173e0ecf424f2f204f8d426be818e44357f8e4..56680772f5f47b4629c4e17f5a5feba08b1d94fc 100644
>> --- a/drivers/media/i2c/Kconfig
>> +++ b/drivers/media/i2c/Kconfig
>> @@ -363,6 +363,16 @@ config VIDEO_OG01A1B
>> To compile this driver as a module, choose M here: the
>> module will be called og01a1b.
>> +config VIDEO_OG0VA1B
>> + tristate "OmniVision OG0VA1B sensor support"
>> + select V4L2_CCI_I2C
>> + help
>> + This is a Video4Linux2 sensor driver for the OmniVision
>> + OG0VA1B camera.
>> +
>> + To compile this driver as a module, choose M here: the
>> + module will be called og0va1b.
>> +
>> config VIDEO_OG0VE1B
>> tristate "OmniVision OG0VE1B sensor support"
>> select V4L2_CCI_I2C
>> diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
>> index
>> e45359efe0e41e13e3c0869e5ead7d6cf4aca3a7..c60851c7fe07e3bdc511c5f482525ba7a044f48e 100644
>> --- a/drivers/media/i2c/Makefile
>> +++ b/drivers/media/i2c/Makefile
>> @@ -83,6 +83,7 @@ obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o
>> obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o
>> obj-$(CONFIG_VIDEO_MT9V111) += mt9v111.o
>> obj-$(CONFIG_VIDEO_OG01A1B) += og01a1b.o
>> +obj-$(CONFIG_VIDEO_OG0VA1B) += og0va1b.o
>> obj-$(CONFIG_VIDEO_OG0VE1B) += og0ve1b.o
>> obj-$(CONFIG_VIDEO_OS05B10) += os05b10.o
>> obj-$(CONFIG_VIDEO_OV01A10) += ov01a10.o
>> diff --git a/drivers/media/i2c/og0va1b.c b/drivers/media/i2c/og0va1b.c
>> new file mode 100644
>> index
>> 0000000000000000000000000000000000000000..f0505b7ba7f329ad57ffafa8f90a24204f002d3c
>> --- /dev/null
>> +++ b/drivers/media/i2c/og0va1b.c
>> @@ -0,0 +1,867 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * OmniVision OG0VA1B Camera Sensor Driver
>> + *
>> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries
>> + */
>> +
>> +#include <linux/clk.h>
>> +#include <linux/delay.h>
>> +#include <linux/gpio/consumer.h>
>> +#include <linux/i2c.h>
>> +#include <linux/module.h>
>> +#include <linux/of.h>
>> +#include <linux/pm_runtime.h>
>> +#include <linux/regulator/consumer.h>
>> +
>> +#include <media/v4l2-cci.h>
>> +#include <media/v4l2-ctrls.h>
>> +#include <media/v4l2-device.h>
>> +#include <media/v4l2-fwnode.h>
>> +#include <media/v4l2-subdev.h>
>> +
>> +#define OG0VA1B_REG_CHIP_ID CCI_REG16(0x300a)
>> +#define OG0VA1B_CHIP_ID 0xC756
>
> This is the same chip id as of the OG0VE1B sensor device.
>
> What's the difference between these two sensors, and do you find it
> possible
> to add support of OG0VA1B sensor/modes into OG0VE1B sensor driver? Or is
> it just the same device?
>
> Hardware specifics described in dt changes also does not show a difference
> in comparison to ovti,og0ve1b.yaml.
>
Hi Vladimir,
Both OG0VE1B and OG0VA1B belong to the same OmniVision VGA monochrome
sensor family. They share the same resolution, power rails, reset GPIO
behavior and power management framework.
But they are different:
OG0VE1B: 8-bit RAW, lower FPS
OG0VA1B: 10-bit RAW, higher FPS
and some registers are not same.
The DT bindings can be reused, but would it be more appropriate for the
driver to remain independent?
Thanks,
Wenmeng
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 2/2] media: i2c: og0va1b: Add OmniVision OG0VA1B camera sensor
2026-06-18 12:36 ` Wenmeng Liu
@ 2026-06-18 13:04 ` Vladimir Zapolskiy
2026-06-18 13:15 ` Kieran Bingham
1 sibling, 0 replies; 11+ messages in thread
From: Vladimir Zapolskiy @ 2026-06-18 13:04 UTC (permalink / raw)
To: Wenmeng Liu, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sakari Ailus
Cc: linux-media, devicetree, linux-kernel
On 6/18/26 15:36, Wenmeng Liu wrote:
>
>
> On 6/18/2026 6:50 PM, Vladimir Zapolskiy wrote:
>> Hello Wenmeng.
>>
>> On 6/18/26 13:37, Wenmeng Liu wrote:
>>> Add V4L2 sub device driver for OmniVision OG0VA1B image sensor.
>>> OmniVision OG0VA1B is an image sensor, which produces frames in 10-bit
>>> raw output format (Y10) over a 1-lane MIPI CSI-2 interface and supports
>>> the 640x480 (VGA) resolution.
>>>
>>> Signed-off-by: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com>
>>> ---
>>> MAINTAINERS | 1 +
>>> drivers/media/i2c/Kconfig | 10 +
>>> drivers/media/i2c/Makefile | 1 +
>>> drivers/media/i2c/og0va1b.c | 867 ++++++++++++++++++++++++++++++++++
>>> ++++++++++
>>> 4 files changed, 879 insertions(+)
>>>
>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>> index
>>> 5aa846c8479b20651291d5bd2e316308310f826c..85a06eb9eacc410a565b80d56979eaa565515d0e 100644
>>> --- a/MAINTAINERS
>>> +++ b/MAINTAINERS
>>> @@ -19891,6 +19891,7 @@ M: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com>
>>> L: linux-media@vger.kernel.org
>>> S: Maintained
>>> F: Documentation/devicetree/bindings/media/i2c/ovti,og0va1b.yaml
>>> +F: drivers/media/i2c/og0va1b.c
>>> OMNIVISION OG0VE1B SENSOR DRIVER
>>> M: Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
>>> diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
>>> index
>>> 5d173e0ecf424f2f204f8d426be818e44357f8e4..56680772f5f47b4629c4e17f5a5feba08b1d94fc 100644
>>> --- a/drivers/media/i2c/Kconfig
>>> +++ b/drivers/media/i2c/Kconfig
>>> @@ -363,6 +363,16 @@ config VIDEO_OG01A1B
>>> To compile this driver as a module, choose M here: the
>>> module will be called og01a1b.
>>> +config VIDEO_OG0VA1B
>>> + tristate "OmniVision OG0VA1B sensor support"
>>> + select V4L2_CCI_I2C
>>> + help
>>> + This is a Video4Linux2 sensor driver for the OmniVision
>>> + OG0VA1B camera.
>>> +
>>> + To compile this driver as a module, choose M here: the
>>> + module will be called og0va1b.
>>> +
>>> config VIDEO_OG0VE1B
>>> tristate "OmniVision OG0VE1B sensor support"
>>> select V4L2_CCI_I2C
>>> diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
>>> index
>>> e45359efe0e41e13e3c0869e5ead7d6cf4aca3a7..c60851c7fe07e3bdc511c5f482525ba7a044f48e 100644
>>> --- a/drivers/media/i2c/Makefile
>>> +++ b/drivers/media/i2c/Makefile
>>> @@ -83,6 +83,7 @@ obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o
>>> obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o
>>> obj-$(CONFIG_VIDEO_MT9V111) += mt9v111.o
>>> obj-$(CONFIG_VIDEO_OG01A1B) += og01a1b.o
>>> +obj-$(CONFIG_VIDEO_OG0VA1B) += og0va1b.o
>>> obj-$(CONFIG_VIDEO_OG0VE1B) += og0ve1b.o
>>> obj-$(CONFIG_VIDEO_OS05B10) += os05b10.o
>>> obj-$(CONFIG_VIDEO_OV01A10) += ov01a10.o
>>> diff --git a/drivers/media/i2c/og0va1b.c b/drivers/media/i2c/og0va1b.c
>>> new file mode 100644
>>> index
>>> 0000000000000000000000000000000000000000..f0505b7ba7f329ad57ffafa8f90a24204f002d3c
>>> --- /dev/null
>>> +++ b/drivers/media/i2c/og0va1b.c
>>> @@ -0,0 +1,867 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +/*
>>> + * OmniVision OG0VA1B Camera Sensor Driver
>>> + *
>>> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries
>>> + */
>>> +
>>> +#include <linux/clk.h>
>>> +#include <linux/delay.h>
>>> +#include <linux/gpio/consumer.h>
>>> +#include <linux/i2c.h>
>>> +#include <linux/module.h>
>>> +#include <linux/of.h>
>>> +#include <linux/pm_runtime.h>
>>> +#include <linux/regulator/consumer.h>
>>> +
>>> +#include <media/v4l2-cci.h>
>>> +#include <media/v4l2-ctrls.h>
>>> +#include <media/v4l2-device.h>
>>> +#include <media/v4l2-fwnode.h>
>>> +#include <media/v4l2-subdev.h>
>>> +
>>> +#define OG0VA1B_REG_CHIP_ID CCI_REG16(0x300a)
>>> +#define OG0VA1B_CHIP_ID 0xC756
>>
>> This is the same chip id as of the OG0VE1B sensor device.
>>
>> What's the difference between these two sensors, and do you find it
>> possible
>> to add support of OG0VA1B sensor/modes into OG0VE1B sensor driver? Or is
>> it just the same device?
>>
>> Hardware specifics described in dt changes also does not show a difference
>> in comparison to ovti,og0ve1b.yaml.
>>
>
> Hi Vladimir,
>
> Both OG0VE1B and OG0VA1B belong to the same OmniVision VGA monochrome
> sensor family. They share the same resolution, power rails, reset GPIO
> behavior and power management framework.
>
> But they are different:
> OG0VE1B: 8-bit RAW, lower FPS
The current OG0VE1B driver supports 640x480@120 FPS, 8-bit mode, however
the sensor itself has 10-bit image output format mode support also.
> OG0VA1B: 10-bit RAW, higher FPS
> and some registers are not same.
The very first one, which I'd like to see in the driver, is the difference
in the CHIP_IP register value.
>
> The DT bindings can be reused, but would it be more appropriate for the
> driver to remain independent?
>
It depends on the actual difference between two devices, if it is lightly
maintainable, then it makes no sense to add another driver IMHO, but this
should be established.
If the difference is about different mode programming, I'd say it can be
kept under one device driver.
FWIW on OmniVision website there are "OG0VE" and "OG0VA" product briefs,
the devices are very similar, but not identical. Obviously there are
Linux device drivers, in particular image sensor drivers, which support
multiple different devices, so having a single device driver is at least
a viable option to consider.
It'd be great to get comments from other developers on the subject.
--
Best wishes,
Vladimir
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 2/2] media: i2c: og0va1b: Add OmniVision OG0VA1B camera sensor
2026-06-18 12:36 ` Wenmeng Liu
2026-06-18 13:04 ` Vladimir Zapolskiy
@ 2026-06-18 13:15 ` Kieran Bingham
2026-06-18 14:00 ` Wenmeng Liu
1 sibling, 1 reply; 11+ messages in thread
From: Kieran Bingham @ 2026-06-18 13:15 UTC (permalink / raw)
To: Conor Dooley, Krzysztof Kozlowski, Mauro Carvalho Chehab,
Rob Herring, Sakari Ailus, Vladimir Zapolskiy, Wenmeng Liu
Cc: linux-media, devicetree, linux-kernel
Quoting Wenmeng Liu (2026-06-18 13:36:27)
>
>
> On 6/18/2026 6:50 PM, Vladimir Zapolskiy wrote:
> > Hello Wenmeng.
> >
> > On 6/18/26 13:37, Wenmeng Liu wrote:
> >> Add V4L2 sub device driver for OmniVision OG0VA1B image sensor.
> >> OmniVision OG0VA1B is an image sensor, which produces frames in 10-bit
> >> raw output format (Y10) over a 1-lane MIPI CSI-2 interface and supports
> >> the 640x480 (VGA) resolution.
> >>
> >> Signed-off-by: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com>
> >> ---
> >> MAINTAINERS | 1 +
> >> drivers/media/i2c/Kconfig | 10 +
> >> drivers/media/i2c/Makefile | 1 +
> >> drivers/media/i2c/og0va1b.c | 867 ++++++++++++++++++++++++++++++++++
> >> ++++++++++
> >> 4 files changed, 879 insertions(+)
> >>
> >> diff --git a/MAINTAINERS b/MAINTAINERS
> >> index
> >> 5aa846c8479b20651291d5bd2e316308310f826c..85a06eb9eacc410a565b80d56979eaa565515d0e 100644
> >> --- a/MAINTAINERS
> >> +++ b/MAINTAINERS
> >> @@ -19891,6 +19891,7 @@ M: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com>
> >> L: linux-media@vger.kernel.org
> >> S: Maintained
> >> F: Documentation/devicetree/bindings/media/i2c/ovti,og0va1b.yaml
> >> +F: drivers/media/i2c/og0va1b.c
> >> OMNIVISION OG0VE1B SENSOR DRIVER
> >> M: Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
> >> diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
> >> index
> >> 5d173e0ecf424f2f204f8d426be818e44357f8e4..56680772f5f47b4629c4e17f5a5feba08b1d94fc 100644
> >> --- a/drivers/media/i2c/Kconfig
> >> +++ b/drivers/media/i2c/Kconfig
> >> @@ -363,6 +363,16 @@ config VIDEO_OG01A1B
> >> To compile this driver as a module, choose M here: the
> >> module will be called og01a1b.
> >> +config VIDEO_OG0VA1B
> >> + tristate "OmniVision OG0VA1B sensor support"
> >> + select V4L2_CCI_I2C
> >> + help
> >> + This is a Video4Linux2 sensor driver for the OmniVision
> >> + OG0VA1B camera.
> >> +
> >> + To compile this driver as a module, choose M here: the
> >> + module will be called og0va1b.
> >> +
> >> config VIDEO_OG0VE1B
> >> tristate "OmniVision OG0VE1B sensor support"
> >> select V4L2_CCI_I2C
> >> diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
> >> index
> >> e45359efe0e41e13e3c0869e5ead7d6cf4aca3a7..c60851c7fe07e3bdc511c5f482525ba7a044f48e 100644
> >> --- a/drivers/media/i2c/Makefile
> >> +++ b/drivers/media/i2c/Makefile
> >> @@ -83,6 +83,7 @@ obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o
> >> obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o
> >> obj-$(CONFIG_VIDEO_MT9V111) += mt9v111.o
> >> obj-$(CONFIG_VIDEO_OG01A1B) += og01a1b.o
> >> +obj-$(CONFIG_VIDEO_OG0VA1B) += og0va1b.o
> >> obj-$(CONFIG_VIDEO_OG0VE1B) += og0ve1b.o
> >> obj-$(CONFIG_VIDEO_OS05B10) += os05b10.o
> >> obj-$(CONFIG_VIDEO_OV01A10) += ov01a10.o
> >> diff --git a/drivers/media/i2c/og0va1b.c b/drivers/media/i2c/og0va1b.c
> >> new file mode 100644
> >> index
> >> 0000000000000000000000000000000000000000..f0505b7ba7f329ad57ffafa8f90a24204f002d3c
> >> --- /dev/null
> >> +++ b/drivers/media/i2c/og0va1b.c
> >> @@ -0,0 +1,867 @@
> >> +// SPDX-License-Identifier: GPL-2.0
> >> +/*
> >> + * OmniVision OG0VA1B Camera Sensor Driver
> >> + *
> >> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries
> >> + */
> >> +
> >> +#include <linux/clk.h>
> >> +#include <linux/delay.h>
> >> +#include <linux/gpio/consumer.h>
> >> +#include <linux/i2c.h>
> >> +#include <linux/module.h>
> >> +#include <linux/of.h>
> >> +#include <linux/pm_runtime.h>
> >> +#include <linux/regulator/consumer.h>
> >> +
> >> +#include <media/v4l2-cci.h>
> >> +#include <media/v4l2-ctrls.h>
> >> +#include <media/v4l2-device.h>
> >> +#include <media/v4l2-fwnode.h>
> >> +#include <media/v4l2-subdev.h>
> >> +
> >> +#define OG0VA1B_REG_CHIP_ID CCI_REG16(0x300a)
> >> +#define OG0VA1B_CHIP_ID 0xC756
> >
> > This is the same chip id as of the OG0VE1B sensor device.
> >
> > What's the difference between these two sensors, and do you find it
> > possible
> > to add support of OG0VA1B sensor/modes into OG0VE1B sensor driver? Or is
> > it just the same device?
> >
> > Hardware specifics described in dt changes also does not show a difference
> > in comparison to ovti,og0ve1b.yaml.
> >
>
>
> Hi Vladimir,
>
>
> Both OG0VE1B and OG0VA1B belong to the same OmniVision VGA monochrome
> sensor family. They share the same resolution, power rails, reset GPIO
> behavior and power management framework.
>
> But they are different:
> OG0VE1B: 8-bit RAW, lower FPS
> OG0VA1B: 10-bit RAW, higher FPS
> and some registers are not same.
Can you identify which registers are not the same?
Mapping between 8bit and 10 bit or different frame rates could easily be
managed in a single driver with exposing different capabilities based on
the variant.
We should really work towards reducing the huge duplication that is
happening with copy/paste sensor drivers.
--
Regards
Kieran
>
>
> The DT bindings can be reused, but would it be more appropriate for the
> driver to remain independent?
>
>
> Thanks,
> Wenmeng
>
>
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 2/2] media: i2c: og0va1b: Add OmniVision OG0VA1B camera sensor
2026-06-18 13:15 ` Kieran Bingham
@ 2026-06-18 14:00 ` Wenmeng Liu
0 siblings, 0 replies; 11+ messages in thread
From: Wenmeng Liu @ 2026-06-18 14:00 UTC (permalink / raw)
To: Kieran Bingham, Conor Dooley, Krzysztof Kozlowski,
Mauro Carvalho Chehab, Rob Herring, Sakari Ailus,
Vladimir Zapolskiy
Cc: linux-media, devicetree, linux-kernel
On 6/18/2026 9:15 PM, Kieran Bingham wrote:
> Quoting Wenmeng Liu (2026-06-18 13:36:27)
>>
>>
>> On 6/18/2026 6:50 PM, Vladimir Zapolskiy wrote:
>>> Hello Wenmeng.
>>>
>>> On 6/18/26 13:37, Wenmeng Liu wrote:
>>>> Add V4L2 sub device driver for OmniVision OG0VA1B image sensor.
>>>> OmniVision OG0VA1B is an image sensor, which produces frames in 10-bit
>>>> raw output format (Y10) over a 1-lane MIPI CSI-2 interface and supports
>>>> the 640x480 (VGA) resolution.
>>>>
>>>> Signed-off-by: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com>
>>>> ---
>>>> MAINTAINERS | 1 +
>>>> drivers/media/i2c/Kconfig | 10 +
>>>> drivers/media/i2c/Makefile | 1 +
>>>> drivers/media/i2c/og0va1b.c | 867 ++++++++++++++++++++++++++++++++++
>>>> ++++++++++
>>>> 4 files changed, 879 insertions(+)
>>>>
>>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>>> index
>>>> 5aa846c8479b20651291d5bd2e316308310f826c..85a06eb9eacc410a565b80d56979eaa565515d0e 100644
>>>> --- a/MAINTAINERS
>>>> +++ b/MAINTAINERS
>>>> @@ -19891,6 +19891,7 @@ M: Wenmeng Liu <wenmeng.liu@oss.qualcomm.com>
>>>> L: linux-media@vger.kernel.org
>>>> S: Maintained
>>>> F: Documentation/devicetree/bindings/media/i2c/ovti,og0va1b.yaml
>>>> +F: drivers/media/i2c/og0va1b.c
>>>> OMNIVISION OG0VE1B SENSOR DRIVER
>>>> M: Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
>>>> diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
>>>> index
>>>> 5d173e0ecf424f2f204f8d426be818e44357f8e4..56680772f5f47b4629c4e17f5a5feba08b1d94fc 100644
>>>> --- a/drivers/media/i2c/Kconfig
>>>> +++ b/drivers/media/i2c/Kconfig
>>>> @@ -363,6 +363,16 @@ config VIDEO_OG01A1B
>>>> To compile this driver as a module, choose M here: the
>>>> module will be called og01a1b.
>>>> +config VIDEO_OG0VA1B
>>>> + tristate "OmniVision OG0VA1B sensor support"
>>>> + select V4L2_CCI_I2C
>>>> + help
>>>> + This is a Video4Linux2 sensor driver for the OmniVision
>>>> + OG0VA1B camera.
>>>> +
>>>> + To compile this driver as a module, choose M here: the
>>>> + module will be called og0va1b.
>>>> +
>>>> config VIDEO_OG0VE1B
>>>> tristate "OmniVision OG0VE1B sensor support"
>>>> select V4L2_CCI_I2C
>>>> diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
>>>> index
>>>> e45359efe0e41e13e3c0869e5ead7d6cf4aca3a7..c60851c7fe07e3bdc511c5f482525ba7a044f48e 100644
>>>> --- a/drivers/media/i2c/Makefile
>>>> +++ b/drivers/media/i2c/Makefile
>>>> @@ -83,6 +83,7 @@ obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o
>>>> obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o
>>>> obj-$(CONFIG_VIDEO_MT9V111) += mt9v111.o
>>>> obj-$(CONFIG_VIDEO_OG01A1B) += og01a1b.o
>>>> +obj-$(CONFIG_VIDEO_OG0VA1B) += og0va1b.o
>>>> obj-$(CONFIG_VIDEO_OG0VE1B) += og0ve1b.o
>>>> obj-$(CONFIG_VIDEO_OS05B10) += os05b10.o
>>>> obj-$(CONFIG_VIDEO_OV01A10) += ov01a10.o
>>>> diff --git a/drivers/media/i2c/og0va1b.c b/drivers/media/i2c/og0va1b.c
>>>> new file mode 100644
>>>> index
>>>> 0000000000000000000000000000000000000000..f0505b7ba7f329ad57ffafa8f90a24204f002d3c
>>>> --- /dev/null
>>>> +++ b/drivers/media/i2c/og0va1b.c
>>>> @@ -0,0 +1,867 @@
>>>> +// SPDX-License-Identifier: GPL-2.0
>>>> +/*
>>>> + * OmniVision OG0VA1B Camera Sensor Driver
>>>> + *
>>>> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries
>>>> + */
>>>> +
>>>> +#include <linux/clk.h>
>>>> +#include <linux/delay.h>
>>>> +#include <linux/gpio/consumer.h>
>>>> +#include <linux/i2c.h>
>>>> +#include <linux/module.h>
>>>> +#include <linux/of.h>
>>>> +#include <linux/pm_runtime.h>
>>>> +#include <linux/regulator/consumer.h>
>>>> +
>>>> +#include <media/v4l2-cci.h>
>>>> +#include <media/v4l2-ctrls.h>
>>>> +#include <media/v4l2-device.h>
>>>> +#include <media/v4l2-fwnode.h>
>>>> +#include <media/v4l2-subdev.h>
>>>> +
>>>> +#define OG0VA1B_REG_CHIP_ID CCI_REG16(0x300a)
>>>> +#define OG0VA1B_CHIP_ID 0xC756
>>>
>>> This is the same chip id as of the OG0VE1B sensor device.
>>>
>>> What's the difference between these two sensors, and do you find it
>>> possible
>>> to add support of OG0VA1B sensor/modes into OG0VE1B sensor driver? Or is
>>> it just the same device?
>>>
>>> Hardware specifics described in dt changes also does not show a difference
>>> in comparison to ovti,og0ve1b.yaml.
>>>
>>
>>
>> Hi Vladimir,
>>
>>
>> Both OG0VE1B and OG0VA1B belong to the same OmniVision VGA monochrome
>> sensor family. They share the same resolution, power rails, reset GPIO
>> behavior and power management framework.
>>
>> But they are different:
>> OG0VE1B: 8-bit RAW, lower FPS
>> OG0VA1B: 10-bit RAW, higher FPS
>> and some registers are not same.
>
> Can you identify which registers are not the same?
>
For example, regarding the CHIP_ID,
OG0VE1B is 0xc75645, while OG0VA1B is 0xc75641, including the test
pattern registers.
Since I do not have the specification for OG0VE1B, I cannot perform a
detailed comparison. However, based on the current observations, OG0VA1B
can be integrated into the OG0VE1B driver.
> Mapping between 8bit and 10 bit or different frame rates could easily be
> managed in a single driver with exposing different capabilities based on
> the variant.
>
> We should really work towards reducing the huge duplication that is
> happening with copy/paste sensor drivers.
Indeed, will do so.
Thanks,
Wenmeng
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 2/2] media: i2c: og0va1b: Add OmniVision OG0VA1B camera sensor
2026-06-18 10:37 ` [PATCH 2/2] media: i2c: og0va1b: Add OmniVision OG0VA1B camera sensor Wenmeng Liu
2026-06-18 10:47 ` sashiko-bot
2026-06-18 10:50 ` Vladimir Zapolskiy
@ 2026-06-18 17:27 ` Uwe Kleine-König
2 siblings, 0 replies; 11+ messages in thread
From: Uwe Kleine-König @ 2026-06-18 17:27 UTC (permalink / raw)
To: Wenmeng Liu
Cc: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Sakari Ailus, linux-media, devicetree, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 260 bytes --]
Hello,
On Thu, Jun 18, 2026 at 06:37:44PM +0800, Wenmeng Liu wrote:
> +static const struct i2c_device_id og0va1b_id[] = {
> + { "og0va1b" },
please make this:
{ .name = "og0va1b" },
> + { }
> +};
> +MODULE_DEVICE_TABLE(i2c, og0va1b_id);
Best regards
Uwe
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2026-06-18 17:27 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-18 10:37 [PATCH 0/2] media: i2c: Add OmniVision OG0VA1B camera sensor driver Wenmeng Liu
2026-06-18 10:37 ` [PATCH 1/2] dt-bindings: media: i2c: Add OmniVision OG0VA1B Wenmeng Liu
2026-06-18 10:55 ` Vladimir Zapolskiy
2026-06-18 10:37 ` [PATCH 2/2] media: i2c: og0va1b: Add OmniVision OG0VA1B camera sensor Wenmeng Liu
2026-06-18 10:47 ` sashiko-bot
2026-06-18 10:50 ` Vladimir Zapolskiy
2026-06-18 12:36 ` Wenmeng Liu
2026-06-18 13:04 ` Vladimir Zapolskiy
2026-06-18 13:15 ` Kieran Bingham
2026-06-18 14:00 ` Wenmeng Liu
2026-06-18 17:27 ` Uwe Kleine-König
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox