* [PATCH v2 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation
@ 2026-07-07 17:04 Dave Stevenson
2026-07-07 17:04 ` [PATCH v2 01/20] media: i2c: imx355: Add support for 24 MHz external clock Dave Stevenson
` (19 more replies)
0 siblings, 20 replies; 34+ messages in thread
From: Dave Stevenson @ 2026-07-07 17:04 UTC (permalink / raw)
To: Tianshu Qiu, Sakari Ailus, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Richard Acayan
Cc: linux-media, linux-kernel, David Heidelberg, Jacopo Mondi,
devicetree, Dave Stevenson
This series came about as we had a customer ask about using imx355,
so I had a look at what was going on.
There was significant duplication between the various mode register lists,
unused parameters around, and no support for advertising the crop
rectangles through get_selection. It also wasn't using V4L2_CCI so
had all the boilerplate for writing registers.
The customer also wanted to run the sensor over only 2 CSI2 data lanes
which required some rework of the clock setup so that the MIPI link
frequency could be run at 445MHz instead of the 360MHz used for 4 lane
mode.
V2 has some fairly substantial differences to V1 as I obtained a datasheet.
Whilst some things worked perfectly, the datasheet declared them as
prohibited. This was largely using dual PLL mode in 2 lane mode, and
LLP is restricted to specific values. Link frequencies are therefore now
derived from the PLL configuration, and pixel rate is computed from that.
Being able to refer against the datasheet, I've pulled an updated version
of David Heidelberg's patch for 24MHz clock support into this series.
I've tried to keep it that the earlier patches are largely cleanups or
minor improvements, and then we get adding 2 lane support, and converting
to using subdev state as they are larger patches.
---
Changes in v2:
- Collected Jacopo's R-b tags and implement his review comments.
- Add patches to switch to using the subdev state, clean up colorspace
(sets RAW), use a define for the exposure offset.
- Added DT binding update to permit 2 CSI2 data lanes.
- Link to v1: https://lore.kernel.org/r/20260506-media-imx355-v1-0-660685030455@raspberrypi.com
---
Dave Stevenson (19):
dt-bindings: media: imx355: Allow 2 CSI2 data lane output
media: imx355: Remove duplicated registers from the mode tables
media: imx355: Remove setting FRM_LENGTH_LINES in the mode regs
media: imx355: Programmatically set the crop parameters for each mode
media: imx355: Set register LINE_LENGTH_PCK programmatically
media: imx355: Set binning mode registers programmatically
media: imx355: Remove link_freq_index from each mode as ununsed
media: imx355: pixel_rate never changes, so don't recompute
media: imx355: Remove redundant fll_min, and implement fixed offset
media: imx355: Add support for get_selection
media: imx355: Use pm_runtime autosuspend_delay
media: imx355: Convert to new CCI register access helpers
media: imx355: Set the colorspace in the format
media: imx355: Define the exposure offset, and use that define
media: imx355: Use NULL ctrl_ops for HBLANK as it is a read-only control
media: imx355: Compute link frequency from PLL setup
media: imx355: Support 2 lane readout
media: imx355: Switch to using the subdev state
media: imx355: Remove storing cur_mode in the state
David Heidelberg (1):
media: i2c: imx355: Add support for 24 MHz external clock
.../devicetree/bindings/media/i2c/sony,imx355.yaml | 11 +-
drivers/media/i2c/Kconfig | 1 +
drivers/media/i2c/imx355.c | 1515 +++++++-------------
3 files changed, 494 insertions(+), 1033 deletions(-)
---
base-commit: 254f49634ee16a731174d2ae34bc50bd5f45e731
change-id: 20260506-media-imx355-a30f5be3deda
Best regards,
--
Dave Stevenson <dave.stevenson@raspberrypi.com>
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH v2 01/20] media: i2c: imx355: Add support for 24 MHz external clock
2026-07-07 17:04 [PATCH v2 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
@ 2026-07-07 17:04 ` Dave Stevenson
2026-07-07 17:04 ` [PATCH v2 02/20] dt-bindings: media: imx355: Allow 2 CSI2 data lane output Dave Stevenson
` (18 subsequent siblings)
19 siblings, 0 replies; 34+ messages in thread
From: Dave Stevenson @ 2026-07-07 17:04 UTC (permalink / raw)
To: Tianshu Qiu, Sakari Ailus, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Richard Acayan
Cc: linux-media, linux-kernel, David Heidelberg, Jacopo Mondi,
devicetree, Dave Stevenson
From: David Heidelberg <david@ixit.cz>
The IMX355 sensor supports multiple external clock frequencies,
including 19.2 MHz and 24 MHz. The driver currently supports only
fixed 19.2 MHz input clock.
Refactor the clock handling to make the PLL configuration dependent
on the external clock frequency and add support for 24 MHz. Introduce
a table of clock parameter sets and program the corresponding EXTCLK
frequency and PLL multipliers to maintain consistent internal VCO
frequencies across supported inputs.
The PLL settings are adjusted so that OP VCO remains at 720 MHz
This preserves existing timing characteristics while allowing systems
using a 24 MHz clock to operate correctly.
No functional change for existing 19.2 MHz users.
Assisted-by: Claude:claude-opus-4-6
Signed-off-by: David Heidelberg <david@ixit.cz>
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/media/i2c/imx355.c | 77 +++++++++++++++++++++++++++-------------------
1 file changed, 45 insertions(+), 32 deletions(-)
diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
index 27a5c212a527..ad9a9464175b 100644
--- a/drivers/media/i2c/imx355.c
+++ b/drivers/media/i2c/imx355.c
@@ -25,6 +25,10 @@
#define IMX355_REG_CHIP_ID 0x0016
#define IMX355_CHIP_ID 0x0355
+/* PLL registers that depend on the external clock frequency */
+#define IMX355_REG_EXTCLK_FREQ 0x0136
+#define IMX355_REG_PLL_OP_MUL 0x030e
+
/* V_TIMING internal */
#define IMX355_REG_FLL 0x0340
#define IMX355_FLL_MAX 0xffff
@@ -63,7 +67,6 @@
/* default link frequency and external clock */
#define IMX355_LINK_FREQ_DEFAULT 360000000LL
-#define IMX355_EXT_CLK 19200000
#define IMX355_LINK_FREQ_INDEX 0
/* number of data lanes */
@@ -100,6 +103,29 @@ struct imx355_mode {
struct imx355_reg_list reg_list;
};
+struct imx355_clk_params {
+ u32 ext_clk;
+ u16 extclk_freq; /* External clock (MHz) in 8.8 fixed point) */
+ u16 pll_op_mpy; /* OP system PLL multiplier */
+};
+
+/*
+ * The clock tree is in single PLL mode, so PREDIV_VT and MPY_IVT do nothing.
+ * All modes use the same PLL setup for OP, with IOPCK being 720MHz.
+ */
+static const struct imx355_clk_params imx355_clk_params[] = {
+ {
+ .ext_clk = 19200000,
+ .extclk_freq = 0x1333, /* 19.2 MHz */
+ .pll_op_mpy = 75, /* 19.2 / 2 * 75 = 720 MHz */
+ },
+ {
+ .ext_clk = 24000000,
+ .extclk_freq = 0x1800, /* 24.0 MHz */
+ .pll_op_mpy = 60, /* 24.0 / 2 * 60 = 720 MHz */
+ },
+};
+
struct imx355_hwcfg {
unsigned long link_freq_bitmap;
};
@@ -125,6 +151,7 @@ struct imx355 {
const struct imx355_mode *cur_mode;
struct imx355_hwcfg *hwcfg;
+ const struct imx355_clk_params *clk_params;
/*
* Mutex for serialized access:
@@ -144,8 +171,6 @@ static const struct regulator_bulk_data imx355_supplies[] = {
};
static const struct imx355_reg imx355_global_regs[] = {
- { 0x0136, 0x13 },
- { 0x0137, 0x33 },
{ 0x304e, 0x03 },
{ 0x4348, 0x16 },
{ 0x4350, 0x19 },
@@ -235,8 +260,6 @@ static const struct imx355_reg mode_3268x2448_regs[] = {
{ 0x0307, 0x78 },
{ 0x030b, 0x01 },
{ 0x030d, 0x02 },
- { 0x030e, 0x00 },
- { 0x030f, 0x4b },
{ 0x0310, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
@@ -284,8 +307,6 @@ static const struct imx355_reg mode_3264x2448_regs[] = {
{ 0x0307, 0x78 },
{ 0x030b, 0x01 },
{ 0x030d, 0x02 },
- { 0x030e, 0x00 },
- { 0x030f, 0x4b },
{ 0x0310, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
@@ -333,8 +354,6 @@ static const struct imx355_reg mode_3280x2464_regs[] = {
{ 0x0307, 0x78 },
{ 0x030b, 0x01 },
{ 0x030d, 0x02 },
- { 0x030e, 0x00 },
- { 0x030f, 0x4b },
{ 0x0310, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
@@ -382,8 +401,6 @@ static const struct imx355_reg mode_1940x1096_regs[] = {
{ 0x0307, 0x78 },
{ 0x030b, 0x01 },
{ 0x030d, 0x02 },
- { 0x030e, 0x00 },
- { 0x030f, 0x4b },
{ 0x0310, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
@@ -431,8 +448,6 @@ static const struct imx355_reg mode_1936x1096_regs[] = {
{ 0x0307, 0x78 },
{ 0x030b, 0x01 },
{ 0x030d, 0x02 },
- { 0x030e, 0x00 },
- { 0x030f, 0x4b },
{ 0x0310, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
@@ -480,8 +495,6 @@ static const struct imx355_reg mode_1924x1080_regs[] = {
{ 0x0307, 0x78 },
{ 0x030b, 0x01 },
{ 0x030d, 0x02 },
- { 0x030e, 0x00 },
- { 0x030f, 0x4b },
{ 0x0310, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
@@ -529,8 +542,6 @@ static const struct imx355_reg mode_1920x1080_regs[] = {
{ 0x0307, 0x78 },
{ 0x030b, 0x01 },
{ 0x030d, 0x02 },
- { 0x030e, 0x00 },
- { 0x030f, 0x4b },
{ 0x0310, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
@@ -578,8 +589,6 @@ static const struct imx355_reg mode_1640x1232_regs[] = {
{ 0x0307, 0x78 },
{ 0x030b, 0x01 },
{ 0x030d, 0x02 },
- { 0x030e, 0x00 },
- { 0x030f, 0x4b },
{ 0x0310, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
@@ -627,8 +636,6 @@ static const struct imx355_reg mode_1640x922_regs[] = {
{ 0x0307, 0x78 },
{ 0x030b, 0x01 },
{ 0x030d, 0x02 },
- { 0x030e, 0x00 },
- { 0x030f, 0x4b },
{ 0x0310, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
@@ -676,8 +683,6 @@ static const struct imx355_reg mode_1300x736_regs[] = {
{ 0x0307, 0x78 },
{ 0x030b, 0x01 },
{ 0x030d, 0x02 },
- { 0x030e, 0x00 },
- { 0x030f, 0x4b },
{ 0x0310, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
@@ -725,8 +730,6 @@ static const struct imx355_reg mode_1296x736_regs[] = {
{ 0x0307, 0x78 },
{ 0x030b, 0x01 },
{ 0x030d, 0x02 },
- { 0x030e, 0x00 },
- { 0x030f, 0x4b },
{ 0x0310, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
@@ -774,8 +777,6 @@ static const struct imx355_reg mode_1284x720_regs[] = {
{ 0x0307, 0x78 },
{ 0x030b, 0x01 },
{ 0x030d, 0x02 },
- { 0x030e, 0x00 },
- { 0x030f, 0x4b },
{ 0x0310, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
@@ -823,8 +824,6 @@ static const struct imx355_reg mode_1280x720_regs[] = {
{ 0x0307, 0x78 },
{ 0x030b, 0x01 },
{ 0x030d, 0x02 },
- { 0x030e, 0x00 },
- { 0x030f, 0x4b },
{ 0x0310, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
@@ -872,8 +871,6 @@ static const struct imx355_reg mode_820x616_regs[] = {
{ 0x0307, 0x78 },
{ 0x030b, 0x01 },
{ 0x030d, 0x02 },
- { 0x030e, 0x00 },
- { 0x030f, 0x4b },
{ 0x0310, 0x00 },
{ 0x0700, 0x02 },
{ 0x0701, 0x78 },
@@ -1422,6 +1419,16 @@ static int imx355_start_streaming(struct imx355 *imx355)
return ret;
}
+ /* Set PLL registers for the external clock frequency */
+ ret = imx355_write_reg(imx355, IMX355_REG_EXTCLK_FREQ, 2,
+ imx355->clk_params->extclk_freq);
+ if (ret)
+ return ret;
+ ret = imx355_write_reg(imx355, IMX355_REG_PLL_OP_MUL, 2,
+ imx355->clk_params->pll_op_mpy);
+ if (ret)
+ return ret;
+
/* set digital gain control to all color mode */
ret = imx355_write_reg(imx355, IMX355_REG_DPGA_USE_GLOBAL_GAIN, 1, 1);
if (ret)
@@ -1749,7 +1756,13 @@ static int imx355_probe(struct i2c_client *client)
"failed to get clock\n");
freq = clk_get_rate(imx355->clk);
- if (freq != IMX355_EXT_CLK)
+ for (unsigned int i = 0; i < ARRAY_SIZE(imx355_clk_params); i++) {
+ if (freq == imx355_clk_params[i].ext_clk) {
+ imx355->clk_params = &imx355_clk_params[i];
+ break;
+ }
+ }
+ if (!imx355->clk_params)
return dev_err_probe(imx355->dev, -EINVAL,
"external clock %lu is not supported\n",
freq);
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v2 02/20] dt-bindings: media: imx355: Allow 2 CSI2 data lane output
2026-07-07 17:04 [PATCH v2 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
2026-07-07 17:04 ` [PATCH v2 01/20] media: i2c: imx355: Add support for 24 MHz external clock Dave Stevenson
@ 2026-07-07 17:04 ` Dave Stevenson
2026-07-08 7:07 ` Krzysztof Kozlowski
2026-07-07 17:04 ` [PATCH v2 03/20] media: imx355: Remove duplicated registers from the mode tables Dave Stevenson
` (17 subsequent siblings)
19 siblings, 1 reply; 34+ messages in thread
From: Dave Stevenson @ 2026-07-07 17:04 UTC (permalink / raw)
To: Tianshu Qiu, Sakari Ailus, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Richard Acayan
Cc: linux-media, linux-kernel, David Heidelberg, Jacopo Mondi,
devicetree, Dave Stevenson
The sensor supports output over either 2 or 4 CSI2 data
lanes. The binding only permitted the 4 lane configuration.
Add the 2 lane configuration as an option.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
The original bindings just used minItems and maxItems which implies
that lane reordering is supported on the sensor and that the lanes
can be entered in any order. This isn't the case as lane reordering
isn't supported.
If this change counts as breaking the binding, then is minItems: 2,
maxItems: 4 the best that can be achieved which leaves 3 permitted
but invalid? Or is there a better syntax?
---
Documentation/devicetree/bindings/media/i2c/sony,imx355.yaml | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx355.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx355.yaml
index 6050d7e7dcfe..d9cdfda699bf 100644
--- a/Documentation/devicetree/bindings/media/i2c/sony,imx355.yaml
+++ b/Documentation/devicetree/bindings/media/i2c/sony,imx355.yaml
@@ -50,8 +50,15 @@ properties:
properties:
data-lanes:
- minItems: 4
- maxItems: 4
+ oneOf:
+ - items:
+ - const: 1
+ - const: 2
+ - const: 3
+ - const: 4
+ - items:
+ - const: 1
+ - const: 2
required:
- link-frequencies
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v2 03/20] media: imx355: Remove duplicated registers from the mode tables
2026-07-07 17:04 [PATCH v2 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
2026-07-07 17:04 ` [PATCH v2 01/20] media: i2c: imx355: Add support for 24 MHz external clock Dave Stevenson
2026-07-07 17:04 ` [PATCH v2 02/20] dt-bindings: media: imx355: Allow 2 CSI2 data lane output Dave Stevenson
@ 2026-07-07 17:04 ` Dave Stevenson
2026-07-07 17:14 ` sashiko-bot
2026-07-07 17:04 ` [PATCH v2 04/20] media: imx355: Remove setting FRM_LENGTH_LINES in the mode regs Dave Stevenson
` (16 subsequent siblings)
19 siblings, 1 reply; 34+ messages in thread
From: Dave Stevenson @ 2026-07-07 17:04 UTC (permalink / raw)
To: Tianshu Qiu, Sakari Ailus, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Richard Acayan
Cc: linux-media, linux-kernel, David Heidelberg, Jacopo Mondi,
devicetree, Dave Stevenson
A large number of registers are identical within all the modes.
Move those to imx355_global_regs.
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/media/i2c/imx355.c | 344 +++------------------------------------------
1 file changed, 22 insertions(+), 322 deletions(-)
diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
index ad9a9464175b..83a59aa8b098 100644
--- a/drivers/media/i2c/imx355.c
+++ b/drivers/media/i2c/imx355.c
@@ -221,6 +221,28 @@ static const struct imx355_reg imx355_global_regs[] = {
{ 0x68b0, 0x00 },
{ 0x3058, 0x00 },
{ 0x305a, 0x00 },
+ { 0x0112, 0x0a },
+ { 0x0113, 0x0a },
+ { 0x0114, 0x03 },
+ { 0x0301, 0x05 },
+ { 0x0303, 0x01 },
+ { 0x0305, 0x02 },
+ { 0x0306, 0x00 },
+ { 0x0307, 0x78 },
+ { 0x030d, 0x02 },
+ { 0x0310, 0x00 },
+ { 0x0220, 0x00 },
+ { 0x0222, 0x01 },
+ { 0x0820, 0x0b },
+ { 0x0821, 0x40 },
+ { 0x3088, 0x04 },
+ { 0x6813, 0x02 },
+ { 0x6835, 0x07 },
+ { 0x6836, 0x01 },
+ { 0x6837, 0x04 },
+ { 0x684d, 0x07 },
+ { 0x684e, 0x01 },
+ { 0x684f, 0x04 },
};
static const struct imx355_reg_list imx355_global_setting = {
@@ -229,9 +251,6 @@ static const struct imx355_reg_list imx355_global_setting = {
};
static const struct imx355_reg mode_3268x2448_regs[] = {
- { 0x0112, 0x0a },
- { 0x0113, 0x0a },
- { 0x0114, 0x03 },
{ 0x0342, 0x0e },
{ 0x0343, 0x58 },
{ 0x0340, 0x0a },
@@ -244,8 +263,6 @@ static const struct imx355_reg mode_3268x2448_regs[] = {
{ 0x0349, 0xcb },
{ 0x034a, 0x09 },
{ 0x034b, 0x97 },
- { 0x0220, 0x00 },
- { 0x0222, 0x01 },
{ 0x0900, 0x00 },
{ 0x0901, 0x11 },
{ 0x0902, 0x00 },
@@ -253,32 +270,11 @@ static const struct imx355_reg mode_3268x2448_regs[] = {
{ 0x034d, 0xc4 },
{ 0x034e, 0x09 },
{ 0x034f, 0x90 },
- { 0x0301, 0x05 },
- { 0x0303, 0x01 },
- { 0x0305, 0x02 },
- { 0x0306, 0x00 },
- { 0x0307, 0x78 },
- { 0x030b, 0x01 },
- { 0x030d, 0x02 },
- { 0x0310, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
- { 0x0820, 0x0b },
- { 0x0821, 0x40 },
- { 0x3088, 0x04 },
- { 0x6813, 0x02 },
- { 0x6835, 0x07 },
- { 0x6836, 0x01 },
- { 0x6837, 0x04 },
- { 0x684d, 0x07 },
- { 0x684e, 0x01 },
- { 0x684f, 0x04 },
};
static const struct imx355_reg mode_3264x2448_regs[] = {
- { 0x0112, 0x0a },
- { 0x0113, 0x0a },
- { 0x0114, 0x03 },
{ 0x0342, 0x0e },
{ 0x0343, 0x58 },
{ 0x0340, 0x0a },
@@ -291,8 +287,6 @@ static const struct imx355_reg mode_3264x2448_regs[] = {
{ 0x0349, 0xc7 },
{ 0x034a, 0x09 },
{ 0x034b, 0x97 },
- { 0x0220, 0x00 },
- { 0x0222, 0x01 },
{ 0x0900, 0x00 },
{ 0x0901, 0x11 },
{ 0x0902, 0x00 },
@@ -300,32 +294,11 @@ static const struct imx355_reg mode_3264x2448_regs[] = {
{ 0x034d, 0xc0 },
{ 0x034e, 0x09 },
{ 0x034f, 0x90 },
- { 0x0301, 0x05 },
- { 0x0303, 0x01 },
- { 0x0305, 0x02 },
- { 0x0306, 0x00 },
- { 0x0307, 0x78 },
- { 0x030b, 0x01 },
- { 0x030d, 0x02 },
- { 0x0310, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
- { 0x0820, 0x0b },
- { 0x0821, 0x40 },
- { 0x3088, 0x04 },
- { 0x6813, 0x02 },
- { 0x6835, 0x07 },
- { 0x6836, 0x01 },
- { 0x6837, 0x04 },
- { 0x684d, 0x07 },
- { 0x684e, 0x01 },
- { 0x684f, 0x04 },
};
static const struct imx355_reg mode_3280x2464_regs[] = {
- { 0x0112, 0x0a },
- { 0x0113, 0x0a },
- { 0x0114, 0x03 },
{ 0x0342, 0x0e },
{ 0x0343, 0x58 },
{ 0x0340, 0x0a },
@@ -338,8 +311,6 @@ static const struct imx355_reg mode_3280x2464_regs[] = {
{ 0x0349, 0xcf },
{ 0x034a, 0x09 },
{ 0x034b, 0x9f },
- { 0x0220, 0x00 },
- { 0x0222, 0x01 },
{ 0x0900, 0x00 },
{ 0x0901, 0x11 },
{ 0x0902, 0x00 },
@@ -347,32 +318,11 @@ static const struct imx355_reg mode_3280x2464_regs[] = {
{ 0x034d, 0xd0 },
{ 0x034e, 0x09 },
{ 0x034f, 0xa0 },
- { 0x0301, 0x05 },
- { 0x0303, 0x01 },
- { 0x0305, 0x02 },
- { 0x0306, 0x00 },
- { 0x0307, 0x78 },
- { 0x030b, 0x01 },
- { 0x030d, 0x02 },
- { 0x0310, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
- { 0x0820, 0x0b },
- { 0x0821, 0x40 },
- { 0x3088, 0x04 },
- { 0x6813, 0x02 },
- { 0x6835, 0x07 },
- { 0x6836, 0x01 },
- { 0x6837, 0x04 },
- { 0x684d, 0x07 },
- { 0x684e, 0x01 },
- { 0x684f, 0x04 },
};
static const struct imx355_reg mode_1940x1096_regs[] = {
- { 0x0112, 0x0a },
- { 0x0113, 0x0a },
- { 0x0114, 0x03 },
{ 0x0342, 0x0e },
{ 0x0343, 0x58 },
{ 0x0340, 0x05 },
@@ -385,8 +335,6 @@ static const struct imx355_reg mode_1940x1096_regs[] = {
{ 0x0349, 0x33 },
{ 0x034a, 0x06 },
{ 0x034b, 0xf3 },
- { 0x0220, 0x00 },
- { 0x0222, 0x01 },
{ 0x0900, 0x00 },
{ 0x0901, 0x11 },
{ 0x0902, 0x00 },
@@ -394,32 +342,11 @@ static const struct imx355_reg mode_1940x1096_regs[] = {
{ 0x034d, 0x94 },
{ 0x034e, 0x04 },
{ 0x034f, 0x48 },
- { 0x0301, 0x05 },
- { 0x0303, 0x01 },
- { 0x0305, 0x02 },
- { 0x0306, 0x00 },
- { 0x0307, 0x78 },
- { 0x030b, 0x01 },
- { 0x030d, 0x02 },
- { 0x0310, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
- { 0x0820, 0x0b },
- { 0x0821, 0x40 },
- { 0x3088, 0x04 },
- { 0x6813, 0x02 },
- { 0x6835, 0x07 },
- { 0x6836, 0x01 },
- { 0x6837, 0x04 },
- { 0x684d, 0x07 },
- { 0x684e, 0x01 },
- { 0x684f, 0x04 },
};
static const struct imx355_reg mode_1936x1096_regs[] = {
- { 0x0112, 0x0a },
- { 0x0113, 0x0a },
- { 0x0114, 0x03 },
{ 0x0342, 0x0e },
{ 0x0343, 0x58 },
{ 0x0340, 0x05 },
@@ -432,8 +359,6 @@ static const struct imx355_reg mode_1936x1096_regs[] = {
{ 0x0349, 0x2f },
{ 0x034a, 0x06 },
{ 0x034b, 0xf3 },
- { 0x0220, 0x00 },
- { 0x0222, 0x01 },
{ 0x0900, 0x00 },
{ 0x0901, 0x11 },
{ 0x0902, 0x00 },
@@ -441,32 +366,11 @@ static const struct imx355_reg mode_1936x1096_regs[] = {
{ 0x034d, 0x90 },
{ 0x034e, 0x04 },
{ 0x034f, 0x48 },
- { 0x0301, 0x05 },
- { 0x0303, 0x01 },
- { 0x0305, 0x02 },
- { 0x0306, 0x00 },
- { 0x0307, 0x78 },
- { 0x030b, 0x01 },
- { 0x030d, 0x02 },
- { 0x0310, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
- { 0x0820, 0x0b },
- { 0x0821, 0x40 },
- { 0x3088, 0x04 },
- { 0x6813, 0x02 },
- { 0x6835, 0x07 },
- { 0x6836, 0x01 },
- { 0x6837, 0x04 },
- { 0x684d, 0x07 },
- { 0x684e, 0x01 },
- { 0x684f, 0x04 },
};
static const struct imx355_reg mode_1924x1080_regs[] = {
- { 0x0112, 0x0a },
- { 0x0113, 0x0a },
- { 0x0114, 0x03 },
{ 0x0342, 0x0e },
{ 0x0343, 0x58 },
{ 0x0340, 0x05 },
@@ -479,8 +383,6 @@ static const struct imx355_reg mode_1924x1080_regs[] = {
{ 0x0349, 0x2b },
{ 0x034a, 0x06 },
{ 0x034b, 0xeb },
- { 0x0220, 0x00 },
- { 0x0222, 0x01 },
{ 0x0900, 0x00 },
{ 0x0901, 0x11 },
{ 0x0902, 0x00 },
@@ -488,32 +390,11 @@ static const struct imx355_reg mode_1924x1080_regs[] = {
{ 0x034d, 0x84 },
{ 0x034e, 0x04 },
{ 0x034f, 0x38 },
- { 0x0301, 0x05 },
- { 0x0303, 0x01 },
- { 0x0305, 0x02 },
- { 0x0306, 0x00 },
- { 0x0307, 0x78 },
- { 0x030b, 0x01 },
- { 0x030d, 0x02 },
- { 0x0310, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
- { 0x0820, 0x0b },
- { 0x0821, 0x40 },
- { 0x3088, 0x04 },
- { 0x6813, 0x02 },
- { 0x6835, 0x07 },
- { 0x6836, 0x01 },
- { 0x6837, 0x04 },
- { 0x684d, 0x07 },
- { 0x684e, 0x01 },
- { 0x684f, 0x04 },
};
static const struct imx355_reg mode_1920x1080_regs[] = {
- { 0x0112, 0x0a },
- { 0x0113, 0x0a },
- { 0x0114, 0x03 },
{ 0x0342, 0x0e },
{ 0x0343, 0x58 },
{ 0x0340, 0x05 },
@@ -526,8 +407,6 @@ static const struct imx355_reg mode_1920x1080_regs[] = {
{ 0x0349, 0x27 },
{ 0x034a, 0x06 },
{ 0x034b, 0xeb },
- { 0x0220, 0x00 },
- { 0x0222, 0x01 },
{ 0x0900, 0x00 },
{ 0x0901, 0x11 },
{ 0x0902, 0x00 },
@@ -535,32 +414,11 @@ static const struct imx355_reg mode_1920x1080_regs[] = {
{ 0x034d, 0x80 },
{ 0x034e, 0x04 },
{ 0x034f, 0x38 },
- { 0x0301, 0x05 },
- { 0x0303, 0x01 },
- { 0x0305, 0x02 },
- { 0x0306, 0x00 },
- { 0x0307, 0x78 },
- { 0x030b, 0x01 },
- { 0x030d, 0x02 },
- { 0x0310, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
- { 0x0820, 0x0b },
- { 0x0821, 0x40 },
- { 0x3088, 0x04 },
- { 0x6813, 0x02 },
- { 0x6835, 0x07 },
- { 0x6836, 0x01 },
- { 0x6837, 0x04 },
- { 0x684d, 0x07 },
- { 0x684e, 0x01 },
- { 0x684f, 0x04 },
};
static const struct imx355_reg mode_1640x1232_regs[] = {
- { 0x0112, 0x0a },
- { 0x0113, 0x0a },
- { 0x0114, 0x03 },
{ 0x0342, 0x07 },
{ 0x0343, 0x2c },
{ 0x0340, 0x05 },
@@ -573,8 +431,6 @@ static const struct imx355_reg mode_1640x1232_regs[] = {
{ 0x0349, 0xcf },
{ 0x034a, 0x09 },
{ 0x034b, 0x9f },
- { 0x0220, 0x00 },
- { 0x0222, 0x01 },
{ 0x0900, 0x01 },
{ 0x0901, 0x22 },
{ 0x0902, 0x00 },
@@ -582,32 +438,11 @@ static const struct imx355_reg mode_1640x1232_regs[] = {
{ 0x034d, 0x68 },
{ 0x034e, 0x04 },
{ 0x034f, 0xd0 },
- { 0x0301, 0x05 },
- { 0x0303, 0x01 },
- { 0x0305, 0x02 },
- { 0x0306, 0x00 },
- { 0x0307, 0x78 },
- { 0x030b, 0x01 },
- { 0x030d, 0x02 },
- { 0x0310, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
- { 0x0820, 0x0b },
- { 0x0821, 0x40 },
- { 0x3088, 0x04 },
- { 0x6813, 0x02 },
- { 0x6835, 0x07 },
- { 0x6836, 0x01 },
- { 0x6837, 0x04 },
- { 0x684d, 0x07 },
- { 0x684e, 0x01 },
- { 0x684f, 0x04 },
};
static const struct imx355_reg mode_1640x922_regs[] = {
- { 0x0112, 0x0a },
- { 0x0113, 0x0a },
- { 0x0114, 0x03 },
{ 0x0342, 0x07 },
{ 0x0343, 0x2c },
{ 0x0340, 0x05 },
@@ -620,8 +455,6 @@ static const struct imx355_reg mode_1640x922_regs[] = {
{ 0x0349, 0xcf },
{ 0x034a, 0x08 },
{ 0x034b, 0x63 },
- { 0x0220, 0x00 },
- { 0x0222, 0x01 },
{ 0x0900, 0x01 },
{ 0x0901, 0x22 },
{ 0x0902, 0x00 },
@@ -629,32 +462,11 @@ static const struct imx355_reg mode_1640x922_regs[] = {
{ 0x034d, 0x68 },
{ 0x034e, 0x03 },
{ 0x034f, 0x9a },
- { 0x0301, 0x05 },
- { 0x0303, 0x01 },
- { 0x0305, 0x02 },
- { 0x0306, 0x00 },
- { 0x0307, 0x78 },
- { 0x030b, 0x01 },
- { 0x030d, 0x02 },
- { 0x0310, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
- { 0x0820, 0x0b },
- { 0x0821, 0x40 },
- { 0x3088, 0x04 },
- { 0x6813, 0x02 },
- { 0x6835, 0x07 },
- { 0x6836, 0x01 },
- { 0x6837, 0x04 },
- { 0x684d, 0x07 },
- { 0x684e, 0x01 },
- { 0x684f, 0x04 },
};
static const struct imx355_reg mode_1300x736_regs[] = {
- { 0x0112, 0x0a },
- { 0x0113, 0x0a },
- { 0x0114, 0x03 },
{ 0x0342, 0x07 },
{ 0x0343, 0x2c },
{ 0x0340, 0x05 },
@@ -667,8 +479,6 @@ static const struct imx355_reg mode_1300x736_regs[] = {
{ 0x0349, 0x7f },
{ 0x034a, 0x07 },
{ 0x034b, 0xaf },
- { 0x0220, 0x00 },
- { 0x0222, 0x01 },
{ 0x0900, 0x01 },
{ 0x0901, 0x22 },
{ 0x0902, 0x00 },
@@ -676,32 +486,11 @@ static const struct imx355_reg mode_1300x736_regs[] = {
{ 0x034d, 0x14 },
{ 0x034e, 0x02 },
{ 0x034f, 0xe0 },
- { 0x0301, 0x05 },
- { 0x0303, 0x01 },
- { 0x0305, 0x02 },
- { 0x0306, 0x00 },
- { 0x0307, 0x78 },
- { 0x030b, 0x01 },
- { 0x030d, 0x02 },
- { 0x0310, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
- { 0x0820, 0x0b },
- { 0x0821, 0x40 },
- { 0x3088, 0x04 },
- { 0x6813, 0x02 },
- { 0x6835, 0x07 },
- { 0x6836, 0x01 },
- { 0x6837, 0x04 },
- { 0x684d, 0x07 },
- { 0x684e, 0x01 },
- { 0x684f, 0x04 },
};
static const struct imx355_reg mode_1296x736_regs[] = {
- { 0x0112, 0x0a },
- { 0x0113, 0x0a },
- { 0x0114, 0x03 },
{ 0x0342, 0x07 },
{ 0x0343, 0x2c },
{ 0x0340, 0x05 },
@@ -714,8 +503,6 @@ static const struct imx355_reg mode_1296x736_regs[] = {
{ 0x0349, 0x77 },
{ 0x034a, 0x07 },
{ 0x034b, 0xaf },
- { 0x0220, 0x00 },
- { 0x0222, 0x01 },
{ 0x0900, 0x01 },
{ 0x0901, 0x22 },
{ 0x0902, 0x00 },
@@ -723,32 +510,11 @@ static const struct imx355_reg mode_1296x736_regs[] = {
{ 0x034d, 0x10 },
{ 0x034e, 0x02 },
{ 0x034f, 0xe0 },
- { 0x0301, 0x05 },
- { 0x0303, 0x01 },
- { 0x0305, 0x02 },
- { 0x0306, 0x00 },
- { 0x0307, 0x78 },
- { 0x030b, 0x01 },
- { 0x030d, 0x02 },
- { 0x0310, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
- { 0x0820, 0x0b },
- { 0x0821, 0x40 },
- { 0x3088, 0x04 },
- { 0x6813, 0x02 },
- { 0x6835, 0x07 },
- { 0x6836, 0x01 },
- { 0x6837, 0x04 },
- { 0x684d, 0x07 },
- { 0x684e, 0x01 },
- { 0x684f, 0x04 },
};
static const struct imx355_reg mode_1284x720_regs[] = {
- { 0x0112, 0x0a },
- { 0x0113, 0x0a },
- { 0x0114, 0x03 },
{ 0x0342, 0x07 },
{ 0x0343, 0x2c },
{ 0x0340, 0x05 },
@@ -761,8 +527,6 @@ static const struct imx355_reg mode_1284x720_regs[] = {
{ 0x0349, 0x6f },
{ 0x034a, 0x07 },
{ 0x034b, 0x9f },
- { 0x0220, 0x00 },
- { 0x0222, 0x01 },
{ 0x0900, 0x01 },
{ 0x0901, 0x22 },
{ 0x0902, 0x00 },
@@ -770,32 +534,11 @@ static const struct imx355_reg mode_1284x720_regs[] = {
{ 0x034d, 0x04 },
{ 0x034e, 0x02 },
{ 0x034f, 0xd0 },
- { 0x0301, 0x05 },
- { 0x0303, 0x01 },
- { 0x0305, 0x02 },
- { 0x0306, 0x00 },
- { 0x0307, 0x78 },
- { 0x030b, 0x01 },
- { 0x030d, 0x02 },
- { 0x0310, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
- { 0x0820, 0x0b },
- { 0x0821, 0x40 },
- { 0x3088, 0x04 },
- { 0x6813, 0x02 },
- { 0x6835, 0x07 },
- { 0x6836, 0x01 },
- { 0x6837, 0x04 },
- { 0x684d, 0x07 },
- { 0x684e, 0x01 },
- { 0x684f, 0x04 },
};
static const struct imx355_reg mode_1280x720_regs[] = {
- { 0x0112, 0x0a },
- { 0x0113, 0x0a },
- { 0x0114, 0x03 },
{ 0x0342, 0x07 },
{ 0x0343, 0x2c },
{ 0x0340, 0x05 },
@@ -808,8 +551,6 @@ static const struct imx355_reg mode_1280x720_regs[] = {
{ 0x0349, 0x67 },
{ 0x034a, 0x07 },
{ 0x034b, 0x9f },
- { 0x0220, 0x00 },
- { 0x0222, 0x01 },
{ 0x0900, 0x01 },
{ 0x0901, 0x22 },
{ 0x0902, 0x00 },
@@ -817,32 +558,11 @@ static const struct imx355_reg mode_1280x720_regs[] = {
{ 0x034d, 0x00 },
{ 0x034e, 0x02 },
{ 0x034f, 0xd0 },
- { 0x0301, 0x05 },
- { 0x0303, 0x01 },
- { 0x0305, 0x02 },
- { 0x0306, 0x00 },
- { 0x0307, 0x78 },
- { 0x030b, 0x01 },
- { 0x030d, 0x02 },
- { 0x0310, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
- { 0x0820, 0x0b },
- { 0x0821, 0x40 },
- { 0x3088, 0x04 },
- { 0x6813, 0x02 },
- { 0x6835, 0x07 },
- { 0x6836, 0x01 },
- { 0x6837, 0x04 },
- { 0x684d, 0x07 },
- { 0x684e, 0x01 },
- { 0x684f, 0x04 },
};
static const struct imx355_reg mode_820x616_regs[] = {
- { 0x0112, 0x0a },
- { 0x0113, 0x0a },
- { 0x0114, 0x03 },
{ 0x0342, 0x0e },
{ 0x0343, 0x58 },
{ 0x0340, 0x02 },
@@ -855,8 +575,6 @@ static const struct imx355_reg mode_820x616_regs[] = {
{ 0x0349, 0xcf },
{ 0x034a, 0x09 },
{ 0x034b, 0x9f },
- { 0x0220, 0x00 },
- { 0x0222, 0x01 },
{ 0x0900, 0x01 },
{ 0x0901, 0x44 },
{ 0x0902, 0x00 },
@@ -864,26 +582,8 @@ static const struct imx355_reg mode_820x616_regs[] = {
{ 0x034d, 0x34 },
{ 0x034e, 0x02 },
{ 0x034f, 0x68 },
- { 0x0301, 0x05 },
- { 0x0303, 0x01 },
- { 0x0305, 0x02 },
- { 0x0306, 0x00 },
- { 0x0307, 0x78 },
- { 0x030b, 0x01 },
- { 0x030d, 0x02 },
- { 0x0310, 0x00 },
{ 0x0700, 0x02 },
{ 0x0701, 0x78 },
- { 0x0820, 0x0b },
- { 0x0821, 0x40 },
- { 0x3088, 0x04 },
- { 0x6813, 0x02 },
- { 0x6835, 0x07 },
- { 0x6836, 0x01 },
- { 0x6837, 0x04 },
- { 0x684d, 0x07 },
- { 0x684e, 0x01 },
- { 0x684f, 0x04 },
};
static const char * const imx355_test_pattern_menu[] = {
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v2 04/20] media: imx355: Remove setting FRM_LENGTH_LINES in the mode regs
2026-07-07 17:04 [PATCH v2 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
` (2 preceding siblings ...)
2026-07-07 17:04 ` [PATCH v2 03/20] media: imx355: Remove duplicated registers from the mode tables Dave Stevenson
@ 2026-07-07 17:04 ` Dave Stevenson
2026-07-07 17:04 ` [PATCH v2 05/20] media: imx355: Programmatically set the crop parameters for each mode Dave Stevenson
` (15 subsequent siblings)
19 siblings, 0 replies; 34+ messages in thread
From: Dave Stevenson @ 2026-07-07 17:04 UTC (permalink / raw)
To: Tianshu Qiu, Sakari Ailus, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Richard Acayan
Cc: linux-media, linux-kernel, David Heidelberg, Jacopo Mondi,
devicetree, Dave Stevenson
Registers 0x0340 and 0x0341 (FRM_LENGTH_LINES) are already written
from the set_ctrl(V4L2_CID_VBLANK) handler, so don't write them
from the mode register list.
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/media/i2c/imx355.c | 28 ----------------------------
1 file changed, 28 deletions(-)
diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
index 83a59aa8b098..28b210f1a868 100644
--- a/drivers/media/i2c/imx355.c
+++ b/drivers/media/i2c/imx355.c
@@ -253,8 +253,6 @@ static const struct imx355_reg_list imx355_global_setting = {
static const struct imx355_reg mode_3268x2448_regs[] = {
{ 0x0342, 0x0e },
{ 0x0343, 0x58 },
- { 0x0340, 0x0a },
- { 0x0341, 0x37 },
{ 0x0344, 0x00 },
{ 0x0345, 0x08 },
{ 0x0346, 0x00 },
@@ -277,8 +275,6 @@ static const struct imx355_reg mode_3268x2448_regs[] = {
static const struct imx355_reg mode_3264x2448_regs[] = {
{ 0x0342, 0x0e },
{ 0x0343, 0x58 },
- { 0x0340, 0x0a },
- { 0x0341, 0x37 },
{ 0x0344, 0x00 },
{ 0x0345, 0x08 },
{ 0x0346, 0x00 },
@@ -301,8 +297,6 @@ static const struct imx355_reg mode_3264x2448_regs[] = {
static const struct imx355_reg mode_3280x2464_regs[] = {
{ 0x0342, 0x0e },
{ 0x0343, 0x58 },
- { 0x0340, 0x0a },
- { 0x0341, 0x37 },
{ 0x0344, 0x00 },
{ 0x0345, 0x00 },
{ 0x0346, 0x00 },
@@ -325,8 +319,6 @@ static const struct imx355_reg mode_3280x2464_regs[] = {
static const struct imx355_reg mode_1940x1096_regs[] = {
{ 0x0342, 0x0e },
{ 0x0343, 0x58 },
- { 0x0340, 0x05 },
- { 0x0341, 0x1a },
{ 0x0344, 0x02 },
{ 0x0345, 0xa0 },
{ 0x0346, 0x02 },
@@ -349,8 +341,6 @@ static const struct imx355_reg mode_1940x1096_regs[] = {
static const struct imx355_reg mode_1936x1096_regs[] = {
{ 0x0342, 0x0e },
{ 0x0343, 0x58 },
- { 0x0340, 0x05 },
- { 0x0341, 0x1a },
{ 0x0344, 0x02 },
{ 0x0345, 0xa0 },
{ 0x0346, 0x02 },
@@ -373,8 +363,6 @@ static const struct imx355_reg mode_1936x1096_regs[] = {
static const struct imx355_reg mode_1924x1080_regs[] = {
{ 0x0342, 0x0e },
{ 0x0343, 0x58 },
- { 0x0340, 0x05 },
- { 0x0341, 0x1a },
{ 0x0344, 0x02 },
{ 0x0345, 0xa8 },
{ 0x0346, 0x02 },
@@ -397,8 +385,6 @@ static const struct imx355_reg mode_1924x1080_regs[] = {
static const struct imx355_reg mode_1920x1080_regs[] = {
{ 0x0342, 0x0e },
{ 0x0343, 0x58 },
- { 0x0340, 0x05 },
- { 0x0341, 0x1a },
{ 0x0344, 0x02 },
{ 0x0345, 0xa8 },
{ 0x0346, 0x02 },
@@ -421,8 +407,6 @@ static const struct imx355_reg mode_1920x1080_regs[] = {
static const struct imx355_reg mode_1640x1232_regs[] = {
{ 0x0342, 0x07 },
{ 0x0343, 0x2c },
- { 0x0340, 0x05 },
- { 0x0341, 0x1a },
{ 0x0344, 0x00 },
{ 0x0345, 0x00 },
{ 0x0346, 0x00 },
@@ -445,8 +429,6 @@ static const struct imx355_reg mode_1640x1232_regs[] = {
static const struct imx355_reg mode_1640x922_regs[] = {
{ 0x0342, 0x07 },
{ 0x0343, 0x2c },
- { 0x0340, 0x05 },
- { 0x0341, 0x1a },
{ 0x0344, 0x00 },
{ 0x0345, 0x00 },
{ 0x0346, 0x01 },
@@ -469,8 +451,6 @@ static const struct imx355_reg mode_1640x922_regs[] = {
static const struct imx355_reg mode_1300x736_regs[] = {
{ 0x0342, 0x07 },
{ 0x0343, 0x2c },
- { 0x0340, 0x05 },
- { 0x0341, 0x1a },
{ 0x0344, 0x01 },
{ 0x0345, 0x58 },
{ 0x0346, 0x01 },
@@ -493,8 +473,6 @@ static const struct imx355_reg mode_1300x736_regs[] = {
static const struct imx355_reg mode_1296x736_regs[] = {
{ 0x0342, 0x07 },
{ 0x0343, 0x2c },
- { 0x0340, 0x05 },
- { 0x0341, 0x1a },
{ 0x0344, 0x01 },
{ 0x0345, 0x58 },
{ 0x0346, 0x01 },
@@ -517,8 +495,6 @@ static const struct imx355_reg mode_1296x736_regs[] = {
static const struct imx355_reg mode_1284x720_regs[] = {
{ 0x0342, 0x07 },
{ 0x0343, 0x2c },
- { 0x0340, 0x05 },
- { 0x0341, 0x1a },
{ 0x0344, 0x01 },
{ 0x0345, 0x68 },
{ 0x0346, 0x02 },
@@ -541,8 +517,6 @@ static const struct imx355_reg mode_1284x720_regs[] = {
static const struct imx355_reg mode_1280x720_regs[] = {
{ 0x0342, 0x07 },
{ 0x0343, 0x2c },
- { 0x0340, 0x05 },
- { 0x0341, 0x1a },
{ 0x0344, 0x01 },
{ 0x0345, 0x68 },
{ 0x0346, 0x02 },
@@ -565,8 +539,6 @@ static const struct imx355_reg mode_1280x720_regs[] = {
static const struct imx355_reg mode_820x616_regs[] = {
{ 0x0342, 0x0e },
{ 0x0343, 0x58 },
- { 0x0340, 0x02 },
- { 0x0341, 0x8c },
{ 0x0344, 0x00 },
{ 0x0345, 0x00 },
{ 0x0346, 0x00 },
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v2 05/20] media: imx355: Programmatically set the crop parameters for each mode
2026-07-07 17:04 [PATCH v2 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
` (3 preceding siblings ...)
2026-07-07 17:04 ` [PATCH v2 04/20] media: imx355: Remove setting FRM_LENGTH_LINES in the mode regs Dave Stevenson
@ 2026-07-07 17:04 ` Dave Stevenson
2026-07-07 17:18 ` sashiko-bot
2026-07-07 17:04 ` [PATCH v2 06/20] media: imx355: Set register LINE_LENGTH_PCK programmatically Dave Stevenson
` (14 subsequent siblings)
19 siblings, 1 reply; 34+ messages in thread
From: Dave Stevenson @ 2026-07-07 17:04 UTC (permalink / raw)
To: Tianshu Qiu, Sakari Ailus, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Richard Acayan
Cc: linux-media, linux-kernel, David Heidelberg, Jacopo Mondi,
devicetree, Dave Stevenson
Currently the cropping is set via register entries in the per mode
register lists. Add the crop information to the mode structure as
a v4l2_rect, and set the registers programmatically.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/media/i2c/imx355.c | 290 +++++++++++++++++++--------------------------
1 file changed, 121 insertions(+), 169 deletions(-)
diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
index 28b210f1a868..363b5667b6c9 100644
--- a/drivers/media/i2c/imx355.c
+++ b/drivers/media/i2c/imx355.c
@@ -33,6 +33,13 @@
#define IMX355_REG_FLL 0x0340
#define IMX355_FLL_MAX 0xffff
+#define IMX355_REG_X_ADD_START 0x0344
+#define IMX355_REG_Y_ADD_START 0x0346
+#define IMX355_REG_X_ADD_END 0x0348
+#define IMX355_REG_Y_ADD_END 0x034a
+#define IMX355_REG_X_OUT_SIZE 0x034c
+#define IMX355_REG_Y_OUT_SIZE 0x034e
+
/* Exposure control */
#define IMX355_REG_EXPOSURE 0x0202
#define IMX355_EXPOSURE_MIN 1
@@ -88,6 +95,7 @@ struct imx355_mode {
u32 width;
/* Frame height */
u32 height;
+ struct v4l2_rect crop;
/* V-timing */
u32 fll_def;
@@ -253,21 +261,9 @@ static const struct imx355_reg_list imx355_global_setting = {
static const struct imx355_reg mode_3268x2448_regs[] = {
{ 0x0342, 0x0e },
{ 0x0343, 0x58 },
- { 0x0344, 0x00 },
- { 0x0345, 0x08 },
- { 0x0346, 0x00 },
- { 0x0347, 0x08 },
- { 0x0348, 0x0c },
- { 0x0349, 0xcb },
- { 0x034a, 0x09 },
- { 0x034b, 0x97 },
{ 0x0900, 0x00 },
{ 0x0901, 0x11 },
{ 0x0902, 0x00 },
- { 0x034c, 0x0c },
- { 0x034d, 0xc4 },
- { 0x034e, 0x09 },
- { 0x034f, 0x90 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
};
@@ -275,21 +271,9 @@ static const struct imx355_reg mode_3268x2448_regs[] = {
static const struct imx355_reg mode_3264x2448_regs[] = {
{ 0x0342, 0x0e },
{ 0x0343, 0x58 },
- { 0x0344, 0x00 },
- { 0x0345, 0x08 },
- { 0x0346, 0x00 },
- { 0x0347, 0x08 },
- { 0x0348, 0x0c },
- { 0x0349, 0xc7 },
- { 0x034a, 0x09 },
- { 0x034b, 0x97 },
{ 0x0900, 0x00 },
{ 0x0901, 0x11 },
{ 0x0902, 0x00 },
- { 0x034c, 0x0c },
- { 0x034d, 0xc0 },
- { 0x034e, 0x09 },
- { 0x034f, 0x90 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
};
@@ -297,21 +281,9 @@ static const struct imx355_reg mode_3264x2448_regs[] = {
static const struct imx355_reg mode_3280x2464_regs[] = {
{ 0x0342, 0x0e },
{ 0x0343, 0x58 },
- { 0x0344, 0x00 },
- { 0x0345, 0x00 },
- { 0x0346, 0x00 },
- { 0x0347, 0x00 },
- { 0x0348, 0x0c },
- { 0x0349, 0xcf },
- { 0x034a, 0x09 },
- { 0x034b, 0x9f },
{ 0x0900, 0x00 },
{ 0x0901, 0x11 },
{ 0x0902, 0x00 },
- { 0x034c, 0x0c },
- { 0x034d, 0xd0 },
- { 0x034e, 0x09 },
- { 0x034f, 0xa0 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
};
@@ -319,21 +291,9 @@ static const struct imx355_reg mode_3280x2464_regs[] = {
static const struct imx355_reg mode_1940x1096_regs[] = {
{ 0x0342, 0x0e },
{ 0x0343, 0x58 },
- { 0x0344, 0x02 },
- { 0x0345, 0xa0 },
- { 0x0346, 0x02 },
- { 0x0347, 0xac },
- { 0x0348, 0x0a },
- { 0x0349, 0x33 },
- { 0x034a, 0x06 },
- { 0x034b, 0xf3 },
{ 0x0900, 0x00 },
{ 0x0901, 0x11 },
{ 0x0902, 0x00 },
- { 0x034c, 0x07 },
- { 0x034d, 0x94 },
- { 0x034e, 0x04 },
- { 0x034f, 0x48 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
};
@@ -341,21 +301,9 @@ static const struct imx355_reg mode_1940x1096_regs[] = {
static const struct imx355_reg mode_1936x1096_regs[] = {
{ 0x0342, 0x0e },
{ 0x0343, 0x58 },
- { 0x0344, 0x02 },
- { 0x0345, 0xa0 },
- { 0x0346, 0x02 },
- { 0x0347, 0xac },
- { 0x0348, 0x0a },
- { 0x0349, 0x2f },
- { 0x034a, 0x06 },
- { 0x034b, 0xf3 },
{ 0x0900, 0x00 },
{ 0x0901, 0x11 },
{ 0x0902, 0x00 },
- { 0x034c, 0x07 },
- { 0x034d, 0x90 },
- { 0x034e, 0x04 },
- { 0x034f, 0x48 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
};
@@ -363,21 +311,9 @@ static const struct imx355_reg mode_1936x1096_regs[] = {
static const struct imx355_reg mode_1924x1080_regs[] = {
{ 0x0342, 0x0e },
{ 0x0343, 0x58 },
- { 0x0344, 0x02 },
- { 0x0345, 0xa8 },
- { 0x0346, 0x02 },
- { 0x0347, 0xb4 },
- { 0x0348, 0x0a },
- { 0x0349, 0x2b },
- { 0x034a, 0x06 },
- { 0x034b, 0xeb },
{ 0x0900, 0x00 },
{ 0x0901, 0x11 },
{ 0x0902, 0x00 },
- { 0x034c, 0x07 },
- { 0x034d, 0x84 },
- { 0x034e, 0x04 },
- { 0x034f, 0x38 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
};
@@ -385,21 +321,9 @@ static const struct imx355_reg mode_1924x1080_regs[] = {
static const struct imx355_reg mode_1920x1080_regs[] = {
{ 0x0342, 0x0e },
{ 0x0343, 0x58 },
- { 0x0344, 0x02 },
- { 0x0345, 0xa8 },
- { 0x0346, 0x02 },
- { 0x0347, 0xb4 },
- { 0x0348, 0x0a },
- { 0x0349, 0x27 },
- { 0x034a, 0x06 },
- { 0x034b, 0xeb },
{ 0x0900, 0x00 },
{ 0x0901, 0x11 },
{ 0x0902, 0x00 },
- { 0x034c, 0x07 },
- { 0x034d, 0x80 },
- { 0x034e, 0x04 },
- { 0x034f, 0x38 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
};
@@ -407,21 +331,9 @@ static const struct imx355_reg mode_1920x1080_regs[] = {
static const struct imx355_reg mode_1640x1232_regs[] = {
{ 0x0342, 0x07 },
{ 0x0343, 0x2c },
- { 0x0344, 0x00 },
- { 0x0345, 0x00 },
- { 0x0346, 0x00 },
- { 0x0347, 0x00 },
- { 0x0348, 0x0c },
- { 0x0349, 0xcf },
- { 0x034a, 0x09 },
- { 0x034b, 0x9f },
{ 0x0900, 0x01 },
{ 0x0901, 0x22 },
{ 0x0902, 0x00 },
- { 0x034c, 0x06 },
- { 0x034d, 0x68 },
- { 0x034e, 0x04 },
- { 0x034f, 0xd0 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
};
@@ -429,21 +341,9 @@ static const struct imx355_reg mode_1640x1232_regs[] = {
static const struct imx355_reg mode_1640x922_regs[] = {
{ 0x0342, 0x07 },
{ 0x0343, 0x2c },
- { 0x0344, 0x00 },
- { 0x0345, 0x00 },
- { 0x0346, 0x01 },
- { 0x0347, 0x30 },
- { 0x0348, 0x0c },
- { 0x0349, 0xcf },
- { 0x034a, 0x08 },
- { 0x034b, 0x63 },
{ 0x0900, 0x01 },
{ 0x0901, 0x22 },
{ 0x0902, 0x00 },
- { 0x034c, 0x06 },
- { 0x034d, 0x68 },
- { 0x034e, 0x03 },
- { 0x034f, 0x9a },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
};
@@ -451,21 +351,9 @@ static const struct imx355_reg mode_1640x922_regs[] = {
static const struct imx355_reg mode_1300x736_regs[] = {
{ 0x0342, 0x07 },
{ 0x0343, 0x2c },
- { 0x0344, 0x01 },
- { 0x0345, 0x58 },
- { 0x0346, 0x01 },
- { 0x0347, 0xf0 },
- { 0x0348, 0x0b },
- { 0x0349, 0x7f },
- { 0x034a, 0x07 },
- { 0x034b, 0xaf },
{ 0x0900, 0x01 },
{ 0x0901, 0x22 },
{ 0x0902, 0x00 },
- { 0x034c, 0x05 },
- { 0x034d, 0x14 },
- { 0x034e, 0x02 },
- { 0x034f, 0xe0 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
};
@@ -473,21 +361,9 @@ static const struct imx355_reg mode_1300x736_regs[] = {
static const struct imx355_reg mode_1296x736_regs[] = {
{ 0x0342, 0x07 },
{ 0x0343, 0x2c },
- { 0x0344, 0x01 },
- { 0x0345, 0x58 },
- { 0x0346, 0x01 },
- { 0x0347, 0xf0 },
- { 0x0348, 0x0b },
- { 0x0349, 0x77 },
- { 0x034a, 0x07 },
- { 0x034b, 0xaf },
{ 0x0900, 0x01 },
{ 0x0901, 0x22 },
{ 0x0902, 0x00 },
- { 0x034c, 0x05 },
- { 0x034d, 0x10 },
- { 0x034e, 0x02 },
- { 0x034f, 0xe0 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
};
@@ -495,21 +371,9 @@ static const struct imx355_reg mode_1296x736_regs[] = {
static const struct imx355_reg mode_1284x720_regs[] = {
{ 0x0342, 0x07 },
{ 0x0343, 0x2c },
- { 0x0344, 0x01 },
- { 0x0345, 0x68 },
- { 0x0346, 0x02 },
- { 0x0347, 0x00 },
- { 0x0348, 0x0b },
- { 0x0349, 0x6f },
- { 0x034a, 0x07 },
- { 0x034b, 0x9f },
{ 0x0900, 0x01 },
{ 0x0901, 0x22 },
{ 0x0902, 0x00 },
- { 0x034c, 0x05 },
- { 0x034d, 0x04 },
- { 0x034e, 0x02 },
- { 0x034f, 0xd0 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
};
@@ -517,21 +381,9 @@ static const struct imx355_reg mode_1284x720_regs[] = {
static const struct imx355_reg mode_1280x720_regs[] = {
{ 0x0342, 0x07 },
{ 0x0343, 0x2c },
- { 0x0344, 0x01 },
- { 0x0345, 0x68 },
- { 0x0346, 0x02 },
- { 0x0347, 0x00 },
- { 0x0348, 0x0b },
- { 0x0349, 0x67 },
- { 0x034a, 0x07 },
- { 0x034b, 0x9f },
{ 0x0900, 0x01 },
{ 0x0901, 0x22 },
{ 0x0902, 0x00 },
- { 0x034c, 0x05 },
- { 0x034d, 0x00 },
- { 0x034e, 0x02 },
- { 0x034f, 0xd0 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
};
@@ -539,21 +391,9 @@ static const struct imx355_reg mode_1280x720_regs[] = {
static const struct imx355_reg mode_820x616_regs[] = {
{ 0x0342, 0x0e },
{ 0x0343, 0x58 },
- { 0x0344, 0x00 },
- { 0x0345, 0x00 },
- { 0x0346, 0x00 },
- { 0x0347, 0x00 },
- { 0x0348, 0x0c },
- { 0x0349, 0xcf },
- { 0x034a, 0x09 },
- { 0x034b, 0x9f },
{ 0x0900, 0x01 },
{ 0x0901, 0x44 },
{ 0x0902, 0x00 },
- { 0x034c, 0x03 },
- { 0x034d, 0x34 },
- { 0x034e, 0x02 },
- { 0x034f, 0x68 },
{ 0x0700, 0x02 },
{ 0x0701, 0x78 },
};
@@ -579,6 +419,12 @@ static const struct imx355_mode supported_modes[] = {
{
.width = 3280,
.height = 2464,
+ .crop = {
+ .width = 3280,
+ .height = 2464,
+ .left = 0,
+ .top = 0,
+ },
.fll_def = 2615,
.fll_min = 2615,
.llp = 3672,
@@ -591,6 +437,12 @@ static const struct imx355_mode supported_modes[] = {
{
.width = 3268,
.height = 2448,
+ .crop = {
+ .width = 3268,
+ .height = 2448,
+ .left = 8,
+ .top = 8,
+ },
.fll_def = 2615,
.fll_min = 2615,
.llp = 3672,
@@ -603,6 +455,12 @@ static const struct imx355_mode supported_modes[] = {
{
.width = 3264,
.height = 2448,
+ .crop = {
+ .width = 3264,
+ .height = 2448,
+ .left = 8,
+ .top = 8,
+ },
.fll_def = 2615,
.fll_min = 2615,
.llp = 3672,
@@ -615,6 +473,12 @@ static const struct imx355_mode supported_modes[] = {
{
.width = 1940,
.height = 1096,
+ .crop = {
+ .width = 1940,
+ .height = 1096,
+ .left = 672,
+ .top = 684,
+ },
.fll_def = 1306,
.fll_min = 1306,
.llp = 3672,
@@ -627,6 +491,12 @@ static const struct imx355_mode supported_modes[] = {
{
.width = 1936,
.height = 1096,
+ .crop = {
+ .width = 1936,
+ .height = 1096,
+ .left = 672,
+ .top = 684,
+ },
.fll_def = 1306,
.fll_min = 1306,
.llp = 3672,
@@ -639,6 +509,12 @@ static const struct imx355_mode supported_modes[] = {
{
.width = 1924,
.height = 1080,
+ .crop = {
+ .width = 1924,
+ .height = 1080,
+ .left = 680,
+ .top = 692,
+ },
.fll_def = 1306,
.fll_min = 1306,
.llp = 3672,
@@ -651,6 +527,12 @@ static const struct imx355_mode supported_modes[] = {
{
.width = 1920,
.height = 1080,
+ .crop = {
+ .width = 1920,
+ .height = 1080,
+ .left = 680,
+ .top = 692,
+ },
.fll_def = 1306,
.fll_min = 1306,
.llp = 3672,
@@ -663,6 +545,12 @@ static const struct imx355_mode supported_modes[] = {
{
.width = 1640,
.height = 1232,
+ .crop = {
+ .width = 3280,
+ .height = 2464,
+ .left = 0,
+ .top = 0,
+ },
.fll_def = 1306,
.fll_min = 1306,
.llp = 1836,
@@ -675,6 +563,12 @@ static const struct imx355_mode supported_modes[] = {
{
.width = 1640,
.height = 922,
+ .crop = {
+ .width = 3280,
+ .height = 1844,
+ .left = 0,
+ .top = 304,
+ },
.fll_def = 1306,
.fll_min = 1306,
.llp = 1836,
@@ -687,6 +581,12 @@ static const struct imx355_mode supported_modes[] = {
{
.width = 1300,
.height = 736,
+ .crop = {
+ .width = 2600,
+ .height = 1472,
+ .left = 344,
+ .top = 496,
+ },
.fll_def = 1306,
.fll_min = 1306,
.llp = 1836,
@@ -699,6 +599,12 @@ static const struct imx355_mode supported_modes[] = {
{
.width = 1296,
.height = 736,
+ .crop = {
+ .width = 2592,
+ .height = 1472,
+ .left = 344,
+ .top = 496,
+ },
.fll_def = 1306,
.fll_min = 1306,
.llp = 1836,
@@ -711,6 +617,12 @@ static const struct imx355_mode supported_modes[] = {
{
.width = 1284,
.height = 720,
+ .crop = {
+ .width = 2568,
+ .height = 1440,
+ .left = 360,
+ .top = 512,
+ },
.fll_def = 1306,
.fll_min = 1306,
.llp = 1836,
@@ -723,6 +635,12 @@ static const struct imx355_mode supported_modes[] = {
{
.width = 1280,
.height = 720,
+ .crop = {
+ .width = 2560,
+ .height = 1440,
+ .left = 360,
+ .top = 512,
+ },
.fll_def = 1306,
.fll_min = 1306,
.llp = 1836,
@@ -735,6 +653,12 @@ static const struct imx355_mode supported_modes[] = {
{
.width = 820,
.height = 616,
+ .crop = {
+ .width = 3280,
+ .height = 2464,
+ .left = 0,
+ .top = 0,
+ },
.fll_def = 652,
.fll_min = 652,
.llp = 3672,
@@ -1073,6 +997,7 @@ imx355_set_pad_format(struct v4l2_subdev *sd,
static int imx355_start_streaming(struct imx355 *imx355)
{
const struct imx355_reg_list *reg_list;
+ const struct imx355_mode *mode;
int ret;
/* Global Setting */
@@ -1084,13 +1009,40 @@ static int imx355_start_streaming(struct imx355 *imx355)
}
/* Apply default values of current mode */
- reg_list = &imx355->cur_mode->reg_list;
+ mode = imx355->cur_mode;
+ reg_list = &mode->reg_list;
ret = imx355_write_regs(imx355, reg_list->regs, reg_list->num_of_regs);
if (ret) {
dev_err(imx355->dev, "failed to set mode");
return ret;
}
+ /* Set readout crop and size registers */
+ ret = imx355_write_reg(imx355, IMX355_REG_X_ADD_START, 2,
+ mode->crop.left);
+ if (ret)
+ return ret;
+ ret = imx355_write_reg(imx355, IMX355_REG_Y_ADD_START, 2,
+ mode->crop.top);
+ if (ret)
+ return ret;
+ ret = imx355_write_reg(imx355, IMX355_REG_X_ADD_END, 2,
+ mode->crop.width + mode->crop.left - 1);
+ if (ret)
+ return ret;
+ ret = imx355_write_reg(imx355, IMX355_REG_Y_ADD_END, 2,
+ mode->crop.height + mode->crop.top - 1);
+ if (ret)
+ return ret;
+ ret = imx355_write_reg(imx355, IMX355_REG_X_OUT_SIZE, 2,
+ mode->width);
+ if (ret)
+ return ret;
+ ret = imx355_write_reg(imx355, IMX355_REG_Y_OUT_SIZE, 2,
+ mode->height);
+ if (ret)
+ return ret;
+
/* Set PLL registers for the external clock frequency */
ret = imx355_write_reg(imx355, IMX355_REG_EXTCLK_FREQ, 2,
imx355->clk_params->extclk_freq);
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v2 06/20] media: imx355: Set register LINE_LENGTH_PCK programmatically
2026-07-07 17:04 [PATCH v2 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
` (4 preceding siblings ...)
2026-07-07 17:04 ` [PATCH v2 05/20] media: imx355: Programmatically set the crop parameters for each mode Dave Stevenson
@ 2026-07-07 17:04 ` Dave Stevenson
2026-07-07 17:12 ` sashiko-bot
2026-07-07 17:04 ` [PATCH v2 07/20] media: imx355: Set binning mode registers programmatically Dave Stevenson
` (13 subsequent siblings)
19 siblings, 1 reply; 34+ messages in thread
From: Dave Stevenson @ 2026-07-07 17:04 UTC (permalink / raw)
To: Tianshu Qiu, Sakari Ailus, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Richard Acayan
Cc: linux-media, linux-kernel, David Heidelberg, Jacopo Mondi,
devicetree, Dave Stevenson
The driver already has the LLP value stored in the mode structure,
but also had the same value set via register writes in the mode's
register list. Remove this duplication.
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/media/i2c/imx355.c | 38 ++++++++++----------------------------
1 file changed, 10 insertions(+), 28 deletions(-)
diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
index 363b5667b6c9..66e70650e666 100644
--- a/drivers/media/i2c/imx355.c
+++ b/drivers/media/i2c/imx355.c
@@ -33,6 +33,9 @@
#define IMX355_REG_FLL 0x0340
#define IMX355_FLL_MAX 0xffff
+#define IMX355_REG_LLP 0x0342
+#define IMX355_LLP_MAX 0xffff
+
#define IMX355_REG_X_ADD_START 0x0344
#define IMX355_REG_Y_ADD_START 0x0346
#define IMX355_REG_X_ADD_END 0x0348
@@ -259,8 +262,6 @@ static const struct imx355_reg_list imx355_global_setting = {
};
static const struct imx355_reg mode_3268x2448_regs[] = {
- { 0x0342, 0x0e },
- { 0x0343, 0x58 },
{ 0x0900, 0x00 },
{ 0x0901, 0x11 },
{ 0x0902, 0x00 },
@@ -269,8 +270,6 @@ static const struct imx355_reg mode_3268x2448_regs[] = {
};
static const struct imx355_reg mode_3264x2448_regs[] = {
- { 0x0342, 0x0e },
- { 0x0343, 0x58 },
{ 0x0900, 0x00 },
{ 0x0901, 0x11 },
{ 0x0902, 0x00 },
@@ -279,8 +278,6 @@ static const struct imx355_reg mode_3264x2448_regs[] = {
};
static const struct imx355_reg mode_3280x2464_regs[] = {
- { 0x0342, 0x0e },
- { 0x0343, 0x58 },
{ 0x0900, 0x00 },
{ 0x0901, 0x11 },
{ 0x0902, 0x00 },
@@ -289,8 +286,6 @@ static const struct imx355_reg mode_3280x2464_regs[] = {
};
static const struct imx355_reg mode_1940x1096_regs[] = {
- { 0x0342, 0x0e },
- { 0x0343, 0x58 },
{ 0x0900, 0x00 },
{ 0x0901, 0x11 },
{ 0x0902, 0x00 },
@@ -299,8 +294,6 @@ static const struct imx355_reg mode_1940x1096_regs[] = {
};
static const struct imx355_reg mode_1936x1096_regs[] = {
- { 0x0342, 0x0e },
- { 0x0343, 0x58 },
{ 0x0900, 0x00 },
{ 0x0901, 0x11 },
{ 0x0902, 0x00 },
@@ -309,8 +302,6 @@ static const struct imx355_reg mode_1936x1096_regs[] = {
};
static const struct imx355_reg mode_1924x1080_regs[] = {
- { 0x0342, 0x0e },
- { 0x0343, 0x58 },
{ 0x0900, 0x00 },
{ 0x0901, 0x11 },
{ 0x0902, 0x00 },
@@ -319,8 +310,6 @@ static const struct imx355_reg mode_1924x1080_regs[] = {
};
static const struct imx355_reg mode_1920x1080_regs[] = {
- { 0x0342, 0x0e },
- { 0x0343, 0x58 },
{ 0x0900, 0x00 },
{ 0x0901, 0x11 },
{ 0x0902, 0x00 },
@@ -329,8 +318,6 @@ static const struct imx355_reg mode_1920x1080_regs[] = {
};
static const struct imx355_reg mode_1640x1232_regs[] = {
- { 0x0342, 0x07 },
- { 0x0343, 0x2c },
{ 0x0900, 0x01 },
{ 0x0901, 0x22 },
{ 0x0902, 0x00 },
@@ -339,8 +326,6 @@ static const struct imx355_reg mode_1640x1232_regs[] = {
};
static const struct imx355_reg mode_1640x922_regs[] = {
- { 0x0342, 0x07 },
- { 0x0343, 0x2c },
{ 0x0900, 0x01 },
{ 0x0901, 0x22 },
{ 0x0902, 0x00 },
@@ -349,8 +334,6 @@ static const struct imx355_reg mode_1640x922_regs[] = {
};
static const struct imx355_reg mode_1300x736_regs[] = {
- { 0x0342, 0x07 },
- { 0x0343, 0x2c },
{ 0x0900, 0x01 },
{ 0x0901, 0x22 },
{ 0x0902, 0x00 },
@@ -359,8 +342,6 @@ static const struct imx355_reg mode_1300x736_regs[] = {
};
static const struct imx355_reg mode_1296x736_regs[] = {
- { 0x0342, 0x07 },
- { 0x0343, 0x2c },
{ 0x0900, 0x01 },
{ 0x0901, 0x22 },
{ 0x0902, 0x00 },
@@ -369,8 +350,6 @@ static const struct imx355_reg mode_1296x736_regs[] = {
};
static const struct imx355_reg mode_1284x720_regs[] = {
- { 0x0342, 0x07 },
- { 0x0343, 0x2c },
{ 0x0900, 0x01 },
{ 0x0901, 0x22 },
{ 0x0902, 0x00 },
@@ -379,8 +358,6 @@ static const struct imx355_reg mode_1284x720_regs[] = {
};
static const struct imx355_reg mode_1280x720_regs[] = {
- { 0x0342, 0x07 },
- { 0x0343, 0x2c },
{ 0x0900, 0x01 },
{ 0x0901, 0x22 },
{ 0x0902, 0x00 },
@@ -389,8 +366,6 @@ static const struct imx355_reg mode_1280x720_regs[] = {
};
static const struct imx355_reg mode_820x616_regs[] = {
- { 0x0342, 0x0e },
- { 0x0343, 0x58 },
{ 0x0900, 0x01 },
{ 0x0901, 0x44 },
{ 0x0902, 0x00 },
@@ -1058,6 +1033,13 @@ static int imx355_start_streaming(struct imx355 *imx355)
if (ret)
return ret;
+ /* set line length */
+ ret = imx355_write_reg(imx355, IMX355_REG_LLP,
+ imx355->hblank->val + imx355->cur_mode->width,
+ 2);
+ if (ret)
+ return ret;
+
/* Apply customized values from user */
ret = __v4l2_ctrl_handler_setup(imx355->sd.ctrl_handler);
if (ret)
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v2 07/20] media: imx355: Set binning mode registers programmatically
2026-07-07 17:04 [PATCH v2 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
` (5 preceding siblings ...)
2026-07-07 17:04 ` [PATCH v2 06/20] media: imx355: Set register LINE_LENGTH_PCK programmatically Dave Stevenson
@ 2026-07-07 17:04 ` Dave Stevenson
2026-07-07 17:15 ` sashiko-bot
2026-07-07 17:04 ` [PATCH v2 08/20] media: imx355: Remove link_freq_index from each mode as ununsed Dave Stevenson
` (12 subsequent siblings)
19 siblings, 1 reply; 34+ messages in thread
From: Dave Stevenson @ 2026-07-07 17:04 UTC (permalink / raw)
To: Tianshu Qiu, Sakari Ailus, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Richard Acayan
Cc: linux-media, linux-kernel, David Heidelberg, Jacopo Mondi,
devicetree, Dave Stevenson
Compute the binning registers based on the difference between
the mode width/height vs the crop width/height.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/media/i2c/imx355.c | 61 +++++++++++++++-------------------------------
1 file changed, 19 insertions(+), 42 deletions(-)
diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
index 66e70650e666..cfc47b5100c4 100644
--- a/drivers/media/i2c/imx355.c
+++ b/drivers/media/i2c/imx355.c
@@ -72,6 +72,10 @@
#define IMX355_TEST_PATTERN_GRAY_COLOR_BARS 3
#define IMX355_TEST_PATTERN_PN9 4
+#define IMX355_REG_BINNING_MODE 0x0900
+#define IMX355_REG_BINNING_TYPE 0x0901
+#define IMX355_REG_BINNING_WEIGHTING 0x0902
+
/* Flip Control */
#define IMX355_REG_ORIENTATION 0x0101
@@ -262,113 +266,71 @@ static const struct imx355_reg_list imx355_global_setting = {
};
static const struct imx355_reg mode_3268x2448_regs[] = {
- { 0x0900, 0x00 },
- { 0x0901, 0x11 },
- { 0x0902, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
};
static const struct imx355_reg mode_3264x2448_regs[] = {
- { 0x0900, 0x00 },
- { 0x0901, 0x11 },
- { 0x0902, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
};
static const struct imx355_reg mode_3280x2464_regs[] = {
- { 0x0900, 0x00 },
- { 0x0901, 0x11 },
- { 0x0902, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
};
static const struct imx355_reg mode_1940x1096_regs[] = {
- { 0x0900, 0x00 },
- { 0x0901, 0x11 },
- { 0x0902, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
};
static const struct imx355_reg mode_1936x1096_regs[] = {
- { 0x0900, 0x00 },
- { 0x0901, 0x11 },
- { 0x0902, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
};
static const struct imx355_reg mode_1924x1080_regs[] = {
- { 0x0900, 0x00 },
- { 0x0901, 0x11 },
- { 0x0902, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
};
static const struct imx355_reg mode_1920x1080_regs[] = {
- { 0x0900, 0x00 },
- { 0x0901, 0x11 },
- { 0x0902, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
};
static const struct imx355_reg mode_1640x1232_regs[] = {
- { 0x0900, 0x01 },
- { 0x0901, 0x22 },
- { 0x0902, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
};
static const struct imx355_reg mode_1640x922_regs[] = {
- { 0x0900, 0x01 },
- { 0x0901, 0x22 },
- { 0x0902, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
};
static const struct imx355_reg mode_1300x736_regs[] = {
- { 0x0900, 0x01 },
- { 0x0901, 0x22 },
- { 0x0902, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
};
static const struct imx355_reg mode_1296x736_regs[] = {
- { 0x0900, 0x01 },
- { 0x0901, 0x22 },
- { 0x0902, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
};
static const struct imx355_reg mode_1284x720_regs[] = {
- { 0x0900, 0x01 },
- { 0x0901, 0x22 },
- { 0x0902, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
};
static const struct imx355_reg mode_1280x720_regs[] = {
- { 0x0900, 0x01 },
- { 0x0901, 0x22 },
- { 0x0902, 0x00 },
{ 0x0700, 0x00 },
{ 0x0701, 0x10 },
};
static const struct imx355_reg mode_820x616_regs[] = {
- { 0x0900, 0x01 },
- { 0x0901, 0x44 },
- { 0x0902, 0x00 },
{ 0x0700, 0x02 },
{ 0x0701, 0x78 },
};
@@ -973,6 +935,7 @@ static int imx355_start_streaming(struct imx355 *imx355)
{
const struct imx355_reg_list *reg_list;
const struct imx355_mode *mode;
+ u8 binning_mode;
int ret;
/* Global Setting */
@@ -1018,6 +981,20 @@ static int imx355_start_streaming(struct imx355 *imx355)
if (ret)
return ret;
+ binning_mode = ((mode->crop.width / mode->width) << 4) |
+ (mode->crop.height / mode->height);
+ ret = imx355_write_reg(imx355, IMX355_REG_BINNING_MODE, 1,
+ binning_mode == 0x11 ? 0x00 : 0x01);
+ if (ret)
+ return ret;
+ ret = imx355_write_reg(imx355, IMX355_REG_BINNING_TYPE, 1,
+ binning_mode);
+ if (ret)
+ return ret;
+ ret = imx355_write_reg(imx355, IMX355_REG_BINNING_WEIGHTING, 1, 0x00);
+ if (ret)
+ return ret;
+
/* Set PLL registers for the external clock frequency */
ret = imx355_write_reg(imx355, IMX355_REG_EXTCLK_FREQ, 2,
imx355->clk_params->extclk_freq);
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v2 08/20] media: imx355: Remove link_freq_index from each mode as ununsed
2026-07-07 17:04 [PATCH v2 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
` (6 preceding siblings ...)
2026-07-07 17:04 ` [PATCH v2 07/20] media: imx355: Set binning mode registers programmatically Dave Stevenson
@ 2026-07-07 17:04 ` Dave Stevenson
2026-07-07 17:04 ` [PATCH v2 09/20] media: imx355: pixel_rate never changes, so don't recompute Dave Stevenson
` (11 subsequent siblings)
19 siblings, 0 replies; 34+ messages in thread
From: Dave Stevenson @ 2026-07-07 17:04 UTC (permalink / raw)
To: Tianshu Qiu, Sakari Ailus, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Richard Acayan
Cc: linux-media, linux-kernel, David Heidelberg, Jacopo Mondi,
devicetree, Dave Stevenson
The link_freq_index value in imx355_mode is unused, so remove it.
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/media/i2c/imx355.c | 18 ------------------
1 file changed, 18 deletions(-)
diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
index cfc47b5100c4..20cf6afee43e 100644
--- a/drivers/media/i2c/imx355.c
+++ b/drivers/media/i2c/imx355.c
@@ -81,7 +81,6 @@
/* default link frequency and external clock */
#define IMX355_LINK_FREQ_DEFAULT 360000000LL
-#define IMX355_LINK_FREQ_INDEX 0
/* number of data lanes */
#define IMX355_DATA_LANES 4
@@ -111,9 +110,6 @@ struct imx355_mode {
/* H-timing */
u32 llp;
- /* index of link frequency */
- u32 link_freq_index;
-
/* Default register values */
struct imx355_reg_list reg_list;
};
@@ -365,7 +361,6 @@ static const struct imx355_mode supported_modes[] = {
.fll_def = 2615,
.fll_min = 2615,
.llp = 3672,
- .link_freq_index = IMX355_LINK_FREQ_INDEX,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_3280x2464_regs),
.regs = mode_3280x2464_regs,
@@ -383,7 +378,6 @@ static const struct imx355_mode supported_modes[] = {
.fll_def = 2615,
.fll_min = 2615,
.llp = 3672,
- .link_freq_index = IMX355_LINK_FREQ_INDEX,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_3268x2448_regs),
.regs = mode_3268x2448_regs,
@@ -401,7 +395,6 @@ static const struct imx355_mode supported_modes[] = {
.fll_def = 2615,
.fll_min = 2615,
.llp = 3672,
- .link_freq_index = IMX355_LINK_FREQ_INDEX,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_3264x2448_regs),
.regs = mode_3264x2448_regs,
@@ -419,7 +412,6 @@ static const struct imx355_mode supported_modes[] = {
.fll_def = 1306,
.fll_min = 1306,
.llp = 3672,
- .link_freq_index = IMX355_LINK_FREQ_INDEX,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_1940x1096_regs),
.regs = mode_1940x1096_regs,
@@ -437,7 +429,6 @@ static const struct imx355_mode supported_modes[] = {
.fll_def = 1306,
.fll_min = 1306,
.llp = 3672,
- .link_freq_index = IMX355_LINK_FREQ_INDEX,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_1936x1096_regs),
.regs = mode_1936x1096_regs,
@@ -455,7 +446,6 @@ static const struct imx355_mode supported_modes[] = {
.fll_def = 1306,
.fll_min = 1306,
.llp = 3672,
- .link_freq_index = IMX355_LINK_FREQ_INDEX,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_1924x1080_regs),
.regs = mode_1924x1080_regs,
@@ -473,7 +463,6 @@ static const struct imx355_mode supported_modes[] = {
.fll_def = 1306,
.fll_min = 1306,
.llp = 3672,
- .link_freq_index = IMX355_LINK_FREQ_INDEX,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_1920x1080_regs),
.regs = mode_1920x1080_regs,
@@ -491,7 +480,6 @@ static const struct imx355_mode supported_modes[] = {
.fll_def = 1306,
.fll_min = 1306,
.llp = 1836,
- .link_freq_index = IMX355_LINK_FREQ_INDEX,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_1640x1232_regs),
.regs = mode_1640x1232_regs,
@@ -509,7 +497,6 @@ static const struct imx355_mode supported_modes[] = {
.fll_def = 1306,
.fll_min = 1306,
.llp = 1836,
- .link_freq_index = IMX355_LINK_FREQ_INDEX,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_1640x922_regs),
.regs = mode_1640x922_regs,
@@ -527,7 +514,6 @@ static const struct imx355_mode supported_modes[] = {
.fll_def = 1306,
.fll_min = 1306,
.llp = 1836,
- .link_freq_index = IMX355_LINK_FREQ_INDEX,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_1300x736_regs),
.regs = mode_1300x736_regs,
@@ -545,7 +531,6 @@ static const struct imx355_mode supported_modes[] = {
.fll_def = 1306,
.fll_min = 1306,
.llp = 1836,
- .link_freq_index = IMX355_LINK_FREQ_INDEX,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_1296x736_regs),
.regs = mode_1296x736_regs,
@@ -563,7 +548,6 @@ static const struct imx355_mode supported_modes[] = {
.fll_def = 1306,
.fll_min = 1306,
.llp = 1836,
- .link_freq_index = IMX355_LINK_FREQ_INDEX,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_1284x720_regs),
.regs = mode_1284x720_regs,
@@ -581,7 +565,6 @@ static const struct imx355_mode supported_modes[] = {
.fll_def = 1306,
.fll_min = 1306,
.llp = 1836,
- .link_freq_index = IMX355_LINK_FREQ_INDEX,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_1280x720_regs),
.regs = mode_1280x720_regs,
@@ -599,7 +582,6 @@ static const struct imx355_mode supported_modes[] = {
.fll_def = 652,
.fll_min = 652,
.llp = 3672,
- .link_freq_index = IMX355_LINK_FREQ_INDEX,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_820x616_regs),
.regs = mode_820x616_regs,
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v2 09/20] media: imx355: pixel_rate never changes, so don't recompute
2026-07-07 17:04 [PATCH v2 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
` (7 preceding siblings ...)
2026-07-07 17:04 ` [PATCH v2 08/20] media: imx355: Remove link_freq_index from each mode as ununsed Dave Stevenson
@ 2026-07-07 17:04 ` Dave Stevenson
2026-07-07 17:15 ` sashiko-bot
2026-07-07 17:04 ` [PATCH v2 10/20] media: imx355: Remove redundant fll_min, and implement fixed offset Dave Stevenson
` (10 subsequent siblings)
19 siblings, 1 reply; 34+ messages in thread
From: Dave Stevenson @ 2026-07-07 17:04 UTC (permalink / raw)
To: Tianshu Qiu, Sakari Ailus, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Richard Acayan
Cc: linux-media, linux-kernel, David Heidelberg, Jacopo Mondi,
devicetree, Dave Stevenson
The pixel rate is always the same, so there is no need to try and
recompute it in imx355_set_pad_format, and then no need to have the
pointer to it stored.
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/media/i2c/imx355.c | 10 ++--------
1 file changed, 2 insertions(+), 8 deletions(-)
diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
index 20cf6afee43e..9d977bac23b6 100644
--- a/drivers/media/i2c/imx355.c
+++ b/drivers/media/i2c/imx355.c
@@ -151,7 +151,6 @@ struct imx355 {
struct v4l2_ctrl_handler ctrl_handler;
/* V4L2 Controls */
struct v4l2_ctrl *link_freq;
- struct v4l2_ctrl *pixel_rate;
struct v4l2_ctrl *vblank;
struct v4l2_ctrl *hblank;
struct v4l2_ctrl *exposure;
@@ -866,7 +865,6 @@ imx355_set_pad_format(struct v4l2_subdev *sd,
s32 vblank_def;
s32 vblank_min;
s64 h_blank;
- u64 pixel_rate;
u32 height;
mutex_lock(&imx355->mutex);
@@ -887,9 +885,6 @@ imx355_set_pad_format(struct v4l2_subdev *sd,
*framefmt = fmt->format;
} else {
imx355->cur_mode = mode;
- pixel_rate = IMX355_LINK_FREQ_DEFAULT * 2 * 4;
- do_div(pixel_rate, 10);
- __v4l2_ctrl_s_ctrl_int64(imx355->pixel_rate, pixel_rate);
/* Update limits and set FPS to default */
height = imx355->cur_mode->height;
vblank_def = imx355->cur_mode->fll_def - height;
@@ -1180,9 +1175,8 @@ static int imx355_init_controls(struct imx355 *imx355)
pixel_rate = IMX355_LINK_FREQ_DEFAULT * 2 * 4;
do_div(pixel_rate, 10);
/* By default, PIXEL_RATE is read only */
- imx355->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops,
- V4L2_CID_PIXEL_RATE, pixel_rate,
- pixel_rate, 1, pixel_rate);
+ v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, V4L2_CID_PIXEL_RATE,
+ pixel_rate, pixel_rate, 1, pixel_rate);
/* Initialize vblank/hblank/exposure parameters based on current mode */
mode = imx355->cur_mode;
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v2 10/20] media: imx355: Remove redundant fll_min, and implement fixed offset
2026-07-07 17:04 [PATCH v2 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
` (8 preceding siblings ...)
2026-07-07 17:04 ` [PATCH v2 09/20] media: imx355: pixel_rate never changes, so don't recompute Dave Stevenson
@ 2026-07-07 17:04 ` Dave Stevenson
2026-07-07 17:18 ` sashiko-bot
2026-07-07 17:04 ` [PATCH v2 11/20] media: imx355: Add support for get_selection Dave Stevenson
` (9 subsequent siblings)
19 siblings, 1 reply; 34+ messages in thread
From: Dave Stevenson @ 2026-07-07 17:04 UTC (permalink / raw)
To: Tianshu Qiu, Sakari Ailus, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Richard Acayan
Cc: linux-media, linux-kernel, David Heidelberg, Jacopo Mondi,
devicetree, Dave Stevenson
fll_min (Frame Length Lines) is set to the same value as fll_def
for all modes, which makes it redundant.
The actual value is also erroneous as the sensor works in all
the defined modes with FLL set at the mode height + 20 lines,
so set the vblank control minimum to 20 rather than varying it.
This also improves the maximum frame rate achievable.
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/media/i2c/imx355.c | 26 ++++----------------------
1 file changed, 4 insertions(+), 22 deletions(-)
diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
index 9d977bac23b6..354092295b7c 100644
--- a/drivers/media/i2c/imx355.c
+++ b/drivers/media/i2c/imx355.c
@@ -32,6 +32,7 @@
/* V_TIMING internal */
#define IMX355_REG_FLL 0x0340
#define IMX355_FLL_MAX 0xffff
+#define IMX355_VBLANK_MIN 20
#define IMX355_REG_LLP 0x0342
#define IMX355_LLP_MAX 0xffff
@@ -105,7 +106,6 @@ struct imx355_mode {
/* V-timing */
u32 fll_def;
- u32 fll_min;
/* H-timing */
u32 llp;
@@ -358,7 +358,6 @@ static const struct imx355_mode supported_modes[] = {
.top = 0,
},
.fll_def = 2615,
- .fll_min = 2615,
.llp = 3672,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_3280x2464_regs),
@@ -375,7 +374,6 @@ static const struct imx355_mode supported_modes[] = {
.top = 8,
},
.fll_def = 2615,
- .fll_min = 2615,
.llp = 3672,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_3268x2448_regs),
@@ -392,7 +390,6 @@ static const struct imx355_mode supported_modes[] = {
.top = 8,
},
.fll_def = 2615,
- .fll_min = 2615,
.llp = 3672,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_3264x2448_regs),
@@ -409,7 +406,6 @@ static const struct imx355_mode supported_modes[] = {
.top = 684,
},
.fll_def = 1306,
- .fll_min = 1306,
.llp = 3672,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_1940x1096_regs),
@@ -426,7 +422,6 @@ static const struct imx355_mode supported_modes[] = {
.top = 684,
},
.fll_def = 1306,
- .fll_min = 1306,
.llp = 3672,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_1936x1096_regs),
@@ -443,7 +438,6 @@ static const struct imx355_mode supported_modes[] = {
.top = 692,
},
.fll_def = 1306,
- .fll_min = 1306,
.llp = 3672,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_1924x1080_regs),
@@ -460,7 +454,6 @@ static const struct imx355_mode supported_modes[] = {
.top = 692,
},
.fll_def = 1306,
- .fll_min = 1306,
.llp = 3672,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_1920x1080_regs),
@@ -477,7 +470,6 @@ static const struct imx355_mode supported_modes[] = {
.top = 0,
},
.fll_def = 1306,
- .fll_min = 1306,
.llp = 1836,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_1640x1232_regs),
@@ -494,7 +486,6 @@ static const struct imx355_mode supported_modes[] = {
.top = 304,
},
.fll_def = 1306,
- .fll_min = 1306,
.llp = 1836,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_1640x922_regs),
@@ -511,7 +502,6 @@ static const struct imx355_mode supported_modes[] = {
.top = 496,
},
.fll_def = 1306,
- .fll_min = 1306,
.llp = 1836,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_1300x736_regs),
@@ -528,7 +518,6 @@ static const struct imx355_mode supported_modes[] = {
.top = 496,
},
.fll_def = 1306,
- .fll_min = 1306,
.llp = 1836,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_1296x736_regs),
@@ -545,7 +534,6 @@ static const struct imx355_mode supported_modes[] = {
.top = 512,
},
.fll_def = 1306,
- .fll_min = 1306,
.llp = 1836,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_1284x720_regs),
@@ -562,7 +550,6 @@ static const struct imx355_mode supported_modes[] = {
.top = 512,
},
.fll_def = 1306,
- .fll_min = 1306,
.llp = 1836,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_1280x720_regs),
@@ -579,7 +566,6 @@ static const struct imx355_mode supported_modes[] = {
.top = 0,
},
.fll_def = 652,
- .fll_min = 652,
.llp = 3672,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_820x616_regs),
@@ -863,7 +849,6 @@ imx355_set_pad_format(struct v4l2_subdev *sd,
const struct imx355_mode *mode;
struct v4l2_mbus_framefmt *framefmt;
s32 vblank_def;
- s32 vblank_min;
s64 h_blank;
u32 height;
@@ -888,10 +873,9 @@ imx355_set_pad_format(struct v4l2_subdev *sd,
/* Update limits and set FPS to default */
height = imx355->cur_mode->height;
vblank_def = imx355->cur_mode->fll_def - height;
- vblank_min = imx355->cur_mode->fll_min - height;
height = IMX355_FLL_MAX - height;
- __v4l2_ctrl_modify_range(imx355->vblank, vblank_min, height, 1,
- vblank_def);
+ __v4l2_ctrl_modify_range(imx355->vblank, IMX355_VBLANK_MIN,
+ height, 1, vblank_def);
__v4l2_ctrl_s_ctrl(imx355->vblank, vblank_def);
h_blank = mode->llp - imx355->cur_mode->width;
/*
@@ -1151,7 +1135,6 @@ static int imx355_init_controls(struct imx355 *imx355)
struct v4l2_ctrl_handler *ctrl_hdlr;
s64 exposure_max;
s64 vblank_def;
- s64 vblank_min;
s64 hblank;
u64 pixel_rate;
const struct imx355_mode *mode;
@@ -1181,9 +1164,8 @@ static int imx355_init_controls(struct imx355 *imx355)
/* Initialize vblank/hblank/exposure parameters based on current mode */
mode = imx355->cur_mode;
vblank_def = mode->fll_def - mode->height;
- vblank_min = mode->fll_min - mode->height;
imx355->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops,
- V4L2_CID_VBLANK, vblank_min,
+ V4L2_CID_VBLANK, IMX355_VBLANK_MIN,
IMX355_FLL_MAX - mode->height,
1, vblank_def);
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v2 11/20] media: imx355: Add support for get_selection
2026-07-07 17:04 [PATCH v2 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
` (9 preceding siblings ...)
2026-07-07 17:04 ` [PATCH v2 10/20] media: imx355: Remove redundant fll_min, and implement fixed offset Dave Stevenson
@ 2026-07-07 17:04 ` Dave Stevenson
2026-07-07 17:18 ` sashiko-bot
2026-07-07 17:04 ` [PATCH v2 12/20] media: imx355: Use pm_runtime autosuspend_delay Dave Stevenson
` (8 subsequent siblings)
19 siblings, 1 reply; 34+ messages in thread
From: Dave Stevenson @ 2026-07-07 17:04 UTC (permalink / raw)
To: Tianshu Qiu, Sakari Ailus, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Richard Acayan
Cc: linux-media, linux-kernel, David Heidelberg, Jacopo Mondi,
devicetree, Dave Stevenson
Provide all the cropping information via get_selection.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/media/i2c/imx355.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 53 insertions(+)
diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
index 354092295b7c..0f5fbe21d7fb 100644
--- a/drivers/media/i2c/imx355.c
+++ b/drivers/media/i2c/imx355.c
@@ -86,6 +86,11 @@
/* number of data lanes */
#define IMX355_DATA_LANES 4
+#define IMX355_PIXEL_ARRAY_TOP 0
+#define IMX355_PIXEL_ARRAY_LEFT 0
+#define IMX355_PIXEL_ARRAY_WIDTH 3280
+#define IMX355_PIXEL_ARRAY_HEIGHT 2464
+
struct imx355_reg {
u16 address;
u8 val;
@@ -676,6 +681,7 @@ static int imx355_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
struct imx355 *imx355 = to_imx355(sd);
struct v4l2_mbus_framefmt *try_fmt =
v4l2_subdev_state_get_format(fh->state, 0);
+ struct v4l2_rect *crop = v4l2_subdev_state_get_crop(fh->state, 0);
mutex_lock(&imx355->mutex);
@@ -685,6 +691,8 @@ static int imx355_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
try_fmt->code = imx355_get_format_code(imx355);
try_fmt->field = V4L2_FIELD_NONE;
+ *crop = imx355->cur_mode->crop;
+
mutex_unlock(&imx355->mutex);
return 0;
@@ -891,6 +899,50 @@ imx355_set_pad_format(struct v4l2_subdev *sd,
return 0;
}
+static void
+__imx355_get_pad_crop(struct imx355 *imx355,
+ struct v4l2_subdev_state *sd_state, unsigned int pad,
+ enum v4l2_subdev_format_whence which, struct v4l2_rect *r)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ *r = *v4l2_subdev_state_get_crop(sd_state, pad);
+ break;
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ *r = imx355->cur_mode->crop;
+ break;
+ }
+}
+
+static int imx355_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_selection *sel)
+{
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP: {
+ struct imx355 *imx355 = to_imx355(sd);
+
+ mutex_lock(&imx355->mutex);
+ __imx355_get_pad_crop(imx355, sd_state, sel->pad, sel->which,
+ &sel->r);
+ mutex_unlock(&imx355->mutex);
+
+ return 0;
+ }
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ case V4L2_SEL_TGT_NATIVE_SIZE:
+ sel->r.top = IMX355_PIXEL_ARRAY_TOP;
+ sel->r.left = IMX355_PIXEL_ARRAY_LEFT;
+ sel->r.width = IMX355_PIXEL_ARRAY_WIDTH;
+ sel->r.height = IMX355_PIXEL_ARRAY_HEIGHT;
+
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
/* Start streaming */
static int imx355_start_streaming(struct imx355 *imx355)
{
@@ -1066,6 +1118,7 @@ static const struct v4l2_subdev_pad_ops imx355_pad_ops = {
.get_fmt = imx355_get_pad_format,
.set_fmt = imx355_set_pad_format,
.enum_frame_size = imx355_enum_frame_size,
+ .get_selection = imx355_get_selection,
};
static const struct v4l2_subdev_ops imx355_subdev_ops = {
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v2 12/20] media: imx355: Use pm_runtime autosuspend_delay
2026-07-07 17:04 [PATCH v2 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
` (10 preceding siblings ...)
2026-07-07 17:04 ` [PATCH v2 11/20] media: imx355: Add support for get_selection Dave Stevenson
@ 2026-07-07 17:04 ` Dave Stevenson
2026-07-07 17:21 ` sashiko-bot
2026-07-07 17:04 ` [PATCH v2 13/20] media: imx355: Convert to new CCI register access helpers Dave Stevenson
` (7 subsequent siblings)
19 siblings, 1 reply; 34+ messages in thread
From: Dave Stevenson @ 2026-07-07 17:04 UTC (permalink / raw)
To: Tianshu Qiu, Sakari Ailus, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Richard Acayan
Cc: linux-media, linux-kernel, David Heidelberg, Jacopo Mondi,
devicetree, Dave Stevenson
Avoid powering the sensor up and down unnecessarily by using
pm_runtime's autosuspend_delay feature.
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/media/i2c/imx355.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
index 0f5fbe21d7fb..c7a24c69c0df 100644
--- a/drivers/media/i2c/imx355.c
+++ b/drivers/media/i2c/imx355.c
@@ -1067,7 +1067,7 @@ static int imx355_set_stream(struct v4l2_subdev *sd, int enable)
goto err_rpm_put;
} else {
imx355_stop_streaming(imx355);
- pm_runtime_put(imx355->dev);
+ pm_runtime_put_autosuspend(imx355->dev);
}
/* vflip and hflip cannot change during streaming */
@@ -1079,7 +1079,7 @@ static int imx355_set_stream(struct v4l2_subdev *sd, int enable)
return ret;
err_rpm_put:
- pm_runtime_put(imx355->dev);
+ pm_runtime_put_autosuspend(imx355->dev);
err_unlock:
mutex_unlock(&imx355->mutex);
@@ -1430,6 +1430,8 @@ static int imx355_probe(struct i2c_client *client)
pm_runtime_set_active(imx355->dev);
pm_runtime_enable(imx355->dev);
pm_runtime_idle(imx355->dev);
+ pm_runtime_set_autosuspend_delay(imx355->dev, 1000);
+ pm_runtime_use_autosuspend(imx355->dev);
ret = v4l2_async_register_subdev_sensor(&imx355->sd);
if (ret < 0)
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v2 13/20] media: imx355: Convert to new CCI register access helpers
2026-07-07 17:04 [PATCH v2 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
` (11 preceding siblings ...)
2026-07-07 17:04 ` [PATCH v2 12/20] media: imx355: Use pm_runtime autosuspend_delay Dave Stevenson
@ 2026-07-07 17:04 ` Dave Stevenson
2026-07-07 17:21 ` sashiko-bot
2026-07-07 17:04 ` [PATCH v2 14/20] media: imx355: Set the colorspace in the format Dave Stevenson
` (6 subsequent siblings)
19 siblings, 1 reply; 34+ messages in thread
From: Dave Stevenson @ 2026-07-07 17:04 UTC (permalink / raw)
To: Tianshu Qiu, Sakari Ailus, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Richard Acayan
Cc: linux-media, linux-kernel, David Heidelberg, Jacopo Mondi,
devicetree, Dave Stevenson
Use the new comon CCI register access helpers to replace the private
register access helpers in the imx355 driver.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/media/i2c/Kconfig | 1 +
drivers/media/i2c/imx355.c | 500 ++++++++++++++++++---------------------------
2 files changed, 196 insertions(+), 305 deletions(-)
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 5d173e0ecf42..06461a70a2cd 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -259,6 +259,7 @@ config VIDEO_IMX335
config VIDEO_IMX355
tristate "Sony IMX355 sensor support"
+ select V4L2_CCI_I2C
help
This is a Video4Linux2 sensor driver for the Sony
IMX355 camera.
diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
index c7a24c69c0df..c710dda5795b 100644
--- a/drivers/media/i2c/imx355.c
+++ b/drivers/media/i2c/imx355.c
@@ -9,76 +9,78 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/unaligned.h>
+#include <media/v4l2-cci.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-event.h>
#include <media/v4l2-fwnode.h>
-#define IMX355_REG_MODE_SELECT 0x0100
+#define IMX355_REG_MODE_SELECT CCI_REG8(0x0100)
#define IMX355_MODE_STANDBY 0x00
#define IMX355_MODE_STREAMING 0x01
/* Chip ID */
-#define IMX355_REG_CHIP_ID 0x0016
+#define IMX355_REG_CHIP_ID CCI_REG16(0x0016)
#define IMX355_CHIP_ID 0x0355
/* PLL registers that depend on the external clock frequency */
-#define IMX355_REG_EXTCLK_FREQ 0x0136
-#define IMX355_REG_PLL_OP_MUL 0x030e
+#define IMX355_REG_EXTCLK_FREQ CCI_REG16(0x0136)
+#define IMX355_REG_PLL_OP_MUL CCI_REG16(0x030e)
/* V_TIMING internal */
-#define IMX355_REG_FLL 0x0340
+#define IMX355_REG_FLL CCI_REG16(0x0340)
#define IMX355_FLL_MAX 0xffff
#define IMX355_VBLANK_MIN 20
-#define IMX355_REG_LLP 0x0342
+#define IMX355_REG_LLP CCI_REG16(0x0342)
#define IMX355_LLP_MAX 0xffff
-#define IMX355_REG_X_ADD_START 0x0344
-#define IMX355_REG_Y_ADD_START 0x0346
-#define IMX355_REG_X_ADD_END 0x0348
-#define IMX355_REG_Y_ADD_END 0x034a
-#define IMX355_REG_X_OUT_SIZE 0x034c
-#define IMX355_REG_Y_OUT_SIZE 0x034e
+#define IMX355_REG_X_ADD_START CCI_REG16(0x0344)
+#define IMX355_REG_Y_ADD_START CCI_REG16(0x0346)
+#define IMX355_REG_X_ADD_END CCI_REG16(0x0348)
+#define IMX355_REG_Y_ADD_END CCI_REG16(0x034a)
+#define IMX355_REG_X_OUT_SIZE CCI_REG16(0x034c)
+#define IMX355_REG_Y_OUT_SIZE CCI_REG16(0x034e)
/* Exposure control */
-#define IMX355_REG_EXPOSURE 0x0202
+#define IMX355_REG_EXPOSURE CCI_REG16(0x0202)
#define IMX355_EXPOSURE_MIN 1
#define IMX355_EXPOSURE_STEP 1
#define IMX355_EXPOSURE_DEFAULT 0x0282
/* Analog gain control */
-#define IMX355_REG_ANALOG_GAIN 0x0204
+#define IMX355_REG_ANALOG_GAIN CCI_REG16(0x0204)
#define IMX355_ANA_GAIN_MIN 0
#define IMX355_ANA_GAIN_MAX 960
#define IMX355_ANA_GAIN_STEP 1
#define IMX355_ANA_GAIN_DEFAULT 0
/* Digital gain control */
-#define IMX355_REG_DPGA_USE_GLOBAL_GAIN 0x3070
-#define IMX355_REG_DIG_GAIN_GLOBAL 0x020e
+#define IMX355_REG_DPGA_USE_GLOBAL_GAIN CCI_REG8(0x3070)
+#define IMX355_REG_DIG_GAIN_GLOBAL CCI_REG16(0x020e)
#define IMX355_DGTL_GAIN_MIN 256
#define IMX355_DGTL_GAIN_MAX 4095
#define IMX355_DGTL_GAIN_STEP 1
#define IMX355_DGTL_GAIN_DEFAULT 256
/* Test Pattern Control */
-#define IMX355_REG_TEST_PATTERN 0x0600
+#define IMX355_REG_TEST_PATTERN CCI_REG8(0x0600)
#define IMX355_TEST_PATTERN_DISABLED 0
#define IMX355_TEST_PATTERN_SOLID_COLOR 1
#define IMX355_TEST_PATTERN_COLOR_BARS 2
#define IMX355_TEST_PATTERN_GRAY_COLOR_BARS 3
#define IMX355_TEST_PATTERN_PN9 4
-#define IMX355_REG_BINNING_MODE 0x0900
-#define IMX355_REG_BINNING_TYPE 0x0901
-#define IMX355_REG_BINNING_WEIGHTING 0x0902
+#define IMX355_REG_BINNING_MODE CCI_REG8(0x0900)
+#define IMX355_REG_BINNING_TYPE CCI_REG8(0x0901)
+#define IMX355_REG_BINNING_WEIGHTING CCI_REG8(0x0902)
/* Flip Control */
-#define IMX355_REG_ORIENTATION 0x0101
+#define IMX355_REG_ORIENTATION CCI_REG8(0x0101)
/* default link frequency and external clock */
#define IMX355_LINK_FREQ_DEFAULT 360000000LL
@@ -91,14 +93,9 @@
#define IMX355_PIXEL_ARRAY_WIDTH 3280
#define IMX355_PIXEL_ARRAY_HEIGHT 2464
-struct imx355_reg {
- u16 address;
- u8 val;
-};
-
struct imx355_reg_list {
u32 num_of_regs;
- const struct imx355_reg *regs;
+ const struct cci_reg_sequence *regs;
};
/* Mode : resolution and related config&values */
@@ -149,6 +146,7 @@ struct imx355_hwcfg {
struct imx355 {
struct device *dev;
struct clk *clk;
+ struct regmap *regmap;
struct v4l2_subdev sd;
struct media_pad pad;
@@ -185,154 +183,149 @@ static const struct regulator_bulk_data imx355_supplies[] = {
{ .supply = "dovdd" },
};
-static const struct imx355_reg imx355_global_regs[] = {
- { 0x304e, 0x03 },
- { 0x4348, 0x16 },
- { 0x4350, 0x19 },
- { 0x4408, 0x0a },
- { 0x440c, 0x0b },
- { 0x4411, 0x5f },
- { 0x4412, 0x2c },
- { 0x4623, 0x00 },
- { 0x462c, 0x0f },
- { 0x462d, 0x00 },
- { 0x462e, 0x00 },
- { 0x4684, 0x54 },
- { 0x480a, 0x07 },
- { 0x4908, 0x07 },
- { 0x4909, 0x07 },
- { 0x490d, 0x0a },
- { 0x491e, 0x0f },
- { 0x4921, 0x06 },
- { 0x4923, 0x28 },
- { 0x4924, 0x28 },
- { 0x4925, 0x29 },
- { 0x4926, 0x29 },
- { 0x4927, 0x1f },
- { 0x4928, 0x20 },
- { 0x4929, 0x20 },
- { 0x492a, 0x20 },
- { 0x492c, 0x05 },
- { 0x492d, 0x06 },
- { 0x492e, 0x06 },
- { 0x492f, 0x06 },
- { 0x4930, 0x03 },
- { 0x4931, 0x04 },
- { 0x4932, 0x04 },
- { 0x4933, 0x05 },
- { 0x595e, 0x01 },
- { 0x5963, 0x01 },
- { 0x3030, 0x01 },
- { 0x3031, 0x01 },
- { 0x3045, 0x01 },
- { 0x4010, 0x00 },
- { 0x4011, 0x00 },
- { 0x4012, 0x00 },
- { 0x4013, 0x01 },
- { 0x68a8, 0xfe },
- { 0x68a9, 0xff },
- { 0x6888, 0x00 },
- { 0x6889, 0x00 },
- { 0x68b0, 0x00 },
- { 0x3058, 0x00 },
- { 0x305a, 0x00 },
- { 0x0112, 0x0a },
- { 0x0113, 0x0a },
- { 0x0114, 0x03 },
- { 0x0301, 0x05 },
- { 0x0303, 0x01 },
- { 0x0305, 0x02 },
- { 0x0306, 0x00 },
- { 0x0307, 0x78 },
- { 0x030d, 0x02 },
- { 0x0310, 0x00 },
- { 0x0220, 0x00 },
- { 0x0222, 0x01 },
- { 0x0820, 0x0b },
- { 0x0821, 0x40 },
- { 0x3088, 0x04 },
- { 0x6813, 0x02 },
- { 0x6835, 0x07 },
- { 0x6836, 0x01 },
- { 0x6837, 0x04 },
- { 0x684d, 0x07 },
- { 0x684e, 0x01 },
- { 0x684f, 0x04 },
+static const struct cci_reg_sequence imx355_global_regs[] = {
+ { CCI_REG8(0x304e), 0x03 },
+ { CCI_REG8(0x4348), 0x16 },
+ { CCI_REG8(0x4350), 0x19 },
+ { CCI_REG8(0x4408), 0x0a },
+ { CCI_REG8(0x440c), 0x0b },
+ { CCI_REG8(0x4411), 0x5f },
+ { CCI_REG8(0x4412), 0x2c },
+ { CCI_REG8(0x4623), 0x00 },
+ { CCI_REG8(0x462c), 0x0f },
+ { CCI_REG8(0x462d), 0x00 },
+ { CCI_REG8(0x462e), 0x00 },
+ { CCI_REG8(0x4684), 0x54 },
+ { CCI_REG8(0x480a), 0x07 },
+ { CCI_REG8(0x4908), 0x07 },
+ { CCI_REG8(0x4909), 0x07 },
+ { CCI_REG8(0x490d), 0x0a },
+ { CCI_REG8(0x491e), 0x0f },
+ { CCI_REG8(0x4921), 0x06 },
+ { CCI_REG8(0x4923), 0x28 },
+ { CCI_REG8(0x4924), 0x28 },
+ { CCI_REG8(0x4925), 0x29 },
+ { CCI_REG8(0x4926), 0x29 },
+ { CCI_REG8(0x4927), 0x1f },
+ { CCI_REG8(0x4928), 0x20 },
+ { CCI_REG8(0x4929), 0x20 },
+ { CCI_REG8(0x492a), 0x20 },
+ { CCI_REG8(0x492c), 0x05 },
+ { CCI_REG8(0x492d), 0x06 },
+ { CCI_REG8(0x492e), 0x06 },
+ { CCI_REG8(0x492f), 0x06 },
+ { CCI_REG8(0x4930), 0x03 },
+ { CCI_REG8(0x4931), 0x04 },
+ { CCI_REG8(0x4932), 0x04 },
+ { CCI_REG8(0x4933), 0x05 },
+ { CCI_REG8(0x595e), 0x01 },
+ { CCI_REG8(0x5963), 0x01 },
+ { CCI_REG8(0x3030), 0x01 },
+ { CCI_REG8(0x3031), 0x01 },
+ { CCI_REG8(0x3045), 0x01 },
+ { CCI_REG8(0x4010), 0x00 },
+ { CCI_REG8(0x4011), 0x00 },
+ { CCI_REG8(0x4012), 0x00 },
+ { CCI_REG8(0x4013), 0x01 },
+ { CCI_REG8(0x68a8), 0xfe },
+ { CCI_REG8(0x68a9), 0xff },
+ { CCI_REG8(0x6888), 0x00 },
+ { CCI_REG8(0x6889), 0x00 },
+ { CCI_REG8(0x68b0), 0x00 },
+ { CCI_REG8(0x3058), 0x00 },
+ { CCI_REG8(0x305a), 0x00 },
+ { CCI_REG8(0x0112), 0x0a },
+ { CCI_REG8(0x0113), 0x0a },
+ { CCI_REG8(0x0114), 0x03 },
+ { CCI_REG8(0x0301), 0x05 },
+ { CCI_REG8(0x0303), 0x01 },
+ { CCI_REG8(0x0305), 0x00 },
+ { CCI_REG8(0x0306), 0x78 },
+ { CCI_REG8(0x0307), 0x02 },
+ { CCI_REG8(0x030d), 0x02 },
+ { CCI_REG8(0x0310), 0x00 },
+ { CCI_REG8(0x0220), 0x00 },
+ { CCI_REG8(0x0222), 0x01 },
+ { CCI_REG8(0x0820), 0x0b },
+ { CCI_REG8(0x0821), 0x40 },
+ { CCI_REG8(0x3088), 0x04 },
+ { CCI_REG8(0x6813), 0x02 },
+ { CCI_REG8(0x6835), 0x07 },
+ { CCI_REG8(0x6836), 0x01 },
+ { CCI_REG8(0x6837), 0x04 },
+ { CCI_REG8(0x684d), 0x07 },
+ { CCI_REG8(0x684e), 0x01 },
+ { CCI_REG8(0x684f), 0x04 },
};
-static const struct imx355_reg_list imx355_global_setting = {
- .num_of_regs = ARRAY_SIZE(imx355_global_regs),
- .regs = imx355_global_regs,
+static const struct cci_reg_sequence mode_3268x2448_regs[] = {
+ { CCI_REG8(0x0700), 0x00 },
+ { CCI_REG8(0x0701), 0x10 },
};
-static const struct imx355_reg mode_3268x2448_regs[] = {
- { 0x0700, 0x00 },
- { 0x0701, 0x10 },
+static const struct cci_reg_sequence mode_3264x2448_regs[] = {
+ { CCI_REG8(0x0700), 0x00 },
+ { CCI_REG8(0x0701), 0x10 },
};
-static const struct imx355_reg mode_3264x2448_regs[] = {
- { 0x0700, 0x00 },
- { 0x0701, 0x10 },
+static const struct cci_reg_sequence mode_3280x2464_regs[] = {
+ { CCI_REG8(0x0700), 0x00 },
+ { CCI_REG8(0x0701), 0x10 },
};
-static const struct imx355_reg mode_3280x2464_regs[] = {
- { 0x0700, 0x00 },
- { 0x0701, 0x10 },
+static const struct cci_reg_sequence mode_1940x1096_regs[] = {
+ { CCI_REG8(0x0700), 0x00 },
+ { CCI_REG8(0x0701), 0x10 },
};
-static const struct imx355_reg mode_1940x1096_regs[] = {
- { 0x0700, 0x00 },
- { 0x0701, 0x10 },
+static const struct cci_reg_sequence mode_1936x1096_regs[] = {
+ { CCI_REG8(0x0700), 0x00 },
+ { CCI_REG8(0x0701), 0x10 },
};
-static const struct imx355_reg mode_1936x1096_regs[] = {
- { 0x0700, 0x00 },
- { 0x0701, 0x10 },
+static const struct cci_reg_sequence mode_1924x1080_regs[] = {
+ { CCI_REG8(0x0700), 0x00 },
+ { CCI_REG8(0x0701), 0x10 },
};
-static const struct imx355_reg mode_1924x1080_regs[] = {
- { 0x0700, 0x00 },
- { 0x0701, 0x10 },
+static const struct cci_reg_sequence mode_1920x1080_regs[] = {
+ { CCI_REG8(0x0700), 0x00 },
+ { CCI_REG8(0x0701), 0x10 },
};
-static const struct imx355_reg mode_1920x1080_regs[] = {
- { 0x0700, 0x00 },
- { 0x0701, 0x10 },
+static const struct cci_reg_sequence mode_1640x1232_regs[] = {
+ { CCI_REG8(0x0700), 0x00 },
+ { CCI_REG8(0x0701), 0x10 },
};
-static const struct imx355_reg mode_1640x1232_regs[] = {
- { 0x0700, 0x00 },
- { 0x0701, 0x10 },
+static const struct cci_reg_sequence mode_1640x922_regs[] = {
+ { CCI_REG8(0x0700), 0x00 },
+ { CCI_REG8(0x0701), 0x10 },
};
-static const struct imx355_reg mode_1640x922_regs[] = {
- { 0x0700, 0x00 },
- { 0x0701, 0x10 },
+static const struct cci_reg_sequence mode_1300x736_regs[] = {
+ { CCI_REG8(0x0700), 0x00 },
+ { CCI_REG8(0x0701), 0x10 },
};
-static const struct imx355_reg mode_1300x736_regs[] = {
- { 0x0700, 0x00 },
- { 0x0701, 0x10 },
+static const struct cci_reg_sequence mode_1296x736_regs[] = {
+ { CCI_REG8(0x0700), 0x00 },
+ { CCI_REG8(0x0701), 0x10 },
};
-static const struct imx355_reg mode_1296x736_regs[] = {
- { 0x0700, 0x00 },
- { 0x0701, 0x10 },
+static const struct cci_reg_sequence mode_1284x720_regs[] = {
+ { CCI_REG8(0x0700), 0x00 },
+ { CCI_REG8(0x0701), 0x10 },
};
-static const struct imx355_reg mode_1284x720_regs[] = {
- { 0x0700, 0x00 },
- { 0x0701, 0x10 },
+static const struct cci_reg_sequence mode_1280x720_regs[] = {
+ { CCI_REG8(0x0700), 0x00 },
+ { CCI_REG8(0x0701), 0x10 },
};
-static const struct imx355_reg mode_1280x720_regs[] = {
- { 0x0700, 0x00 },
- { 0x0701, 0x10 },
-};
-
-static const struct imx355_reg mode_820x616_regs[] = {
- { 0x0700, 0x02 },
- { 0x0701, 0x78 },
+static const struct cci_reg_sequence mode_820x616_regs[] = {
+ { CCI_REG8(0x0700), 0x02 },
+ { CCI_REG8(0x0701), 0x78 },
};
static const char * const imx355_test_pattern_menu[] = {
@@ -603,78 +596,6 @@ static u32 imx355_get_format_code(struct imx355 *imx355)
return code;
}
-/* Read registers up to 4 at a time */
-static int imx355_read_reg(struct imx355 *imx355, u16 reg, u32 len, u32 *val)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd);
- struct i2c_msg msgs[2];
- u8 addr_buf[2];
- u8 data_buf[4] = { 0 };
- int ret;
-
- if (len > 4)
- return -EINVAL;
-
- put_unaligned_be16(reg, addr_buf);
- /* Write register address */
- msgs[0].addr = client->addr;
- msgs[0].flags = 0;
- msgs[0].len = ARRAY_SIZE(addr_buf);
- msgs[0].buf = addr_buf;
-
- /* Read data from register */
- msgs[1].addr = client->addr;
- msgs[1].flags = I2C_M_RD;
- msgs[1].len = len;
- msgs[1].buf = &data_buf[4 - len];
-
- ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
- if (ret != ARRAY_SIZE(msgs))
- return -EIO;
-
- *val = get_unaligned_be32(data_buf);
-
- return 0;
-}
-
-/* Write registers up to 4 at a time */
-static int imx355_write_reg(struct imx355 *imx355, u16 reg, u32 len, u32 val)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd);
- u8 buf[6];
-
- if (len > 4)
- return -EINVAL;
-
- put_unaligned_be16(reg, buf);
- put_unaligned_be32(val << (8 * (4 - len)), buf + 2);
- if (i2c_master_send(client, buf, len + 2) != len + 2)
- return -EIO;
-
- return 0;
-}
-
-/* Write a list of registers */
-static int imx355_write_regs(struct imx355 *imx355,
- const struct imx355_reg *regs, u32 len)
-{
- int ret;
- u32 i;
-
- for (i = 0; i < len; i++) {
- ret = imx355_write_reg(imx355, regs[i].address, 1, regs[i].val);
- if (ret) {
- dev_err_ratelimited(imx355->dev,
- "write reg 0x%4.4x return err %d",
- regs[i].address, ret);
-
- return ret;
- }
- }
-
- return 0;
-}
-
/* Open sub-device */
static int imx355_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
@@ -726,31 +647,31 @@ static int imx355_set_ctrl(struct v4l2_ctrl *ctrl)
switch (ctrl->id) {
case V4L2_CID_ANALOGUE_GAIN:
/* Analog gain = 1024/(1024 - ctrl->val) times */
- ret = imx355_write_reg(imx355, IMX355_REG_ANALOG_GAIN, 2,
- ctrl->val);
+ ret = cci_write(imx355->regmap, IMX355_REG_ANALOG_GAIN,
+ ctrl->val, NULL);
break;
case V4L2_CID_DIGITAL_GAIN:
- ret = imx355_write_reg(imx355, IMX355_REG_DIG_GAIN_GLOBAL, 2,
- ctrl->val);
+ ret = cci_write(imx355->regmap, IMX355_REG_DIG_GAIN_GLOBAL,
+ ctrl->val, NULL);
break;
case V4L2_CID_EXPOSURE:
- ret = imx355_write_reg(imx355, IMX355_REG_EXPOSURE, 2,
- ctrl->val);
+ ret = cci_write(imx355->regmap, IMX355_REG_EXPOSURE,
+ ctrl->val, NULL);
break;
case V4L2_CID_VBLANK:
/* Update FLL that meets expected vertical blanking */
- ret = imx355_write_reg(imx355, IMX355_REG_FLL, 2,
- imx355->cur_mode->height + ctrl->val);
+ ret = cci_write(imx355->regmap, IMX355_REG_FLL,
+ imx355->cur_mode->height + ctrl->val, NULL);
break;
case V4L2_CID_TEST_PATTERN:
- ret = imx355_write_reg(imx355, IMX355_REG_TEST_PATTERN,
- 2, ctrl->val);
+ ret = cci_write(imx355->regmap, IMX355_REG_TEST_PATTERN,
+ ctrl->val, NULL);
break;
case V4L2_CID_HFLIP:
case V4L2_CID_VFLIP:
- ret = imx355_write_reg(imx355, IMX355_REG_ORIENTATION, 1,
- imx355->hflip->val |
- imx355->vflip->val << 1);
+ ret = cci_write(imx355->regmap, IMX355_REG_ORIENTATION,
+ imx355->hflip->val | imx355->vflip->val << 1,
+ NULL);
break;
default:
ret = -EINVAL;
@@ -949,101 +870,64 @@ static int imx355_start_streaming(struct imx355 *imx355)
const struct imx355_reg_list *reg_list;
const struct imx355_mode *mode;
u8 binning_mode;
- int ret;
+ int ret = 0;
/* Global Setting */
- reg_list = &imx355_global_setting;
- ret = imx355_write_regs(imx355, reg_list->regs, reg_list->num_of_regs);
- if (ret) {
- dev_err(imx355->dev, "failed to set global settings");
- return ret;
- }
+ cci_multi_reg_write(imx355->regmap, imx355_global_regs,
+ ARRAY_SIZE(imx355_global_regs), &ret);
/* Apply default values of current mode */
mode = imx355->cur_mode;
reg_list = &mode->reg_list;
- ret = imx355_write_regs(imx355, reg_list->regs, reg_list->num_of_regs);
- if (ret) {
- dev_err(imx355->dev, "failed to set mode");
- return ret;
- }
+ cci_multi_reg_write(imx355->regmap, reg_list->regs,
+ reg_list->num_of_regs, &ret);
/* Set readout crop and size registers */
- ret = imx355_write_reg(imx355, IMX355_REG_X_ADD_START, 2,
- mode->crop.left);
- if (ret)
- return ret;
- ret = imx355_write_reg(imx355, IMX355_REG_Y_ADD_START, 2,
- mode->crop.top);
- if (ret)
- return ret;
- ret = imx355_write_reg(imx355, IMX355_REG_X_ADD_END, 2,
- mode->crop.width + mode->crop.left - 1);
- if (ret)
- return ret;
- ret = imx355_write_reg(imx355, IMX355_REG_Y_ADD_END, 2,
- mode->crop.height + mode->crop.top - 1);
- if (ret)
- return ret;
- ret = imx355_write_reg(imx355, IMX355_REG_X_OUT_SIZE, 2,
- mode->width);
- if (ret)
- return ret;
- ret = imx355_write_reg(imx355, IMX355_REG_Y_OUT_SIZE, 2,
- mode->height);
- if (ret)
- return ret;
+ cci_write(imx355->regmap, IMX355_REG_X_ADD_START, mode->crop.left,
+ &ret);
+ cci_write(imx355->regmap, IMX355_REG_Y_ADD_START, mode->crop.top, &ret);
+ cci_write(imx355->regmap, IMX355_REG_X_ADD_END,
+ mode->crop.width + mode->crop.left - 1, &ret);
+ cci_write(imx355->regmap, IMX355_REG_Y_ADD_END,
+ mode->crop.height + mode->crop.top - 1, &ret);
+ cci_write(imx355->regmap, IMX355_REG_X_OUT_SIZE, mode->width, &ret);
+ cci_write(imx355->regmap, IMX355_REG_Y_OUT_SIZE, mode->height, &ret);
binning_mode = ((mode->crop.width / mode->width) << 4) |
(mode->crop.height / mode->height);
- ret = imx355_write_reg(imx355, IMX355_REG_BINNING_MODE, 1,
- binning_mode == 0x11 ? 0x00 : 0x01);
- if (ret)
- return ret;
- ret = imx355_write_reg(imx355, IMX355_REG_BINNING_TYPE, 1,
- binning_mode);
- if (ret)
- return ret;
- ret = imx355_write_reg(imx355, IMX355_REG_BINNING_WEIGHTING, 1, 0x00);
- if (ret)
- return ret;
+ cci_write(imx355->regmap, IMX355_REG_BINNING_MODE,
+ binning_mode == 0x11 ? 0x00 : 0x01, &ret);
+ cci_write(imx355->regmap, IMX355_REG_BINNING_TYPE, binning_mode, &ret);
+ cci_write(imx355->regmap, IMX355_REG_BINNING_WEIGHTING, 0x00, &ret);
/* Set PLL registers for the external clock frequency */
- ret = imx355_write_reg(imx355, IMX355_REG_EXTCLK_FREQ, 2,
- imx355->clk_params->extclk_freq);
- if (ret)
- return ret;
- ret = imx355_write_reg(imx355, IMX355_REG_PLL_OP_MUL, 2,
- imx355->clk_params->pll_op_mpy);
- if (ret)
- return ret;
+ cci_write(imx355->regmap, IMX355_REG_EXTCLK_FREQ,
+ imx355->clk_params->extclk_freq, &ret);
+ cci_write(imx355->regmap, IMX355_REG_PLL_OP_MUL,
+ imx355->clk_params->pll_op_mpy, &ret);
/* set digital gain control to all color mode */
- ret = imx355_write_reg(imx355, IMX355_REG_DPGA_USE_GLOBAL_GAIN, 1, 1);
- if (ret)
- return ret;
+ cci_write(imx355->regmap, IMX355_REG_DPGA_USE_GLOBAL_GAIN, 1, &ret);
/* set line length */
- ret = imx355_write_reg(imx355, IMX355_REG_LLP,
- imx355->hblank->val + imx355->cur_mode->width,
- 2);
- if (ret)
- return ret;
+ cci_write(imx355->regmap, IMX355_REG_LLP,
+ imx355->hblank->val + imx355->cur_mode->width, &ret);
/* Apply customized values from user */
- ret = __v4l2_ctrl_handler_setup(imx355->sd.ctrl_handler);
- if (ret)
- return ret;
+ if (!ret)
+ ret = __v4l2_ctrl_handler_setup(imx355->sd.ctrl_handler);
- return imx355_write_reg(imx355, IMX355_REG_MODE_SELECT,
- 1, IMX355_MODE_STREAMING);
+ cci_write(imx355->regmap, IMX355_REG_MODE_SELECT, IMX355_MODE_STREAMING,
+ &ret);
+
+ return ret;
}
/* Stop streaming */
static int imx355_stop_streaming(struct imx355 *imx355)
{
- return imx355_write_reg(imx355, IMX355_REG_MODE_SELECT,
- 1, IMX355_MODE_STANDBY);
+ return cci_write(imx355->regmap, IMX355_REG_MODE_SELECT,
+ IMX355_MODE_STANDBY, NULL);
}
static int imx355_set_stream(struct v4l2_subdev *sd, int enable)
@@ -1090,14 +974,14 @@ static int imx355_set_stream(struct v4l2_subdev *sd, int enable)
static int imx355_identify_module(struct imx355 *imx355)
{
int ret;
- u32 val;
+ u64 val;
- ret = imx355_read_reg(imx355, IMX355_REG_CHIP_ID, 2, &val);
+ ret = cci_read(imx355->regmap, IMX355_REG_CHIP_ID, &val, NULL);
if (ret)
return ret;
if (val != IMX355_CHIP_ID) {
- dev_err(imx355->dev, "chip id mismatch: %x!=%x",
+ dev_err(imx355->dev, "chip id mismatch: %x!=%llx",
IMX355_CHIP_ID, val);
return -EIO;
}
@@ -1344,6 +1228,12 @@ static int imx355_probe(struct i2c_client *client)
mutex_init(&imx355->mutex);
+ imx355->regmap = devm_cci_regmap_init_i2c(client, 16);
+ if (IS_ERR(imx355->regmap)) {
+ dev_err(imx355->dev, "Unable to initialize I2C\n");
+ return -ENODEV;
+ }
+
imx355->clk = devm_v4l2_sensor_clk_get(imx355->dev, NULL);
if (IS_ERR(imx355->clk))
return dev_err_probe(imx355->dev, PTR_ERR(imx355->clk),
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v2 14/20] media: imx355: Set the colorspace in the format
2026-07-07 17:04 [PATCH v2 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
` (12 preceding siblings ...)
2026-07-07 17:04 ` [PATCH v2 13/20] media: imx355: Convert to new CCI register access helpers Dave Stevenson
@ 2026-07-07 17:04 ` Dave Stevenson
2026-07-07 17:16 ` sashiko-bot
2026-07-07 17:04 ` [PATCH v2 15/20] media: imx355: Define the exposure offset, and use that define Dave Stevenson
` (5 subsequent siblings)
19 siblings, 1 reply; 34+ messages in thread
From: Dave Stevenson @ 2026-07-07 17:04 UTC (permalink / raw)
To: Tianshu Qiu, Sakari Ailus, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Richard Acayan
Cc: linux-media, linux-kernel, David Heidelberg, Jacopo Mondi,
devicetree, Dave Stevenson
The colorspace fields were left set to 0 when they should be
set appropriately for a raw image sensor. Add those values.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/media/i2c/imx355.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
index c710dda5795b..ff9eaec39fe5 100644
--- a/drivers/media/i2c/imx355.c
+++ b/drivers/media/i2c/imx355.c
@@ -737,6 +737,10 @@ static void imx355_update_pad_format(struct imx355 *imx355,
fmt->format.height = mode->height;
fmt->format.code = imx355_get_format_code(imx355);
fmt->format.field = V4L2_FIELD_NONE;
+ fmt->format.colorspace = V4L2_COLORSPACE_RAW;
+ fmt->format.ycbcr_enc = V4L2_YCBCR_ENC_601;
+ fmt->format.quantization = V4L2_QUANTIZATION_FULL_RANGE;
+ fmt->format.xfer_func = V4L2_XFER_FUNC_NONE;
}
static int imx355_do_get_pad_format(struct imx355 *imx355,
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v2 15/20] media: imx355: Define the exposure offset, and use that define
2026-07-07 17:04 [PATCH v2 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
` (13 preceding siblings ...)
2026-07-07 17:04 ` [PATCH v2 14/20] media: imx355: Set the colorspace in the format Dave Stevenson
@ 2026-07-07 17:04 ` Dave Stevenson
2026-07-07 17:04 ` [PATCH v2 16/20] media: imx355: Use NULL ctrl_ops for HBLANK as it is a read-only control Dave Stevenson
` (4 subsequent siblings)
19 siblings, 0 replies; 34+ messages in thread
From: Dave Stevenson @ 2026-07-07 17:04 UTC (permalink / raw)
To: Tianshu Qiu, Sakari Ailus, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Richard Acayan
Cc: linux-media, linux-kernel, David Heidelberg, Jacopo Mondi,
devicetree, Dave Stevenson
The difference between frame length and max exposure time in
lines is 10. That had been used as a bare value in calculations.
Move it to a define, and use that define.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/media/i2c/imx355.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
index ff9eaec39fe5..0b95027983a7 100644
--- a/drivers/media/i2c/imx355.c
+++ b/drivers/media/i2c/imx355.c
@@ -51,6 +51,7 @@
#define IMX355_EXPOSURE_MIN 1
#define IMX355_EXPOSURE_STEP 1
#define IMX355_EXPOSURE_DEFAULT 0x0282
+#define IMX355_EXPOSURE_OFFSET 10
/* Analog gain control */
#define IMX355_REG_ANALOG_GAIN CCI_REG16(0x0204)
@@ -630,7 +631,7 @@ static int imx355_set_ctrl(struct v4l2_ctrl *ctrl)
switch (ctrl->id) {
case V4L2_CID_VBLANK:
/* Update max exposure while meeting expected vblanking */
- max = imx355->cur_mode->height + ctrl->val - 10;
+ max = imx355->cur_mode->height + ctrl->val - IMX355_EXPOSURE_OFFSET;
__v4l2_ctrl_modify_range(imx355->exposure,
imx355->exposure->minimum,
max, imx355->exposure->step, max);
@@ -1118,7 +1119,7 @@ static int imx355_init_controls(struct imx355 *imx355)
imx355->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
/* fll >= exposure time + adjust parameter (default value is 10) */
- exposure_max = mode->fll_def - 10;
+ exposure_max = mode->fll_def - IMX355_EXPOSURE_OFFSET;
imx355->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops,
V4L2_CID_EXPOSURE,
IMX355_EXPOSURE_MIN, exposure_max,
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v2 16/20] media: imx355: Use NULL ctrl_ops for HBLANK as it is a read-only control
2026-07-07 17:04 [PATCH v2 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
` (14 preceding siblings ...)
2026-07-07 17:04 ` [PATCH v2 15/20] media: imx355: Define the exposure offset, and use that define Dave Stevenson
@ 2026-07-07 17:04 ` Dave Stevenson
2026-07-07 17:04 ` [PATCH v2 17/20] media: imx355: Compute link frequency from PLL setup Dave Stevenson
` (3 subsequent siblings)
19 siblings, 0 replies; 34+ messages in thread
From: Dave Stevenson @ 2026-07-07 17:04 UTC (permalink / raw)
To: Tianshu Qiu, Sakari Ailus, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Richard Acayan
Cc: linux-media, linux-kernel, David Heidelberg, Jacopo Mondi,
devicetree, Dave Stevenson
This avoids the set_ctrl handler being called under any
circumstances, as it will return an error for the unhandled
ctrl.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/media/i2c/imx355.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
index 0b95027983a7..cff87c6ea789 100644
--- a/drivers/media/i2c/imx355.c
+++ b/drivers/media/i2c/imx355.c
@@ -1112,9 +1112,8 @@ static int imx355_init_controls(struct imx355 *imx355)
1, vblank_def);
hblank = mode->llp - mode->width;
- imx355->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops,
- V4L2_CID_HBLANK, hblank, hblank,
- 1, hblank);
+ imx355->hblank = v4l2_ctrl_new_std(ctrl_hdlr, NULL, V4L2_CID_HBLANK,
+ hblank, hblank, 1, hblank);
if (imx355->hblank)
imx355->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v2 17/20] media: imx355: Compute link frequency from PLL setup
2026-07-07 17:04 [PATCH v2 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
` (15 preceding siblings ...)
2026-07-07 17:04 ` [PATCH v2 16/20] media: imx355: Use NULL ctrl_ops for HBLANK as it is a read-only control Dave Stevenson
@ 2026-07-07 17:04 ` Dave Stevenson
2026-07-07 17:04 ` [PATCH v2 18/20] media: imx355: Support 2 lane readout Dave Stevenson
` (2 subsequent siblings)
19 siblings, 0 replies; 34+ messages in thread
From: Dave Stevenson @ 2026-07-07 17:04 UTC (permalink / raw)
To: Tianshu Qiu, Sakari Ailus, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Richard Acayan
Cc: linux-media, linux-kernel, David Heidelberg, Jacopo Mondi,
devicetree, Dave Stevenson
In preparation for additional options in the PLL setup, compute
the link frequency rather than using a hardcoded value.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/media/i2c/imx355.c | 41 ++++++++++++++++++-----------------------
1 file changed, 18 insertions(+), 23 deletions(-)
diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
index cff87c6ea789..3586c4cd3fbe 100644
--- a/drivers/media/i2c/imx355.c
+++ b/drivers/media/i2c/imx355.c
@@ -29,7 +29,11 @@
/* PLL registers that depend on the external clock frequency */
#define IMX355_REG_EXTCLK_FREQ CCI_REG16(0x0136)
+#define IMX355_REG_PLL_OP_PREDIV CCI_REG8(0x030d)
#define IMX355_REG_PLL_OP_MUL CCI_REG16(0x030e)
+#define IMX355_REG_PLL_IVT_PCK_DIV CCI_REG8(0x0301)
+#define IMX355_PLL_OP_PREDIV 2
+#define IMX355_PLL_IVT_PCK_DIV 5
/* V_TIMING internal */
#define IMX355_REG_FLL CCI_REG16(0x0340)
@@ -83,9 +87,6 @@
/* Flip Control */
#define IMX355_REG_ORIENTATION CCI_REG8(0x0101)
-/* default link frequency and external clock */
-#define IMX355_LINK_FREQ_DEFAULT 360000000LL
-
/* number of data lanes */
#define IMX355_DATA_LANES 4
@@ -141,6 +142,7 @@ static const struct imx355_clk_params imx355_clk_params[] = {
};
struct imx355_hwcfg {
+ s64 link_freq_menu;
unsigned long link_freq_bitmap;
};
@@ -238,12 +240,12 @@ static const struct cci_reg_sequence imx355_global_regs[] = {
{ CCI_REG8(0x0112), 0x0a },
{ CCI_REG8(0x0113), 0x0a },
{ CCI_REG8(0x0114), 0x03 },
- { CCI_REG8(0x0301), 0x05 },
+ { IMX355_REG_PLL_IVT_PCK_DIV, IMX355_PLL_IVT_PCK_DIV },
{ CCI_REG8(0x0303), 0x01 },
- { CCI_REG8(0x0305), 0x00 },
+ { CCI_REG8(0x0305), 0x02 },
{ CCI_REG8(0x0306), 0x78 },
{ CCI_REG8(0x0307), 0x02 },
- { CCI_REG8(0x030d), 0x02 },
+ { IMX355_REG_PLL_OP_PREDIV, IMX355_PLL_OP_PREDIV },
{ CCI_REG8(0x0310), 0x00 },
{ CCI_REG8(0x0220), 0x00 },
{ CCI_REG8(0x0222), 0x01 },
@@ -337,14 +339,6 @@ static const char * const imx355_test_pattern_menu[] = {
"Pseudorandom Sequence (PN9)",
};
-/*
- * When adding more than the one below, make sure the disallowed ones will
- * actually be disabled in the LINK_FREQ control.
- */
-static const s64 link_freq_menu_items[] = {
- IMX355_LINK_FREQ_DEFAULT,
-};
-
/* Mode configs */
static const struct imx355_mode supported_modes[] = {
{
@@ -1080,7 +1074,6 @@ static int imx355_init_controls(struct imx355 *imx355)
s64 hblank;
u64 pixel_rate;
const struct imx355_mode *mode;
- u32 max;
int ret;
ctrl_hdlr = &imx355->ctrl_handler;
@@ -1089,15 +1082,14 @@ static int imx355_init_controls(struct imx355 *imx355)
return ret;
ctrl_hdlr->lock = &imx355->mutex;
- max = ARRAY_SIZE(link_freq_menu_items) - 1;
imx355->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx355_ctrl_ops,
- V4L2_CID_LINK_FREQ, max, 0,
- link_freq_menu_items);
+ V4L2_CID_LINK_FREQ, 0, 0,
+ &imx355->hwcfg->link_freq_menu);
if (imx355->link_freq)
imx355->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
/* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */
- pixel_rate = IMX355_LINK_FREQ_DEFAULT * 2 * 4;
+ pixel_rate = imx355->hwcfg->link_freq_menu * 2 * 4;
do_div(pixel_rate, 10);
/* By default, PIXEL_RATE is read only */
v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, V4L2_CID_PIXEL_RATE,
@@ -1172,12 +1164,14 @@ static int imx355_init_controls(struct imx355 *imx355)
return ret;
}
-static struct imx355_hwcfg *imx355_get_hwcfg(struct device *dev)
+static struct imx355_hwcfg *imx355_get_hwcfg(struct imx355 *imx355)
{
+ struct device *dev = imx355->dev;
struct imx355_hwcfg *cfg;
struct v4l2_fwnode_endpoint bus_cfg = {
.bus_type = V4L2_MBUS_CSI2_DPHY
};
+ const struct imx355_clk_params *clk = imx355->clk_params;
struct fwnode_handle *ep;
struct fwnode_handle *fwnode = dev_fwnode(dev);
int ret;
@@ -1200,10 +1194,11 @@ static struct imx355_hwcfg *imx355_get_hwcfg(struct device *dev)
if (bus_cfg.bus.mipi_csi2.num_data_lanes != IMX355_DATA_LANES)
goto out_err;
+ cfg->link_freq_menu = (clk->ext_clk * clk->pll_op_mpy) /
+ (IMX355_PLL_OP_PREDIV * 2);
ret = v4l2_link_freq_to_bitmap(dev, bus_cfg.link_frequencies,
bus_cfg.nr_of_link_frequencies,
- link_freq_menu_items,
- ARRAY_SIZE(link_freq_menu_items),
+ &cfg->link_freq_menu, 1,
&cfg->link_freq_bitmap);
if (ret)
goto out_err;
@@ -1275,7 +1270,7 @@ static int imx355_probe(struct i2c_client *client)
/* Initialize subdev */
v4l2_i2c_subdev_init(&imx355->sd, client, &imx355_subdev_ops);
- imx355->hwcfg = imx355_get_hwcfg(imx355->dev);
+ imx355->hwcfg = imx355_get_hwcfg(imx355);
if (!imx355->hwcfg) {
dev_err(imx355->dev, "failed to get hwcfg");
ret = -ENODEV;
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v2 18/20] media: imx355: Support 2 lane readout
2026-07-07 17:04 [PATCH v2 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
` (16 preceding siblings ...)
2026-07-07 17:04 ` [PATCH v2 17/20] media: imx355: Compute link frequency from PLL setup Dave Stevenson
@ 2026-07-07 17:04 ` Dave Stevenson
2026-07-07 17:04 ` [PATCH v2 19/20] media: imx355: Switch to using the subdev state Dave Stevenson
2026-07-07 17:04 ` [PATCH v2 20/20] media: imx355: Remove storing cur_mode in the state Dave Stevenson
19 siblings, 0 replies; 34+ messages in thread
From: Dave Stevenson @ 2026-07-07 17:04 UTC (permalink / raw)
To: Tianshu Qiu, Sakari Ailus, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Richard Acayan
Cc: linux-media, linux-kernel, David Heidelberg, Jacopo Mondi,
devicetree, Dave Stevenson
The sensor supports 2 or 4 lane readout, but the driver only allowed
for 4 lanes. Add 2 lane support.
The clock tree only supports single PLL mode to feed both IOP (MIPI)
and IVT (Pixel array).
2 lane mode supports a MIPI link frequency of up to 445MHz (890Mbit/s)
cf 360MHz (720Mbit/s) for 4lane. Update clock setup and pixel rates to
match.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/media/i2c/imx355.c | 67 +++++++++++++++++++++++++++++++++-------------
1 file changed, 48 insertions(+), 19 deletions(-)
diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
index 3586c4cd3fbe..10b9cf56e8c5 100644
--- a/drivers/media/i2c/imx355.c
+++ b/drivers/media/i2c/imx355.c
@@ -27,11 +27,14 @@
#define IMX355_REG_CHIP_ID CCI_REG16(0x0016)
#define IMX355_CHIP_ID 0x0355
+#define IMX355_REG_LANE_SEL CCI_REG8(0x0114)
+
/* PLL registers that depend on the external clock frequency */
#define IMX355_REG_EXTCLK_FREQ CCI_REG16(0x0136)
#define IMX355_REG_PLL_OP_PREDIV CCI_REG8(0x030d)
#define IMX355_REG_PLL_OP_MUL CCI_REG16(0x030e)
#define IMX355_REG_PLL_IVT_PCK_DIV CCI_REG8(0x0301)
+#define IMX355_REG_PLL_IVT_SYSCK_DIV CCI_REG8(0x0303)
#define IMX355_PLL_OP_PREDIV 2
#define IMX355_PLL_IVT_PCK_DIV 5
@@ -80,6 +83,8 @@
#define IMX355_TEST_PATTERN_GRAY_COLOR_BARS 3
#define IMX355_TEST_PATTERN_PN9 4
+#define IMX355_REG_REQ_LINK_BIT_RATE CCI_REG16(0x0820)
+
#define IMX355_REG_BINNING_MODE CCI_REG8(0x0900)
#define IMX355_REG_BINNING_TYPE CCI_REG8(0x0901)
#define IMX355_REG_BINNING_WEIGHTING CCI_REG8(0x0902)
@@ -87,9 +92,6 @@
/* Flip Control */
#define IMX355_REG_ORIENTATION CCI_REG8(0x0101)
-/* number of data lanes */
-#define IMX355_DATA_LANES 4
-
#define IMX355_PIXEL_ARRAY_TOP 0
#define IMX355_PIXEL_ARRAY_LEFT 0
#define IMX355_PIXEL_ARRAY_WIDTH 3280
@@ -120,30 +122,38 @@ struct imx355_mode {
struct imx355_clk_params {
u32 ext_clk;
- u16 extclk_freq; /* External clock (MHz) in 8.8 fixed point) */
- u16 pll_op_mpy; /* OP system PLL multiplier */
+ u16 extclk_freq; /* External clock (MHz) in 8.8 fixed point) */
+ u16 pll_op_mpy[2]; /* OP system PLL multiplier */
+ u8 pll_op_prediv[2]; /* OP system pre PLL d */
};
/*
* The clock tree is in single PLL mode, so PREDIV_VT and MPY_IVT do nothing.
- * All modes use the same PLL setup for OP, with IOPCK being 720MHz.
+ * In 4 lane mode the MIPI rate is 360Mhz (720Mbit/s) and pixel rate is
+ * 288MPix/s.
+ * In 2 lane mode the MIPI rate is 444MHz (888Mbit/s) and pixel rate
+ * 177.6MPix/s with a 24MHz clock, and 441.6MHz (883.2Mbit/s) and 176.6MPix/s
+ * with a 19.2MHz clock.
*/
static const struct imx355_clk_params imx355_clk_params[] = {
{
.ext_clk = 19200000,
- .extclk_freq = 0x1333, /* 19.2 MHz */
- .pll_op_mpy = 75, /* 19.2 / 2 * 75 = 720 MHz */
+ .extclk_freq = 0x1333,
+ .pll_op_mpy = { 75, 92 },
+ .pll_op_prediv = { 2, 2 }
},
{
.ext_clk = 24000000,
- .extclk_freq = 0x1800, /* 24.0 MHz */
- .pll_op_mpy = 60, /* 24.0 / 2 * 60 = 720 MHz */
+ .extclk_freq = 0x1800,
+ .pll_op_mpy = { 60, 111 },
+ .pll_op_prediv = { 2, 3 }
},
};
struct imx355_hwcfg {
s64 link_freq_menu;
unsigned long link_freq_bitmap;
+ unsigned int num_lanes;
};
struct imx355 {
@@ -239,7 +249,6 @@ static const struct cci_reg_sequence imx355_global_regs[] = {
{ CCI_REG8(0x305a), 0x00 },
{ CCI_REG8(0x0112), 0x0a },
{ CCI_REG8(0x0113), 0x0a },
- { CCI_REG8(0x0114), 0x03 },
{ IMX355_REG_PLL_IVT_PCK_DIV, IMX355_PLL_IVT_PCK_DIV },
{ CCI_REG8(0x0303), 0x01 },
{ CCI_REG8(0x0305), 0x02 },
@@ -249,8 +258,6 @@ static const struct cci_reg_sequence imx355_global_regs[] = {
{ CCI_REG8(0x0310), 0x00 },
{ CCI_REG8(0x0220), 0x00 },
{ CCI_REG8(0x0222), 0x01 },
- { CCI_REG8(0x0820), 0x0b },
- { CCI_REG8(0x0821), 0x40 },
{ CCI_REG8(0x3088), 0x04 },
{ CCI_REG8(0x6813), 0x02 },
{ CCI_REG8(0x6835), 0x07 },
@@ -805,6 +812,7 @@ imx355_set_pad_format(struct v4l2_subdev *sd,
__v4l2_ctrl_modify_range(imx355->vblank, IMX355_VBLANK_MIN,
height, 1, vblank_def);
__v4l2_ctrl_s_ctrl(imx355->vblank, vblank_def);
+
h_blank = mode->llp - imx355->cur_mode->width;
/*
* Currently hblank is not changeable.
@@ -868,6 +876,8 @@ static int imx355_start_streaming(struct imx355 *imx355)
{
const struct imx355_reg_list *reg_list;
const struct imx355_mode *mode;
+ int lane_idx = imx355->hwcfg->num_lanes == 4 ? 0 : 1;
+ u64 link_bitrate;
u8 binning_mode;
int ret = 0;
@@ -903,7 +913,21 @@ static int imx355_start_streaming(struct imx355 *imx355)
cci_write(imx355->regmap, IMX355_REG_EXTCLK_FREQ,
imx355->clk_params->extclk_freq, &ret);
cci_write(imx355->regmap, IMX355_REG_PLL_OP_MUL,
- imx355->clk_params->pll_op_mpy, &ret);
+ imx355->clk_params->pll_op_mpy[lane_idx], &ret);
+ cci_write(imx355->regmap, IMX355_REG_PLL_OP_PREDIV,
+ imx355->clk_params->pll_op_prediv[lane_idx], &ret);
+ cci_write(imx355->regmap, IMX355_REG_PLL_IVT_SYSCK_DIV,
+ lane_idx ? 2 : 1, &ret);
+
+ /* Set MIPI configuration */
+ cci_write(imx355->regmap, IMX355_REG_LANE_SEL,
+ imx355->hwcfg->num_lanes - 1, &ret);
+
+ link_bitrate = imx355->link_freq->qmenu_int[imx355->link_freq->val] *
+ imx355->hwcfg->num_lanes * 2;
+ do_div(link_bitrate, 1000000);
+ cci_write(imx355->regmap, IMX355_REG_REQ_LINK_BIT_RATE, link_bitrate,
+ &ret);
/* set digital gain control to all color mode */
cci_write(imx355->regmap, IMX355_REG_DPGA_USE_GLOBAL_GAIN, 1, &ret);
@@ -1089,9 +1113,9 @@ static int imx355_init_controls(struct imx355 *imx355)
imx355->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
/* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */
- pixel_rate = imx355->hwcfg->link_freq_menu * 2 * 4;
+ pixel_rate = imx355->hwcfg->link_freq_menu * 2 * imx355->hwcfg->num_lanes;
do_div(pixel_rate, 10);
- /* By default, PIXEL_RATE is read only */
+
v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, V4L2_CID_PIXEL_RATE,
pixel_rate, pixel_rate, 1, pixel_rate);
@@ -1174,6 +1198,7 @@ static struct imx355_hwcfg *imx355_get_hwcfg(struct imx355 *imx355)
const struct imx355_clk_params *clk = imx355->clk_params;
struct fwnode_handle *ep;
struct fwnode_handle *fwnode = dev_fwnode(dev);
+ int lane_idx;
int ret;
if (!fwnode)
@@ -1191,11 +1216,15 @@ static struct imx355_hwcfg *imx355_get_hwcfg(struct imx355 *imx355)
if (!cfg)
goto out_err;
- if (bus_cfg.bus.mipi_csi2.num_data_lanes != IMX355_DATA_LANES)
+ if (bus_cfg.bus.mipi_csi2.num_data_lanes != 2 &&
+ bus_cfg.bus.mipi_csi2.num_data_lanes != 4)
goto out_err;
- cfg->link_freq_menu = (clk->ext_clk * clk->pll_op_mpy) /
- (IMX355_PLL_OP_PREDIV * 2);
+ cfg->num_lanes = bus_cfg.bus.mipi_csi2.num_data_lanes;
+
+ lane_idx = cfg->num_lanes == 4 ? 0 : 1;
+ cfg->link_freq_menu = (clk->ext_clk * clk->pll_op_mpy[lane_idx]) /
+ (clk->pll_op_prediv[lane_idx] * 2);
ret = v4l2_link_freq_to_bitmap(dev, bus_cfg.link_frequencies,
bus_cfg.nr_of_link_frequencies,
&cfg->link_freq_menu, 1,
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v2 19/20] media: imx355: Switch to using the subdev state
2026-07-07 17:04 [PATCH v2 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
` (17 preceding siblings ...)
2026-07-07 17:04 ` [PATCH v2 18/20] media: imx355: Support 2 lane readout Dave Stevenson
@ 2026-07-07 17:04 ` Dave Stevenson
2026-07-07 19:34 ` sashiko-bot
2026-07-07 17:04 ` [PATCH v2 20/20] media: imx355: Remove storing cur_mode in the state Dave Stevenson
19 siblings, 1 reply; 34+ messages in thread
From: Dave Stevenson @ 2026-07-07 17:04 UTC (permalink / raw)
To: Tianshu Qiu, Sakari Ailus, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Richard Acayan
Cc: linux-media, linux-kernel, David Heidelberg, Jacopo Mondi,
devicetree, Dave Stevenson
The subdev state is now preferred rather than handling crop
and format within the driver state, so switch the driver to
using it.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/media/i2c/imx355.c | 169 +++++++++++++--------------------------------
1 file changed, 49 insertions(+), 120 deletions(-)
diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
index 10b9cf56e8c5..bb620ebb074f 100644
--- a/drivers/media/i2c/imx355.c
+++ b/drivers/media/i2c/imx355.c
@@ -179,13 +179,6 @@ struct imx355 {
struct imx355_hwcfg *hwcfg;
const struct imx355_clk_params *clk_params;
- /*
- * Mutex for serialized access:
- * Protect sensor set pad format and start/stop streaming safely.
- * Protect access to sensor v4l2 controls.
- */
- struct mutex mutex;
-
struct gpio_desc *reset_gpio;
struct regulator_bulk_data *supplies;
};
@@ -592,35 +585,11 @@ static u32 imx355_get_format_code(struct imx355 *imx355)
{ MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SBGGR10_1X10, },
};
- lockdep_assert_held(&imx355->mutex);
code = codes[imx355->vflip->val][imx355->hflip->val];
return code;
}
-/* Open sub-device */
-static int imx355_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
-{
- struct imx355 *imx355 = to_imx355(sd);
- struct v4l2_mbus_framefmt *try_fmt =
- v4l2_subdev_state_get_format(fh->state, 0);
- struct v4l2_rect *crop = v4l2_subdev_state_get_crop(fh->state, 0);
-
- mutex_lock(&imx355->mutex);
-
- /* Initialize try_fmt */
- try_fmt->width = imx355->cur_mode->width;
- try_fmt->height = imx355->cur_mode->height;
- try_fmt->code = imx355_get_format_code(imx355);
- try_fmt->field = V4L2_FIELD_NONE;
-
- *crop = imx355->cur_mode->crop;
-
- mutex_unlock(&imx355->mutex);
-
- return 0;
-}
-
static int imx355_set_ctrl(struct v4l2_ctrl *ctrl)
{
struct imx355 *imx355 = container_of(ctrl->handler,
@@ -628,6 +597,9 @@ static int imx355_set_ctrl(struct v4l2_ctrl *ctrl)
s64 max;
int ret;
+ state = v4l2_subdev_get_locked_active_state(&imx355->sd);
+ format = v4l2_subdev_state_get_format(state, 0);
+
/* Propagate change of current control to all related controls */
switch (ctrl->id) {
case V4L2_CID_VBLANK:
@@ -700,9 +672,7 @@ static int imx355_enum_mbus_code(struct v4l2_subdev *sd,
if (code->index > 0)
return -EINVAL;
- mutex_lock(&imx355->mutex);
code->code = imx355_get_format_code(imx355);
- mutex_unlock(&imx355->mutex);
return 0;
}
@@ -716,12 +686,9 @@ static int imx355_enum_frame_size(struct v4l2_subdev *sd,
if (fse->index >= ARRAY_SIZE(supported_modes))
return -EINVAL;
- mutex_lock(&imx355->mutex);
if (fse->code != imx355_get_format_code(imx355)) {
- mutex_unlock(&imx355->mutex);
return -EINVAL;
}
- mutex_unlock(&imx355->mutex);
fse->min_width = supported_modes[fse->index].width;
fse->max_width = fse->min_width;
@@ -745,36 +712,6 @@ static void imx355_update_pad_format(struct imx355 *imx355,
fmt->format.xfer_func = V4L2_XFER_FUNC_NONE;
}
-static int imx355_do_get_pad_format(struct imx355 *imx355,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *fmt)
-{
- struct v4l2_mbus_framefmt *framefmt;
-
- if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
- fmt->format = *framefmt;
- } else {
- imx355_update_pad_format(imx355, imx355->cur_mode, fmt);
- }
-
- return 0;
-}
-
-static int imx355_get_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *fmt)
-{
- struct imx355 *imx355 = to_imx355(sd);
- int ret;
-
- mutex_lock(&imx355->mutex);
- ret = imx355_do_get_pad_format(imx355, sd_state, fmt);
- mutex_unlock(&imx355->mutex);
-
- return ret;
-}
-
static int
imx355_set_pad_format(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
@@ -783,12 +720,11 @@ imx355_set_pad_format(struct v4l2_subdev *sd,
struct imx355 *imx355 = to_imx355(sd);
const struct imx355_mode *mode;
struct v4l2_mbus_framefmt *framefmt;
+ struct v4l2_rect *crop;
s32 vblank_def;
s64 h_blank;
u32 height;
- mutex_lock(&imx355->mutex);
-
/*
* Only one bayer order is supported.
* It depends on the flip settings.
@@ -800,10 +736,18 @@ imx355_set_pad_format(struct v4l2_subdev *sd,
width, height,
fmt->format.width, fmt->format.height);
imx355_update_pad_format(imx355, mode, fmt);
- if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
- *framefmt = fmt->format;
- } else {
+
+ framefmt = v4l2_subdev_state_get_format(sd_state, 0);
+
+ *framefmt = fmt->format;
+
+ crop = v4l2_subdev_state_get_crop(sd_state, 0);
+ crop->width = mode->crop.width;
+ crop->height = mode->crop.height;
+ crop->left = mode->crop.left;
+ crop->top = mode->crop.top;
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
imx355->cur_mode = mode;
/* Update limits and set FPS to default */
height = imx355->cur_mode->height;
@@ -822,41 +766,17 @@ imx355_set_pad_format(struct v4l2_subdev *sd,
h_blank, 1, h_blank);
}
- mutex_unlock(&imx355->mutex);
-
return 0;
}
-static void
-__imx355_get_pad_crop(struct imx355 *imx355,
- struct v4l2_subdev_state *sd_state, unsigned int pad,
- enum v4l2_subdev_format_whence which, struct v4l2_rect *r)
-{
- switch (which) {
- case V4L2_SUBDEV_FORMAT_TRY:
- *r = *v4l2_subdev_state_get_crop(sd_state, pad);
- break;
- case V4L2_SUBDEV_FORMAT_ACTIVE:
- *r = imx355->cur_mode->crop;
- break;
- }
-}
-
static int imx355_get_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
switch (sel->target) {
- case V4L2_SEL_TGT_CROP: {
- struct imx355 *imx355 = to_imx355(sd);
-
- mutex_lock(&imx355->mutex);
- __imx355_get_pad_crop(imx355, sd_state, sel->pad, sel->which,
- &sel->r);
- mutex_unlock(&imx355->mutex);
-
+ case V4L2_SEL_TGT_CROP:
+ sel->r = *v4l2_subdev_state_get_crop(sd_state, 0);
return 0;
- }
case V4L2_SEL_TGT_CROP_DEFAULT:
case V4L2_SEL_TGT_CROP_BOUNDS:
case V4L2_SEL_TGT_NATIVE_SIZE:
@@ -871,6 +791,21 @@ static int imx355_get_selection(struct v4l2_subdev *sd,
return -EINVAL;
}
+static int imx355_entity_init_state(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *sd_state)
+{
+ struct v4l2_subdev_format fmt = { };
+
+ fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+ fmt.format.code = MEDIA_BUS_FMT_SRGGB10_1X10;
+ fmt.format.width = supported_modes[0].width;
+ fmt.format.height = supported_modes[0].height;
+
+ imx355_set_pad_format(subdev, sd_state, &fmt);
+
+ return 0;
+}
+
/* Start streaming */
static int imx355_start_streaming(struct imx355 *imx355)
{
@@ -958,12 +893,10 @@ static int imx355_set_stream(struct v4l2_subdev *sd, int enable)
struct imx355 *imx355 = to_imx355(sd);
int ret = 0;
- mutex_lock(&imx355->mutex);
-
if (enable) {
ret = pm_runtime_resume_and_get(imx355->dev);
if (ret < 0)
- goto err_unlock;
+ return ret;
/*
* Apply default & customized values
@@ -981,14 +914,10 @@ static int imx355_set_stream(struct v4l2_subdev *sd, int enable)
__v4l2_ctrl_grab(imx355->vflip, enable);
__v4l2_ctrl_grab(imx355->hflip, enable);
- mutex_unlock(&imx355->mutex);
-
return ret;
err_rpm_put:
pm_runtime_put_autosuspend(imx355->dev);
-err_unlock:
- mutex_unlock(&imx355->mutex);
return ret;
}
@@ -1022,7 +951,7 @@ static const struct v4l2_subdev_video_ops imx355_video_ops = {
static const struct v4l2_subdev_pad_ops imx355_pad_ops = {
.enum_mbus_code = imx355_enum_mbus_code,
- .get_fmt = imx355_get_pad_format,
+ .get_fmt = v4l2_subdev_get_fmt,
.set_fmt = imx355_set_pad_format,
.enum_frame_size = imx355_enum_frame_size,
.get_selection = imx355_get_selection,
@@ -1039,7 +968,7 @@ static const struct media_entity_operations imx355_subdev_entity_ops = {
};
static const struct v4l2_subdev_internal_ops imx355_internal_ops = {
- .open = imx355_open,
+ .init_state = imx355_entity_init_state,
};
static int imx355_power_off(struct device *dev)
@@ -1105,7 +1034,6 @@ static int imx355_init_controls(struct imx355 *imx355)
if (ret)
return ret;
- ctrl_hdlr->lock = &imx355->mutex;
imx355->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx355_ctrl_ops,
V4L2_CID_LINK_FREQ, 0, 0,
&imx355->hwcfg->link_freq_menu);
@@ -1254,8 +1182,6 @@ static int imx355_probe(struct i2c_client *client)
imx355->dev = &client->dev;
- mutex_init(&imx355->mutex);
-
imx355->regmap = devm_cci_regmap_init_i2c(client, 16);
if (IS_ERR(imx355->regmap)) {
dev_err(imx355->dev, "Unable to initialize I2C\n");
@@ -1285,7 +1211,7 @@ static int imx355_probe(struct i2c_client *client)
&imx355->supplies);
if (ret) {
dev_err_probe(imx355->dev, ret, "could not get regulators");
- goto error_probe;
+ return ret;
}
imx355->reset_gpio = devm_gpiod_get_optional(imx355->dev, "reset",
@@ -1293,7 +1219,7 @@ static int imx355_probe(struct i2c_client *client)
if (IS_ERR(imx355->reset_gpio)) {
ret = dev_err_probe(imx355->dev, PTR_ERR(imx355->reset_gpio),
"failed to get gpios");
- goto error_probe;
+ return ret;
}
/* Initialize subdev */
@@ -1302,13 +1228,12 @@ static int imx355_probe(struct i2c_client *client)
imx355->hwcfg = imx355_get_hwcfg(imx355);
if (!imx355->hwcfg) {
dev_err(imx355->dev, "failed to get hwcfg");
- ret = -ENODEV;
- goto error_probe;
+ return -ENODEV;
}
ret = imx355_power_on(imx355->dev);
if (ret)
- goto error_probe;
+ return ret;
/* Check module identity */
ret = imx355_identify_module(imx355);
@@ -1341,6 +1266,13 @@ static int imx355_probe(struct i2c_client *client)
goto error_handler_free;
}
+ imx355->sd.state_lock = imx355->ctrl_handler.lock;
+ ret = v4l2_subdev_init_finalize(&imx355->sd);
+ if (ret < 0) {
+ dev_err_probe(imx355->dev, ret, "subdev init error\n");
+ goto error_handler_free;
+ }
+
/*
* Device is already turned on by i2c-core with ACPI domain PM.
* Enable runtime PM and turn off the device.
@@ -1360,6 +1292,7 @@ static int imx355_probe(struct i2c_client *client)
error_media_entity_runtime_pm:
pm_runtime_disable(imx355->dev);
pm_runtime_set_suspended(imx355->dev);
+ v4l2_subdev_cleanup(&imx355->sd);
media_entity_cleanup(&imx355->sd.entity);
error_handler_free:
@@ -1368,9 +1301,6 @@ static int imx355_probe(struct i2c_client *client)
error_power_off:
imx355_power_off(imx355->dev);
-error_probe:
- mutex_destroy(&imx355->mutex);
-
return ret;
}
@@ -1380,6 +1310,7 @@ static void imx355_remove(struct i2c_client *client)
struct imx355 *imx355 = to_imx355(sd);
v4l2_async_unregister_subdev(sd);
+ v4l2_subdev_cleanup(sd);
media_entity_cleanup(&sd->entity);
v4l2_ctrl_handler_free(sd->ctrl_handler);
@@ -1389,8 +1320,6 @@ static void imx355_remove(struct i2c_client *client)
imx355_power_off(imx355->dev);
pm_runtime_set_suspended(imx355->dev);
}
-
- mutex_destroy(&imx355->mutex);
}
static const struct acpi_device_id imx355_acpi_ids[] __maybe_unused = {
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v2 20/20] media: imx355: Remove storing cur_mode in the state
2026-07-07 17:04 [PATCH v2 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
` (18 preceding siblings ...)
2026-07-07 17:04 ` [PATCH v2 19/20] media: imx355: Switch to using the subdev state Dave Stevenson
@ 2026-07-07 17:04 ` Dave Stevenson
2026-07-07 17:37 ` sashiko-bot
19 siblings, 1 reply; 34+ messages in thread
From: Dave Stevenson @ 2026-07-07 17:04 UTC (permalink / raw)
To: Tianshu Qiu, Sakari Ailus, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Richard Acayan
Cc: linux-media, linux-kernel, David Heidelberg, Jacopo Mondi,
devicetree, Dave Stevenson
All the information for the mode is now stored within
the subdev state, so configure the sensor based on that.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/media/i2c/imx355.c | 65 ++++++++++++++++++++++------------------------
1 file changed, 31 insertions(+), 34 deletions(-)
diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
index bb620ebb074f..f31833e5d1d1 100644
--- a/drivers/media/i2c/imx355.c
+++ b/drivers/media/i2c/imx355.c
@@ -173,9 +173,6 @@ struct imx355 {
struct v4l2_ctrl *vflip;
struct v4l2_ctrl *hflip;
- /* Current mode */
- const struct imx355_mode *cur_mode;
-
struct imx355_hwcfg *hwcfg;
const struct imx355_clk_params *clk_params;
@@ -594,6 +591,8 @@ static int imx355_set_ctrl(struct v4l2_ctrl *ctrl)
{
struct imx355 *imx355 = container_of(ctrl->handler,
struct imx355, ctrl_handler);
+ const struct v4l2_mbus_framefmt *format = NULL;
+ struct v4l2_subdev_state *state;
s64 max;
int ret;
@@ -604,7 +603,7 @@ static int imx355_set_ctrl(struct v4l2_ctrl *ctrl)
switch (ctrl->id) {
case V4L2_CID_VBLANK:
/* Update max exposure while meeting expected vblanking */
- max = imx355->cur_mode->height + ctrl->val - IMX355_EXPOSURE_OFFSET;
+ max = format->height + ctrl->val - IMX355_EXPOSURE_OFFSET;
__v4l2_ctrl_modify_range(imx355->exposure,
imx355->exposure->minimum,
max, imx355->exposure->step, max);
@@ -635,7 +634,7 @@ static int imx355_set_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_VBLANK:
/* Update FLL that meets expected vertical blanking */
ret = cci_write(imx355->regmap, IMX355_REG_FLL,
- imx355->cur_mode->height + ctrl->val, NULL);
+ format->height + ctrl->val, NULL);
break;
case V4L2_CID_TEST_PATTERN:
ret = cci_write(imx355->regmap, IMX355_REG_TEST_PATTERN,
@@ -721,9 +720,7 @@ imx355_set_pad_format(struct v4l2_subdev *sd,
const struct imx355_mode *mode;
struct v4l2_mbus_framefmt *framefmt;
struct v4l2_rect *crop;
- s32 vblank_def;
s64 h_blank;
- u32 height;
/*
* Only one bayer order is supported.
@@ -748,16 +745,14 @@ imx355_set_pad_format(struct v4l2_subdev *sd,
crop->top = mode->crop.top;
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
- imx355->cur_mode = mode;
/* Update limits and set FPS to default */
- height = imx355->cur_mode->height;
- vblank_def = imx355->cur_mode->fll_def - height;
- height = IMX355_FLL_MAX - height;
__v4l2_ctrl_modify_range(imx355->vblank, IMX355_VBLANK_MIN,
- height, 1, vblank_def);
- __v4l2_ctrl_s_ctrl(imx355->vblank, vblank_def);
+ IMX355_FLL_MAX - mode->height, 1,
+ mode->fll_def - mode->height);
+ __v4l2_ctrl_s_ctrl(imx355->vblank, mode->fll_def - mode->height);
+
+ h_blank = mode->llp - mode->width;
- h_blank = mode->llp - imx355->cur_mode->width;
/*
* Currently hblank is not changeable.
* So FPS control is done only by vblank.
@@ -809,9 +804,11 @@ static int imx355_entity_init_state(struct v4l2_subdev *subdev,
/* Start streaming */
static int imx355_start_streaming(struct imx355 *imx355)
{
- const struct imx355_reg_list *reg_list;
+ const struct v4l2_mbus_framefmt *fmt;
+ struct v4l2_subdev_state *state;
const struct imx355_mode *mode;
int lane_idx = imx355->hwcfg->num_lanes == 4 ? 0 : 1;
+ struct v4l2_rect *crop;
u64 link_bitrate;
u8 binning_mode;
int ret = 0;
@@ -820,25 +817,29 @@ static int imx355_start_streaming(struct imx355 *imx355)
cci_multi_reg_write(imx355->regmap, imx355_global_regs,
ARRAY_SIZE(imx355_global_regs), &ret);
- /* Apply default values of current mode */
- mode = imx355->cur_mode;
- reg_list = &mode->reg_list;
- cci_multi_reg_write(imx355->regmap, reg_list->regs,
- reg_list->num_of_regs, &ret);
+ /* Apply values of current mode */
+ state = v4l2_subdev_get_locked_active_state(&imx355->sd);
+ fmt = v4l2_subdev_state_get_format(state, 0);
+ crop = v4l2_subdev_state_get_crop(state, 0);
+ mode = v4l2_find_nearest_size(supported_modes,
+ ARRAY_SIZE(supported_modes),
+ width, height, fmt->width, fmt->height);
+ cci_multi_reg_write(imx355->regmap, mode->reg_list.regs,
+ mode->reg_list.num_of_regs, &ret);
/* Set readout crop and size registers */
- cci_write(imx355->regmap, IMX355_REG_X_ADD_START, mode->crop.left,
+ cci_write(imx355->regmap, IMX355_REG_X_ADD_START, crop->left,
&ret);
- cci_write(imx355->regmap, IMX355_REG_Y_ADD_START, mode->crop.top, &ret);
+ cci_write(imx355->regmap, IMX355_REG_Y_ADD_START, crop->top, &ret);
cci_write(imx355->regmap, IMX355_REG_X_ADD_END,
- mode->crop.width + mode->crop.left - 1, &ret);
+ crop->width + crop->left - 1, &ret);
cci_write(imx355->regmap, IMX355_REG_Y_ADD_END,
- mode->crop.height + mode->crop.top - 1, &ret);
- cci_write(imx355->regmap, IMX355_REG_X_OUT_SIZE, mode->width, &ret);
- cci_write(imx355->regmap, IMX355_REG_Y_OUT_SIZE, mode->height, &ret);
+ crop->height + crop->top - 1, &ret);
+ cci_write(imx355->regmap, IMX355_REG_X_OUT_SIZE, fmt->width, &ret);
+ cci_write(imx355->regmap, IMX355_REG_Y_OUT_SIZE, fmt->height, &ret);
- binning_mode = ((mode->crop.width / mode->width) << 4) |
- (mode->crop.height / mode->height);
+ binning_mode = ((crop->width / fmt->width) << 4) |
+ (crop->height / fmt->height);
cci_write(imx355->regmap, IMX355_REG_BINNING_MODE,
binning_mode == 0x11 ? 0x00 : 0x01, &ret);
cci_write(imx355->regmap, IMX355_REG_BINNING_TYPE, binning_mode, &ret);
@@ -869,7 +870,7 @@ static int imx355_start_streaming(struct imx355 *imx355)
/* set line length */
cci_write(imx355->regmap, IMX355_REG_LLP,
- imx355->hblank->val + imx355->cur_mode->width, &ret);
+ imx355->hblank->val + fmt->width, &ret);
/* Apply customized values from user */
if (!ret)
@@ -1022,11 +1023,11 @@ static int imx355_init_controls(struct imx355 *imx355)
{
struct v4l2_fwnode_device_properties props;
struct v4l2_ctrl_handler *ctrl_hdlr;
+ const struct imx355_mode *mode = &supported_modes[0];
s64 exposure_max;
s64 vblank_def;
s64 hblank;
u64 pixel_rate;
- const struct imx355_mode *mode;
int ret;
ctrl_hdlr = &imx355->ctrl_handler;
@@ -1048,7 +1049,6 @@ static int imx355_init_controls(struct imx355 *imx355)
pixel_rate, pixel_rate, 1, pixel_rate);
/* Initialize vblank/hblank/exposure parameters based on current mode */
- mode = imx355->cur_mode;
vblank_def = mode->fll_def - mode->height;
imx355->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops,
V4L2_CID_VBLANK, IMX355_VBLANK_MIN,
@@ -1242,9 +1242,6 @@ static int imx355_probe(struct i2c_client *client)
goto error_power_off;
}
- /* Set default mode to max resolution */
- imx355->cur_mode = &supported_modes[0];
-
ret = imx355_init_controls(imx355);
if (ret) {
dev_err(imx355->dev, "failed to init controls: %d", ret);
--
2.34.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* Re: [PATCH v2 06/20] media: imx355: Set register LINE_LENGTH_PCK programmatically
2026-07-07 17:04 ` [PATCH v2 06/20] media: imx355: Set register LINE_LENGTH_PCK programmatically Dave Stevenson
@ 2026-07-07 17:12 ` sashiko-bot
0 siblings, 0 replies; 34+ messages in thread
From: sashiko-bot @ 2026-07-07 17:12 UTC (permalink / raw)
To: Dave Stevenson; +Cc: conor+dt, robh, devicetree
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] The arguments `len` and `val` are swapped in the call to `imx355_write_reg()` for `IMX355_REG_LLP`, causing streaming to fail unconditionally with `-EINVAL`.
--
--- Patch [6]: [PATCH v2 06/20] media: imx355: Set register LINE_LENGTH_PCK programmatically ---
commit 0e41a9d7ebe7908de03f784b605b040468271935
Author: Dave Stevenson <dave.stevenson@raspberrypi.com>
media: imx355: Set register LINE_LENGTH_PCK programmatically
This commit removes duplicated Line Length Pixel (LLP) values from the mode
register lists and sets the LLP register programmatically when starting
the stream.
> diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
> index 363b5667b6c9a..66e70650e666b 100644
> --- a/drivers/media/i2c/imx355.c
> +++ b/drivers/media/i2c/imx355.c
[ ... ]
> @@ -1058,6 +1033,13 @@ static int imx355_start_streaming(struct imx355 *imx355)
> if (ret)
> return ret;
>
> + /* set line length */
> + ret = imx355_write_reg(imx355, IMX355_REG_LLP,
> + imx355->hblank->val + imx355->cur_mode->width,
> + 2);
[Severity: High]
Are the len and val arguments swapped in this call to imx355_write_reg()?
If the line length value (which can exceed 3000) is passed as the len
argument, won't this unconditionally fail the bounds check in
imx355_write_reg():
drivers/media/i2c/imx355.c:imx355_write_reg() {
...
if (len > 4)
return -EINVAL;
...
}
and return -EINVAL, effectively preventing the camera from starting?
> + if (ret)
> + return ret;
> +
> /* Apply customized values from user */
> ret = __v4l2_ctrl_handler_setup(imx355->sd.ctrl_handler);
> if (ret)
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260707-media-imx355-v2-0-1683ec07b897@raspberrypi.com?part=6
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v2 03/20] media: imx355: Remove duplicated registers from the mode tables
2026-07-07 17:04 ` [PATCH v2 03/20] media: imx355: Remove duplicated registers from the mode tables Dave Stevenson
@ 2026-07-07 17:14 ` sashiko-bot
0 siblings, 0 replies; 34+ messages in thread
From: sashiko-bot @ 2026-07-07 17:14 UTC (permalink / raw)
To: Dave Stevenson; +Cc: conor+dt, robh, devicetree
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Register 0x030b (value 0x01) was accidentally omitted when common registers were moved into the global register array, causing it to be dropped entirely from the initialization sequence.
--
--- Patch [3]: [PATCH v2 03/20] media: imx355: Remove duplicated registers from the mode tables ---
commit 5dff7585c6b01310348ab92104e830ef77f11da0
Author: Dave Stevenson <dave.stevenson@raspberrypi.com>
media: imx355: Remove duplicated registers from the mode tables
A large number of registers are identical within all the modes.
This patch moves those duplicated registers to imx355_global_regs to
reduce duplication.
> diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
> index ad9a9464175b1..83a59aa8b0985 100644
> --- a/drivers/media/i2c/imx355.c
> +++ b/drivers/media/i2c/imx355.c
> @@ -221,6 +221,28 @@ static const struct imx355_reg imx355_global_regs[] = {
> { 0x68b0, 0x00 },
> { 0x3058, 0x00 },
> { 0x305a, 0x00 },
> + { 0x0112, 0x0a },
> + { 0x0113, 0x0a },
> + { 0x0114, 0x03 },
> + { 0x0301, 0x05 },
> + { 0x0303, 0x01 },
> + { 0x0305, 0x02 },
> + { 0x0306, 0x00 },
> + { 0x0307, 0x78 },
> + { 0x030d, 0x02 },
[Severity: High]
Was register 0x030b unintentionally omitted from this list?
The original mode tables contained { 0x030b, 0x01 } between 0x0307 and 0x030d,
but it appears missing in the new global register array.
Omitting this PLL configuration register initialization could leave the clock
divider in an undefined state. Does this misconfigure the pixel clock when
imx355_global_regs is applied during sensor start-up?
> + { 0x0310, 0x00 },
> + { 0x0220, 0x00 },
> + { 0x0222, 0x01 },
[ ... ]
> @@ -253,32 +270,11 @@ static const struct imx355_reg mode_3268x2448_regs[] = {
> { 0x034d, 0xc4 },
> { 0x034e, 0x09 },
> { 0x034f, 0x90 },
> - { 0x0301, 0x05 },
> - { 0x0303, 0x01 },
> - { 0x0305, 0x02 },
> - { 0x0306, 0x00 },
> - { 0x0307, 0x78 },
> - { 0x030b, 0x01 },
> - { 0x030d, 0x02 },
> - { 0x0310, 0x00 },
> { 0x0700, 0x00 },
> { 0x0701, 0x10 },
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260707-media-imx355-v2-0-1683ec07b897@raspberrypi.com?part=3
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v2 09/20] media: imx355: pixel_rate never changes, so don't recompute
2026-07-07 17:04 ` [PATCH v2 09/20] media: imx355: pixel_rate never changes, so don't recompute Dave Stevenson
@ 2026-07-07 17:15 ` sashiko-bot
0 siblings, 0 replies; 34+ messages in thread
From: sashiko-bot @ 2026-07-07 17:15 UTC (permalink / raw)
To: Dave Stevenson; +Cc: conor+dt, robh, devicetree
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] In the probe error path, `imx355_power_off()` can be called twice if `v4l2_async_register_subdev_sensor()` fails, leading to unbalanced clock and regulator disables.
--
--- Patch [9]: [PATCH v2 09/20] media: imx355: pixel_rate never changes, so don't recompute ---
commit b383e35f1be32e2228da9d8a41ed9f15cb5ff8e5
Author: Dave Stevenson <dave.stevenson@raspberrypi.com>
media: imx355: pixel_rate never changes, so don't recompute
The pixel rate is always the same, so there is no need to try and
recompute it in imx355_set_pad_format, and then no need to have the
pointer to it stored.
> diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
> index 20cf6afee43ee..9d977bac23b6c 100644
> --- a/drivers/media/i2c/imx355.c
> +++ b/drivers/media/i2c/imx355.c
[ ... ]
This is a pre-existing issue, but I noticed a potential double power-off
in the probe error handling path while reviewing this file.
drivers/media/i2c/imx355.c:imx355_probe() {
...
pm_runtime_set_active(imx355->dev);
pm_runtime_enable(imx355->dev);
pm_runtime_idle(imx355->dev);
pm_runtime_set_autosuspend_delay(imx355->dev, 1000);
pm_runtime_use_autosuspend(imx355->dev);
ret = v4l2_async_register_subdev_sensor(&imx355->sd);
if (ret < 0)
goto error_media_entity_runtime_pm;
return 0;
error_media_entity_runtime_pm:
pm_runtime_disable(imx355->dev);
pm_runtime_set_suspended(imx355->dev);
v4l2_subdev_cleanup(&imx355->sd);
media_entity_cleanup(&imx355->sd.entity);
error_handler_free:
v4l2_ctrl_handler_free(imx355->sd.ctrl_handler);
error_power_off:
imx355_power_off(imx355->dev);
return ret;
}
[Severity: High]
If v4l2_async_register_subdev_sensor() fails after the device was already
suspended by pm_runtime_idle(), won't the code fall through to
error_power_off and call imx355_power_off() a second time?
Calling regulator_bulk_disable() and clk_disable_unprepare() on already
disabled resources might cause unbalanced disable warnings and refcount
underflows. If these resources are shared with other active devices, could
this unexpected force-disable break functionality for those other devices?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260707-media-imx355-v2-0-1683ec07b897@raspberrypi.com?part=9
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v2 07/20] media: imx355: Set binning mode registers programmatically
2026-07-07 17:04 ` [PATCH v2 07/20] media: imx355: Set binning mode registers programmatically Dave Stevenson
@ 2026-07-07 17:15 ` sashiko-bot
0 siblings, 0 replies; 34+ messages in thread
From: sashiko-bot @ 2026-07-07 17:15 UTC (permalink / raw)
To: Dave Stevenson; +Cc: conor+dt, devicetree, robh
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] The arguments for 'length' and 'value' are swapped in the `imx355_write_reg()` call for `IMX355_REG_LLP`, breaking sensor streaming.
Pre-existing issues:
- [High] This problem wasn't introduced by this patch, but it causes a double-disable of regulators and clocks in the probe error path due to unconditional power off after PM runtime idle.
--
--- Patch [7]: [PATCH v2 07/20] media: imx355: Set binning mode registers programmatically ---
commit 1bc86e7b2e33db0b1ab1611b670669f99ca08232
Author: Dave Stevenson <dave.stevenson@raspberrypi.com>
media: imx355: Set binning mode registers programmatically
Compute the binning registers based on the difference between
the mode width/height vs the crop width/height.
> diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
> index 66e70650e666b..cfc47b5100c46 100644
> --- a/drivers/media/i2c/imx355.c
> +++ b/drivers/media/i2c/imx355.c
[ ... ]
> @@ -1018,6 +981,20 @@ static int imx355_start_streaming(struct imx355 *imx355)
> if (ret)
> return ret;
>
[Severity: High]
Are the arguments for value and length swapped in the imx355_write_reg() call
for IMX355_REG_LLP?
Looking at the code just before this addition in imx355_start_streaming():
/* set line length */
ret = imx355_write_reg(imx355, IMX355_REG_LLP,
imx355->hblank->val + imx355->cur_mode->width,
2);
The length parameter receives the computed line length (which can be in the
thousands), while imx355_write_reg() strictly enforces a maximum length of 4.
Will this cause imx355_start_streaming() to immediately fail with -EINVAL and
prevent the sensor from starting?
> + binning_mode = ((mode->crop.width / mode->width) << 4) |
> + (mode->crop.height / mode->height);
> + ret = imx355_write_reg(imx355, IMX355_REG_BINNING_MODE, 1,
> + binning_mode == 0x11 ? 0x00 : 0x01);
> + if (ret)
> + return ret;
[ ... ]
[Severity: High]
This isn't a bug introduced by this patch, but does the error path in
imx355_probe() unconditionally cause a double-disable of regulators and
clocks?
When pm_runtime_idle() is called with a usage count of 0, it can invoke
imx355_power_off() to physically power down the sensor. If
v4l2_async_register_subdev_sensor() subsequently fails, the error path
blindly calls imx355_power_off() a second time:
drivers/media/i2c/imx355.c:imx355_probe() {
...
error_power_off:
imx355_power_off(imx355->dev);
...
}
Will this lead to an unbalanced disable, potentially causing issues if the
clocks or regulators are shared and actively used by another subsystem?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260707-media-imx355-v2-0-1683ec07b897@raspberrypi.com?part=7
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v2 14/20] media: imx355: Set the colorspace in the format
2026-07-07 17:04 ` [PATCH v2 14/20] media: imx355: Set the colorspace in the format Dave Stevenson
@ 2026-07-07 17:16 ` sashiko-bot
0 siblings, 0 replies; 34+ messages in thread
From: sashiko-bot @ 2026-07-07 17:16 UTC (permalink / raw)
To: Dave Stevenson; +Cc: robh, devicetree, conor+dt
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The newly added colorspace fields are not initialized for the default TRY format in `imx355_open()`.
--
--- Patch [14]: [PATCH v2 14/20] media: imx355: Set the colorspace in the format ---
commit 8e7fc1bcad81f6e37fba5685592010dfd48dcc99
Author: Dave Stevenson <dave.stevenson@raspberrypi.com>
media: imx355: Set the colorspace in the format
This commit updates the imx355 driver to set the appropriate colorspace
fields for a raw image sensor, rather than leaving them as 0.
(Note: The format of this review is altered to provide a free-form summary
due to restrictions on quoting the original patch code.)
[Severity: Medium]
Does this code leave the TRY format in an inconsistent state?
The commit adds assignments for colorspace, ycbcr_enc, quantization, and
xfer_func in imx355_update_pad_format(). However, looking at imx355_open()
in drivers/media/i2c/imx355.c, the try_fmt fields are manually initialized
when the subdev file handle is opened, but the new colorspace assignments
are missing from this initialization.
This means the initial TRY format queried via VIDIOC_SUBDEV_G_FMT might
return an inconsistent colorspace (V4L2_COLORSPACE_DEFAULT) compared to the
ACTIVE format default (V4L2_COLORSPACE_RAW) until a format is explicitly
set. Should the TRY format initialization in imx355_open() be updated to
include these new default values?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260707-media-imx355-v2-0-1683ec07b897@raspberrypi.com?part=14
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v2 11/20] media: imx355: Add support for get_selection
2026-07-07 17:04 ` [PATCH v2 11/20] media: imx355: Add support for get_selection Dave Stevenson
@ 2026-07-07 17:18 ` sashiko-bot
0 siblings, 0 replies; 34+ messages in thread
From: sashiko-bot @ 2026-07-07 17:18 UTC (permalink / raw)
To: Dave Stevenson; +Cc: conor+dt, robh, devicetree
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The TRY crop rectangle is not updated when the TRY format is changed, causing get_selection(TRY) to return stale or incorrect crop data.
--
--- Patch [11]: [PATCH v2 11/20] media: imx355: Add support for get_selection ---
commit c10d5f7839a602e25b0eddb66d5d44872dd34f8a
Author: Dave Stevenson <dave.stevenson@raspberrypi.com>
media: imx355: Add support for get_selection
Provide all the cropping information via get_selection.
> diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
> index 354092295b7c3..0f5fbe21d7fb2 100644
> --- a/drivers/media/i2c/imx355.c
> +++ b/drivers/media/i2c/imx355.c
[ ... ]
> @@ -891,6 +899,50 @@ imx355_set_pad_format(struct v4l2_subdev *sd,
> return 0;
> }
>
> +static void
> +__imx355_get_pad_crop(struct imx355 *imx355,
> + struct v4l2_subdev_state *sd_state, unsigned int pad,
> + enum v4l2_subdev_format_whence which, struct v4l2_rect *r)
> +{
> + switch (which) {
> + case V4L2_SUBDEV_FORMAT_TRY:
> + *r = *v4l2_subdev_state_get_crop(sd_state, pad);
[Severity: Medium]
Will this return stale or incorrect crop data when negotiating the TRY format?
In imx355_set_pad_format(), when the TRY format is changed via
VIDIOC_SUBDEV_S_FMT, only the frame format is updated:
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
*framefmt = fmt->format;
} else {
imx355->cur_mode = mode;
...
Because the corresponding TRY crop rectangle in the subdev state is left
unmodified, a subsequent call to VIDIOC_SUBDEV_G_SELECTION with
V4L2_SUBDEV_FORMAT_TRY and V4L2_SEL_TGT_CROP seems like it will return
outdated crop geometry.
Should imx355_set_pad_format() be updated to keep the TRY crop rectangle
in sync?
> + break;
> + case V4L2_SUBDEV_FORMAT_ACTIVE:
> + *r = imx355->cur_mode->crop;
> + break;
> + }
> +}
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260707-media-imx355-v2-0-1683ec07b897@raspberrypi.com?part=11
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v2 05/20] media: imx355: Programmatically set the crop parameters for each mode
2026-07-07 17:04 ` [PATCH v2 05/20] media: imx355: Programmatically set the crop parameters for each mode Dave Stevenson
@ 2026-07-07 17:18 ` sashiko-bot
0 siblings, 0 replies; 34+ messages in thread
From: sashiko-bot @ 2026-07-07 17:18 UTC (permalink / raw)
To: Dave Stevenson; +Cc: robh, conor+dt, devicetree
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Missing initialization of the 0x030b PLL configuration register.
--
--- Patch [5]: [PATCH v2 05/20] media: imx355: Programmatically set the crop parameters for each mode ---
commit 4df459187456782ee3ca7366e5ecefcdad82a80b
Author: Dave Stevenson <dave.stevenson@raspberrypi.com>
media: imx355: Programmatically set the crop parameters for each mode
Currently the cropping is set via register entries in the per mode
register lists. Add the crop information to the mode structure as
a v4l2_rect, and set the registers programmatically.
> diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
> index 28b210f1a8689..363b5667b6c9a 100644
> --- a/drivers/media/i2c/imx355.c
> +++ b/drivers/media/i2c/imx355.c
[ ... ]
> @@ -253,21 +261,9 @@ static const struct imx355_reg_list imx355_global_setting = {
> static const struct imx355_reg mode_3268x2448_regs[] = {
> { 0x0342, 0x0e },
> { 0x0343, 0x58 },
[Severity: High]
Is the 0x030b PLL configuration register missing from the global settings?
It looks like the 0x030b register (value 0x01) was accidentally omitted
when moving identical registers from the per-mode arrays to the global
register array in the commit "media: imx355: Remove duplicated registers
from the mode tables".
Could this omission leave the hardware at its power-on reset state and
prevent the sensor from streaming correctly when imx355_start_streaming()
applies the global settings?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260707-media-imx355-v2-0-1683ec07b897@raspberrypi.com?part=5
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v2 10/20] media: imx355: Remove redundant fll_min, and implement fixed offset
2026-07-07 17:04 ` [PATCH v2 10/20] media: imx355: Remove redundant fll_min, and implement fixed offset Dave Stevenson
@ 2026-07-07 17:18 ` sashiko-bot
0 siblings, 0 replies; 34+ messages in thread
From: sashiko-bot @ 2026-07-07 17:18 UTC (permalink / raw)
To: Dave Stevenson; +Cc: devicetree, robh, conor+dt
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [Medium] The V4L2_CID_EXPOSURE control's maximum limit is not reliably updated when the sensor mode changes, causing incorrect exposure limits to be exposed to userspace.
--
--- Patch [10]: [PATCH v2 10/20] media: imx355: Remove redundant fll_min, and implement fixed offset ---
commit bafcea33e8f344729e8a8a61b9272b5555ee1f02
Author: Dave Stevenson <dave.stevenson@raspberrypi.com>
media: imx355: Remove redundant fll_min, and implement fixed offset
The patch removes the redundant fll_min from imx355_mode configurations.
It sets the vblank control minimum to a fixed 20 lines to improve the
maximum achievable frame rate.
> diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
> index 9d977bac23b6c..354092295b7c3 100644
> --- a/drivers/media/i2c/imx355.c
> +++ b/drivers/media/i2c/imx355.c
[ ... ]
> @@ -888,10 +873,9 @@ imx355_set_pad_format(struct v4l2_subdev *sd,
> /* Update limits and set FPS to default */
> height = imx355->cur_mode->height;
> vblank_def = imx355->cur_mode->fll_def - height;
> - vblank_min = imx355->cur_mode->fll_min - height;
> height = IMX355_FLL_MAX - height;
> - __v4l2_ctrl_modify_range(imx355->vblank, vblank_min, height, 1,
> - vblank_def);
> + __v4l2_ctrl_modify_range(imx355->vblank, IMX355_VBLANK_MIN,
> + height, 1, vblank_def);
> __v4l2_ctrl_s_ctrl(imx355->vblank, vblank_def);
[Severity: Medium]
This isn't a bug introduced by this patch, but does this skip updating the
EXPOSURE control's maximum limit if the new default VBLANK matches the
current VBLANK value?
If userspace sets VBLANK to a value (e.g., 151 in Mode 3) and then switches
to a new mode (e.g., Mode 0) where the new default VBLANK exactly matches
the current VBLANK value, the V4L2 core optimization will skip calling the
s_ctrl callback.
Since the mode's height changed, the EXPOSURE limits must be recalculated.
Because the s_ctrl callback (imx355_set_ctrl) is skipped, does this cause
incorrect exposure limits to be exposed to userspace until streaming starts?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260707-media-imx355-v2-0-1683ec07b897@raspberrypi.com?part=10
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v2 13/20] media: imx355: Convert to new CCI register access helpers
2026-07-07 17:04 ` [PATCH v2 13/20] media: imx355: Convert to new CCI register access helpers Dave Stevenson
@ 2026-07-07 17:21 ` sashiko-bot
0 siblings, 0 replies; 34+ messages in thread
From: sashiko-bot @ 2026-07-07 17:21 UTC (permalink / raw)
To: Dave Stevenson; +Cc: robh, conor+dt, devicetree
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
New issues:
- [High] Unintended permutation of initialization values for registers 0x0305, 0x0306, and 0x0307 in `imx355_global_regs`.
- [Medium] `IMX355_REG_TEST_PATTERN` is incorrectly defined as an 8-bit register, causing truncated writes and breaking test pattern configuration.
- [Low] The error code from `devm_cci_regmap_init_i2c()` is incorrectly discarded and replaced with a hardcoded `-ENODEV`.
Pre-existing issues:
- [High] Incorrect check of `pm_runtime_get_if_in_use()` in `imx355_set_ctrl` allows unpowered hardware access and PM counter underflow when runtime PM is disabled.
--
--- Patch [13]: [PATCH v2 13/20] media: imx355: Convert to new CCI register access helpers ---
commit 85e1b3f8ecdbe34d874840dcfedd44c3422e9cf3
Author: Dave Stevenson <dave.stevenson@raspberrypi.com>
media: imx355: Convert to new CCI register access helpers
This patch updates the imx355 driver to use the common v4l2 CCI register
access helpers. It replaces the private i2c transfer logic with cci_read
and cci_write calls, and updates the register definition tables.
> diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
> index c7a24c69c0df8..c710dda5795b6 100644
> --- a/drivers/media/i2c/imx355.c
> +++ b/drivers/media/i2c/imx355.c
[ ... ]
> /* Digital gain control */
> -#define IMX355_REG_DPGA_USE_GLOBAL_GAIN 0x3070
> -#define IMX355_REG_DIG_GAIN_GLOBAL 0x020e
> +#define IMX355_REG_DPGA_USE_GLOBAL_GAIN CCI_REG8(0x3070)
> +#define IMX355_REG_DIG_GAIN_GLOBAL CCI_REG16(0x020e)
> #define IMX355_DGTL_GAIN_MIN 256
> #define IMX355_DGTL_GAIN_MAX 4095
> #define IMX355_DGTL_GAIN_STEP 1
> #define IMX355_DGTL_GAIN_DEFAULT 256
>
> /* Test Pattern Control */
> -#define IMX355_REG_TEST_PATTERN 0x0600
> +#define IMX355_REG_TEST_PATTERN CCI_REG8(0x0600)
[Severity: Medium]
Does this change the width of the test pattern write?
The original code used imx355_write_reg() with a length of 2 for
IMX355_REG_TEST_PATTERN, performing a 16-bit write. With this macro
defined as an 8-bit register, cci_write() will truncate the payload into
a 1-byte write, dropping the lower byte that actually contains the
control value. Should this be defined as CCI_REG16(0x0600)?
[ ... ]
> -static const struct imx355_reg imx355_global_regs[] = {
[ ... ]
> - { 0x0301, 0x05 },
> - { 0x0303, 0x01 },
> - { 0x0305, 0x02 },
> - { 0x0306, 0x00 },
> - { 0x0307, 0x78 },
> - { 0x030d, 0x02 },
> - { 0x0310, 0x00 },
[ ... ]
> +static const struct cci_reg_sequence imx355_global_regs[] = {
[ ... ]
> + { CCI_REG8(0x0301), 0x05 },
> + { CCI_REG8(0x0303), 0x01 },
> + { CCI_REG8(0x0305), 0x00 },
> + { CCI_REG8(0x0306), 0x78 },
> + { CCI_REG8(0x0307), 0x02 },
> + { CCI_REG8(0x030d), 0x02 },
> + { CCI_REG8(0x0310), 0x00 },
[Severity: High]
Were the values for these three registers accidentally swapped during the
conversion?
The original sequence was:
{ 0x0305, 0x02 }
{ 0x0306, 0x00 }
{ 0x0307, 0x78 }
The new sequence assigns 0x00 to 0x0305, 0x78 to 0x0306, and 0x02 to 0x0307.
Could this incorrect initialization sequence break the sensor's hardware
timing configuration?
[ ... ]
> @@ -726,31 +647,31 @@ static int imx355_set_ctrl(struct v4l2_ctrl *ctrl)
[Severity: High]
This isn't a bug introduced by this patch, but does the runtime PM check in
this function handle negative error codes correctly?
In imx355_set_ctrl(), the code checks:
if (!pm_runtime_get_if_in_use(imx355->dev))
return 0;
pm_runtime_get_if_in_use() returns -EINVAL when runtime PM is disabled.
Since -EINVAL is non-zero, the check evaluates to false, and the code
falls through to hardware accesses while the device might be unpowered.
Could this also lead to an underflow when pm_runtime_put() is called at
the end of the function?
[ ... ]
> @@ -1344,6 +1228,12 @@ static int imx355_probe(struct i2c_client *client)
>
> mutex_init(&imx355->mutex);
>
> + imx355->regmap = devm_cci_regmap_init_i2c(client, 16);
> + if (IS_ERR(imx355->regmap)) {
> + dev_err(imx355->dev, "Unable to initialize I2C\n");
> + return -ENODEV;
> + }
> +
> imx355->clk = devm_v4l2_sensor_clk_get(imx355->dev, NULL);
> if (IS_ERR(imx355->clk))
[Severity: Low]
Should this propagate the actual error code instead of returning -ENODEV?
When devm_cci_regmap_init_i2c() fails (e.g., due to memory allocation
failure returning -ENOMEM), returning a hardcoded -ENODEV masks the true
cause of the failure. Would it be better to return PTR_ERR(imx355->regmap)?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260707-media-imx355-v2-0-1683ec07b897@raspberrypi.com?part=13
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v2 12/20] media: imx355: Use pm_runtime autosuspend_delay
2026-07-07 17:04 ` [PATCH v2 12/20] media: imx355: Use pm_runtime autosuspend_delay Dave Stevenson
@ 2026-07-07 17:21 ` sashiko-bot
0 siblings, 0 replies; 34+ messages in thread
From: sashiko-bot @ 2026-07-07 17:21 UTC (permalink / raw)
To: Dave Stevenson; +Cc: conor+dt, devicetree, robh
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Missing pm_runtime_dont_use_autosuspend() leaves device PM configuration in an inconsistent state on teardown.
--
--- Patch [12]: [PATCH v2 12/20] media: imx355: Use pm_runtime autosuspend_delay ---
commit 2fa89d9640a2f437c76ce04712298549178132d2
Author: Dave Stevenson <dave.stevenson@raspberrypi.com>
media: imx355: Use pm_runtime autosuspend_delay
Avoid powering the sensor up and down unnecessarily by using pm_runtime's
autosuspend_delay feature.
> diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
> index 0f5fbe21d7fb2..c7a24c69c0df8 100644
> --- a/drivers/media/i2c/imx355.c
> +++ b/drivers/media/i2c/imx355.c
[ ... ]
> @@ -1430,6 +1430,8 @@ static int imx355_probe(struct i2c_client *client)
> pm_runtime_set_active(imx355->dev);
> pm_runtime_enable(imx355->dev);
> pm_runtime_idle(imx355->dev);
> + pm_runtime_set_autosuspend_delay(imx355->dev, 1000);
> + pm_runtime_use_autosuspend(imx355->dev);
>
> ret = v4l2_async_register_subdev_sensor(&imx355->sd);
> if (ret < 0)
[Severity: Medium]
Should there be matching calls to pm_runtime_dont_use_autosuspend() during
teardown?
Since pm_runtime_use_autosuspend() sets the use_autosuspend flag, leaving it
set on driver unbind or probe failure leaves the device PM configuration in an
inconsistent state.
For example, if probe fails after this point, the error path disables runtime
PM without undoing the autosuspend usage:
imx355_probe() {
...
error_media_entity_runtime_pm:
pm_runtime_disable(imx355->dev);
pm_runtime_set_suspended(imx355->dev);
...
}
The same pattern appears in the driver removal path:
imx355_remove() {
...
pm_runtime_disable(imx355->dev);
if (!pm_runtime_status_suspended(imx355->dev)) {
...
}
Could this cause state leakage that affects subsequent driver bindings?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260707-media-imx355-v2-0-1683ec07b897@raspberrypi.com?part=12
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v2 20/20] media: imx355: Remove storing cur_mode in the state
2026-07-07 17:04 ` [PATCH v2 20/20] media: imx355: Remove storing cur_mode in the state Dave Stevenson
@ 2026-07-07 17:37 ` sashiko-bot
0 siblings, 0 replies; 34+ messages in thread
From: sashiko-bot @ 2026-07-07 17:37 UTC (permalink / raw)
To: Dave Stevenson; +Cc: robh, conor+dt, devicetree
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] The `imx355_set_stream` function and its callee `imx355_start_streaming` execute without acquiring the subdevice active state lock, leading to `lockdep_assert_held` failures and data races with controls.
- [High] Use-after-free of subdev active state in `imx355_set_ctrl()` during device unbind due to incorrect cleanup ordering.
--
--- Patch [20]: [PATCH v2 20/20] media: imx355: Remove storing cur_mode in the state ---
commit d3278174d03d9c643934fc21a9e1c67e3a90a3fb
Author: Dave Stevenson <dave.stevenson@raspberrypi.com>
media: imx355: Remove storing cur_mode in the state
All the information for the mode is now stored within
the subdev state, so configure the sensor based on that.
> diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
> index bb620ebb074f7..f31833e5d1d12 100644
> --- a/drivers/media/i2c/imx355.c
> +++ b/drivers/media/i2c/imx355.c
> @@ -594,6 +591,8 @@ static int imx355_set_ctrl(struct v4l2_ctrl *ctrl)
> {
> struct imx355 *imx355 = container_of(ctrl->handler,
> struct imx355, ctrl_handler);
> + const struct v4l2_mbus_framefmt *format = NULL;
> + struct v4l2_subdev_state *state;
> s64 max;
> int ret;
>
> @@ -604,7 +603,7 @@ static int imx355_set_ctrl(struct v4l2_ctrl *ctrl)
> switch (ctrl->id) {
> case V4L2_CID_VBLANK:
> /* Update max exposure while meeting expected vblanking */
> - max = imx355->cur_mode->height + ctrl->val - IMX355_EXPOSURE_OFFSET;
> + max = format->height + ctrl->val - IMX355_EXPOSURE_OFFSET;
[Severity: High]
Can this dereference a freed active state?
If the driver is unbound (e.g. via sysfs) while a userspace process
concurrently accesses a v4l2 control, imx355_remove() is called.
In imx355_remove(), the active state is freed before the control handler:
imx355_remove()
v4l2_subdev_cleanup(sd);
media_entity_cleanup(&sd->entity);
v4l2_ctrl_handler_free(sd->ctrl_handler);
This leaves a window where the concurrent ioctl can acquire the control lock,
enter imx355_set_ctrl(), retrieve the now-freed active state, and trigger a
use-after-free when reading format->height.
[ ... ]
> @@ -809,9 +804,11 @@ static int imx355_entity_init_state(struct v4l2_subdev *subdev,
> /* Start streaming */
> static int imx355_start_streaming(struct imx355 *imx355)
> {
> - const struct imx355_reg_list *reg_list;
> + const struct v4l2_mbus_framefmt *fmt;
> + struct v4l2_subdev_state *state;
> const struct imx355_mode *mode;
> int lane_idx = imx355->hwcfg->num_lanes == 4 ? 0 : 1;
> + struct v4l2_rect *crop;
> u64 link_bitrate;
> u8 binning_mode;
> int ret = 0;
> @@ -820,25 +817,29 @@ static int imx355_start_streaming(struct imx355 *imx355)
> cci_multi_reg_write(imx355->regmap, imx355_global_regs,
> ARRAY_SIZE(imx355_global_regs), &ret);
>
> - /* Apply default values of current mode */
> - mode = imx355->cur_mode;
> - reg_list = &mode->reg_list;
> - cci_multi_reg_write(imx355->regmap, reg_list->regs,
> - reg_list->num_of_regs, &ret);
> + /* Apply values of current mode */
> + state = v4l2_subdev_get_locked_active_state(&imx355->sd);
[Severity: High]
Does this code execute without acquiring the subdevice active state lock?
Calling v4l2_subdev_get_locked_active_state() will trigger a lockdep failure
if the lock is not held.
This can happen when starting the video stream via userspace invokes the
.s_stream callback:
imx355_set_stream()
imx355_start_streaming()
state = v4l2_subdev_get_locked_active_state(&imx355->sd);
Since imx355_set_stream() doesn't acquire the lock before calling
imx355_start_streaming(), this triggers a lockdep failure.
Additionally, the missing lock leaves the subsequent calls to
__v4l2_ctrl_handler_setup() and __v4l2_ctrl_grab() unlocked, exposing a data
race with concurrent userspace control updates.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260707-media-imx355-v2-0-1683ec07b897@raspberrypi.com?part=20
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v2 19/20] media: imx355: Switch to using the subdev state
2026-07-07 17:04 ` [PATCH v2 19/20] media: imx355: Switch to using the subdev state Dave Stevenson
@ 2026-07-07 19:34 ` sashiko-bot
0 siblings, 0 replies; 34+ messages in thread
From: sashiko-bot @ 2026-07-07 19:34 UTC (permalink / raw)
To: Dave Stevenson; +Cc: conor+dt, devicetree, robh
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Missing state lock acquisition in imx355_set_stream() leading to lockdep BUGs and data races.
--
--- Patch [19]: [PATCH v2 19/20] media: imx355: Switch to using the subdev state ---
commit bbaa67e1db37273f6e97e0631f0e7e19179737fd
Author: Dave Stevenson <dave.stevenson@raspberrypi.com>
media: imx355: Switch to using the subdev state
The commit transitions the imx355 driver to use the v4l2 subdev state for
handling crop and format instead of maintaining its own state variables, and
removes the driver-specific mutex.
> diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
> index 10b9cf56e8c56..bb620ebb074f7 100644
> --- a/drivers/media/i2c/imx355.c
> +++ b/drivers/media/i2c/imx355.c
[ ... ]
> @@ -958,12 +893,10 @@ static int imx355_set_stream(struct v4l2_subdev *sd, int enable)
> struct imx355 *imx355 = to_imx355(sd);
> int ret = 0;
>
> - mutex_lock(&imx355->mutex);
> -
> if (enable) {
> ret = pm_runtime_resume_and_get(imx355->dev);
> if (ret < 0)
> - goto err_unlock;
> + return ret;
>
> /*
> * Apply default & customized values
[Severity: High]
Does this leave imx355_set_stream() entirely lockless?
This function calls imx355_start_streaming(), which calls
v4l2_subdev_get_locked_active_state() to get the subdev state. That function
asserts that the state lock is held.
Without holding the state lock here, won't lockdep unconditionally trigger
BUG splats when calling v4l2_subdev_get_locked_active_state() and later
when calling __v4l2_ctrl_grab() in this function?
Also, without the lock, couldn't these reads race against concurrent
VIDIOC_SUBDEV_S_FMT and VIDIOC_S_CTRL ioctls?
> @@ -981,14 +914,10 @@ static int imx355_set_stream(struct v4l2_subdev *sd, int enable)
> __v4l2_ctrl_grab(imx355->vflip, enable);
> __v4l2_ctrl_grab(imx355->hflip, enable);
>
> - mutex_unlock(&imx355->mutex);
> -
> return ret;
>
> err_rpm_put:
> pm_runtime_put_autosuspend(imx355->dev);
> -err_unlock:
> - mutex_unlock(&imx355->mutex);
>
> return ret;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260707-media-imx355-v2-0-1683ec07b897@raspberrypi.com?part=19
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v2 02/20] dt-bindings: media: imx355: Allow 2 CSI2 data lane output
2026-07-07 17:04 ` [PATCH v2 02/20] dt-bindings: media: imx355: Allow 2 CSI2 data lane output Dave Stevenson
@ 2026-07-08 7:07 ` Krzysztof Kozlowski
0 siblings, 0 replies; 34+ messages in thread
From: Krzysztof Kozlowski @ 2026-07-08 7:07 UTC (permalink / raw)
To: Dave Stevenson
Cc: Tianshu Qiu, Sakari Ailus, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Richard Acayan, linux-media,
linux-kernel, David Heidelberg, Jacopo Mondi, devicetree
On Tue, Jul 07, 2026 at 06:04:34PM +0100, Dave Stevenson wrote:
> The sensor supports output over either 2 or 4 CSI2 data
> lanes. The binding only permitted the 4 lane configuration.
>
> Add the 2 lane configuration as an option.
>
> Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 34+ messages in thread
end of thread, other threads:[~2026-07-08 7:07 UTC | newest]
Thread overview: 34+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-07 17:04 [PATCH v2 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
2026-07-07 17:04 ` [PATCH v2 01/20] media: i2c: imx355: Add support for 24 MHz external clock Dave Stevenson
2026-07-07 17:04 ` [PATCH v2 02/20] dt-bindings: media: imx355: Allow 2 CSI2 data lane output Dave Stevenson
2026-07-08 7:07 ` Krzysztof Kozlowski
2026-07-07 17:04 ` [PATCH v2 03/20] media: imx355: Remove duplicated registers from the mode tables Dave Stevenson
2026-07-07 17:14 ` sashiko-bot
2026-07-07 17:04 ` [PATCH v2 04/20] media: imx355: Remove setting FRM_LENGTH_LINES in the mode regs Dave Stevenson
2026-07-07 17:04 ` [PATCH v2 05/20] media: imx355: Programmatically set the crop parameters for each mode Dave Stevenson
2026-07-07 17:18 ` sashiko-bot
2026-07-07 17:04 ` [PATCH v2 06/20] media: imx355: Set register LINE_LENGTH_PCK programmatically Dave Stevenson
2026-07-07 17:12 ` sashiko-bot
2026-07-07 17:04 ` [PATCH v2 07/20] media: imx355: Set binning mode registers programmatically Dave Stevenson
2026-07-07 17:15 ` sashiko-bot
2026-07-07 17:04 ` [PATCH v2 08/20] media: imx355: Remove link_freq_index from each mode as ununsed Dave Stevenson
2026-07-07 17:04 ` [PATCH v2 09/20] media: imx355: pixel_rate never changes, so don't recompute Dave Stevenson
2026-07-07 17:15 ` sashiko-bot
2026-07-07 17:04 ` [PATCH v2 10/20] media: imx355: Remove redundant fll_min, and implement fixed offset Dave Stevenson
2026-07-07 17:18 ` sashiko-bot
2026-07-07 17:04 ` [PATCH v2 11/20] media: imx355: Add support for get_selection Dave Stevenson
2026-07-07 17:18 ` sashiko-bot
2026-07-07 17:04 ` [PATCH v2 12/20] media: imx355: Use pm_runtime autosuspend_delay Dave Stevenson
2026-07-07 17:21 ` sashiko-bot
2026-07-07 17:04 ` [PATCH v2 13/20] media: imx355: Convert to new CCI register access helpers Dave Stevenson
2026-07-07 17:21 ` sashiko-bot
2026-07-07 17:04 ` [PATCH v2 14/20] media: imx355: Set the colorspace in the format Dave Stevenson
2026-07-07 17:16 ` sashiko-bot
2026-07-07 17:04 ` [PATCH v2 15/20] media: imx355: Define the exposure offset, and use that define Dave Stevenson
2026-07-07 17:04 ` [PATCH v2 16/20] media: imx355: Use NULL ctrl_ops for HBLANK as it is a read-only control Dave Stevenson
2026-07-07 17:04 ` [PATCH v2 17/20] media: imx355: Compute link frequency from PLL setup Dave Stevenson
2026-07-07 17:04 ` [PATCH v2 18/20] media: imx355: Support 2 lane readout Dave Stevenson
2026-07-07 17:04 ` [PATCH v2 19/20] media: imx355: Switch to using the subdev state Dave Stevenson
2026-07-07 19:34 ` sashiko-bot
2026-07-07 17:04 ` [PATCH v2 20/20] media: imx355: Remove storing cur_mode in the state Dave Stevenson
2026-07-07 17:37 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox