[PATCH v4 14/15] media: i2c: os05b10: add 2-lane support

From: Tarang Raval

Date: Fri Oct 30 2026 - 06:43:55 EST


Add support for 2-lane operation.

The link frequency depends on the number of data lanes: 750 MHz for
2-lane and 600 MHz for 4-lane. Select the matching frequency table while
parsing the endpoint and use it for the LINK_FREQ control and the pixel
rate computation. Accept 2 or 4 data lanes in the endpoint.

The PLL and MIPI lane configuration registers differ between the two
configurations, so move them out of the common register list and write
the lane specific set at stream start.

Signed-off-by: Tarang Raval <tarang.raval@xxxxxxxxxxxxxxxxx>
---
drivers/media/i2c/os05b10.c | 70 +++++++++++++++++++++++++++++--------
1 file changed, 55 insertions(+), 15 deletions(-)

diff --git a/drivers/media/i2c/os05b10.c b/drivers/media/i2c/os05b10.c
index 507d714fbd21..9284b21a92c7 100644
--- a/drivers/media/i2c/os05b10.c
+++ b/drivers/media/i2c/os05b10.c
@@ -111,6 +111,7 @@
#define OS05B10_ROLLING_BAR_EFFECT 0xc0

#define OS05B10_LINK_FREQ_600MHZ (600 * HZ_PER_MHZ)
+#define OS05B10_LINK_FREQ_750MHZ (750 * HZ_PER_MHZ)

static const struct v4l2_rect os05b10_native_area = {
.top = 0,
@@ -133,13 +134,7 @@ static const char * const os05b10_supply_name[] = {
};

static const struct cci_reg_sequence os05b10_common_regs[] = {
- { OS05B10_REG_PLL_CTRL(0x01), 0x44 },
- { OS05B10_REG_PLL_CTRL(0x03), 0x02 },
- { OS05B10_REG_PLL_CTRL(0x05), 0x32 },
- { OS05B10_REG_PLL_CTRL(0x06), 0x00 },
- { OS05B10_REG_PLL_CTRL(0x25), 0x3b },
{ CCI_REG8(0x3002), 0x21 },
- { OS05B10_REG_MIPI_SC_CTRL, OS05B10_4_LANE_MODE },
{ CCI_REG8(0x301e), 0xb4 },
{ CCI_REG8(0x301f), 0xd0 },
{ CCI_REG8(0x3021), 0x03 },
@@ -529,6 +524,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(0x01), 0x44 },
+ { OS05B10_REG_PLL_CTRL(0x03), 0x02 },
+ { OS05B10_REG_PLL_CTRL(0x05), 0x64 },
+ { OS05B10_REG_PLL_CTRL(0x06), 0x00 },
+ { OS05B10_REG_PLL_CTRL(0x25), 0x3b },
+ { OS05B10_REG_MIPI_SC_CTRL, OS05B10_2_LANE_MODE },
+};
+
+static const struct cci_reg_sequence os05b10_4lane_regs[] = {
+ { OS05B10_REG_PLL_CTRL(0x01), 0x44 },
+ { OS05B10_REG_PLL_CTRL(0x03), 0x02 },
+ { OS05B10_REG_PLL_CTRL(0x05), 0x32 },
+ { OS05B10_REG_PLL_CTRL(0x06), 0x00 },
+ { OS05B10_REG_PLL_CTRL(0x25), 0x3b },
+ { OS05B10_REG_MIPI_SC_CTRL, OS05B10_4_LANE_MODE },
+};
+
struct os05b10 {
struct device *dev;
struct regmap *cci;
@@ -547,6 +560,7 @@ struct os05b10 {
struct v4l2_ctrl *vflip;
struct v4l2_ctrl *hflip;

+ const s64 *link_frequencies;
u32 link_freq_index;
u32 data_lanes;
};
@@ -644,10 +658,14 @@ static const struct os05b10_mode supported_modes_10bit[] = {
},
};

-static const s64 link_frequencies[] = {
+static const s64 link_frequencies_4lane[] = {
OS05B10_LINK_FREQ_600MHZ,
};

+static const s64 link_frequencies_2lane[] = {
+ OS05B10_LINK_FREQ_750MHZ,
+};
+
static const u32 os05b10_mbus_codes[] = {
MEDIA_BUS_FMT_SBGGR10_1X10,
MEDIA_BUS_FMT_SBGGR12_1X12,
@@ -983,6 +1001,19 @@ static int os05b10_enable_streams(struct v4l2_subdev *sd,
if (ret < 0)
return ret;

+ /* Write PLL and MIPI lane configuration */
+ if (os05b10->data_lanes == 2)
+ ret = cci_multi_reg_write(os05b10->cci, os05b10_2lane_regs,
+ ARRAY_SIZE(os05b10_2lane_regs), NULL);
+ else
+ ret = cci_multi_reg_write(os05b10->cci, os05b10_4lane_regs,
+ ARRAY_SIZE(os05b10_4lane_regs), NULL);
+ if (ret) {
+ dev_err(os05b10->dev,
+ "failed to write PLL and MIPI lane registers\n");
+ goto err_rpm_put;
+ }
+
/* Write common registers */
ret = cci_multi_reg_write(os05b10->cci, os05b10_common_regs,
ARRAY_SIZE(os05b10_common_regs), NULL);
@@ -1194,9 +1225,16 @@ static int os05b10_parse_endpoint(struct os05b10 *os05b10)
if (ret)
return ret;

- if (bus_cfg.bus.mipi_csi2.num_data_lanes != 4) {
+ switch (bus_cfg.bus.mipi_csi2.num_data_lanes) {
+ case 2:
+ os05b10->link_frequencies = link_frequencies_2lane;
+ break;
+ case 4:
+ os05b10->link_frequencies = link_frequencies_4lane;
+ break;
+ default:
ret = dev_err_probe(os05b10->dev, -EINVAL,
- "only 4 data lanes are supported\n");
+ "only 2 or 4 data lanes are supported\n");
goto error_out;
}

@@ -1204,11 +1242,13 @@ static int os05b10_parse_endpoint(struct os05b10 *os05b10)

ret = v4l2_link_freq_to_bitmap(os05b10->dev, bus_cfg.link_frequencies,
bus_cfg.nr_of_link_frequencies,
- link_frequencies,
- ARRAY_SIZE(link_frequencies),
+ os05b10->link_frequencies,
+ ARRAY_SIZE(link_frequencies_4lane),
&link_freq_bitmap);
if (ret) {
- dev_err(os05b10->dev, "only 600MHz frequency is available\n");
+ dev_err(os05b10->dev, "%u MHz link frequency required for %u lanes\n",
+ (unsigned int)(os05b10->link_frequencies[0] / HZ_PER_MHZ),
+ os05b10->data_lanes);
goto error_out;
}

@@ -1223,7 +1263,7 @@ static int os05b10_parse_endpoint(struct os05b10 *os05b10)
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->link_frequencies[os05b10->link_freq_index];
u64 pixel_rate = div_u64(link_freq * 2 * os05b10->data_lanes, mode->bpp);

dev_dbg(os05b10->dev,
@@ -1255,9 +1295,9 @@ static int os05b10_init_controls(struct 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->link_frequencies);

hblank_def = mode->hts - mode->width;
os05b10->hblank = v4l2_ctrl_new_std(ctrl_hdlr, NULL, V4L2_CID_HBLANK,
--
2.34.1