* [PATCH v2 01/15] media: i2c: os05b10: Use pm_runtime_get_if_active() when applying controls
2026-03-25 11:43 [PATCH v2 00/15] media: i2c: os05b10: Refactor driver and Add new features Tarang Raval
@ 2026-03-25 11:43 ` Tarang Raval
2026-03-25 11:43 ` [PATCH v2 02/15] media: i2c: os05b10: drop unused group-hold programming Tarang Raval
` (13 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Tarang Raval @ 2026-03-25 11:43 UTC (permalink / raw)
To: Sakari Ailus
Cc: Tarang Raval, stable, Himanshu Bhavani, Elgin Perumbilly,
Mauro Carvalho Chehab, Hans Verkuil, Vladimir Zapolskiy,
linux-media, linux-kernel
os05b10_set_ctrl() currently uses pm_runtime_get_if_in_use() to decide
whether controls should be applied to hardware.
This is not correct for the intended behavior. If the runtime PM usage
count is 0 while the device is still active, pm_runtime_get_if_in_use()
returns 0 and the control update is skipped, leaving the software state
updated but not the hardware state.
Use pm_runtime_get_if_active() instead so controls are applied whenever
the device is runtime-active, regardless of the current usage count.
Cc: stable@vger.kernel.org
Fixes: 3aa9296a23ec4("media: i2c: add os05b10 image sensor driver")
Signed-off-by: Tarang Raval <tarang.raval@siliconsignals.io>
---
drivers/media/i2c/os05b10.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/media/i2c/os05b10.c b/drivers/media/i2c/os05b10.c
index e0453c988e4a..5da5b7d21f31 100644
--- a/drivers/media/i2c/os05b10.c
+++ b/drivers/media/i2c/os05b10.c
@@ -531,7 +531,7 @@ static int os05b10_set_ctrl(struct v4l2_ctrl *ctrl)
return ret;
}
- if (pm_runtime_get_if_in_use(os05b10->dev) == 0)
+ if (pm_runtime_get_if_active(os05b10->dev) == 0)
return 0;
switch (ctrl->id) {
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v2 02/15] media: i2c: os05b10: drop unused group-hold programming
2026-03-25 11:43 [PATCH v2 00/15] media: i2c: os05b10: Refactor driver and Add new features Tarang Raval
2026-03-25 11:43 ` [PATCH v2 01/15] media: i2c: os05b10: Use pm_runtime_get_if_active() when applying controls Tarang Raval
@ 2026-03-25 11:43 ` Tarang Raval
2026-03-25 11:43 ` [PATCH v2 03/15] media: i2c: os05b10: add register definitions and use them in init table Tarang Raval
` (12 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Tarang Raval @ 2026-03-25 11:43 UTC (permalink / raw)
To: Sakari Ailus
Cc: Tarang Raval, Himanshu Bhavani, Elgin Perumbilly,
Mauro Carvalho Chehab, Hans Verkuil, Vladimir Zapolskiy,
Mehdi Djait, linux-media, linux-kernel
Register table included group-hold (0x3208) sequences for
groups 6/7/8/9 that only stage alternative tuning values in SRAM but are
never launched by the driver. Remove these group-hold blocks.
Also remove a duplicate register entry for 0x37bf.
Signed-off-by: Tarang Raval <tarang.raval@siliconsignals.io>
---
drivers/media/i2c/os05b10.c | 37 -------------------------------------
1 file changed, 37 deletions(-)
diff --git a/drivers/media/i2c/os05b10.c b/drivers/media/i2c/os05b10.c
index 5da5b7d21f31..62fb856cbdea 100644
--- a/drivers/media/i2c/os05b10.c
+++ b/drivers/media/i2c/os05b10.c
@@ -250,7 +250,6 @@ static const struct cci_reg_sequence os05b10_common_regs[] = {
{ CCI_REG8(0x37ab), 0x0e },
{ CCI_REG8(0x37ac), 0xa0 },
{ CCI_REG8(0x37be), 0x0a },
- { CCI_REG8(0x37bf), 0x05 },
{ CCI_REG8(0x37bb), 0x02 },
{ CCI_REG8(0x37bf), 0x05 },
{ CCI_REG8(0x37c2), 0x04 },
@@ -415,42 +414,6 @@ static const struct cci_reg_sequence os05b10_common_regs[] = {
{ CCI_REG8(0x5820), 0x00 },
{ CCI_REG8(0x5821), 0x00 },
{ CCI_REG8(0x3222), 0x03 },
- { CCI_REG8(0x3208), 0x06 },
- { CCI_REG8(0x3701), 0x1d },
- { CCI_REG8(0x37ab), 0x01 },
- { CCI_REG8(0x3790), 0x21 },
- { CCI_REG8(0x38be), 0x00 },
- { CCI_REG8(0x3791), 0x5a },
- { CCI_REG8(0x37bf), 0x1c },
- { CCI_REG8(0x3610), 0x37 },
- { CCI_REG8(0x3208), 0x16 },
- { CCI_REG8(0x3208), 0x07 },
- { CCI_REG8(0x3701), 0x1d },
- { CCI_REG8(0x37ab), 0x0e },
- { CCI_REG8(0x3790), 0x21 },
- { CCI_REG8(0x38be), 0x00 },
- { CCI_REG8(0x3791), 0x5a },
- { CCI_REG8(0x37bf), 0x0a },
- { CCI_REG8(0x3610), 0x87 },
- { CCI_REG8(0x3208), 0x17 },
- { CCI_REG8(0x3208), 0x08 },
- { CCI_REG8(0x3701), 0x1d },
- { CCI_REG8(0x37ab), 0x0e },
- { CCI_REG8(0x3790), 0x21 },
- { CCI_REG8(0x38be), 0x00 },
- { CCI_REG8(0x3791), 0x5a },
- { CCI_REG8(0x37bf), 0x0a },
- { CCI_REG8(0x3610), 0x87 },
- { CCI_REG8(0x3208), 0x18 },
- { CCI_REG8(0x3208), 0x09 },
- { CCI_REG8(0x3701), 0x1d },
- { CCI_REG8(0x37ab), 0x0e },
- { CCI_REG8(0x3790), 0x28 },
- { CCI_REG8(0x38be), 0x00 },
- { CCI_REG8(0x3791), 0x63 },
- { CCI_REG8(0x37bf), 0x0a },
- { CCI_REG8(0x3610), 0x87 },
- { CCI_REG8(0x3208), 0x19 },
};
struct os05b10 {
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v2 03/15] media: i2c: os05b10: add register definitions and use them in init table
2026-03-25 11:43 [PATCH v2 00/15] media: i2c: os05b10: Refactor driver and Add new features Tarang Raval
2026-03-25 11:43 ` [PATCH v2 01/15] media: i2c: os05b10: Use pm_runtime_get_if_active() when applying controls Tarang Raval
2026-03-25 11:43 ` [PATCH v2 02/15] media: i2c: os05b10: drop unused group-hold programming Tarang Raval
@ 2026-03-25 11:43 ` Tarang Raval
2026-03-25 11:43 ` [PATCH v2 04/15] media: i2c: os05b10: split common and mode-specific init registers Tarang Raval
` (11 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Tarang Raval @ 2026-03-25 11:43 UTC (permalink / raw)
To: Sakari Ailus
Cc: Tarang Raval, Himanshu Bhavani, Elgin Perumbilly,
Mauro Carvalho Chehab, Mehdi Djait, Vladimir Zapolskiy,
Hans Verkuil, linux-media, linux-kernel
Define named register macros for OS05B10 and replace raw register
addresses in the common initialization array with the new definitions.
This improves readability and maintainability without changing
functionality.
Signed-off-by: Tarang Raval <tarang.raval@siliconsignals.io>
---
drivers/media/i2c/os05b10.c | 111 +++++++++++++++++++++++-------------
1 file changed, 71 insertions(+), 40 deletions(-)
diff --git a/drivers/media/i2c/os05b10.c b/drivers/media/i2c/os05b10.c
index 62fb856cbdea..751494fdba6d 100644
--- a/drivers/media/i2c/os05b10.c
+++ b/drivers/media/i2c/os05b10.c
@@ -38,6 +38,20 @@
#define OS05B10_MODE_STANDBY 0x00
#define OS05B10_MODE_STREAMING 0x01
+#define OS05B10_REG_PLL_CTRL_01 CCI_REG8(0x0301)
+#define OS05B10_REG_PLL_CTRL_03 CCI_REG8(0x0303)
+#define OS05B10_REG_PLL_CTRL_05 CCI_REG8(0x0305)
+#define OS05B10_REG_PLL_CTRL_06 CCI_REG8(0x0306)
+#define OS05B10_REG_PLL_CTRL_25 CCI_REG8(0x0325)
+
+#define OS05B10_REG_MIPI_SC_CTRL CCI_REG8(0x3016)
+#define OS05B10_4_LANE_MODE 0x72
+#define OS05B10_2_LANE_MODE 0x32
+
+#define OS05B10_REG_MIPI_SC_CTRL_1 CCI_REG8(0x3022)
+#define OS05B10_10BIT_MODE 0x01
+#define OS05B10_12BIT_MODE 0x61
+
#define OS05B10_REG_EXPOSURE CCI_REG24(0x3500)
#define OS05B10_EXPOSURE_MIN 2
#define OS05B10_EXPOSURE_STEP 1
@@ -49,11 +63,42 @@
#define OS05B10_ANALOG_GAIN_STEP 1
#define OS05B10_ANALOG_GAIN_DEFAULT 0x80
+#define OS05B10_REG_DIGITAL_GAIN CCI_REG16(0x350a)
+#define OS05B10_DIGITAL_GAIN_MIN 0x400
+#define OS05B10_DIGITAL_GAIN_MAX 0x3fff
+#define OS05B10_DIGITAL_GAIN_STEP 16
+#define OS05B10_DIGITAL_GAIN_DEFAULT 0x400
+
+#define OS05B10_REG_ANALOG_GAIN_SHORT CCI_REG16(0x350c)
+#define OS05B10_REG_DIGITAL_GAIN_SHORT CCI_REG16(0x350e)
+#define OS05B10_REG_EXPOSURE_SHORT CCI_REG24(0x3510)
+
+#define OS05B10_REG_X_ADDR_START CCI_REG16(0x3800)
+#define OS05B10_REG_Y_ADDR_START CCI_REG16(0x3802)
+#define OS05B10_REG_X_ADDR_END CCI_REG16(0x3804)
+#define OS05B10_REG_Y_ADDR_END CCI_REG16(0x3806)
+#define OS05B10_REG_X_OUTPUT_SIZE CCI_REG16(0x3808)
+#define OS05B10_REG_Y_OUTPUT_SIZE CCI_REG16(0x380a)
+
#define OS05B10_REG_HTS CCI_REG16(0x380c)
#define OS05B10_REG_VTS CCI_REG16(0x380e)
#define OS05B10_VTS_MAX 0x7fff
+#define OS05B10_REG_ISP_X_WIN CCI_REG16(0x3810)
+#define OS05B10_REG_ISP_Y_WIN CCI_REG16(0x3812)
+#define OS05B10_REG_X_INC_ODD CCI_REG8(0x3814)
+#define OS05B10_REG_X_INC_EVEN CCI_REG8(0x3815)
+#define OS05B10_REG_Y_INC_ODD CCI_REG8(0x3816)
+#define OS05B10_REG_Y_INC_EVEN CCI_REG8(0x3817)
+
+#define OS05B10_REG_FORMAT1 CCI_REG8(0x3820)
+#define OS05B10_MIRROR BIT(3)
+#define OS05B10_FLIP GENMASK(5, 4)
+
+#define OS05B10_REG_FORMAT2 CCI_REG8(0x3821)
+#define OS05B10_HDR_ENABLE 0x04
+
#define OS05B10_LINK_FREQ_600MHZ (600 * HZ_PER_MHZ)
static const struct v4l2_rect os05b10_native_area = {
@@ -77,30 +122,25 @@ static const char * const os05b10_supply_name[] = {
};
static const struct cci_reg_sequence os05b10_common_regs[] = {
- { CCI_REG8(0x0301), 0x44 },
- { CCI_REG8(0x0303), 0x02 },
- { CCI_REG8(0x0305), 0x32 },
- { CCI_REG8(0x0306), 0x00 },
- { CCI_REG8(0x0325), 0x3b },
+ { OS05B10_REG_PLL_CTRL_01, 0x44 },
+ { OS05B10_REG_PLL_CTRL_03, 0x02 },
+ { OS05B10_REG_PLL_CTRL_05, 0x32 },
+ { OS05B10_REG_PLL_CTRL_06, 0x00 },
+ { OS05B10_REG_PLL_CTRL_25, 0x3b },
{ CCI_REG8(0x3002), 0x21 },
- { CCI_REG8(0x3016), 0x72 },
+ { OS05B10_REG_MIPI_SC_CTRL, 0x72 },
{ CCI_REG8(0x301e), 0xb4 },
{ CCI_REG8(0x301f), 0xd0 },
{ CCI_REG8(0x3021), 0x03 },
- { CCI_REG8(0x3022), 0x01 },
+ { OS05B10_REG_MIPI_SC_CTRL_1, 0x01 },
{ CCI_REG8(0x3107), 0xa1 },
{ CCI_REG8(0x3108), 0x7d },
{ CCI_REG8(0x3109), 0xfc },
{ CCI_REG8(0x3503), 0x88 },
- { CCI_REG8(0x350a), 0x04 },
- { CCI_REG8(0x350b), 0x00 },
- { CCI_REG8(0x350c), 0x00 },
- { CCI_REG8(0x350d), 0x80 },
- { CCI_REG8(0x350e), 0x04 },
- { CCI_REG8(0x350f), 0x00 },
- { CCI_REG8(0x3510), 0x00 },
- { CCI_REG8(0x3511), 0x00 },
- { CCI_REG8(0x3512), 0x20 },
+ { OS05B10_REG_DIGITAL_GAIN, 0x0400 },
+ { OS05B10_REG_ANALOG_GAIN_SHORT, 0x0080 },
+ { OS05B10_REG_DIGITAL_GAIN_SHORT, 0x0400 },
+ { OS05B10_REG_EXPOSURE_SHORT, 0x000020 },
{ CCI_REG8(0x3600), 0x4d },
{ CCI_REG8(0x3601), 0x08 },
{ CCI_REG8(0x3610), 0x87 },
@@ -274,34 +314,25 @@ static const struct cci_reg_sequence os05b10_common_regs[] = {
{ CCI_REG8(0x37f5), 0x00 },
{ CCI_REG8(0x37f6), 0x00 },
{ CCI_REG8(0x37f7), 0x00 },
- { CCI_REG8(0x3800), 0x01 },
- { CCI_REG8(0x3801), 0x30 },
- { CCI_REG8(0x3802), 0x00 },
- { CCI_REG8(0x3803), 0x00 },
- { CCI_REG8(0x3804), 0x0b },
- { CCI_REG8(0x3805), 0x5f },
- { CCI_REG8(0x3806), 0x07 },
- { CCI_REG8(0x3807), 0xa7 },
- { CCI_REG8(0x3808), 0x0a },
- { CCI_REG8(0x3809), 0x20 },
- { CCI_REG8(0x380a), 0x07 },
- { CCI_REG8(0x380b), 0x98 },
- { CCI_REG8(0x380c), 0x06 },
- { CCI_REG8(0x380d), 0xd0 },
- { CCI_REG8(0x3810), 0x00 },
- { CCI_REG8(0x3811), 0x08 },
- { CCI_REG8(0x3812), 0x00 },
- { CCI_REG8(0x3813), 0x08 },
- { CCI_REG8(0x3814), 0x01 },
- { CCI_REG8(0x3815), 0x01 },
- { CCI_REG8(0x3816), 0x01 },
- { CCI_REG8(0x3817), 0x01 },
+ { OS05B10_REG_X_ADDR_START, 0x0130 },
+ { OS05B10_REG_Y_ADDR_START, 0x0000 },
+ { OS05B10_REG_X_ADDR_END, 0x0b5f },
+ { OS05B10_REG_Y_ADDR_END, 0x07a7 },
+ { OS05B10_REG_X_OUTPUT_SIZE, 0x0a20 },
+ { OS05B10_REG_Y_OUTPUT_SIZE, 0x0798 },
+ { OS05B10_REG_HTS, 0x06d0 },
+ { OS05B10_REG_ISP_X_WIN, 0x0008 },
+ { OS05B10_REG_ISP_Y_WIN, 0x0008 },
+ { OS05B10_REG_X_INC_ODD, 0x01 },
+ { OS05B10_REG_X_INC_EVEN, 0x01 },
+ { OS05B10_REG_Y_INC_ODD, 0x01 },
+ { OS05B10_REG_Y_INC_EVEN, 0x01 },
{ CCI_REG8(0x3818), 0x00 },
{ CCI_REG8(0x3819), 0x00 },
{ CCI_REG8(0x381a), 0x00 },
{ CCI_REG8(0x381b), 0x01 },
- { CCI_REG8(0x3820), 0x88 },
- { CCI_REG8(0x3821), 0x00 },
+ { OS05B10_REG_FORMAT1, 0x88 },
+ { OS05B10_REG_FORMAT2, 0x00 },
{ CCI_REG8(0x3822), 0x12 },
{ CCI_REG8(0x3823), 0x08 },
{ CCI_REG8(0x3824), 0x00 },
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v2 04/15] media: i2c: os05b10: split common and mode-specific init registers
2026-03-25 11:43 [PATCH v2 00/15] media: i2c: os05b10: Refactor driver and Add new features Tarang Raval
` (2 preceding siblings ...)
2026-03-25 11:43 ` [PATCH v2 03/15] media: i2c: os05b10: add register definitions and use them in init table Tarang Raval
@ 2026-03-25 11:43 ` Tarang Raval
2026-03-25 11:43 ` [PATCH v2 05/15] media: i2c: os05b10: add V4L2 digital gain control Tarang Raval
` (10 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Tarang Raval @ 2026-03-25 11:43 UTC (permalink / raw)
To: Sakari Ailus
Cc: Tarang Raval, Himanshu Bhavani, Elgin Perumbilly,
Mauro Carvalho Chehab, Hans Verkuil, Vladimir Zapolskiy,
linux-media, linux-kernel
Separate common initialization registers from mode-specific settings.
Move resolution-dependent registers into a per-mode register list and
program them during stream enable.
Signed-off-by: Tarang Raval <tarang.raval@siliconsignals.io>
---
drivers/media/i2c/os05b10.c | 118 ++++++++++++++++++++++--------------
1 file changed, 74 insertions(+), 44 deletions(-)
diff --git a/drivers/media/i2c/os05b10.c b/drivers/media/i2c/os05b10.c
index 751494fdba6d..9499867ad40e 100644
--- a/drivers/media/i2c/os05b10.c
+++ b/drivers/media/i2c/os05b10.c
@@ -122,37 +122,34 @@ static const char * const os05b10_supply_name[] = {
};
static const struct cci_reg_sequence os05b10_common_regs[] = {
- { OS05B10_REG_PLL_CTRL_01, 0x44 },
- { OS05B10_REG_PLL_CTRL_03, 0x02 },
- { OS05B10_REG_PLL_CTRL_05, 0x32 },
- { OS05B10_REG_PLL_CTRL_06, 0x00 },
- { OS05B10_REG_PLL_CTRL_25, 0x3b },
+ { OS05B10_REG_PLL_CTRL_01, 0x44 },
+ { OS05B10_REG_PLL_CTRL_03, 0x02 },
+ { OS05B10_REG_PLL_CTRL_05, 0x32 },
+ { OS05B10_REG_PLL_CTRL_06, 0x00 },
+ { OS05B10_REG_PLL_CTRL_25, 0x3b },
+ { OS05B10_REG_MIPI_SC_CTRL, 0x72 },
+ { OS05B10_REG_MIPI_SC_CTRL_1, 0x01 },
+ { OS05B10_REG_DIGITAL_GAIN, 0x0400 },
+ { OS05B10_REG_ANALOG_GAIN_SHORT, 0x0080 },
+ { OS05B10_REG_DIGITAL_GAIN_SHORT, 0x0400 },
+ { OS05B10_REG_EXPOSURE_SHORT, 0x000020 },
{ CCI_REG8(0x3002), 0x21 },
- { OS05B10_REG_MIPI_SC_CTRL, 0x72 },
{ CCI_REG8(0x301e), 0xb4 },
{ CCI_REG8(0x301f), 0xd0 },
{ CCI_REG8(0x3021), 0x03 },
- { OS05B10_REG_MIPI_SC_CTRL_1, 0x01 },
{ CCI_REG8(0x3107), 0xa1 },
{ CCI_REG8(0x3108), 0x7d },
{ CCI_REG8(0x3109), 0xfc },
{ CCI_REG8(0x3503), 0x88 },
- { OS05B10_REG_DIGITAL_GAIN, 0x0400 },
- { OS05B10_REG_ANALOG_GAIN_SHORT, 0x0080 },
- { OS05B10_REG_DIGITAL_GAIN_SHORT, 0x0400 },
- { OS05B10_REG_EXPOSURE_SHORT, 0x000020 },
{ CCI_REG8(0x3600), 0x4d },
{ CCI_REG8(0x3601), 0x08 },
- { CCI_REG8(0x3610), 0x87 },
{ CCI_REG8(0x3611), 0x24 },
{ CCI_REG8(0x3614), 0x4c },
- { CCI_REG8(0x3620), 0x0c },
{ CCI_REG8(0x3632), 0x80 },
{ CCI_REG8(0x3633), 0x00 },
{ CCI_REG8(0x3636), 0xcc },
{ CCI_REG8(0x3637), 0x27 },
{ CCI_REG8(0x3660), 0x00 },
- { CCI_REG8(0x3662), 0x10 },
{ CCI_REG8(0x3665), 0x00 },
{ CCI_REG8(0x3666), 0x00 },
{ CCI_REG8(0x366a), 0x14 },
@@ -236,7 +233,6 @@ static const struct cci_reg_sequence os05b10_common_regs[] = {
{ CCI_REG8(0x370f), 0x1c },
{ CCI_REG8(0x3710), 0x00 },
{ CCI_REG8(0x3713), 0x00 },
- { CCI_REG8(0x3714), 0x24 },
{ CCI_REG8(0x3716), 0x24 },
{ CCI_REG8(0x371a), 0x1e },
{ CCI_REG8(0x3724), 0x09 },
@@ -245,7 +241,6 @@ static const struct cci_reg_sequence os05b10_common_regs[] = {
{ CCI_REG8(0x3730), 0xe1 },
{ CCI_REG8(0x3735), 0x80 },
{ CCI_REG8(0x3739), 0x10 },
- { CCI_REG8(0x373f), 0xb0 },
{ CCI_REG8(0x3740), 0x28 },
{ CCI_REG8(0x3741), 0x21 },
{ CCI_REG8(0x3742), 0x21 },
@@ -291,8 +286,6 @@ static const struct cci_reg_sequence os05b10_common_regs[] = {
{ CCI_REG8(0x37ac), 0xa0 },
{ CCI_REG8(0x37be), 0x0a },
{ CCI_REG8(0x37bb), 0x02 },
- { CCI_REG8(0x37bf), 0x05 },
- { CCI_REG8(0x37c2), 0x04 },
{ CCI_REG8(0x37c4), 0x11 },
{ CCI_REG8(0x37c5), 0x80 },
{ CCI_REG8(0x37c6), 0x14 },
@@ -301,7 +294,6 @@ static const struct cci_reg_sequence os05b10_common_regs[] = {
{ CCI_REG8(0x37cd), 0x17 },
{ CCI_REG8(0x37ce), 0x01 },
{ CCI_REG8(0x37d8), 0x02 },
- { CCI_REG8(0x37d9), 0x08 },
{ CCI_REG8(0x37dc), 0x01 },
{ CCI_REG8(0x37e0), 0x0c },
{ CCI_REG8(0x37e1), 0x20 },
@@ -314,25 +306,10 @@ static const struct cci_reg_sequence os05b10_common_regs[] = {
{ CCI_REG8(0x37f5), 0x00 },
{ CCI_REG8(0x37f6), 0x00 },
{ CCI_REG8(0x37f7), 0x00 },
- { OS05B10_REG_X_ADDR_START, 0x0130 },
- { OS05B10_REG_Y_ADDR_START, 0x0000 },
- { OS05B10_REG_X_ADDR_END, 0x0b5f },
- { OS05B10_REG_Y_ADDR_END, 0x07a7 },
- { OS05B10_REG_X_OUTPUT_SIZE, 0x0a20 },
- { OS05B10_REG_Y_OUTPUT_SIZE, 0x0798 },
- { OS05B10_REG_HTS, 0x06d0 },
- { OS05B10_REG_ISP_X_WIN, 0x0008 },
- { OS05B10_REG_ISP_Y_WIN, 0x0008 },
- { OS05B10_REG_X_INC_ODD, 0x01 },
- { OS05B10_REG_X_INC_EVEN, 0x01 },
- { OS05B10_REG_Y_INC_ODD, 0x01 },
- { OS05B10_REG_Y_INC_EVEN, 0x01 },
{ CCI_REG8(0x3818), 0x00 },
{ CCI_REG8(0x3819), 0x00 },
{ CCI_REG8(0x381a), 0x00 },
{ CCI_REG8(0x381b), 0x01 },
- { OS05B10_REG_FORMAT1, 0x88 },
- { OS05B10_REG_FORMAT2, 0x00 },
{ CCI_REG8(0x3822), 0x12 },
{ CCI_REG8(0x3823), 0x08 },
{ CCI_REG8(0x3824), 0x00 },
@@ -342,7 +319,6 @@ static const struct cci_reg_sequence os05b10_common_regs[] = {
{ CCI_REG8(0x3829), 0x03 },
{ CCI_REG8(0x382a), 0x00 },
{ CCI_REG8(0x382b), 0x00 },
- { CCI_REG8(0x3832), 0x08 },
{ CCI_REG8(0x3838), 0x00 },
{ CCI_REG8(0x3839), 0x00 },
{ CCI_REG8(0x383a), 0x00 },
@@ -363,26 +339,19 @@ static const struct cci_reg_sequence os05b10_common_regs[] = {
{ CCI_REG8(0x38a7), 0x04 },
{ CCI_REG8(0x38b8), 0x02 },
{ CCI_REG8(0x3c80), 0x3e },
- { CCI_REG8(0x3c86), 0x01 },
{ CCI_REG8(0x3c87), 0x02 },
{ CCI_REG8(0x389c), 0x00 },
{ CCI_REG8(0x3ca2), 0x0c },
{ CCI_REG8(0x3d85), 0x1b },
- { CCI_REG8(0x3d8c), 0x01 },
{ CCI_REG8(0x3d8d), 0xe2 },
{ CCI_REG8(0x3f00), 0xcb },
- { CCI_REG8(0x3f03), 0x08 },
{ CCI_REG8(0x3f9e), 0x07 },
{ CCI_REG8(0x3f9f), 0x04 },
{ CCI_REG8(0x4000), 0xf3 },
{ CCI_REG8(0x4002), 0x00 },
{ CCI_REG8(0x4003), 0x40 },
- { CCI_REG8(0x4008), 0x02 },
- { CCI_REG8(0x4009), 0x0d },
- { CCI_REG8(0x400a), 0x01 },
{ CCI_REG8(0x400b), 0x00 },
{ CCI_REG8(0x4040), 0x00 },
- { CCI_REG8(0x4041), 0x07 },
{ CCI_REG8(0x4090), 0x14 },
{ CCI_REG8(0x40b0), 0x01 },
{ CCI_REG8(0x40b1), 0x01 },
@@ -402,7 +371,6 @@ static const struct cci_reg_sequence os05b10_common_regs[] = {
{ CCI_REG8(0x4305), 0x83 },
{ CCI_REG8(0x4306), 0x21 },
{ CCI_REG8(0x430d), 0x00 },
- { CCI_REG8(0x4505), 0xc4 },
{ CCI_REG8(0x4506), 0x00 },
{ CCI_REG8(0x4507), 0x60 },
{ CCI_REG8(0x4803), 0x00 },
@@ -414,7 +382,6 @@ static const struct cci_reg_sequence os05b10_common_regs[] = {
{ CCI_REG8(0x481f), 0x30 },
{ CCI_REG8(0x4825), 0x34 },
{ CCI_REG8(0x4829), 0x64 },
- { CCI_REG8(0x4837), 0x12 },
{ CCI_REG8(0x484b), 0x07 },
{ CCI_REG8(0x4883), 0x36 },
{ CCI_REG8(0x4885), 0x03 },
@@ -447,6 +414,42 @@ static const struct cci_reg_sequence os05b10_common_regs[] = {
{ CCI_REG8(0x3222), 0x03 },
};
+static const struct cci_reg_sequence mode_2592_1944_regs[] = {
+ { OS05B10_REG_X_ADDR_START, 0x0130 },
+ { OS05B10_REG_Y_ADDR_START, 0x0000 },
+ { OS05B10_REG_X_ADDR_END, 0x0b5f },
+ { OS05B10_REG_Y_ADDR_END, 0x07a7 },
+ { OS05B10_REG_X_OUTPUT_SIZE, 0x0a20 },
+ { OS05B10_REG_Y_OUTPUT_SIZE, 0x0798 },
+ { OS05B10_REG_HTS, 0x06d0 },
+ { OS05B10_REG_ISP_X_WIN, 0x0008 },
+ { OS05B10_REG_ISP_Y_WIN, 0x0008 },
+ { OS05B10_REG_X_INC_ODD, 0x01 },
+ { OS05B10_REG_X_INC_EVEN, 0x01 },
+ { OS05B10_REG_Y_INC_ODD, 0x01 },
+ { OS05B10_REG_Y_INC_EVEN, 0x01 },
+ { OS05B10_REG_FORMAT1, 0x88 },
+ { OS05B10_REG_FORMAT2, 0x00 },
+ { CCI_REG8(0x3610), 0x87 },
+ { CCI_REG8(0x3620), 0x0c },
+ { CCI_REG8(0x3662), 0x10 },
+ { CCI_REG8(0x3714), 0x24 },
+ { CCI_REG8(0x373f), 0xb0 },
+ { CCI_REG8(0x37bf), 0x05 },
+ { CCI_REG8(0x37c2), 0x04 },
+ { CCI_REG8(0x37d9), 0x08 },
+ { CCI_REG8(0x3832), 0x08 },
+ { CCI_REG8(0x3c86), 0x01 },
+ { CCI_REG8(0x3d8c), 0x01 },
+ { CCI_REG8(0x3f03), 0x08 },
+ { CCI_REG8(0x4008), 0x02 },
+ { CCI_REG8(0x4009), 0x0d },
+ { CCI_REG8(0x400a), 0x01 },
+ { CCI_REG8(0x4041), 0x07 },
+ { CCI_REG8(0x4505), 0xc4 },
+ { CCI_REG8(0x4837), 0x12 },
+};
+
struct os05b10 {
struct device *dev;
struct regmap *cci;
@@ -469,6 +472,11 @@ struct os05b10 {
u32 data_lanes;
};
+struct os05b10_reg_list {
+ u32 num_of_regs;
+ const struct cci_reg_sequence *regs;
+};
+
struct os05b10_mode {
u32 width;
u32 height;
@@ -476,6 +484,7 @@ struct os05b10_mode {
u32 hts;
u32 exp;
u8 bpp;
+ struct os05b10_reg_list reg_list;
};
static const struct os05b10_mode supported_modes_10bit[] = {
@@ -486,6 +495,10 @@ static const struct os05b10_mode supported_modes_10bit[] = {
.hts = 1744,
.exp = 1944,
.bpp = 10,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_2592_1944_regs),
+ .regs = mode_2592_1944_regs,
+ },
},
};
@@ -655,8 +668,16 @@ static int os05b10_enable_streams(struct v4l2_subdev *sd,
u32 pad, u64 streams_mask)
{
struct os05b10 *os05b10 = to_os05b10(sd);
+ const struct os05b10_reg_list *reg_list;
+ const struct v4l2_mbus_framefmt *fmt;
+ const struct os05b10_mode *mode;
int ret;
+ fmt = v4l2_subdev_state_get_format(state, 0);
+ mode = v4l2_find_nearest_size(supported_modes_10bit,
+ ARRAY_SIZE(supported_modes_10bit), width,
+ height, fmt->width, fmt->height);
+
ret = pm_runtime_resume_and_get(os05b10->dev);
if (ret < 0)
return ret;
@@ -669,6 +690,15 @@ static int os05b10_enable_streams(struct v4l2_subdev *sd,
goto err_rpm_put;
}
+ /* Write sensor mode registers */
+ reg_list = &mode->reg_list;
+ ret = cci_multi_reg_write(os05b10->cci, reg_list->regs,
+ reg_list->num_of_regs, NULL);
+ if (ret) {
+ dev_err(os05b10->dev, "fail to write initial registers\n");
+ goto err_rpm_put;
+ }
+
/* Apply customized user controls */
ret = __v4l2_ctrl_handler_setup(os05b10->sd.ctrl_handler);
if (ret)
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v2 05/15] media: i2c: os05b10: add V4L2 digital gain control
2026-03-25 11:43 [PATCH v2 00/15] media: i2c: os05b10: Refactor driver and Add new features Tarang Raval
` (3 preceding siblings ...)
2026-03-25 11:43 ` [PATCH v2 04/15] media: i2c: os05b10: split common and mode-specific init registers Tarang Raval
@ 2026-03-25 11:43 ` Tarang Raval
2026-03-25 11:43 ` [PATCH v2 06/15] media: i2c: os05b10: Add H/V flip support Tarang Raval
` (9 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Tarang Raval @ 2026-03-25 11:43 UTC (permalink / raw)
To: Sakari Ailus
Cc: Tarang Raval, Himanshu Bhavani, Elgin Perumbilly,
Mauro Carvalho Chehab, Vladimir Zapolskiy, Hans Verkuil,
linux-media, linux-kernel
Stop programming digital gain in the common register sequence and expose it as
a V4L2_CID_DIGITAL_GAIN control. Initialize the new control and handle writes
in the ctrl callback.
Signed-off-by: Tarang Raval <tarang.raval@siliconsignals.io>
---
drivers/media/i2c/os05b10.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/media/i2c/os05b10.c b/drivers/media/i2c/os05b10.c
index 9499867ad40e..2f47b02149b7 100644
--- a/drivers/media/i2c/os05b10.c
+++ b/drivers/media/i2c/os05b10.c
@@ -129,7 +129,6 @@ static const struct cci_reg_sequence os05b10_common_regs[] = {
{ OS05B10_REG_PLL_CTRL_25, 0x3b },
{ OS05B10_REG_MIPI_SC_CTRL, 0x72 },
{ OS05B10_REG_MIPI_SC_CTRL_1, 0x01 },
- { OS05B10_REG_DIGITAL_GAIN, 0x0400 },
{ OS05B10_REG_ANALOG_GAIN_SHORT, 0x0080 },
{ OS05B10_REG_DIGITAL_GAIN_SHORT, 0x0400 },
{ OS05B10_REG_EXPOSURE_SHORT, 0x000020 },
@@ -550,6 +549,10 @@ static int os05b10_set_ctrl(struct v4l2_ctrl *ctrl)
ret = cci_write(os05b10->cci, OS05B10_REG_ANALOG_GAIN,
ctrl->val, NULL);
break;
+ case V4L2_CID_DIGITAL_GAIN:
+ ret = cci_write(os05b10->cci, OS05B10_REG_DIGITAL_GAIN,
+ ctrl->val, NULL);
+ break;
case V4L2_CID_EXPOSURE:
ret = cci_write(os05b10->cci, OS05B10_REG_EXPOSURE,
ctrl->val, NULL);
@@ -926,7 +929,7 @@ static int os05b10_init_controls(struct os05b10 *os05b10)
int ret;
ctrl_hdlr = &os05b10->handler;
- v4l2_ctrl_handler_init(ctrl_hdlr, 8);
+ v4l2_ctrl_handler_init(ctrl_hdlr, 9);
pixel_rate = os05b10_pixel_rate(os05b10, mode);
v4l2_ctrl_new_std(ctrl_hdlr, &os05b10_ctrl_ops, V4L2_CID_PIXEL_RATE,
@@ -968,6 +971,10 @@ static int os05b10_init_controls(struct os05b10 *os05b10)
OS05B10_ANALOG_GAIN_STEP,
OS05B10_ANALOG_GAIN_DEFAULT);
+ v4l2_ctrl_new_std(ctrl_hdlr, &os05b10_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
+ OS05B10_DIGITAL_GAIN_MIN, OS05B10_DIGITAL_GAIN_MAX,
+ OS05B10_DIGITAL_GAIN_STEP, OS05B10_DIGITAL_GAIN_DEFAULT);
+
if (ctrl_hdlr->error) {
ret = ctrl_hdlr->error;
dev_err(os05b10->dev, "control init failed (%d)\n", ret);
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v2 06/15] media: i2c: os05b10: Add H/V flip support
2026-03-25 11:43 [PATCH v2 00/15] media: i2c: os05b10: Refactor driver and Add new features Tarang Raval
` (4 preceding siblings ...)
2026-03-25 11:43 ` [PATCH v2 05/15] media: i2c: os05b10: add V4L2 digital gain control Tarang Raval
@ 2026-03-25 11:43 ` Tarang Raval
2026-03-25 11:43 ` [PATCH v2 07/15] media: i2c: os05b10: Add test pattern options Tarang Raval
` (8 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Tarang Raval @ 2026-03-25 11:43 UTC (permalink / raw)
To: Sakari Ailus
Cc: Tarang Raval, Himanshu Bhavani, Elgin Perumbilly,
Mauro Carvalho Chehab, Hans Verkuil, Mehdi Djait, linux-media,
linux-kernel
Add HFLIP and VFLIP controls, lock them while streaming,
and update the reported Bayer format based on the flip state.
Signed-off-by: Tarang Raval <tarang.raval@siliconsignals.io>
---
drivers/media/i2c/os05b10.c | 59 ++++++++++++++++++++++++++++++++++---
1 file changed, 55 insertions(+), 4 deletions(-)
diff --git a/drivers/media/i2c/os05b10.c b/drivers/media/i2c/os05b10.c
index 2f47b02149b7..bf848eb9ba52 100644
--- a/drivers/media/i2c/os05b10.c
+++ b/drivers/media/i2c/os05b10.c
@@ -96,6 +96,10 @@
#define OS05B10_MIRROR BIT(3)
#define OS05B10_FLIP GENMASK(5, 4)
+#define OS05B10_REG_ANALOG_FLIP CCI_REG8(0x3716)
+#define OS05B10_FLIP_ENABLE 0x04
+#define OS05B10_FLIP_DISABLE 0x24
+
#define OS05B10_REG_FORMAT2 CCI_REG8(0x3821)
#define OS05B10_HDR_ENABLE 0x04
@@ -232,7 +236,6 @@ static const struct cci_reg_sequence os05b10_common_regs[] = {
{ CCI_REG8(0x370f), 0x1c },
{ CCI_REG8(0x3710), 0x00 },
{ CCI_REG8(0x3713), 0x00 },
- { CCI_REG8(0x3716), 0x24 },
{ CCI_REG8(0x371a), 0x1e },
{ CCI_REG8(0x3724), 0x09 },
{ CCI_REG8(0x3725), 0xb2 },
@@ -466,6 +469,8 @@ struct os05b10 {
struct v4l2_ctrl *vblank;
struct v4l2_ctrl *gain;
struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *vflip;
+ struct v4l2_ctrl *hflip;
u32 link_freq_index;
u32 data_lanes;
@@ -514,6 +519,18 @@ static inline struct os05b10 *to_os05b10(struct v4l2_subdev *sd)
return container_of_const(sd, struct os05b10, sd);
};
+static u32 os05b10_get_format_code(struct os05b10 *os05b10)
+{
+ static const u32 codes[2][2] = {
+ { MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SGBRG10_1X10, },
+ { MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SRGGB10_1X10, },
+ };
+
+ u32 code = codes[os05b10->vflip->val][os05b10->hflip->val];
+
+ return code;
+}
+
static int os05b10_set_ctrl(struct v4l2_ctrl *ctrl)
{
struct os05b10 *os05b10 = container_of_const(ctrl->handler,
@@ -557,6 +574,21 @@ static int os05b10_set_ctrl(struct v4l2_ctrl *ctrl)
ret = cci_write(os05b10->cci, OS05B10_REG_EXPOSURE,
ctrl->val, NULL);
break;
+ case V4L2_CID_HFLIP:
+ case V4L2_CID_VFLIP:
+ ret = cci_update_bits(os05b10->cci, OS05B10_REG_FORMAT1,
+ GENMASK(5, 3),
+ (!os05b10->hflip->val) << 3 |
+ os05b10->vflip->val << 5 |
+ os05b10->vflip->val << 4, NULL);
+ if (ret)
+ return ret;
+
+ ret = cci_write(os05b10->cci, OS05B10_REG_ANALOG_FLIP,
+ (os05b10->vflip->val == 1) ?
+ OS05B10_FLIP_ENABLE : OS05B10_FLIP_DISABLE,
+ NULL);
+ break;
default:
ret = -EINVAL;
break;
@@ -571,10 +603,12 @@ static int os05b10_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
+ struct os05b10 *os05b10 = to_os05b10(sd);
+
if (code->index >= ARRAY_SIZE(os05b10_mbus_codes))
return -EINVAL;
- code->code = os05b10_mbus_codes[code->index];
+ code->code = os05b10_get_format_code(os05b10);
return 0;
}
@@ -713,6 +747,9 @@ static int os05b10_enable_streams(struct v4l2_subdev *sd,
if (ret)
goto err_rpm_put;
+ __v4l2_ctrl_grab(os05b10->vflip, true);
+ __v4l2_ctrl_grab(os05b10->hflip, true);
+
return 0;
err_rpm_put:
@@ -733,6 +770,9 @@ static int os05b10_disable_streams(struct v4l2_subdev *sd,
if (ret)
dev_err(os05b10->dev, "failed to set stream off\n");
+ __v4l2_ctrl_grab(os05b10->vflip, false);
+ __v4l2_ctrl_grab(os05b10->hflip, false);
+
pm_runtime_put(os05b10->dev);
return 0;
@@ -741,6 +781,7 @@ static int os05b10_disable_streams(struct v4l2_subdev *sd,
static int os05b10_init_state(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state)
{
+ struct os05b10 *os05b10 = to_os05b10(sd);
struct v4l2_mbus_framefmt *format;
const struct os05b10_mode *mode;
@@ -748,7 +789,7 @@ static int os05b10_init_state(struct v4l2_subdev *sd,
format = v4l2_subdev_state_get_format(state, 0);
mode = &supported_modes_10bit[0];
- format->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+ format->code = os05b10_get_format_code(os05b10);
/* Update image pad formate */
format->width = mode->width;
@@ -929,7 +970,7 @@ static int os05b10_init_controls(struct os05b10 *os05b10)
int ret;
ctrl_hdlr = &os05b10->handler;
- v4l2_ctrl_handler_init(ctrl_hdlr, 9);
+ v4l2_ctrl_handler_init(ctrl_hdlr, 11);
pixel_rate = os05b10_pixel_rate(os05b10, mode);
v4l2_ctrl_new_std(ctrl_hdlr, &os05b10_ctrl_ops, V4L2_CID_PIXEL_RATE,
@@ -975,6 +1016,16 @@ static int os05b10_init_controls(struct os05b10 *os05b10)
OS05B10_DIGITAL_GAIN_MIN, OS05B10_DIGITAL_GAIN_MAX,
OS05B10_DIGITAL_GAIN_STEP, OS05B10_DIGITAL_GAIN_DEFAULT);
+ os05b10->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &os05b10_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ if (os05b10->hflip)
+ os05b10->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+
+ os05b10->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &os05b10_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ if (os05b10->vflip)
+ os05b10->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+
if (ctrl_hdlr->error) {
ret = ctrl_hdlr->error;
dev_err(os05b10->dev, "control init failed (%d)\n", ret);
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v2 07/15] media: i2c: os05b10: Add test pattern options
2026-03-25 11:43 [PATCH v2 00/15] media: i2c: os05b10: Refactor driver and Add new features Tarang Raval
` (5 preceding siblings ...)
2026-03-25 11:43 ` [PATCH v2 06/15] media: i2c: os05b10: Add H/V flip support Tarang Raval
@ 2026-03-25 11:43 ` Tarang Raval
2026-03-25 11:43 ` [PATCH v2 08/15] media: i2c: os05b10: add 12-bit RAW mode support Tarang Raval
` (7 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Tarang Raval @ 2026-03-25 11:43 UTC (permalink / raw)
To: Sakari Ailus
Cc: Tarang Raval, Himanshu Bhavani, Elgin Perumbilly,
Mauro Carvalho Chehab, Hans Verkuil, Mehdi Djait,
Vladimir Zapolskiy, linux-media, linux-kernel
Add V4L2_CID_TEST_PATTERN support with multiple sensor test-pattern modes
and program them via register 0x5080. Drop the fixed 0x5080 setting from
the common register sequence so the pattern is selected only through the
control.
Signed-off-by: Tarang Raval <tarang.raval@siliconsignals.io>
---
drivers/media/i2c/os05b10.c | 55 +++++++++++++++++++++++++++++++++++--
1 file changed, 53 insertions(+), 2 deletions(-)
diff --git a/drivers/media/i2c/os05b10.c b/drivers/media/i2c/os05b10.c
index bf848eb9ba52..c8de7f5601bf 100644
--- a/drivers/media/i2c/os05b10.c
+++ b/drivers/media/i2c/os05b10.c
@@ -103,6 +103,17 @@
#define OS05B10_REG_FORMAT2 CCI_REG8(0x3821)
#define OS05B10_HDR_ENABLE 0x04
+#define OS05B10_REG_PRE_ISP_20_0 CCI_REG8(0x5080)
+#define OS05B10_DISABLED 0x00
+#define OS05B10_COLOR_BAR_1 0x80
+#define OS05B10_COLOR_BAR_2 0x84
+#define OS05B10_COLOR_BAR_3 0x88
+#define OS05B10_COLOR_BAR_4 0x8c
+#define OS05B10_COLOR_SQUARE 0x82
+#define OS05B10_BW_SQUARE 0x92
+#define OS05B10_TRANSPARENT_EFFECT 0xa0
+#define OS05B10_ROLLING_BAR_EFFECT 0xc0
+
#define OS05B10_LINK_FREQ_600MHZ (600 * HZ_PER_MHZ)
static const struct v4l2_rect os05b10_native_area = {
@@ -396,7 +407,6 @@ static const struct cci_reg_sequence os05b10_common_regs[] = {
{ CCI_REG8(0x5004), 0x00 },
{ CCI_REG8(0x5005), 0x0e },
{ CCI_REG8(0x5036), 0x00 },
- { CCI_REG8(0x5080), 0x04 },
{ CCI_REG8(0x5082), 0x00 },
{ CCI_REG8(0x5180), 0x00 },
{ CCI_REG8(0x5181), 0x10 },
@@ -514,6 +524,30 @@ static const u32 os05b10_mbus_codes[] = {
MEDIA_BUS_FMT_SBGGR10_1X10,
};
+static const char * const os05b10_test_pattern_menu[] = {
+ "Disabled",
+ "colour bar type 1",
+ "colour bar type 2",
+ "colour bar type 3",
+ "colour bar type 4",
+ "color square",
+ "black-white square",
+ "transparent effect",
+ "rolling bar effect",
+};
+
+static const int os05b10_tp_val[] = {
+ OS05B10_DISABLED,
+ OS05B10_COLOR_BAR_1,
+ OS05B10_COLOR_BAR_2,
+ OS05B10_COLOR_BAR_3,
+ OS05B10_COLOR_BAR_4,
+ OS05B10_COLOR_SQUARE,
+ OS05B10_BW_SQUARE,
+ OS05B10_TRANSPARENT_EFFECT,
+ OS05B10_ROLLING_BAR_EFFECT,
+};
+
static inline struct os05b10 *to_os05b10(struct v4l2_subdev *sd)
{
return container_of_const(sd, struct os05b10, sd);
@@ -531,6 +565,15 @@ static u32 os05b10_get_format_code(struct os05b10 *os05b10)
return code;
}
+static int os05b10_update_test_pattern(struct os05b10 *os05b10, u32 pattern)
+{
+ if (pattern >= ARRAY_SIZE(os05b10_test_pattern_menu))
+ return -EINVAL;
+
+ return cci_write(os05b10->cci, OS05B10_REG_PRE_ISP_20_0,
+ os05b10_tp_val[pattern], NULL);
+}
+
static int os05b10_set_ctrl(struct v4l2_ctrl *ctrl)
{
struct os05b10 *os05b10 = container_of_const(ctrl->handler,
@@ -589,6 +632,9 @@ static int os05b10_set_ctrl(struct v4l2_ctrl *ctrl)
OS05B10_FLIP_ENABLE : OS05B10_FLIP_DISABLE,
NULL);
break;
+ case V4L2_CID_TEST_PATTERN:
+ ret = os05b10_update_test_pattern(os05b10, ctrl->val);
+ break;
default:
ret = -EINVAL;
break;
@@ -970,7 +1016,7 @@ static int os05b10_init_controls(struct os05b10 *os05b10)
int ret;
ctrl_hdlr = &os05b10->handler;
- v4l2_ctrl_handler_init(ctrl_hdlr, 11);
+ v4l2_ctrl_handler_init(ctrl_hdlr, 12);
pixel_rate = os05b10_pixel_rate(os05b10, mode);
v4l2_ctrl_new_std(ctrl_hdlr, &os05b10_ctrl_ops, V4L2_CID_PIXEL_RATE,
@@ -1026,6 +1072,11 @@ static int os05b10_init_controls(struct os05b10 *os05b10)
if (os05b10->vflip)
os05b10->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+ v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &os05b10_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(os05b10_test_pattern_menu) - 1,
+ 0, 0, os05b10_test_pattern_menu);
+
if (ctrl_hdlr->error) {
ret = ctrl_hdlr->error;
dev_err(os05b10->dev, "control init failed (%d)\n", ret);
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v2 08/15] media: i2c: os05b10: add 12-bit RAW mode support
2026-03-25 11:43 [PATCH v2 00/15] media: i2c: os05b10: Refactor driver and Add new features Tarang Raval
` (6 preceding siblings ...)
2026-03-25 11:43 ` [PATCH v2 07/15] media: i2c: os05b10: Add test pattern options Tarang Raval
@ 2026-03-25 11:43 ` Tarang Raval
2026-03-25 11:43 ` [PATCH v2 09/15] media: i2c: os05b10: update pixel rate on 10/12-bit mode switch Tarang Raval
` (6 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Tarang Raval @ 2026-03-25 11:43 UTC (permalink / raw)
To: Sakari Ailus
Cc: Tarang Raval, Himanshu Bhavani, Elgin Perumbilly,
Mauro Carvalho Chehab, Vladimir Zapolskiy, Mehdi Djait,
Hans Verkuil, linux-media, linux-kernel
Expose a 12-bit Bayer output option in the OS05B10 V4L2 sub-device driver.
Add a 12-bit mode table alongside the existing 10-bit mode, extend the
enumerated mbus codes to include RAW12, and select the correct mode table
based on the requested mbus format in enum_frame_size and stream enable.
Also move OS05B10_REG_MIPI_SC_CTRL_1 programming out of the common register
list and program it at stream-on depending on the selected mode bpp (10/12).
Signed-off-by: Tarang Raval <tarang.raval@siliconsignals.io>
---
drivers/media/i2c/os05b10.c | 90 +++++++++++++++++++++++++++++++------
1 file changed, 77 insertions(+), 13 deletions(-)
diff --git a/drivers/media/i2c/os05b10.c b/drivers/media/i2c/os05b10.c
index c8de7f5601bf..5c191d58a636 100644
--- a/drivers/media/i2c/os05b10.c
+++ b/drivers/media/i2c/os05b10.c
@@ -143,7 +143,6 @@ static const struct cci_reg_sequence os05b10_common_regs[] = {
{ OS05B10_REG_PLL_CTRL_06, 0x00 },
{ OS05B10_REG_PLL_CTRL_25, 0x3b },
{ OS05B10_REG_MIPI_SC_CTRL, 0x72 },
- { OS05B10_REG_MIPI_SC_CTRL_1, 0x01 },
{ OS05B10_REG_ANALOG_GAIN_SHORT, 0x0080 },
{ OS05B10_REG_DIGITAL_GAIN_SHORT, 0x0400 },
{ OS05B10_REG_EXPOSURE_SHORT, 0x000020 },
@@ -501,6 +500,21 @@ struct os05b10_mode {
struct os05b10_reg_list reg_list;
};
+static const struct os05b10_mode supported_modes_12bit[] = {
+ {
+ .width = 2592,
+ .height = 1944,
+ .vts = 2007,
+ .hts = 1744,
+ .exp = 1900,
+ .bpp = 12,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_2592_1944_regs),
+ .regs = mode_2592_1944_regs,
+ },
+ },
+};
+
static const struct os05b10_mode supported_modes_10bit[] = {
{
.width = 2592,
@@ -522,6 +536,7 @@ static const s64 link_frequencies[] = {
static const u32 os05b10_mbus_codes[] = {
MEDIA_BUS_FMT_SBGGR10_1X10,
+ MEDIA_BUS_FMT_SBGGR12_1X12,
};
static const char * const os05b10_test_pattern_menu[] = {
@@ -553,13 +568,20 @@ static inline struct os05b10 *to_os05b10(struct v4l2_subdev *sd)
return container_of_const(sd, struct os05b10, sd);
};
-static u32 os05b10_get_format_code(struct os05b10 *os05b10)
+static u32 os05b10_get_format_code(struct os05b10 *os05b10, u8 bpp)
{
- static const u32 codes[2][2] = {
+ static const u32 codes_12[2][2] = {
+ { MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SGBRG12_1X12, },
+ { MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SRGGB12_1X12, },
+ };
+
+ static const u32 codes_10[2][2] = {
{ MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SGBRG10_1X10, },
{ MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SRGGB10_1X10, },
};
+ const u32 (*codes)[2] = (bpp == 12) ? codes_12 : codes_10;
+
u32 code = codes[os05b10->vflip->val][os05b10->hflip->val];
return code;
@@ -654,8 +676,8 @@ static int os05b10_enum_mbus_code(struct v4l2_subdev *sd,
if (code->index >= ARRAY_SIZE(os05b10_mbus_codes))
return -EINVAL;
- code->code = os05b10_get_format_code(os05b10);
-
+ code->code = os05b10_get_format_code(os05b10,
+ (code->index == 1) ? 12 : 10);
return 0;
}
@@ -684,15 +706,42 @@ static int os05b10_set_framing_limits(struct os05b10 *os05b10,
OS05B10_EXPOSURE_STEP, mode->exp);
}
+static inline void get_mode_table(unsigned int code,
+ const struct os05b10_mode **mode_list,
+ unsigned int *num_modes)
+{
+ switch (code) {
+ case MEDIA_BUS_FMT_SBGGR12_1X12:
+ *mode_list = supported_modes_12bit;
+ *num_modes = ARRAY_SIZE(supported_modes_12bit);
+ break;
+
+ case MEDIA_BUS_FMT_SBGGR10_1X10:
+ *mode_list = supported_modes_10bit;
+ *num_modes = ARRAY_SIZE(supported_modes_10bit);
+ break;
+ default:
+ *mode_list = NULL;
+ *num_modes = 0;
+ break;
+ }
+}
+
static int os05b10_set_pad_format(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
- const struct os05b10_mode *mode = &supported_modes_10bit[0];
struct os05b10 *os05b10 = to_os05b10(sd);
+ const struct os05b10_mode *mode_list;
struct v4l2_mbus_framefmt *format;
+ const struct os05b10_mode *mode;
+ unsigned int num_modes;
int ret;
+ get_mode_table(fmt->format.code, &mode_list, &num_modes);
+ mode = v4l2_find_nearest_size(mode_list, num_modes, width, height,
+ fmt->format.width, fmt->format.height);
+
fmt->format.width = mode->width;
fmt->format.height = mode->height;
fmt->format.field = V4L2_FIELD_NONE;
@@ -735,12 +784,17 @@ static int os05b10_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_10bit))
+ const struct os05b10_mode *mode_list;
+ unsigned int num_modes;
+
+ get_mode_table(fse->code, &mode_list, &num_modes);
+
+ if (fse->index >= num_modes)
return -EINVAL;
- fse->min_width = supported_modes_10bit[fse->index].width;
+ fse->min_width = mode_list[fse->index].width;
fse->max_width = fse->min_width;
- fse->min_height = supported_modes_10bit[fse->index].height;
+ fse->min_height = mode_list[fse->index].height;
fse->max_height = fse->min_height;
return 0;
@@ -753,13 +807,15 @@ static int os05b10_enable_streams(struct v4l2_subdev *sd,
struct os05b10 *os05b10 = to_os05b10(sd);
const struct os05b10_reg_list *reg_list;
const struct v4l2_mbus_framefmt *fmt;
+ const struct os05b10_mode *mode_list;
const struct os05b10_mode *mode;
+ unsigned int num_modes;
int ret;
fmt = v4l2_subdev_state_get_format(state, 0);
- mode = v4l2_find_nearest_size(supported_modes_10bit,
- ARRAY_SIZE(supported_modes_10bit), width,
- height, fmt->width, fmt->height);
+ get_mode_table(fmt->code, &mode_list, &num_modes);
+ mode = v4l2_find_nearest_size(mode_list, num_modes, width, height,
+ fmt->width, fmt->height);
ret = pm_runtime_resume_and_get(os05b10->dev);
if (ret < 0)
@@ -773,6 +829,14 @@ static int os05b10_enable_streams(struct v4l2_subdev *sd,
goto err_rpm_put;
}
+ ret = cci_write(os05b10->cci, OS05B10_REG_MIPI_SC_CTRL_1,
+ (mode->bpp == 12) ? OS05B10_12BIT_MODE :
+ OS05B10_10BIT_MODE, NULL);
+ if (ret) {
+ dev_err(os05b10->dev, "failed to write pixel bit registers\n");
+ goto err_rpm_put;
+ }
+
/* Write sensor mode registers */
reg_list = &mode->reg_list;
ret = cci_multi_reg_write(os05b10->cci, reg_list->regs,
@@ -835,7 +899,7 @@ static int os05b10_init_state(struct v4l2_subdev *sd,
format = v4l2_subdev_state_get_format(state, 0);
mode = &supported_modes_10bit[0];
- format->code = os05b10_get_format_code(os05b10);
+ format->code = os05b10_get_format_code(os05b10, 10);
/* Update image pad formate */
format->width = mode->width;
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v2 09/15] media: i2c: os05b10: update pixel rate on 10/12-bit mode switch
2026-03-25 11:43 [PATCH v2 00/15] media: i2c: os05b10: Refactor driver and Add new features Tarang Raval
` (7 preceding siblings ...)
2026-03-25 11:43 ` [PATCH v2 08/15] media: i2c: os05b10: add 12-bit RAW mode support Tarang Raval
@ 2026-03-25 11:43 ` Tarang Raval
2026-03-25 11:43 ` [PATCH v2 10/15] media: i2c: os05b10: Add 1080p and 2x2 binning 720p modes Tarang Raval
` (5 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Tarang Raval @ 2026-03-25 11:43 UTC (permalink / raw)
To: Sakari Ailus
Cc: Tarang Raval, Himanshu Bhavani, Elgin Perumbilly,
Mauro Carvalho Chehab, Vladimir Zapolskiy, Mehdi Djait,
linux-media, linux-kernel
After adding 12-bit RAW support, the pixel rate depends on the selected
mode bpp. Store the V4L2_CID_PIXEL_RATE control pointer and update its
range/value when the mode changes so 10/12-bit switching reports the
correct pixel rate.
Signed-off-by: Tarang Raval <tarang.raval@siliconsignals.io>
---
drivers/media/i2c/os05b10.c | 41 ++++++++++++++++++++++++-------------
1 file changed, 27 insertions(+), 14 deletions(-)
diff --git a/drivers/media/i2c/os05b10.c b/drivers/media/i2c/os05b10.c
index 5c191d58a636..1fe5650680bb 100644
--- a/drivers/media/i2c/os05b10.c
+++ b/drivers/media/i2c/os05b10.c
@@ -474,6 +474,7 @@ struct os05b10 {
/* V4L2 Controls */
struct v4l2_ctrl_handler handler;
struct v4l2_ctrl *link_freq;
+ struct v4l2_ctrl *pixel_rate;
struct v4l2_ctrl *hblank;
struct v4l2_ctrl *vblank;
struct v4l2_ctrl *gain;
@@ -681,12 +682,35 @@ static int os05b10_enum_mbus_code(struct v4l2_subdev *sd,
return 0;
}
+static u64 os05b10_pixel_rate(struct os05b10 *os05b10,
+ const struct os05b10_mode *mode)
+{
+ u64 link_freq = link_frequencies[os05b10->link_freq_index];
+ u64 pixel_rate = div_u64(link_freq * 2 * os05b10->data_lanes, mode->bpp);
+
+ dev_dbg(os05b10->dev,
+ "link_freq=%llu bpp=%u lanes=%u pixel_rate=%llu\n",
+ link_freq, mode->bpp, os05b10->data_lanes, pixel_rate);
+
+ return pixel_rate;
+}
+
static int os05b10_set_framing_limits(struct os05b10 *os05b10,
const struct os05b10_mode *mode)
{
+ u64 pixel_rate = os05b10_pixel_rate(os05b10, mode);
u32 hblank, vblank, vblank_max, max_exp;
int ret;
+ ret = __v4l2_ctrl_modify_range(os05b10->pixel_rate, pixel_rate,
+ pixel_rate, 1, pixel_rate);
+ if (ret)
+ return ret;
+
+ ret = __v4l2_ctrl_s_ctrl_int64(os05b10->pixel_rate, pixel_rate);
+ if (ret)
+ return ret;
+
hblank = mode->hts - mode->width;
ret = __v4l2_ctrl_modify_range(os05b10->hblank, hblank, hblank, 1,
hblank);
@@ -1058,18 +1082,6 @@ static int os05b10_parse_endpoint(struct os05b10 *os05b10)
return ret;
}
-static u64 os05b10_pixel_rate(struct os05b10 *os05b10,
- const struct os05b10_mode *mode)
-{
- u64 link_freq = link_frequencies[os05b10->link_freq_index];
- u64 pixel_rate = div_u64(link_freq * 2 * os05b10->data_lanes, mode->bpp);
-
- dev_dbg(os05b10->dev,
- "link_freq=%llu bpp=%u lanes=%u pixel_rate=%llu\n",
- link_freq, mode->bpp, os05b10->data_lanes, pixel_rate);
-
- return pixel_rate;
-}
static int os05b10_init_controls(struct os05b10 *os05b10)
{
@@ -1083,8 +1095,9 @@ static int os05b10_init_controls(struct os05b10 *os05b10)
v4l2_ctrl_handler_init(ctrl_hdlr, 12);
pixel_rate = os05b10_pixel_rate(os05b10, mode);
- v4l2_ctrl_new_std(ctrl_hdlr, &os05b10_ctrl_ops, V4L2_CID_PIXEL_RATE,
- pixel_rate, pixel_rate, 1, pixel_rate);
+ os05b10->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &os05b10_ctrl_ops,
+ V4L2_CID_PIXEL_RATE, pixel_rate,
+ pixel_rate, 1, pixel_rate);
os05b10->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &os05b10_ctrl_ops,
V4L2_CID_LINK_FREQ,
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v2 10/15] media: i2c: os05b10: Add 1080p and 2x2 binning 720p modes
2026-03-25 11:43 [PATCH v2 00/15] media: i2c: os05b10: Refactor driver and Add new features Tarang Raval
` (8 preceding siblings ...)
2026-03-25 11:43 ` [PATCH v2 09/15] media: i2c: os05b10: update pixel rate on 10/12-bit mode switch Tarang Raval
@ 2026-03-25 11:43 ` Tarang Raval
2026-03-25 11:43 ` [PATCH v2 11/15] media: i2c: os05b10: keep vblank and exposure range in sync on mode switch Tarang Raval
` (4 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Tarang Raval @ 2026-03-25 11:43 UTC (permalink / raw)
To: Sakari Ailus
Cc: Tarang Raval, Himanshu Bhavani, Elgin Perumbilly,
Mauro Carvalho Chehab, Vladimir Zapolskiy, Hans Verkuil,
Mehdi Djait, linux-media, linux-kernel
Add support for 1920x1080 and 1280x720 resolutions.
The 1280x720 mode uses 2x2 binning.
Both 10-bit and 12-bit pixel formats are supported.
Signed-off-by: Tarang Raval <tarang.raval@siliconsignals.io>
---
drivers/media/i2c/os05b10.c | 120 ++++++++++++++++++++++++++++++++++++
1 file changed, 120 insertions(+)
diff --git a/drivers/media/i2c/os05b10.c b/drivers/media/i2c/os05b10.c
index 1fe5650680bb..1496342c24d3 100644
--- a/drivers/media/i2c/os05b10.c
+++ b/drivers/media/i2c/os05b10.c
@@ -461,6 +461,78 @@ static const struct cci_reg_sequence mode_2592_1944_regs[] = {
{ CCI_REG8(0x4837), 0x12 },
};
+static const struct cci_reg_sequence mode_1920_1080_regs[] = {
+ { OS05B10_REG_X_ADDR_START, 0x0280 },
+ { OS05B10_REG_Y_ADDR_START, 0x01b4 },
+ { OS05B10_REG_X_ADDR_END, 0x0a0f },
+ { OS05B10_REG_Y_ADDR_END, 0x05f3 },
+ { OS05B10_REG_X_OUTPUT_SIZE, 0x0780 },
+ { OS05B10_REG_Y_OUTPUT_SIZE, 0x0438 },
+ { OS05B10_REG_HTS, 0x06d0 },
+ { OS05B10_REG_ISP_X_WIN, 0x0008 },
+ { OS05B10_REG_ISP_Y_WIN, 0x0008 },
+ { OS05B10_REG_X_INC_ODD, 0x01 },
+ { OS05B10_REG_X_INC_EVEN, 0x01 },
+ { OS05B10_REG_Y_INC_ODD, 0x01 },
+ { OS05B10_REG_Y_INC_EVEN, 0x01 },
+ { OS05B10_REG_FORMAT1, 0x88 },
+ { OS05B10_REG_FORMAT2, 0x00 },
+ { CCI_REG8(0x3610), 0x87 },
+ { CCI_REG8(0x3620), 0x0c },
+ { CCI_REG8(0x3662), 0x10 },
+ { CCI_REG8(0x3714), 0x24 },
+ { CCI_REG8(0x373f), 0xb0 },
+ { CCI_REG8(0x37bf), 0x05 },
+ { CCI_REG8(0x37c2), 0x04 },
+ { CCI_REG8(0x37d9), 0x08 },
+ { CCI_REG8(0x3832), 0x08 },
+ { CCI_REG8(0x3c86), 0x03 },
+ { CCI_REG8(0x3d8c), 0x71 },
+ { CCI_REG8(0x3f03), 0x08 },
+ { CCI_REG8(0x4008), 0x02 },
+ { CCI_REG8(0x4009), 0x0d },
+ { CCI_REG8(0x400a), 0x02 },
+ { CCI_REG8(0x4041), 0x07 },
+ { CCI_REG8(0x4505), 0xc4 },
+ { CCI_REG8(0x4837), 0x0d },
+};
+
+static const struct cci_reg_sequence mode_1280_720_regs[] = {
+ { OS05B10_REG_X_ADDR_START, 0x0140 },
+ { OS05B10_REG_Y_ADDR_START, 0x00fc },
+ { OS05B10_REG_X_ADDR_END, 0x0b4f },
+ { OS05B10_REG_Y_ADDR_END, 0x06ab },
+ { OS05B10_REG_X_OUTPUT_SIZE, 0x0500 },
+ { OS05B10_REG_Y_OUTPUT_SIZE, 0x02d0 },
+ { OS05B10_REG_HTS, 0x0368 },
+ { OS05B10_REG_ISP_X_WIN, 0x0004 },
+ { OS05B10_REG_ISP_Y_WIN, 0x0004 },
+ { OS05B10_REG_X_INC_ODD, 0x03 },
+ { OS05B10_REG_X_INC_EVEN, 0x01 },
+ { OS05B10_REG_Y_INC_ODD, 0x03 },
+ { OS05B10_REG_Y_INC_EVEN, 0x01 },
+ { OS05B10_REG_FORMAT1, 0x8b },
+ { OS05B10_REG_FORMAT2, 0x00 },
+ { CCI_REG8(0x3610), 0x57 },
+ { CCI_REG8(0x3620), 0x01 },
+ { CCI_REG8(0x3662), 0x08 },
+ { CCI_REG8(0x3714), 0x28 },
+ { CCI_REG8(0x373f), 0xa0 },
+ { CCI_REG8(0x37bf), 0x05 },
+ { CCI_REG8(0x37c2), 0x14 },
+ { CCI_REG8(0x37d9), 0x04 },
+ { CCI_REG8(0x3832), 0x00 },
+ { CCI_REG8(0x3c86), 0x03 },
+ { CCI_REG8(0x3d8c), 0x71 },
+ { CCI_REG8(0x3f03), 0x1d },
+ { CCI_REG8(0x4008), 0x01 },
+ { CCI_REG8(0x4009), 0x06 },
+ { CCI_REG8(0x400a), 0x02 },
+ { CCI_REG8(0x4041), 0x03 },
+ { CCI_REG8(0x4505), 0xe4 },
+ { CCI_REG8(0x4837), 0x0d },
+};
+
struct os05b10 {
struct device *dev;
struct regmap *cci;
@@ -514,6 +586,30 @@ static const struct os05b10_mode supported_modes_12bit[] = {
.regs = mode_2592_1944_regs,
},
},
+ { /* 40 fps */
+ .width = 1920,
+ .height = 1080,
+ .vts = 1504,
+ .hts = 1744,
+ .exp = 1472,
+ .bpp = 12,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_1920_1080_regs),
+ .regs = mode_1920_1080_regs,
+ },
+ },
+ { /* 2x2 binning 120 fps */
+ .width = 1280,
+ .height = 720,
+ .vts = 1003,
+ .hts = 872,
+ .exp = 970,
+ .bpp = 12,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_1280_720_regs),
+ .regs = mode_1280_720_regs,
+ },
+ },
};
static const struct os05b10_mode supported_modes_10bit[] = {
@@ -529,6 +625,30 @@ static const struct os05b10_mode supported_modes_10bit[] = {
.regs = mode_2592_1944_regs,
},
},
+ { /* 40 fps */
+ .width = 1920,
+ .height = 1080,
+ .vts = 1504,
+ .hts = 1744,
+ .exp = 1472,
+ .bpp = 10,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_1920_1080_regs),
+ .regs = mode_1920_1080_regs,
+ },
+ },
+ { /* 2x2 binning 120 fps */
+ .width = 1280,
+ .height = 720,
+ .vts = 1003,
+ .hts = 872,
+ .exp = 970,
+ .bpp = 10,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_1280_720_regs),
+ .regs = mode_1280_720_regs,
+ },
+ },
};
static const s64 link_frequencies[] = {
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v2 11/15] media: i2c: os05b10: keep vblank and exposure range in sync on mode switch
2026-03-25 11:43 [PATCH v2 00/15] media: i2c: os05b10: Refactor driver and Add new features Tarang Raval
` (9 preceding siblings ...)
2026-03-25 11:43 ` [PATCH v2 10/15] media: i2c: os05b10: Add 1080p and 2x2 binning 720p modes Tarang Raval
@ 2026-03-25 11:43 ` Tarang Raval
2026-03-25 11:43 ` [PATCH v2 12/15] media: i2c: os05b10: Update active format before adjusting framing controls Tarang Raval
` (3 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Tarang Raval @ 2026-03-25 11:43 UTC (permalink / raw)
To: Sakari Ailus
Cc: Tarang Raval, Himanshu Bhavani, Elgin Perumbilly,
Mauro Carvalho Chehab, Hans Verkuil, Vladimir Zapolskiy,
Mehdi Djait, linux-media, linux-kernel
Update vblank through the control path on mode changes so exposure
limits and default values are recalculated consistently from the
active mode.
Move get_mode_table() before its first use to avoid the build issue.
Signed-off-by: Tarang Raval <tarang.raval@siliconsignals.io>
---
drivers/media/i2c/os05b10.c | 59 +++++++++++++++++++------------------
1 file changed, 31 insertions(+), 28 deletions(-)
diff --git a/drivers/media/i2c/os05b10.c b/drivers/media/i2c/os05b10.c
index 1496342c24d3..e3dea793121d 100644
--- a/drivers/media/i2c/os05b10.c
+++ b/drivers/media/i2c/os05b10.c
@@ -717,25 +717,52 @@ static int os05b10_update_test_pattern(struct os05b10 *os05b10, u32 pattern)
os05b10_tp_val[pattern], NULL);
}
+static inline void get_mode_table(unsigned int code,
+ const struct os05b10_mode **mode_list,
+ unsigned int *num_modes)
+{
+ switch (code) {
+ case MEDIA_BUS_FMT_SBGGR12_1X12:
+ *mode_list = supported_modes_12bit;
+ *num_modes = ARRAY_SIZE(supported_modes_12bit);
+ break;
+
+ case MEDIA_BUS_FMT_SBGGR10_1X10:
+ *mode_list = supported_modes_10bit;
+ *num_modes = ARRAY_SIZE(supported_modes_10bit);
+ break;
+ default:
+ *mode_list = NULL;
+ *num_modes = 0;
+ break;
+ }
+}
+
static int os05b10_set_ctrl(struct v4l2_ctrl *ctrl)
{
struct os05b10 *os05b10 = container_of_const(ctrl->handler,
struct os05b10, handler);
+ const struct os05b10_mode *mode_list;
+ const struct os05b10_mode *mode;
struct v4l2_subdev_state *state;
struct v4l2_mbus_framefmt *fmt;
+ unsigned int num_modes;
int vmax, ret;
state = v4l2_subdev_get_locked_active_state(&os05b10->sd);
fmt = v4l2_subdev_state_get_format(state, 0);
+ get_mode_table(fmt->code, &mode_list, &num_modes);
+ mode = v4l2_find_nearest_size(mode_list, num_modes, width, height,
+ fmt->width, fmt->height);
+
if (ctrl->id == V4L2_CID_VBLANK) {
/* Honour the VBLANK limits when setting exposure. */
s64 max = fmt->height + ctrl->val - OS05B10_EXPOSURE_MARGIN;
-
ret = __v4l2_ctrl_modify_range(os05b10->exposure,
os05b10->exposure->minimum, max,
os05b10->exposure->step,
- os05b10->exposure->default_value);
+ mode->exp);
if (ret)
return ret;
}
@@ -819,7 +846,7 @@ static int os05b10_set_framing_limits(struct os05b10 *os05b10,
const struct os05b10_mode *mode)
{
u64 pixel_rate = os05b10_pixel_rate(os05b10, mode);
- u32 hblank, vblank, vblank_max, max_exp;
+ u32 hblank, vblank, vblank_max;
int ret;
ret = __v4l2_ctrl_modify_range(os05b10->pixel_rate, pixel_rate,
@@ -844,31 +871,7 @@ static int os05b10_set_framing_limits(struct os05b10 *os05b10,
if (ret)
return ret;
- max_exp = mode->vts - OS05B10_EXPOSURE_MARGIN;
- return __v4l2_ctrl_modify_range(os05b10->exposure,
- OS05B10_EXPOSURE_MIN, max_exp,
- OS05B10_EXPOSURE_STEP, mode->exp);
-}
-
-static inline void get_mode_table(unsigned int code,
- const struct os05b10_mode **mode_list,
- unsigned int *num_modes)
-{
- switch (code) {
- case MEDIA_BUS_FMT_SBGGR12_1X12:
- *mode_list = supported_modes_12bit;
- *num_modes = ARRAY_SIZE(supported_modes_12bit);
- break;
-
- case MEDIA_BUS_FMT_SBGGR10_1X10:
- *mode_list = supported_modes_10bit;
- *num_modes = ARRAY_SIZE(supported_modes_10bit);
- break;
- default:
- *mode_list = NULL;
- *num_modes = 0;
- break;
- }
+ return __v4l2_ctrl_s_ctrl(os05b10->vblank, vblank);
}
static int os05b10_set_pad_format(struct v4l2_subdev *sd,
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v2 12/15] media: i2c: os05b10: Update active format before adjusting framing controls
2026-03-25 11:43 [PATCH v2 00/15] media: i2c: os05b10: Refactor driver and Add new features Tarang Raval
` (10 preceding siblings ...)
2026-03-25 11:43 ` [PATCH v2 11/15] media: i2c: os05b10: keep vblank and exposure range in sync on mode switch Tarang Raval
@ 2026-03-25 11:43 ` Tarang Raval
2026-03-25 11:43 ` [PATCH v2 13/15] media: i2c: os05b10: Rename vmax variable in VBLANK control Tarang Raval
` (2 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Tarang Raval @ 2026-03-25 11:43 UTC (permalink / raw)
To: Sakari Ailus
Cc: Tarang Raval, Himanshu Bhavani, Elgin Perumbilly,
Mauro Carvalho Chehab, Hans Verkuil, Mehdi Djait,
Vladimir Zapolskiy, linux-media, linux-kernel
os05b10_set_pad_format() calls os05b10_set_framing_limits() before updating
the ACTIVE format. As a result, the VBLANK control handler uses the old
height when recalculating exposure limits, causing -ERANGE when switching
to a larger resolution.
Update the ACTIVE format before adjusting framing controls so control
callbacks use the correct dimensions.
Signed-off-by: Tarang Raval <tarang.raval@siliconsignals.io>
---
drivers/media/i2c/os05b10.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/media/i2c/os05b10.c b/drivers/media/i2c/os05b10.c
index e3dea793121d..4db257570689 100644
--- a/drivers/media/i2c/os05b10.c
+++ b/drivers/media/i2c/os05b10.c
@@ -898,14 +898,14 @@ static int os05b10_set_pad_format(struct v4l2_subdev *sd,
format = v4l2_subdev_state_get_format(sd_state, 0);
+ *format = fmt->format;
+
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
ret = os05b10_set_framing_limits(os05b10, mode);
if (ret)
return ret;
}
- *format = fmt->format;
-
return 0;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v2 13/15] media: i2c: os05b10: Rename vmax variable in VBLANK control
2026-03-25 11:43 [PATCH v2 00/15] media: i2c: os05b10: Refactor driver and Add new features Tarang Raval
` (11 preceding siblings ...)
2026-03-25 11:43 ` [PATCH v2 12/15] media: i2c: os05b10: Update active format before adjusting framing controls Tarang Raval
@ 2026-03-25 11:43 ` Tarang Raval
2026-03-25 11:44 ` [PATCH v2 14/15] media: i2c: os05b10: add 2-lane support Tarang Raval
2026-03-25 11:44 ` [PATCH v2 15/15] media: i2c: os05b10: fix negative hblank calculation Tarang Raval
14 siblings, 0 replies; 16+ messages in thread
From: Tarang Raval @ 2026-03-25 11:43 UTC (permalink / raw)
To: Sakari Ailus
Cc: Tarang Raval, Himanshu Bhavani, Elgin Perumbilly,
Mauro Carvalho Chehab, Vladimir Zapolskiy, Hans Verkuil,
Mehdi Djait, linux-media, linux-kernel
The VBLANK control programs the sensor VTS register. Rename the local
variable from vmax to vts to match the register meaning and improve
readability.
Signed-off-by: Tarang Raval <tarang.raval@siliconsignals.io>
---
drivers/media/i2c/os05b10.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/media/i2c/os05b10.c b/drivers/media/i2c/os05b10.c
index 4db257570689..bc6df8c8faf0 100644
--- a/drivers/media/i2c/os05b10.c
+++ b/drivers/media/i2c/os05b10.c
@@ -747,7 +747,7 @@ static int os05b10_set_ctrl(struct v4l2_ctrl *ctrl)
struct v4l2_subdev_state *state;
struct v4l2_mbus_framefmt *fmt;
unsigned int num_modes;
- int vmax, ret;
+ int vts, ret;
state = v4l2_subdev_get_locked_active_state(&os05b10->sd);
fmt = v4l2_subdev_state_get_format(state, 0);
@@ -772,8 +772,8 @@ static int os05b10_set_ctrl(struct v4l2_ctrl *ctrl)
switch (ctrl->id) {
case V4L2_CID_VBLANK:
- vmax = fmt->height + ctrl->val;
- ret = cci_write(os05b10->cci, OS05B10_REG_VTS, vmax, NULL);
+ vts = fmt->height + ctrl->val;
+ ret = cci_write(os05b10->cci, OS05B10_REG_VTS, vts, NULL);
break;
case V4L2_CID_ANALOGUE_GAIN:
ret = cci_write(os05b10->cci, OS05B10_REG_ANALOG_GAIN,
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v2 14/15] media: i2c: os05b10: add 2-lane support
2026-03-25 11:43 [PATCH v2 00/15] media: i2c: os05b10: Refactor driver and Add new features Tarang Raval
` (12 preceding siblings ...)
2026-03-25 11:43 ` [PATCH v2 13/15] media: i2c: os05b10: Rename vmax variable in VBLANK control Tarang Raval
@ 2026-03-25 11:44 ` Tarang Raval
2026-03-25 11:44 ` [PATCH v2 15/15] media: i2c: os05b10: fix negative hblank calculation Tarang Raval
14 siblings, 0 replies; 16+ messages in thread
From: Tarang Raval @ 2026-03-25 11:44 UTC (permalink / raw)
To: Sakari Ailus
Cc: Tarang Raval, Himanshu Bhavani, Elgin Perumbilly,
Mauro Carvalho Chehab, Hans Verkuil, Vladimir Zapolskiy,
Mehdi Djait, linux-media, linux-kernel
Add support for 2-lane.
Update link-frequency handling to select 750 MHz for 2-lane and 600 MHz for
4-lane, and adjust pixel rate computation accordingly. Extend endpoint
parsing to accept 2 or 4 data lanes.
Signed-off-by: Tarang Raval <tarang.raval@siliconsignals.io>
---
drivers/media/i2c/os05b10.c | 94 ++++++++++++++++++++++++++++---------
1 file changed, 71 insertions(+), 23 deletions(-)
diff --git a/drivers/media/i2c/os05b10.c b/drivers/media/i2c/os05b10.c
index bc6df8c8faf0..bdfd203bf672 100644
--- a/drivers/media/i2c/os05b10.c
+++ b/drivers/media/i2c/os05b10.c
@@ -114,7 +114,8 @@
#define OS05B10_TRANSPARENT_EFFECT 0xa0
#define OS05B10_ROLLING_BAR_EFFECT 0xc0
-#define OS05B10_LINK_FREQ_600MHZ (600 * HZ_PER_MHZ)
+#define OS05B10_LINK_FREQ_4LANE (600 * HZ_PER_MHZ)
+#define OS05B10_LINK_FREQ_2LANE (750 * HZ_PER_MHZ)
static const struct v4l2_rect os05b10_native_area = {
.top = 0,
@@ -137,12 +138,6 @@ static const char * const os05b10_supply_name[] = {
};
static const struct cci_reg_sequence os05b10_common_regs[] = {
- { OS05B10_REG_PLL_CTRL_01, 0x44 },
- { OS05B10_REG_PLL_CTRL_03, 0x02 },
- { OS05B10_REG_PLL_CTRL_05, 0x32 },
- { OS05B10_REG_PLL_CTRL_06, 0x00 },
- { OS05B10_REG_PLL_CTRL_25, 0x3b },
- { OS05B10_REG_MIPI_SC_CTRL, 0x72 },
{ OS05B10_REG_ANALOG_GAIN_SHORT, 0x0080 },
{ OS05B10_REG_DIGITAL_GAIN_SHORT, 0x0400 },
{ OS05B10_REG_EXPOSURE_SHORT, 0x000020 },
@@ -533,6 +528,24 @@ static const struct cci_reg_sequence mode_1280_720_regs[] = {
{ CCI_REG8(0x4837), 0x0d },
};
+static const struct cci_reg_sequence os05b10_2lane_regs[] = {
+ { OS05B10_REG_PLL_CTRL_01, 0x44 },
+ { OS05B10_REG_PLL_CTRL_03, 0x02 },
+ { OS05B10_REG_PLL_CTRL_05, 0x64 },
+ { OS05B10_REG_PLL_CTRL_06, 0x00 },
+ { OS05B10_REG_PLL_CTRL_25, 0x3b },
+ { OS05B10_REG_MIPI_SC_CTRL, OS05B10_2_LANE_MODE },
+};
+
+static const struct cci_reg_sequence os05b10_4lane_regs[] = {
+ { OS05B10_REG_PLL_CTRL_01, 0x44 },
+ { OS05B10_REG_PLL_CTRL_03, 0x02 },
+ { OS05B10_REG_PLL_CTRL_05, 0x32 },
+ { OS05B10_REG_PLL_CTRL_06, 0x00 },
+ { OS05B10_REG_PLL_CTRL_25, 0x3b },
+ { OS05B10_REG_MIPI_SC_CTRL, OS05B10_4_LANE_MODE },
+};
+
struct os05b10 {
struct device *dev;
struct regmap *cci;
@@ -651,8 +664,12 @@ static const struct os05b10_mode supported_modes_10bit[] = {
},
};
-static const s64 link_frequencies[] = {
- OS05B10_LINK_FREQ_600MHZ,
+static const s64 link_frequencies_4lane[] = {
+ OS05B10_LINK_FREQ_4LANE,
+};
+
+static const s64 link_frequencies_2lane[] = {
+ OS05B10_LINK_FREQ_2LANE,
};
static const u32 os05b10_mbus_codes[] = {
@@ -832,7 +849,9 @@ static int os05b10_enum_mbus_code(struct v4l2_subdev *sd,
static u64 os05b10_pixel_rate(struct os05b10 *os05b10,
const struct os05b10_mode *mode)
{
- u64 link_freq = link_frequencies[os05b10->link_freq_index];
+ u64 link_freq = (os05b10->data_lanes == 2) ?
+ link_frequencies_2lane[os05b10->link_freq_index] :
+ link_frequencies_4lane[os05b10->link_freq_index];
u64 pixel_rate = div_u64(link_freq * 2 * os05b10->data_lanes, mode->bpp);
dev_dbg(os05b10->dev,
@@ -967,6 +986,17 @@ static int os05b10_enable_streams(struct v4l2_subdev *sd,
ret = pm_runtime_resume_and_get(os05b10->dev);
if (ret < 0)
return ret;
+ /* Set pll & mipi lane configuration */
+ if (os05b10->data_lanes == 2)
+ cci_multi_reg_write(os05b10->cci, os05b10_2lane_regs,
+ ARRAY_SIZE(os05b10_2lane_regs), &ret);
+ else
+ cci_multi_reg_write(os05b10->cci, os05b10_4lane_regs,
+ ARRAY_SIZE(os05b10_4lane_regs), &ret);
+ if (ret) {
+ dev_err(os05b10->dev, "failed to write pll & mipi lane registers\n");
+ goto err_rpm_put;
+ }
/* Write common registers */
ret = cci_multi_reg_write(os05b10->cci, os05b10_common_regs,
@@ -1179,22 +1209,39 @@ static int os05b10_parse_endpoint(struct os05b10 *os05b10)
if (ret)
return ret;
- if (bus_cfg.bus.mipi_csi2.num_data_lanes != 4) {
+ if (bus_cfg.bus.mipi_csi2.num_data_lanes != 4 &&
+ bus_cfg.bus.mipi_csi2.num_data_lanes != 2) {
ret = dev_err_probe(os05b10->dev, -EINVAL,
- "only 4 data lanes are supported\n");
+ "4 and 2 data lanes are supported\n");
goto error_out;
}
os05b10->data_lanes = bus_cfg.bus.mipi_csi2.num_data_lanes;
- ret = v4l2_link_freq_to_bitmap(os05b10->dev, bus_cfg.link_frequencies,
- bus_cfg.nr_of_link_frequencies,
- link_frequencies,
- ARRAY_SIZE(link_frequencies),
- &link_freq_bitmap);
- if (ret) {
- dev_err(os05b10->dev, "only 600MHz frequency is available\n");
- goto error_out;
+ if (os05b10->data_lanes == 2) {
+ ret = v4l2_link_freq_to_bitmap(os05b10->dev,
+ bus_cfg.link_frequencies,
+ bus_cfg.nr_of_link_frequencies,
+ link_frequencies_2lane,
+ ARRAY_SIZE(link_frequencies_2lane),
+ &link_freq_bitmap);
+ if (ret) {
+ dev_err(os05b10->dev,
+ "For 2 lane 750MHz frequency is available\n");
+ goto error_out;
+ }
+ } else {
+ ret = v4l2_link_freq_to_bitmap(os05b10->dev,
+ bus_cfg.link_frequencies,
+ bus_cfg.nr_of_link_frequencies,
+ link_frequencies_4lane,
+ ARRAY_SIZE(link_frequencies_4lane),
+ &link_freq_bitmap);
+ if (ret) {
+ dev_err(os05b10->dev,
+ "For 4 lane 600MHz frequency is available\n");
+ goto error_out;
+ }
}
os05b10->link_freq_index = __ffs(link_freq_bitmap);
@@ -1224,10 +1271,11 @@ static int os05b10_init_controls(struct os05b10 *os05b10)
os05b10->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &os05b10_ctrl_ops,
V4L2_CID_LINK_FREQ,
- ARRAY_SIZE(link_frequencies) - 1,
+ ARRAY_SIZE(link_frequencies_4lane) - 1,
os05b10->link_freq_index,
- link_frequencies);
-
+ (os05b10->data_lanes == 2) ?
+ link_frequencies_2lane :
+ link_frequencies_4lane);
if (os05b10->link_freq)
os05b10->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v2 15/15] media: i2c: os05b10: fix negative hblank calculation
2026-03-25 11:43 [PATCH v2 00/15] media: i2c: os05b10: Refactor driver and Add new features Tarang Raval
` (13 preceding siblings ...)
2026-03-25 11:44 ` [PATCH v2 14/15] media: i2c: os05b10: add 2-lane support Tarang Raval
@ 2026-03-25 11:44 ` Tarang Raval
14 siblings, 0 replies; 16+ messages in thread
From: Tarang Raval @ 2026-03-25 11:44 UTC (permalink / raw)
To: Sakari Ailus
Cc: Tarang Raval, Himanshu Bhavani, Elgin Perumbilly,
Mauro Carvalho Chehab, Vladimir Zapolskiy, Mehdi Djait,
linux-media, linux-kernel
Using HTS directly in the hblank calculation results in a negative
value, such as 2592x1944 with HTS set to 1744.
Scale HTS by 2 before subtracting the active width so that hblank is
derived correctly.
The datasheet describes 0x380c/0x380d as HTS, but does not document the
exact unit used for this value.
Signed-off-by: Tarang Raval <tarang.raval@siliconsignals.io>
---
drivers/media/i2c/os05b10.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/media/i2c/os05b10.c b/drivers/media/i2c/os05b10.c
index bdfd203bf672..8acb4d76c90f 100644
--- a/drivers/media/i2c/os05b10.c
+++ b/drivers/media/i2c/os05b10.c
@@ -877,7 +877,16 @@ static int os05b10_set_framing_limits(struct os05b10 *os05b10,
if (ret)
return ret;
- hblank = mode->hts - mode->width;
+ /*
+ * Using HTS directly results in a negative hblank.
+ * (e.g. 2592x1944 with HTS = 1744). Doubling HTS produces a valid
+ * horizontal blanking value.
+ *
+ * The datasheet defines HTS (0x380c/0x380d) as total horizontal
+ * timing size, but does not specify the unit (whether it is
+ * in pixel clocks or requires scaling).
+ */
+ hblank = mode->hts * 2 - mode->width;
ret = __v4l2_ctrl_modify_range(os05b10->hblank, hblank, hblank, 1,
hblank);
if (ret)
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread