* [PATCH v3 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation
@ 2026-07-08 14:48 Dave Stevenson
2026-07-08 14:48 ` [PATCH v3 01/20] media: i2c: imx355: Add support for 24 MHz external clock Dave Stevenson
` (19 more replies)
0 siblings, 20 replies; 31+ messages in thread
From: Dave Stevenson @ 2026-07-08 14:48 UTC (permalink / raw)
To: 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, Krzysztof Kozlowski
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 v3:
- Fixed a number of issues picked up by sashiko-bot
- Unintentionally dropped writing reg 0x030b, which is at the default value anyway.
- Swapped len and val in intermediate patches adding imx355_write_reg before converting
to cci_write
- Initialise colorspace in _open for try_fmt.
- IMX355_REG_TEST_PATTERN is a 16 bit register, but was defined as 8 bit.
- Call pm_runtime_dont_use_autosuspend on remove / probe error
- Missed subdev_lock in set_stream.
- Not addressed the pre-existing issues of double power_off in _probe error path, nor
potential for VBLANK update on mode change not calling s_ctrl if the new value happens
to be the same and therefore exposure range being incorrect. I'll look at them as
separate fixes.
- Variable definition for format and state in imx355_set_ctrl got pushed into the wrong patch
- Collected Krzysztof's R-b tag for the binding patch.
- Link to v2: https://lore.kernel.org/r/20260707-media-imx355-v2-0-1683ec07b897@raspberrypi.com
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 | 1518 +++++++-------------
3 files changed, 498 insertions(+), 1032 deletions(-)
---
base-commit: 254f49634ee16a731174d2ae34bc50bd5f45e731
change-id: 20260506-media-imx355-a30f5be3deda
Best regards,
--
Dave Stevenson <dave.stevenson@raspberrypi.com>
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v3 01/20] media: i2c: imx355: Add support for 24 MHz external clock
2026-07-08 14:48 [PATCH v3 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
@ 2026-07-08 14:48 ` Dave Stevenson
2026-07-08 14:48 ` [PATCH v3 02/20] dt-bindings: media: imx355: Allow 2 CSI2 data lane output Dave Stevenson
` (18 subsequent siblings)
19 siblings, 0 replies; 31+ messages in thread
From: Dave Stevenson @ 2026-07-08 14:48 UTC (permalink / raw)
To: 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] 31+ messages in thread
* [PATCH v3 02/20] dt-bindings: media: imx355: Allow 2 CSI2 data lane output
2026-07-08 14:48 [PATCH v3 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
2026-07-08 14:48 ` [PATCH v3 01/20] media: i2c: imx355: Add support for 24 MHz external clock Dave Stevenson
@ 2026-07-08 14:48 ` Dave Stevenson
2026-07-08 14:48 ` [PATCH v3 03/20] media: imx355: Remove duplicated registers from the mode tables Dave Stevenson
` (17 subsequent siblings)
19 siblings, 0 replies; 31+ messages in thread
From: Dave Stevenson @ 2026-07-08 14:48 UTC (permalink / raw)
To: 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, Krzysztof Kozlowski
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>
---
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] 31+ messages in thread
* [PATCH v3 03/20] media: imx355: Remove duplicated registers from the mode tables
2026-07-08 14:48 [PATCH v3 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
2026-07-08 14:48 ` [PATCH v3 01/20] media: i2c: imx355: Add support for 24 MHz external clock Dave Stevenson
2026-07-08 14:48 ` [PATCH v3 02/20] dt-bindings: media: imx355: Allow 2 CSI2 data lane output Dave Stevenson
@ 2026-07-08 14:48 ` Dave Stevenson
2026-07-08 15:00 ` sashiko-bot
2026-07-08 14:48 ` [PATCH v3 04/20] media: imx355: Remove setting FRM_LENGTH_LINES in the mode regs Dave Stevenson
` (16 subsequent siblings)
19 siblings, 1 reply; 31+ messages in thread
From: Dave Stevenson @ 2026-07-08 14:48 UTC (permalink / raw)
To: 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.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
---
drivers/media/i2c/imx355.c | 345 +++------------------------------------------
1 file changed, 23 insertions(+), 322 deletions(-)
diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
index ad9a9464175b..4eaccd9e90f1 100644
--- a/drivers/media/i2c/imx355.c
+++ b/drivers/media/i2c/imx355.c
@@ -221,6 +221,29 @@ 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 },
+ { 0x030b, 0x01 },
+ { 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 +252,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 +264,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 +271,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 +288,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 +295,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 +312,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 +319,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 +336,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 +343,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 +360,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 +367,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 +384,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 +391,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 +408,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 +415,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 +432,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 +439,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 +456,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 +463,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 +480,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 +487,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 +504,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 +511,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 +528,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 +535,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 +552,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 +559,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 +576,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 +583,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] 31+ messages in thread
* [PATCH v3 04/20] media: imx355: Remove setting FRM_LENGTH_LINES in the mode regs
2026-07-08 14:48 [PATCH v3 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
` (2 preceding siblings ...)
2026-07-08 14:48 ` [PATCH v3 03/20] media: imx355: Remove duplicated registers from the mode tables Dave Stevenson
@ 2026-07-08 14:48 ` Dave Stevenson
2026-07-08 14:48 ` [PATCH v3 05/20] media: imx355: Programmatically set the crop parameters for each mode Dave Stevenson
` (15 subsequent siblings)
19 siblings, 0 replies; 31+ messages in thread
From: Dave Stevenson @ 2026-07-08 14:48 UTC (permalink / raw)
To: 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.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.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 4eaccd9e90f1..24c883a6c520 100644
--- a/drivers/media/i2c/imx355.c
+++ b/drivers/media/i2c/imx355.c
@@ -254,8 +254,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 },
@@ -278,8 +276,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 },
@@ -302,8 +298,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 },
@@ -326,8 +320,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 },
@@ -350,8 +342,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 },
@@ -374,8 +364,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 },
@@ -398,8 +386,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 },
@@ -422,8 +408,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 },
@@ -446,8 +430,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 },
@@ -470,8 +452,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 },
@@ -494,8 +474,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 },
@@ -518,8 +496,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 },
@@ -542,8 +518,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 },
@@ -566,8 +540,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] 31+ messages in thread
* [PATCH v3 05/20] media: imx355: Programmatically set the crop parameters for each mode
2026-07-08 14:48 [PATCH v3 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
` (3 preceding siblings ...)
2026-07-08 14:48 ` [PATCH v3 04/20] media: imx355: Remove setting FRM_LENGTH_LINES in the mode regs Dave Stevenson
@ 2026-07-08 14:48 ` Dave Stevenson
2026-07-08 14:48 ` [PATCH v3 06/20] media: imx355: Set register LINE_LENGTH_PCK programmatically Dave Stevenson
` (14 subsequent siblings)
19 siblings, 0 replies; 31+ messages in thread
From: Dave Stevenson @ 2026-07-08 14:48 UTC (permalink / raw)
To: 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 24c883a6c520..29bca1d98791 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;
@@ -254,21 +262,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 },
};
@@ -276,21 +272,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 },
};
@@ -298,21 +282,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 },
};
@@ -320,21 +292,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 },
};
@@ -342,21 +302,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 },
};
@@ -364,21 +312,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 },
};
@@ -386,21 +322,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 },
};
@@ -408,21 +332,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 },
};
@@ -430,21 +342,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 },
};
@@ -452,21 +352,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 },
};
@@ -474,21 +362,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 },
};
@@ -496,21 +372,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 },
};
@@ -518,21 +382,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 },
};
@@ -540,21 +392,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 },
};
@@ -580,6 +420,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,
@@ -592,6 +438,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,
@@ -604,6 +456,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,
@@ -616,6 +474,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,
@@ -628,6 +492,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,
@@ -640,6 +510,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,
@@ -652,6 +528,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,
@@ -664,6 +546,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,
@@ -676,6 +564,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,
@@ -688,6 +582,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,
@@ -700,6 +600,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,
@@ -712,6 +618,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,
@@ -724,6 +636,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,
@@ -736,6 +654,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,
@@ -1074,6 +998,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 */
@@ -1085,13 +1010,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] 31+ messages in thread
* [PATCH v3 06/20] media: imx355: Set register LINE_LENGTH_PCK programmatically
2026-07-08 14:48 [PATCH v3 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
` (4 preceding siblings ...)
2026-07-08 14:48 ` [PATCH v3 05/20] media: imx355: Programmatically set the crop parameters for each mode Dave Stevenson
@ 2026-07-08 14:48 ` Dave Stevenson
2026-07-08 14:48 ` [PATCH v3 07/20] media: imx355: Set binning mode registers programmatically Dave Stevenson
` (13 subsequent siblings)
19 siblings, 0 replies; 31+ messages in thread
From: Dave Stevenson @ 2026-07-08 14:48 UTC (permalink / raw)
To: 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.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
---
drivers/media/i2c/imx355.c | 37 +++++++++----------------------------
1 file changed, 9 insertions(+), 28 deletions(-)
diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
index 29bca1d98791..7aabd281cd3c 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
@@ -260,8 +263,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 },
@@ -270,8 +271,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 },
@@ -280,8 +279,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 },
@@ -290,8 +287,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 },
@@ -300,8 +295,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 },
@@ -310,8 +303,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 },
@@ -320,8 +311,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 },
@@ -330,8 +319,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 },
@@ -340,8 +327,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 },
@@ -350,8 +335,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 },
@@ -360,8 +343,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 },
@@ -370,8 +351,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 },
@@ -380,8 +359,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 },
@@ -390,8 +367,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 },
@@ -1059,6 +1034,12 @@ static int imx355_start_streaming(struct imx355 *imx355)
if (ret)
return ret;
+ /* set line length */
+ ret = imx355_write_reg(imx355, IMX355_REG_LLP, 2,
+ imx355->hblank->val + imx355->cur_mode->width);
+ 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] 31+ messages in thread
* [PATCH v3 07/20] media: imx355: Set binning mode registers programmatically
2026-07-08 14:48 [PATCH v3 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
` (5 preceding siblings ...)
2026-07-08 14:48 ` [PATCH v3 06/20] media: imx355: Set register LINE_LENGTH_PCK programmatically Dave Stevenson
@ 2026-07-08 14:48 ` Dave Stevenson
2026-07-08 14:48 ` [PATCH v3 08/20] media: imx355: Remove link_freq_index from each mode as ununsed Dave Stevenson
` (12 subsequent siblings)
19 siblings, 0 replies; 31+ messages in thread
From: Dave Stevenson @ 2026-07-08 14:48 UTC (permalink / raw)
To: 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 7aabd281cd3c..1010c32fe969 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
@@ -263,113 +267,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 },
};
@@ -974,6 +936,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 */
@@ -1019,6 +982,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] 31+ messages in thread
* [PATCH v3 08/20] media: imx355: Remove link_freq_index from each mode as ununsed
2026-07-08 14:48 [PATCH v3 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
` (6 preceding siblings ...)
2026-07-08 14:48 ` [PATCH v3 07/20] media: imx355: Set binning mode registers programmatically Dave Stevenson
@ 2026-07-08 14:48 ` Dave Stevenson
2026-07-08 14:48 ` [PATCH v3 09/20] media: imx355: pixel_rate never changes, so don't recompute Dave Stevenson
` (11 subsequent siblings)
19 siblings, 0 replies; 31+ messages in thread
From: Dave Stevenson @ 2026-07-08 14:48 UTC (permalink / raw)
To: 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.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.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 1010c32fe969..2880e03b3f08 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;
};
@@ -366,7 +362,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,
@@ -384,7 +379,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,
@@ -402,7 +396,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,
@@ -420,7 +413,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,
@@ -438,7 +430,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,
@@ -456,7 +447,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,
@@ -474,7 +464,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,
@@ -492,7 +481,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,
@@ -510,7 +498,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,
@@ -528,7 +515,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,
@@ -546,7 +532,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,
@@ -564,7 +549,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,
@@ -582,7 +566,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,
@@ -600,7 +583,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] 31+ messages in thread
* [PATCH v3 09/20] media: imx355: pixel_rate never changes, so don't recompute
2026-07-08 14:48 [PATCH v3 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
` (7 preceding siblings ...)
2026-07-08 14:48 ` [PATCH v3 08/20] media: imx355: Remove link_freq_index from each mode as ununsed Dave Stevenson
@ 2026-07-08 14:48 ` Dave Stevenson
2026-07-08 15:01 ` sashiko-bot
2026-07-08 14:48 ` [PATCH v3 10/20] media: imx355: Remove redundant fll_min, and implement fixed offset Dave Stevenson
` (10 subsequent siblings)
19 siblings, 1 reply; 31+ messages in thread
From: Dave Stevenson @ 2026-07-08 14:48 UTC (permalink / raw)
To: 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.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.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 2880e03b3f08..2a97e076bff7 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;
@@ -867,7 +866,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);
@@ -888,9 +886,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] 31+ messages in thread
* [PATCH v3 10/20] media: imx355: Remove redundant fll_min, and implement fixed offset
2026-07-08 14:48 [PATCH v3 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
` (8 preceding siblings ...)
2026-07-08 14:48 ` [PATCH v3 09/20] media: imx355: pixel_rate never changes, so don't recompute Dave Stevenson
@ 2026-07-08 14:48 ` Dave Stevenson
2026-07-08 15:05 ` sashiko-bot
2026-07-08 14:48 ` [PATCH v3 11/20] media: imx355: Add support for get_selection Dave Stevenson
` (9 subsequent siblings)
19 siblings, 1 reply; 31+ messages in thread
From: Dave Stevenson @ 2026-07-08 14:48 UTC (permalink / raw)
To: 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.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.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 2a97e076bff7..c6f27cf269b4 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;
@@ -359,7 +359,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),
@@ -376,7 +375,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),
@@ -393,7 +391,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),
@@ -410,7 +407,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),
@@ -427,7 +423,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),
@@ -444,7 +439,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),
@@ -461,7 +455,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),
@@ -478,7 +471,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),
@@ -495,7 +487,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),
@@ -512,7 +503,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),
@@ -529,7 +519,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),
@@ -546,7 +535,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),
@@ -563,7 +551,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),
@@ -580,7 +567,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),
@@ -864,7 +850,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;
@@ -889,10 +874,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] 31+ messages in thread
* [PATCH v3 11/20] media: imx355: Add support for get_selection
2026-07-08 14:48 [PATCH v3 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
` (9 preceding siblings ...)
2026-07-08 14:48 ` [PATCH v3 10/20] media: imx355: Remove redundant fll_min, and implement fixed offset Dave Stevenson
@ 2026-07-08 14:48 ` Dave Stevenson
2026-07-08 15:11 ` sashiko-bot
2026-07-08 14:48 ` [PATCH v3 12/20] media: imx355: Use pm_runtime autosuspend_delay Dave Stevenson
` (8 subsequent siblings)
19 siblings, 1 reply; 31+ messages in thread
From: Dave Stevenson @ 2026-07-08 14:48 UTC (permalink / raw)
To: 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 | 59 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 59 insertions(+)
diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
index c6f27cf269b4..ee1f41a66a0b 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;
@@ -677,6 +682,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);
@@ -686,6 +692,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;
@@ -869,6 +877,12 @@ imx355_set_pad_format(struct v4l2_subdev *sd,
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
*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;
} else {
imx355->cur_mode = mode;
/* Update limits and set FPS to default */
@@ -892,6 +906,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 +1124,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] 31+ messages in thread
* [PATCH v3 12/20] media: imx355: Use pm_runtime autosuspend_delay
2026-07-08 14:48 [PATCH v3 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
` (10 preceding siblings ...)
2026-07-08 14:48 ` [PATCH v3 11/20] media: imx355: Add support for get_selection Dave Stevenson
@ 2026-07-08 14:48 ` Dave Stevenson
2026-07-08 15:06 ` sashiko-bot
2026-07-08 14:48 ` [PATCH v3 13/20] media: imx355: Convert to new CCI register access helpers Dave Stevenson
` (7 subsequent siblings)
19 siblings, 1 reply; 31+ messages in thread
From: Dave Stevenson @ 2026-07-08 14:48 UTC (permalink / raw)
To: 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.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
---
drivers/media/i2c/imx355.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
index ee1f41a66a0b..f01a1a5ae7c9 100644
--- a/drivers/media/i2c/imx355.c
+++ b/drivers/media/i2c/imx355.c
@@ -1073,7 +1073,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 */
@@ -1085,7 +1085,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);
@@ -1436,6 +1436,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)
@@ -1446,6 +1448,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);
+ pm_runtime_dont_use_autosuspend(imx355->dev);
media_entity_cleanup(&imx355->sd.entity);
error_handler_free:
@@ -1476,6 +1479,8 @@ static void imx355_remove(struct i2c_client *client)
pm_runtime_set_suspended(imx355->dev);
}
+ pm_runtime_dont_use_autosuspend(imx355->dev);
+
mutex_destroy(&imx355->mutex);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH v3 13/20] media: imx355: Convert to new CCI register access helpers
2026-07-08 14:48 [PATCH v3 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
` (11 preceding siblings ...)
2026-07-08 14:48 ` [PATCH v3 12/20] media: imx355: Use pm_runtime autosuspend_delay Dave Stevenson
@ 2026-07-08 14:48 ` Dave Stevenson
2026-07-08 15:08 ` sashiko-bot
2026-07-08 14:48 ` [PATCH v3 14/20] media: imx355: Set the colorspace in the format Dave Stevenson
` (6 subsequent siblings)
19 siblings, 1 reply; 31+ messages in thread
From: Dave Stevenson @ 2026-07-08 14:48 UTC (permalink / raw)
To: 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 f01a1a5ae7c9..b27329143e48 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_REG16(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,155 +183,150 @@ 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 },
- { 0x030b, 0x01 },
- { 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), 0x02 },
+ { CCI_REG8(0x0306), 0x00 },
+ { CCI_REG8(0x0307), 0x78 },
+ { CCI_REG8(0x030b), 0x01 },
+ { 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[] = {
@@ -604,78 +597,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)
{
@@ -727,31 +648,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;
@@ -956,100 +877,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, 2,
- imx355->hblank->val + imx355->cur_mode->width);
- 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);
+
+ cci_write(imx355->regmap, IMX355_REG_MODE_SELECT, IMX355_MODE_STREAMING,
+ &ret);
- return imx355_write_reg(imx355, IMX355_REG_MODE_SELECT,
- 1, IMX355_MODE_STREAMING);
+ 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)
@@ -1096,14 +981,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;
}
@@ -1350,6 +1235,11 @@ 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))
+ return dev_err_probe(imx355->dev, PTR_ERR(imx355->regmap),
+ "Unable to initialize I2C\n");
+
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] 31+ messages in thread
* [PATCH v3 14/20] media: imx355: Set the colorspace in the format
2026-07-08 14:48 [PATCH v3 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
` (12 preceding siblings ...)
2026-07-08 14:48 ` [PATCH v3 13/20] media: imx355: Convert to new CCI register access helpers Dave Stevenson
@ 2026-07-08 14:48 ` Dave Stevenson
2026-07-08 15:01 ` sashiko-bot
2026-07-08 14:48 ` [PATCH v3 15/20] media: imx355: Define the exposure offset, and use that define Dave Stevenson
` (5 subsequent siblings)
19 siblings, 1 reply; 31+ messages in thread
From: Dave Stevenson @ 2026-07-08 14:48 UTC (permalink / raw)
To: 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 | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
index b27329143e48..2bf8da7469fe 100644
--- a/drivers/media/i2c/imx355.c
+++ b/drivers/media/i2c/imx355.c
@@ -612,6 +612,10 @@ static int imx355_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
try_fmt->height = imx355->cur_mode->height;
try_fmt->code = imx355_get_format_code(imx355);
try_fmt->field = V4L2_FIELD_NONE;
+ try_fmt->format.colorspace = V4L2_COLORSPACE_RAW;
+ try_fmt->format.ycbcr_enc = V4L2_YCBCR_ENC_601;
+ try_fmt->format.quantization = V4L2_QUANTIZATION_FULL_RANGE;
+ try_fmt->format.xfer_func = V4L2_XFER_FUNC_NONE;
*crop = imx355->cur_mode->crop;
@@ -738,6 +742,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] 31+ messages in thread
* [PATCH v3 15/20] media: imx355: Define the exposure offset, and use that define
2026-07-08 14:48 [PATCH v3 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
` (13 preceding siblings ...)
2026-07-08 14:48 ` [PATCH v3 14/20] media: imx355: Set the colorspace in the format Dave Stevenson
@ 2026-07-08 14:48 ` Dave Stevenson
2026-07-08 15:07 ` sashiko-bot
2026-07-08 14:48 ` [PATCH v3 16/20] media: imx355: Use NULL ctrl_ops for HBLANK as it is a read-only control Dave Stevenson
` (4 subsequent siblings)
19 siblings, 1 reply; 31+ messages in thread
From: Dave Stevenson @ 2026-07-08 14:48 UTC (permalink / raw)
To: 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 2bf8da7469fe..3b86bd2e2e5e 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)
@@ -635,7 +636,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);
@@ -1129,7 +1130,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] 31+ messages in thread
* [PATCH v3 16/20] media: imx355: Use NULL ctrl_ops for HBLANK as it is a read-only control
2026-07-08 14:48 [PATCH v3 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
` (14 preceding siblings ...)
2026-07-08 14:48 ` [PATCH v3 15/20] media: imx355: Define the exposure offset, and use that define Dave Stevenson
@ 2026-07-08 14:48 ` Dave Stevenson
2026-07-08 14:48 ` [PATCH v3 17/20] media: imx355: Compute link frequency from PLL setup Dave Stevenson
` (3 subsequent siblings)
19 siblings, 0 replies; 31+ messages in thread
From: Dave Stevenson @ 2026-07-08 14:48 UTC (permalink / raw)
To: 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 3b86bd2e2e5e..6a779d700a4b 100644
--- a/drivers/media/i2c/imx355.c
+++ b/drivers/media/i2c/imx355.c
@@ -1123,9 +1123,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] 31+ messages in thread
* [PATCH v3 17/20] media: imx355: Compute link frequency from PLL setup
2026-07-08 14:48 [PATCH v3 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
` (15 preceding siblings ...)
2026-07-08 14:48 ` [PATCH v3 16/20] media: imx355: Use NULL ctrl_ops for HBLANK as it is a read-only control Dave Stevenson
@ 2026-07-08 14:48 ` Dave Stevenson
2026-07-08 14:48 ` [PATCH v3 18/20] media: imx355: Support 2 lane readout Dave Stevenson
` (2 subsequent siblings)
19 siblings, 0 replies; 31+ messages in thread
From: Dave Stevenson @ 2026-07-08 14:48 UTC (permalink / raw)
To: 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 | 39 +++++++++++++++++----------------------
1 file changed, 17 insertions(+), 22 deletions(-)
diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
index 6a779d700a4b..e45d60d665a1 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,13 +240,13 @@ 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), 0x02 },
{ CCI_REG8(0x0306), 0x00 },
{ CCI_REG8(0x0307), 0x78 },
{ CCI_REG8(0x030b), 0x01 },
- { 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 },
@@ -338,14 +340,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[] = {
{
@@ -1091,7 +1085,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;
@@ -1100,15 +1093,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,
@@ -1183,12 +1175,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;
@@ -1211,10 +1205,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;
@@ -1285,7 +1280,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] 31+ messages in thread
* [PATCH v3 18/20] media: imx355: Support 2 lane readout
2026-07-08 14:48 [PATCH v3 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
` (16 preceding siblings ...)
2026-07-08 14:48 ` [PATCH v3 17/20] media: imx355: Compute link frequency from PLL setup Dave Stevenson
@ 2026-07-08 14:48 ` Dave Stevenson
2026-07-08 14:48 ` [PATCH v3 19/20] media: imx355: Switch to using the subdev state Dave Stevenson
2026-07-08 14:48 ` [PATCH v3 20/20] media: imx355: Remove storing cur_mode in the state Dave Stevenson
19 siblings, 0 replies; 31+ messages in thread
From: Dave Stevenson @ 2026-07-08 14:48 UTC (permalink / raw)
To: 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 e45d60d665a1..2be665b5b453 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 },
@@ -250,8 +259,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 },
@@ -816,6 +823,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.
@@ -879,6 +887,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;
@@ -914,7 +924,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);
@@ -1100,9 +1124,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);
@@ -1185,6 +1209,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)
@@ -1202,11 +1227,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] 31+ messages in thread
* [PATCH v3 19/20] media: imx355: Switch to using the subdev state
2026-07-08 14:48 [PATCH v3 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
` (17 preceding siblings ...)
2026-07-08 14:48 ` [PATCH v3 18/20] media: imx355: Support 2 lane readout Dave Stevenson
@ 2026-07-08 14:48 ` Dave Stevenson
2026-07-08 15:10 ` sashiko-bot
2026-07-08 14:48 ` [PATCH v3 20/20] media: imx355: Remove storing cur_mode in the state Dave Stevenson
19 siblings, 1 reply; 31+ messages in thread
From: Dave Stevenson @ 2026-07-08 14:48 UTC (permalink / raw)
To: 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 | 180 +++++++++++++--------------------------------
1 file changed, 50 insertions(+), 130 deletions(-)
diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
index 2be665b5b453..ee012efe25bf 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;
};
@@ -593,46 +586,23 @@ 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;
- try_fmt->format.colorspace = V4L2_COLORSPACE_RAW;
- try_fmt->format.ycbcr_enc = V4L2_YCBCR_ENC_601;
- try_fmt->format.quantization = V4L2_QUANTIZATION_FULL_RANGE;
- try_fmt->format.xfer_func = V4L2_XFER_FUNC_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,
struct imx355, ctrl_handler);
+ const struct v4l2_mbus_framefmt *format = NULL;
+ struct v4l2_subdev_state *state;
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:
@@ -705,9 +675,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;
}
@@ -721,12 +689,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;
@@ -750,36 +715,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,
@@ -788,12 +723,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.
@@ -805,16 +739,17 @@ 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;
-
- 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;
- } 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;
@@ -833,41 +768,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:
@@ -882,6 +793,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)
{
@@ -969,12 +895,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
@@ -992,14 +916,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;
}
@@ -1033,7 +953,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,
@@ -1050,7 +970,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)
@@ -1116,7 +1036,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);
@@ -1265,8 +1184,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))
return dev_err_probe(imx355->dev, PTR_ERR(imx355->regmap),
@@ -1295,7 +1212,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",
@@ -1303,7 +1220,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 */
@@ -1312,13 +1229,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);
@@ -1351,6 +1267,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.
@@ -1371,6 +1294,7 @@ static int imx355_probe(struct i2c_client *client)
pm_runtime_disable(imx355->dev);
pm_runtime_set_suspended(imx355->dev);
pm_runtime_dont_use_autosuspend(imx355->dev);
+ v4l2_subdev_cleanup(&imx355->sd);
media_entity_cleanup(&imx355->sd.entity);
error_handler_free:
@@ -1379,9 +1303,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;
}
@@ -1391,6 +1312,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);
@@ -1402,8 +1324,6 @@ static void imx355_remove(struct i2c_client *client)
}
pm_runtime_dont_use_autosuspend(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] 31+ messages in thread
* [PATCH v3 20/20] media: imx355: Remove storing cur_mode in the state
2026-07-08 14:48 [PATCH v3 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
` (18 preceding siblings ...)
2026-07-08 14:48 ` [PATCH v3 19/20] media: imx355: Switch to using the subdev state Dave Stevenson
@ 2026-07-08 14:48 ` Dave Stevenson
2026-07-08 15:17 ` sashiko-bot
19 siblings, 1 reply; 31+ messages in thread
From: Dave Stevenson @ 2026-07-08 14:48 UTC (permalink / raw)
To: 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 | 66 ++++++++++++++++++++++------------------------
1 file changed, 32 insertions(+), 34 deletions(-)
diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
index ee012efe25bf..8e5eb5998591 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;
@@ -607,7 +604,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);
@@ -638,7 +635,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,
@@ -724,9 +721,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.
@@ -750,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.
@@ -811,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;
@@ -822,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);
@@ -871,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)
@@ -893,6 +892,7 @@ static int imx355_stop_streaming(struct imx355 *imx355)
static int imx355_set_stream(struct v4l2_subdev *sd, int enable)
{
struct imx355 *imx355 = to_imx355(sd);
+ struct v4l2_subdev_state *state;
int ret = 0;
if (enable) {
@@ -904,7 +904,9 @@ static int imx355_set_stream(struct v4l2_subdev *sd, int enable)
* Apply default & customized values
* and then start streaming.
*/
+ state = v4l2_subdev_lock_and_get_active_state(sd);
ret = imx355_start_streaming(imx355);
+ v4l2_subdev_unlock_state(state);
if (ret)
goto err_rpm_put;
} else {
@@ -1024,11 +1026,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;
@@ -1050,7 +1052,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,
@@ -1243,9 +1244,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] 31+ messages in thread
* Re: [PATCH v3 03/20] media: imx355: Remove duplicated registers from the mode tables
2026-07-08 14:48 ` [PATCH v3 03/20] media: imx355: Remove duplicated registers from the mode tables Dave Stevenson
@ 2026-07-08 15:00 ` sashiko-bot
0 siblings, 0 replies; 31+ messages in thread
From: sashiko-bot @ 2026-07-08 15:00 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:
Pre-existing issues:
- [High] Runtime PM Double Power-Off on probe error path.
--
--- Patch [3]: [PATCH v3 03/20] media: imx355: Remove duplicated registers from the mode tables ---
commit 149de34debabe64c5c7c327e825451e79b0feb6c
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.
Move those to imx355_global_regs.
> diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
> index ad9a9464175b1..4eaccd9e90f10 100644
> --- a/drivers/media/i2c/imx355.c
> +++ b/drivers/media/i2c/imx355.c
[ ... ]
[Severity: High]
This is a pre-existing issue, but I noticed a potential problem in the
error handling path of imx355_probe():
drivers/media/i2c/imx355.c:imx355_probe() {
...
pm_runtime_set_active(imx355->dev);
pm_runtime_enable(imx355->dev);
pm_runtime_idle(imx355->dev);
ret = v4l2_async_register_subdev_sensor(&imx355->sd);
if (ret < 0)
goto error_media_entity_runtime_pm;
...
error_media_entity_runtime_pm:
pm_runtime_disable(imx355->dev);
pm_runtime_set_suspended(imx355->dev);
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);
...
}
Does this code call imx355_power_off() a second time on the error path?
If v4l2_async_register_subdev_sensor() fails, the code jumps to
error_media_entity_runtime_pm. Earlier in the probe, pm_runtime_idle() was
called, which synchronously suspends the device by invoking imx355_power_off().
The error handler then disables runtime PM and falls through to error_power_off,
where it explicitly calls imx355_power_off() again.
Could this double-disabling of regulators and clocks cause reference count
underflows and trigger kernel WARNs (which might panic the system with
panic_on_warn)?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260708-media-imx355-v3-0-9df386a623d7@raspberrypi.com?part=3
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v3 14/20] media: imx355: Set the colorspace in the format
2026-07-08 14:48 ` [PATCH v3 14/20] media: imx355: Set the colorspace in the format Dave Stevenson
@ 2026-07-08 15:01 ` sashiko-bot
0 siblings, 0 replies; 31+ messages in thread
From: sashiko-bot @ 2026-07-08 15:01 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:
- [Low] Accessing a non-existent `format` field on a `struct v4l2_mbus_framefmt` pointer leads to a build failure.
--
--- Patch [14]: [PATCH v3 14/20] media: imx355: Set the colorspace in the format ---
commit 7db2a6f63330856f1837e4b7a0ae932c8ac63b94
Author: Dave Stevenson <dave.stevenson@raspberrypi.com>
media: imx355: Set the colorspace in the format
This commit sets the colorspace fields appropriately for a raw image
sensor in the imx355 driver.
> diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
> index b27329143e481..2bf8da7469fe5 100644
> --- a/drivers/media/i2c/imx355.c
> +++ b/drivers/media/i2c/imx355.c
> @@ -612,6 +612,10 @@ static int imx355_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
> try_fmt->height = imx355->cur_mode->height;
> try_fmt->code = imx355_get_format_code(imx355);
> try_fmt->field = V4L2_FIELD_NONE;
> + try_fmt->format.colorspace = V4L2_COLORSPACE_RAW;
> + try_fmt->format.ycbcr_enc = V4L2_YCBCR_ENC_601;
> + try_fmt->format.quantization = V4L2_QUANTIZATION_FULL_RANGE;
> + try_fmt->format.xfer_func = V4L2_XFER_FUNC_NONE;
[Severity: Low]
Does this cause a build failure? try_fmt is a pointer to struct
v4l2_mbus_framefmt, which doesn't contain a format member.
Should this access the fields directly via try_fmt->colorspace and so on,
similar to how try_fmt->height is accessed just above this change?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260708-media-imx355-v3-0-9df386a623d7@raspberrypi.com?part=14
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v3 09/20] media: imx355: pixel_rate never changes, so don't recompute
2026-07-08 14:48 ` [PATCH v3 09/20] media: imx355: pixel_rate never changes, so don't recompute Dave Stevenson
@ 2026-07-08 15:01 ` sashiko-bot
0 siblings, 0 replies; 31+ messages in thread
From: sashiko-bot @ 2026-07-08 15:01 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:
- [High] Double power-off on the probe error path leads to unbalanced clock and regulator disables.
--
--- Patch [9]: [PATCH v3 09/20] media: imx355: pixel_rate never changes, so don't recompute ---
commit 7b1b03fa06b5d964ffe6862ea61125935053b34e
Author: Dave Stevenson <dave.stevenson@raspberrypi.com>
media: imx355: pixel_rate never changes, so don't recompute
This commit removes the recalculation of the pixel rate in
imx355_set_pad_format, as it remains constant. It also removes the stored
pointer to the pixel_rate control in the imx355 structure since it is no
longer needed.
> diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
> index 2880e03b3f08a..2a97e076bff76 100644
> --- a/drivers/media/i2c/imx355.c
> +++ b/drivers/media/i2c/imx355.c
[ ... ]
> @@ -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;
[Severity: High]
This is a pre-existing issue, but while reviewing this file I noticed a
potential double power-off bug in the probe error path.
If v4l2_async_register_subdev_sensor() fails in imx355_probe(), the code
jumps to the error handler:
drivers/media/i2c/imx355.c:imx355_probe() {
...
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;
...
error_media_entity_runtime_pm:
...
error_power_off:
imx355_power_off(imx355->dev);
...
}
Since pm_runtime_idle() synchronously suspends the device when the usage
count is zero (which calls imx355_power_off()), won't falling through to
error_power_off and calling imx355_power_off() again lead to unbalanced
clock and regulator disables?
If regulators or clocks are shared with other devices, could this extra
disable drop the use count to zero and inadvertently power off resources
that other active devices are relying on?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260708-media-imx355-v3-0-9df386a623d7@raspberrypi.com?part=9
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v3 10/20] media: imx355: Remove redundant fll_min, and implement fixed offset
2026-07-08 14:48 ` [PATCH v3 10/20] media: imx355: Remove redundant fll_min, and implement fixed offset Dave Stevenson
@ 2026-07-08 15:05 ` sashiko-bot
0 siblings, 0 replies; 31+ messages in thread
From: sashiko-bot @ 2026-07-08 15:05 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:
Pre-existing issues:
- [High] When changing the format via `imx355_set_pad_format()`, the driver attempts to reset `vblank` to its default value using `__v4l2_ctrl_s_ctrl()`. It relies on this call to trigger the `s_ctrl` callback (`imx355_set_ctrl()`), which updates the `exposure` control's maximum limit based on the new format's height. However, the V4L2 control framework explicitly optimizes out calls to `s_ctrl` if the new control value equals the current value. If a user manually sets `vblank` to a value that matches the target format's `vblank_def` prior to a format switch, `s_ctrl` is skipped and the `exposure` bounds are not updated. This leaves the control completely out-of-sync with the new format's Frame Length Lines (FLL).
--
--- Patch [10]: [PATCH v3 10/20] media: imx355: Remove redundant fll_min, and implement fixed offset ---
commit 3cb4d69cef75e79b15075f8e2c250b2bb53d96a4
Author: Dave Stevenson <dave.stevenson@raspberrypi.com>
Subject: media: imx355: Remove redundant fll_min, and implement fixed offset
This commit removes the redundant fll_min field from the imx355 mode
configurations, as it is always identical to fll_def. It also sets a fixed
minimum vertical blanking (vblank) limit of 20 to improve the maximum frame
rate achievable across all modes.
> diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
> index 2a97e076bff76..c6f27cf269b40 100644
> --- a/drivers/media/i2c/imx355.c
> +++ b/drivers/media/i2c/imx355.c
[ ... ]
> @@ -889,10 +874,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: High]
This is a pre-existing issue, but I noticed a potential problem in how
exposure limits are updated during a format change in
imx355_set_pad_format().
The code relies on __v4l2_ctrl_s_ctrl() to reset the vblank value, expecting
it to trigger the s_ctrl callback (imx355_set_ctrl) to update the exposure
control limits.
However, the V4L2 control framework optimizes out calls to s_ctrl if the
new control value matches the current value. If userspace manually sets
vblank to a value that exactly equals the new format's vblank_def prior to
the format switch, the s_ctrl callback will be skipped.
Could this leave the exposure limits out of sync with the new format's Frame
Length Lines (FLL), resulting in userspace seeing stale limits and potentially
setting an invalid exposure value?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260708-media-imx355-v3-0-9df386a623d7@raspberrypi.com?part=10
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v3 12/20] media: imx355: Use pm_runtime autosuspend_delay
2026-07-08 14:48 ` [PATCH v3 12/20] media: imx355: Use pm_runtime autosuspend_delay Dave Stevenson
@ 2026-07-08 15:06 ` sashiko-bot
0 siblings, 0 replies; 31+ messages in thread
From: sashiko-bot @ 2026-07-08 15:06 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:
- [Medium] The autosuspend optimization is bypassed during driver probe because `pm_runtime_idle()` is called before autosuspend is enabled.
--
--- Patch [12]: [PATCH v3 12/20] media: imx355: Use pm_runtime autosuspend_delay ---
commit c848098f5125edf42a401c819297cfe0a783116c
Author: Dave Stevenson <dave.stevenson@raspberrypi.com>
media: imx355: Use pm_runtime autosuspend_delay
This commit introduces pm_runtime autosuspend functionality to the imx355
sensor driver. It configures a 1000ms autosuspend delay to prevent
unnecessary power cycling between operations.
> diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
> index ee1f41a66a0b6..f01a1a5ae7c9a 100644
> --- a/drivers/media/i2c/imx355.c
> +++ b/drivers/media/i2c/imx355.c
[ ... ]
> @@ -1436,6 +1436,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);
[Severity: Medium]
Does this sequence cause the device to power off immediately during probe?
Because pm_runtime_idle() is called before pm_runtime_use_autosuspend(), the
device usage count is 0 and autosuspend is not yet enabled. This seems to
trigger a synchronous suspend right away, bypassing the 1000ms delay
optimization intended by this patch.
Would it be better to reorder these so the autosuspend properties are
configured before triggering the idle check?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260708-media-imx355-v3-0-9df386a623d7@raspberrypi.com?part=12
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v3 15/20] media: imx355: Define the exposure offset, and use that define
2026-07-08 14:48 ` [PATCH v3 15/20] media: imx355: Define the exposure offset, and use that define Dave Stevenson
@ 2026-07-08 15:07 ` sashiko-bot
0 siblings, 0 replies; 31+ messages in thread
From: sashiko-bot @ 2026-07-08 15:07 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:
Pre-existing issues:
- [High] The check `!pm_runtime_get_if_in_use(imx355->dev)` incorrectly treats `-EINVAL` as success, causing the driver to write to hardware that is likely powered off and perform an unbalanced `pm_runtime_put()`.
- [High] When switching frame formats, the maximum exposure limit might fail to update to the new mode's geometry if the new format's `vblank_def` matches the current `vblank` value.
--
--- Patch [15]: [PATCH v3 15/20] media: imx355: Define the exposure offset, and use that define ---
commit 271b8bad9a7b25d1cb2eae62528be12497b83823
Author: Dave Stevenson <dave.stevenson@raspberrypi.com>
media: imx355: Define the exposure offset, and use that define
This commit introduces a new define, IMX355_EXPOSURE_OFFSET, to represent
the 10-line difference between frame length and maximum exposure time. It
replaces the bare value of 10 in the driver's control calculations with
this new define.
> diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
> index 2bf8da7469fe5..3b86bd2e2e5e8 100644
> --- a/drivers/media/i2c/imx355.c
> +++ b/drivers/media/i2c/imx355.c
[ ... ]
> @@ -635,7 +636,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);
> break;
> }
>
> /*
> * Applying V4L2 control value only happens
> * when power is up for streaming
> */
> if (!pm_runtime_get_if_in_use(imx355->dev))
> return 0;
[Severity: High]
This is a pre-existing issue, but does this correctly handle negative return
values?
If pm_runtime_get_if_in_use() returns -EINVAL (which occurs when PM runtime
is disabled or during driver unbind), the driver evaluates !(-EINVAL) as
false (0).
This bypasses the early return, leading to I2C writes to potentially
powered-off hardware, followed by a pm_runtime_put() that drops the usage
counter without a corresponding get. This unbalanced put can cause the
device usage count to prematurely reach 0 while other components hold
references.
[Severity: High]
This isn't a bug introduced by this patch, but does the exposure limit
correctly update when changing frame formats?
drivers/media/i2c/imx355.c:imx355_set_pad_format() {
...
__v4l2_ctrl_modify_range(imx355->vblank, IMX355_VBLANK_MIN,
height, 1, vblank_def);
__v4l2_ctrl_s_ctrl(imx355->vblank, vblank_def);
...
}
The driver relies on __v4l2_ctrl_s_ctrl() to trigger the vblank s_ctrl
callback (imx355_set_ctrl) to update the exposure maximum limit based on
the new mode's geometry.
However, if the new format's default vblank_def happens to equal the
currently set vblank value, the V4L2 framework considers the control
unchanged and short-circuits the callback. As a result, the exposure
maximum limit is not updated, potentially allowing users to set an exposure
time that exceeds the frame length.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260708-media-imx355-v3-0-9df386a623d7@raspberrypi.com?part=15
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v3 13/20] media: imx355: Convert to new CCI register access helpers
2026-07-08 14:48 ` [PATCH v3 13/20] media: imx355: Convert to new CCI register access helpers Dave Stevenson
@ 2026-07-08 15:08 ` sashiko-bot
0 siblings, 0 replies; 31+ messages in thread
From: sashiko-bot @ 2026-07-08 15:08 UTC (permalink / raw)
To: Dave Stevenson; +Cc: devicetree, conor+dt, robh
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Missing lock when calling `__v4l2_ctrl_grab` in `imx355_set_stream` leading to data race
--
--- Patch [13]: [PATCH v3 13/20] media: imx355: Convert to new CCI register access helpers ---
commit fe9b8fcf594a4a8149bc0b6b2e99148353f94fe2
Author: Dave Stevenson <dave.stevenson@raspberrypi.com>
media: imx355: Convert to new CCI register access helpers
This commit replaces the private register access helpers in the imx355 driver
with the new common CCI register access helpers.
> diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
> index f01a1a5ae7c9a..b27329143e481 100644
> --- a/drivers/media/i2c/imx355.c
> +++ b/drivers/media/i2c/imx355.c
[ ... ]
> @@ -1096,14 +981,14 @@ static int imx355_set_stream(struct v4l2_subdev *sd, int enable)
[Severity: High]
Does this code now lack a lock when calling __v4l2_ctrl_grab() in
imx355_set_stream()?
Since the outer mutex_lock(&imx355->mutex) was removed in this series in
favor of localized locking via v4l2_subdev_lock_and_get_active_state(sd),
the __v4l2_ctrl_grab() calls appear to be left unprotected:
if (enable) {
...
state = v4l2_subdev_lock_and_get_active_state(sd);
ret = imx355_start_streaming(imx355);
v4l2_subdev_unlock_state(state);
...
} else {
imx355_stop_streaming(imx355);
...
}
/* vflip and hflip cannot change during streaming */
__v4l2_ctrl_grab(imx355->vflip, enable);
__v4l2_ctrl_grab(imx355->hflip, enable);
__v4l2_ctrl_grab() modifies control flags and invokes send_event(), which
iterates over the event subscription list (ctrl->ev_subs).
If userspace concurrently calls VIDIOC_SUBSCRIBE_EVENT or
VIDIOC_UNSUBSCRIBE_EVENT on the flip controls while another thread starts or
stops streaming (VIDIOC_STREAMON / VIDIOC_STREAMOFF), could this cause list
corruption and a kernel panic?
Additionally, __v4l2_ctrl_grab() asserts lockdep_assert_held(), which would
trigger a lockdep splat if the control handler's lock is not held.
> 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;
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260708-media-imx355-v3-0-9df386a623d7@raspberrypi.com?part=13
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v3 19/20] media: imx355: Switch to using the subdev state
2026-07-08 14:48 ` [PATCH v3 19/20] media: imx355: Switch to using the subdev state Dave Stevenson
@ 2026-07-08 15:10 ` sashiko-bot
0 siblings, 0 replies; 31+ messages in thread
From: sashiko-bot @ 2026-07-08 15:10 UTC (permalink / raw)
To: Dave Stevenson; +Cc: conor+dt, robh, devicetree
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] `__v4l2_ctrl_grab()` is called without holding the required control handler lock, leading to lockdep assertions and data races.
- [Medium] V4L2 control values (`vflip` and `hflip`) are accessed locklessly during TRY state pad operations, introducing data races.
- [Medium] The error path for `v4l2_subdev_init_finalize()` bypasses `media_entity_cleanup()`.
--
--- Patch [19]: [PATCH v3 19/20] media: imx355: Switch to using the subdev state ---
commit 71948b5f6b6de08ab0164654fbf608971cc7cfe3
Author: Dave Stevenson <dave.stevenson@raspberrypi.com>
media: imx355: Switch to using the subdev state
The subdev state is now preferred rather than handling crop and format within
the driver state, so switch the driver to using it.
> diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
> --- a/drivers/media/i2c/imx355.c
> +++ b/drivers/media/i2c/imx355.c
[ ... ]
> @@ -705,9 +675,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);
[Severity: Medium]
Will this lead to unprotected reads of the vflip and hflip controls?
When performing TRY operations, the V4L2 framework only holds the file handle
lock, not the subdev active state lock (which aliases to the control handler
lock).
Because the explicit driver mutex was removed here, it seems concurrent
operations could modify the control values while imx355_get_format_code()
reads them. Should the control handler lock be acquired before reading
these values?
> - mutex_unlock(&imx355->mutex);
>
> return 0;
> }
[ ... ]
> @@ -992,14 +916,10 @@ static int imx355_set_stream(struct v4l2_subdev *sd, int enable)
> __v4l2_ctrl_grab(imx355->vflip, enable);
> __v4l2_ctrl_grab(imx355->hflip, enable);
[Severity: High]
Does this execute __v4l2_ctrl_grab() without holding the required lock?
Looking at __v4l2_ctrl_grab(), it asserts that the control handler lock is
held. Since the explicit driver mutex was removed and the subdev active
state lock is released before reaching this point (or not acquired at all
on the disable path), will this trigger a lockdep splat and introduce a
data race in the control flag modification?
> - mutex_unlock(&imx355->mutex);
> -
> return ret;
>
> err_rpm_put:
> pm_runtime_put_autosuspend(imx355->dev);
> -err_unlock:
> - mutex_unlock(&imx355->mutex);
>
> return ret;
> }
[ ... ]
> @@ -1351,6 +1267,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;
[Severity: Medium]
Does this error path leak the media entity pads?
Earlier in imx355_probe(), media_entity_pads_init() is called. If
v4l2_subdev_init_finalize() fails, the code jumps to error_handler_free,
which bypasses the media_entity_cleanup() call located under the
error_media_entity_runtime_pm label. Should this jump to a label that
cleans up the media entity instead?
> + }
> +
> /*
> * Device is already turned on by i2c-core with ACPI domain PM.
> * Enable runtime PM and turn off the device.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260708-media-imx355-v3-0-9df386a623d7@raspberrypi.com?part=19
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v3 11/20] media: imx355: Add support for get_selection
2026-07-08 14:48 ` [PATCH v3 11/20] media: imx355: Add support for get_selection Dave Stevenson
@ 2026-07-08 15:11 ` sashiko-bot
0 siblings, 0 replies; 31+ messages in thread
From: sashiko-bot @ 2026-07-08 15:11 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:
- [Low] Undeclared variable `crop` used in `imx355_set_pad_format()` causing a compilation error.
--
--- Patch [11]: [PATCH v3 11/20] media: imx355: Add support for get_selection ---
commit 16a5ac6200fbe4b75d8e6b726a26958a450dfdf0
Author: Dave Stevenson <dave.stevenson@raspberrypi.com>
media: imx355: Add support for get_selection
This commit provides all cropping information via get_selection. It updates
the subdev pad format operations to maintain crop rectangles in the try state
and implements the get_selection callback.
> diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
> index c6f27cf269b40..ee1f41a66a0b6 100644
> --- a/drivers/media/i2c/imx355.c
> +++ b/drivers/media/i2c/imx355.c
[ ... ]
> @@ -869,6 +877,12 @@ imx355_set_pad_format(struct v4l2_subdev *sd,
> if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
> framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
> *framefmt = fmt->format;
> +
> + crop = v4l2_subdev_state_get_crop(sd_state, 0);
[Severity: Low]
Does this code introduce a compilation error? Looking at imx355_set_pad_format(),
it appears the crop variable is assigned and dereferenced here but is never
declared as a local variable within the function.
> + crop->width = mode->crop.width;
> + crop->height = mode->crop.height;
> + crop->left = mode->crop.left;
> + crop->top = mode->crop.top;
> } else {
> imx355->cur_mode = mode;
> /* Update limits and set FPS to default */
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260708-media-imx355-v3-0-9df386a623d7@raspberrypi.com?part=11
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v3 20/20] media: imx355: Remove storing cur_mode in the state
2026-07-08 14:48 ` [PATCH v3 20/20] media: imx355: Remove storing cur_mode in the state Dave Stevenson
@ 2026-07-08 15:17 ` sashiko-bot
0 siblings, 0 replies; 31+ messages in thread
From: sashiko-bot @ 2026-07-08 15:17 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:
- [High] The `__v4l2_ctrl_grab()` function is called without holding the required control handler lock, triggering a lockdep BUG and causing a data race.
--
--- Patch [20]: [PATCH v3 20/20] media: imx355: Remove storing cur_mode in the state ---
commit 0f6829a36bfe297cb0fe5da42f9da61884297d27
Author: Dave Stevenson <dave.stevenson@raspberrypi.com>
media: imx355: Remove storing cur_mode in the state
This commit removes the cur_mode pointer from the imx355 structure. It
changes the driver to retrieve the mode information directly from the subdev
state instead.
> diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
> --- a/drivers/media/i2c/imx355.c
> +++ b/drivers/media/i2c/imx355.c
> @@ -892,19 +892,23 @@ static int imx355_stop_streaming(struct imx355 *imx355)
> static int imx355_set_stream(struct v4l2_subdev *sd, int enable)
> {
> struct imx355 *imx355 = to_imx355(sd);
> + struct v4l2_subdev_state *state;
> int ret = 0;
>
> if (enable) {
> ret = pm_runtime_resume_and_get(imx355->dev);
> if (ret < 0)
> return ret;
>
> /*
> * Apply default & customized values
> * and then start streaming.
> */
> + state = v4l2_subdev_lock_and_get_active_state(sd);
> ret = imx355_start_streaming(imx355);
> + v4l2_subdev_unlock_state(state);
> if (ret)
> goto err_rpm_put;
> } else {
> imx355_stop_streaming(imx355);
> pm_runtime_put_autosuspend(imx355->dev);
> }
>
> /* vflip and hflip cannot change during streaming */
> __v4l2_ctrl_grab(imx355->vflip, enable);
> __v4l2_ctrl_grab(imx355->hflip, enable);
[Severity: High]
Is it safe to call __v4l2_ctrl_grab() without holding the control handler lock
here?
This patch adds v4l2_subdev_lock_and_get_active_state() around
imx355_start_streaming(), but releases the lock immediately with
v4l2_subdev_unlock_state().
It then calls __v4l2_ctrl_grab() completely unprotected. In the enable == 0
path, the lock is never taken at all.
Since __v4l2_ctrl_grab() asserts lockdep_assert_held(ctrl->handler->lock),
could this cause a lockdep splat or a data race on the control state? Should
the driver use the locked v4l2_ctrl_grab() variant here instead?
>
> return ret;
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260708-media-imx355-v3-0-9df386a623d7@raspberrypi.com?part=20
^ permalink raw reply [flat|nested] 31+ messages in thread
end of thread, other threads:[~2026-07-08 15:17 UTC | newest]
Thread overview: 31+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-08 14:48 [PATCH v3 00/20] media/imx355: General code cleanups, and adding support for 2 lane operation Dave Stevenson
2026-07-08 14:48 ` [PATCH v3 01/20] media: i2c: imx355: Add support for 24 MHz external clock Dave Stevenson
2026-07-08 14:48 ` [PATCH v3 02/20] dt-bindings: media: imx355: Allow 2 CSI2 data lane output Dave Stevenson
2026-07-08 14:48 ` [PATCH v3 03/20] media: imx355: Remove duplicated registers from the mode tables Dave Stevenson
2026-07-08 15:00 ` sashiko-bot
2026-07-08 14:48 ` [PATCH v3 04/20] media: imx355: Remove setting FRM_LENGTH_LINES in the mode regs Dave Stevenson
2026-07-08 14:48 ` [PATCH v3 05/20] media: imx355: Programmatically set the crop parameters for each mode Dave Stevenson
2026-07-08 14:48 ` [PATCH v3 06/20] media: imx355: Set register LINE_LENGTH_PCK programmatically Dave Stevenson
2026-07-08 14:48 ` [PATCH v3 07/20] media: imx355: Set binning mode registers programmatically Dave Stevenson
2026-07-08 14:48 ` [PATCH v3 08/20] media: imx355: Remove link_freq_index from each mode as ununsed Dave Stevenson
2026-07-08 14:48 ` [PATCH v3 09/20] media: imx355: pixel_rate never changes, so don't recompute Dave Stevenson
2026-07-08 15:01 ` sashiko-bot
2026-07-08 14:48 ` [PATCH v3 10/20] media: imx355: Remove redundant fll_min, and implement fixed offset Dave Stevenson
2026-07-08 15:05 ` sashiko-bot
2026-07-08 14:48 ` [PATCH v3 11/20] media: imx355: Add support for get_selection Dave Stevenson
2026-07-08 15:11 ` sashiko-bot
2026-07-08 14:48 ` [PATCH v3 12/20] media: imx355: Use pm_runtime autosuspend_delay Dave Stevenson
2026-07-08 15:06 ` sashiko-bot
2026-07-08 14:48 ` [PATCH v3 13/20] media: imx355: Convert to new CCI register access helpers Dave Stevenson
2026-07-08 15:08 ` sashiko-bot
2026-07-08 14:48 ` [PATCH v3 14/20] media: imx355: Set the colorspace in the format Dave Stevenson
2026-07-08 15:01 ` sashiko-bot
2026-07-08 14:48 ` [PATCH v3 15/20] media: imx355: Define the exposure offset, and use that define Dave Stevenson
2026-07-08 15:07 ` sashiko-bot
2026-07-08 14:48 ` [PATCH v3 16/20] media: imx355: Use NULL ctrl_ops for HBLANK as it is a read-only control Dave Stevenson
2026-07-08 14:48 ` [PATCH v3 17/20] media: imx355: Compute link frequency from PLL setup Dave Stevenson
2026-07-08 14:48 ` [PATCH v3 18/20] media: imx355: Support 2 lane readout Dave Stevenson
2026-07-08 14:48 ` [PATCH v3 19/20] media: imx355: Switch to using the subdev state Dave Stevenson
2026-07-08 15:10 ` sashiko-bot
2026-07-08 14:48 ` [PATCH v3 20/20] media: imx355: Remove storing cur_mode in the state Dave Stevenson
2026-07-08 15:17 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox