Re: [PATCH 2/2] media: i2c: Add OmniVision OG0VE1B camera sensor
From: Tarang Raval <hidden>
Date: 2025-08-21 06:52:08
Also in:
linux-media
Hi Vladimir,
OmniVision OG0VE1B is a monochrome image sensor, which produces frames in 8/10-bit raw output format and supports 640x480, 400x400, 200x200 and 100x100 output image resolution modes. Signed-off-by: Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org> --- MAINTAINERS | 8 + drivers/media/i2c/Kconfig | 10 + drivers/media/i2c/Makefile | 1 + drivers/media/i2c/og0ve1b.c | 858 ++++++++++++++++++++++++++++++++++++ 4 files changed, 877 insertions(+) create mode 100644 drivers/media/i2c/og0ve1b.c
...
+static const struct cci_reg_sequence og0ve1b_640x480_120fps_mode[] = {
+ { CCI_REG8(0x30a0), 0x02 },
+ { CCI_REG8(0x30a1), 0x00 },
+ { CCI_REG8(0x30a2), 0x48 },
+ { CCI_REG8(0x30a3), 0x34 },
+ { CCI_REG8(0x30a4), 0xf7 },
+ { CCI_REG8(0x30a5), 0x00 },
+ { CCI_REG8(0x3082), 0x32 },
+ { CCI_REG8(0x3083), 0x01 },
+ { CCI_REG8(0x301c), 0xf0 },
+ { CCI_REG8(0x301e), 0x0b },
+ { CCI_REG8(0x3106), 0x10 },
+ { CCI_REG8(0x3708), 0x77 },
+ { CCI_REG8(0x3709), 0xf8 },
+ { CCI_REG8(0x3717), 0x00 },
+ { CCI_REG8(0x3782), 0x00 },
+ { CCI_REG8(0x3783), 0x47 },
+ { CCI_REG8(0x37a2), 0x00 },
+ { CCI_REG8(0x3503), 0x07 },
+ { CCI_REG8(0x3509), 0x10 },
+ { CCI_REG8(0x3600), 0x83 },
+ { CCI_REG8(0x3601), 0x21 },
+ { CCI_REG8(0x3602), 0xf1 },
+ { CCI_REG8(0x360a), 0x18 },
+ { CCI_REG8(0x360e), 0xb3 },
+ { CCI_REG8(0x3613), 0x20 },
+ { CCI_REG8(0x366a), 0x78 },
+ { CCI_REG8(0x3706), 0x63 },
+ { CCI_REG8(0x3713), 0x00 },
+ { CCI_REG8(0x3716), 0xb0 },
+ { CCI_REG8(0x37a1), 0x38 },
+ { CCI_REG8(0x3800), 0x00 },
+ { CCI_REG8(0x3801), 0x04 },
+ { CCI_REG8(0x3802), 0x00 },
+ { CCI_REG8(0x3803), 0x04 },
+ { CCI_REG8(0x3804), 0x02 },
+ { CCI_REG8(0x3805), 0x8b },
+ { CCI_REG8(0x3806), 0x01 },
+ { CCI_REG8(0x3807), 0xeb },
+ { CCI_REG8(0x3808), 0x02 }, /* output width */
+ { CCI_REG8(0x3809), 0x80 },
+ { CCI_REG8(0x380a), 0x01 }, /* output height */
+ { CCI_REG8(0x380b), 0xe0 },
+ { CCI_REG8(0x380c), 0x03 }, /* horizontal timing size */
+ { CCI_REG8(0x380d), 0x18 },
+ { CCI_REG8(0x380e), 0x02 }, /* vertical timing size */Do you have the datasheet for this sensor? If so, it would be better to divide this array into two parts. Currently, all of these registers are not related to the mode. One part should be for common registers, and the other for mode-related registers.
+ { CCI_REG8(0x380f), 0x38 },
+ { CCI_REG8(0x3811), 0x04 },
+ { CCI_REG8(0x3813), 0x04 },
+ { CCI_REG8(0x3814), 0x11 },
+ { CCI_REG8(0x3815), 0x11 },
+ { CCI_REG8(0x3820), 0x00 },
+ { CCI_REG8(0x3821), 0x00 },
+ { CCI_REG8(0x3823), 0x04 },
+ { CCI_REG8(0x382a), 0x00 },
+ { CCI_REG8(0x382b), 0x03 },
+ { CCI_REG8(0x3840), 0x00 },
+ { CCI_REG8(0x389e), 0x00 },
+ { CCI_REG8(0x3c05), 0x08 },
+ { CCI_REG8(0x3c26), 0x02 },
+ { CCI_REG8(0x3c27), 0xc0 },
+ { CCI_REG8(0x3c28), 0x00 },
+ { CCI_REG8(0x3c29), 0x40 },
+ { CCI_REG8(0x3c2c), 0x00 },
+ { CCI_REG8(0x3c2d), 0x50 },
+ { CCI_REG8(0x3c2e), 0x02 },
+ { CCI_REG8(0x3c2f), 0x66 },
+ { CCI_REG8(0x3c33), 0x08 },
+ { CCI_REG8(0x3c35), 0x00 },
+ { CCI_REG8(0x3c36), 0x00 },
+ { CCI_REG8(0x3c37), 0x00 },
+ { CCI_REG8(0x3f52), 0x9b },
+ { CCI_REG8(0x4001), 0x42 },
+ { CCI_REG8(0x4004), 0x08 },
+ { CCI_REG8(0x4005), 0x00 },
+ { CCI_REG8(0x4007), 0x28 },
+ { CCI_REG8(0x4009), 0x40 },
+ { CCI_REG8(0x4307), 0x30 },
+ { CCI_REG8(0x4500), 0x80 },
+ { CCI_REG8(0x4501), 0x02 },
+ { CCI_REG8(0x4502), 0x47 },
+ { CCI_REG8(0x4504), 0x7f },
+ { CCI_REG8(0x4601), 0x48 },
+ { CCI_REG8(0x4800), 0x64 },
+ { CCI_REG8(0x4801), 0x0f },
+ { CCI_REG8(0x4806), 0x2f },
+ { CCI_REG8(0x4819), 0xaa },
+ { CCI_REG8(0x4823), 0x3e },
+ { CCI_REG8(0x5000), 0x85 },
+ { CCI_REG8(0x5e00), 0x0c },
+ { CCI_REG8(0x3899), 0x09 },
+ { CCI_REG8(0x4f00), 0x64 },
+ { CCI_REG8(0x4f02), 0x0a },
+ { CCI_REG8(0x4f05), 0x0e },
+ { CCI_REG8(0x4f06), 0x11 },
+ { CCI_REG8(0x4f08), 0x0b },
+ { CCI_REG8(0x4f0a), 0xc4 },
+ { CCI_REG8(0x4f20), 0x1f },
+ { CCI_REG8(0x4f25), 0x10 },
+ { CCI_REG8(0x3016), 0x10 },
+ { CCI_REG8(0x3017), 0x00 },
+ { CCI_REG8(0x3018), 0x00 },
+ { CCI_REG8(0x3019), 0x00 },
+ { CCI_REG8(0x301a), 0x00 },
+ { CCI_REG8(0x301b), 0x00 },
+ { CCI_REG8(0x301c), 0x72 },
+ { CCI_REG8(0x3037), 0x40 },
+ { CCI_REG8(0x4f2c), 0x00 },
+ { CCI_REG8(0x4f21), 0x00 },
+ { CCI_REG8(0x4f23), 0x00 },
+ { CCI_REG8(0x4f2a), 0x00 },
+ { CCI_REG8(0x3665), 0xe7 },
+ { CCI_REG8(0x3668), 0x48 },
+ { CCI_REG8(0x3671), 0x3c },
+ { CCI_REG8(0x389a), 0x02 },
+ { CCI_REG8(0x389b), 0x00 },
+ { CCI_REG8(0x303c), 0xa0 },
+ { CCI_REG8(0x300f), 0xf0 },
+ { CCI_REG8(0x304b), 0x0f },
+ { CCI_REG8(0x3662), 0x24 },
+ { CCI_REG8(0x3006), 0x40 },
+ { CCI_REG8(0x4f26), 0x45 },
+ { CCI_REG8(0x3607), 0x34 },
+ { CCI_REG8(0x3608), 0x01 },
+ { CCI_REG8(0x360a), 0x0c },
+ { CCI_REG8(0x360b), 0x86 },
+ { CCI_REG8(0x360c), 0xcc },
+ { CCI_REG8(0x3013), 0x00 },
+ { CCI_REG8(0x3083), 0x02 },
+ { CCI_REG8(0x3084), 0x12 },
+ { CCI_REG8(0x4601), 0x38 },
+ { CCI_REG8(0x366f), 0x3a },
+ { CCI_REG8(0x3713), 0x19 },
+ { CCI_REG8(0x37a2), 0x00 },
+ { CCI_REG8(0x3f43), 0x27 },
+ { CCI_REG8(0x3f45), 0x27 },
+ { CCI_REG8(0x3f47), 0x32 },
+ { CCI_REG8(0x3f49), 0x3e },
+ { CCI_REG8(0x3f4b), 0x20 },
+ { CCI_REG8(0x3f4d), 0x30 },
+ { CCI_REG8(0x4300), 0x3f },
+ { CCI_REG8(0x4009), 0x10 },
+ { CCI_REG8(0x3f02), 0x68 },
+ { CCI_REG8(0x3700), 0x8c },
+ { CCI_REG8(0x370b), 0x7e },
+ { CCI_REG8(0x3f47), 0x35 },
+};...
+static int og0ve1b_probe(struct i2c_client *client)
+{
+ struct og0ve1b *og0ve1b;
+ unsigned long freq;
+ int ret;
+
+ og0ve1b = devm_kzalloc(&client->dev, sizeof(*og0ve1b), GFP_KERNEL);
+ if (!og0ve1b)
+ return -ENOMEM;
+
+ og0ve1b->dev = &client->dev;
+
+ v4l2_i2c_subdev_init(&og0ve1b->sd, client, &og0ve1b_subdev_ops);
+ og0ve1b->sd.dev = og0ve1b->dev;This seems unnecessary; drop this line.
+ + og0ve1b->regmap = devm_cci_regmap_init_i2c(client, 16); + if (IS_ERR(og0ve1b->regmap)) + return dev_err_probe(og0ve1b->dev, PTR_ERR(og0ve1b->regmap), + "failed to init CCI\n"); + + og0ve1b->xvclk = devm_v4l2_sensor_clk_get(og0ve1b->dev, NULL); + if (IS_ERR(og0ve1b->xvclk)) + return dev_err_probe(og0ve1b->dev, PTR_ERR(og0ve1b->xvclk), + "failed to get XVCLK clock\n"); + + freq = clk_get_rate(og0ve1b->xvclk); + if (freq && freq != OG0VE1B_MCLK_FREQ_24MHZ) + return dev_err_probe(og0ve1b->dev, -EINVAL, + "XVCLK clock frequency %lu is not supported\n", + freq);
...
+static const struct dev_pm_ops og0ve1b_pm_ops = {
+ SET_RUNTIME_PM_OPS(og0ve1b_power_off, og0ve1b_power_on, NULL)
+};
+
+static const struct of_device_id og0ve1b_of_match[] = {
+ { .compatible = "ovti,og0ve1b" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, og0ve1b_of_match);
+
+static struct i2c_driver og0ve1b_i2c_driver = {
+ .driver = {
+ .name = "og0ve1b",
+ .pm = &og0ve1b_pm_ops,
+ .of_match_table = og0ve1b_of_match,
+ },
+ .probe = og0ve1b_probe,
+ .remove = og0ve1b_remove,
+};
+
+module_i2c_driver(og0ve1b_i2c_driver);
+
+MODULE_AUTHOR("Vladimir Zapolskiy [off-list ref]");
+MODULE_DESCRIPTION("OmniVision OG0VE1B sensor driver");
+MODULE_LICENSE("GPL");
--
2.49.0Best Regards, Tarang