[PATCH v5 14/15] media: i2c: os05b10: add 2-lane support
From: Tarang Raval
Date: Fri Oct 30 2026 - 06:55:25 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.
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