On Thu, 18 Jun 2026 at 13:11, David Heidelberg <[email protected]> wrote: > > On 17/06/2026 19:40, Dave Stevenson wrote: > > Hi David > > > > On Thu, 16 Apr 2026 at 12:26, Dave Stevenson > > <[email protected]> wrote: > >> > >> Hi David > >> > >> On Tue, 14 Apr 2026 at 11:17, David Heidelberg via B4 Relay > >> <[email protected]> wrote: > >>> > >>> From: David Heidelberg <[email protected]> > >>> > >>> 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: > >>> - VT VCO remains at 1152 MHz > >>> - OP VCO remains at 720 MHz > >>> > >>> This preserves existing timing characteristics while allowing systems > >>> using a 24 MHz clock to operate correctly. > >> > >> I happened to have someone asking for this same requirement, so tried > >> out your patch. > >> > >> I don't have a datasheet for IMX355, but the patterns very closely > >> follow IMX477 and IMX708 for which I do. > >> Those both have a single PLL and a dual PLL mode selected via register > >> PLL_MULT_DRIV (0x0310). The imx355 driver is setting that to 0 for > >> single PLL mode, which means that the PREDIV_IVT (0x0305) and MPY_IVT > >> PLL (0x0306/7) settings do nothing as the IVT block is driven from > >> IOPCK. > > > > I now have the datasheet and software reference manual for IMX355. > > > > It says that dual PLL mode is not available. > > "In PLL single mode, IOP_PREPLLCK_DIV and IOP_PLL_MPY are applied to > > IOPCK PLL, and IVT_PREPLLCK_DIV and IVT_PLL_MPY are ignored". > > So there is no need to have alternate pll_vt_mpy values for 24MHz. > > > > I have no idea why Sony say that dual PLL mode isn't available. When I > > was adding the 2 lane support I used it without any issues. I'm now > > reworking those patches to avoid dual PLL mode. > > Maybe there is some ERRATA which makes it unstable or problematic?
Not mentioned in the information I've got, so it must have been deleted as a feature very early in development. C'est la vie. > > Then again the datasheet also says that LINE_LENGTH_PCK is constrained > > to 3672 in full res and 4x4 binning mode, and 1836 in 2x2 binned modes > > "to avoid sensor internal interference (FPN)", so they obviously hit > > some odd behaviours and just added constraints. > > > > Do you wish to send a V2 dropping pll_vt_mpy, or shall I pull it into my > > series? > > What works for you better (since u sending bigger changes than I do). I'm happy to merge it into my series as that avoids having to declare dependencies. I had hoped to get my v2 out this week, but it just hasn't happened. It won't be next week, but hopefully within the fortnight. Dave > David > > > > > Thanks > > Dave > > > >> Your patch therefore works, but does more than is necessary - you > >> really can set pll_vt_mpy to any value and it works exactly the same. > >> I guess changing the unconnected IVTCK clock within the sensor could > >> feasibly change EMC emissions, but that feels pretty unlikely. > >> Possibly add a comment to your existing comment of "VT VCO = 1152 MHz" > >> to say that it's unused to avoid others going down the rabbit hole I > >> encountered. > >> > >> (For those referencing the other datasheets, the description for > >> single PLL mode lists configuring IVT_PREPLLCK_DIV and IVT_PLL_MPY, > >> but the diagram shows that IOP is always driven from IOPCK, and IVT is > >> muxed between IOPCK and IVTCK) > >> > >>> No functional change for existing 19.2 MHz users. > >>> > >>> Assisted-by: Claude:claude-opus-4-6 > >>> Signed-off-by: David Heidelberg <[email protected]> > >> > >> Whilst useful comments could be added, it does what it says and works: > >> > >> Reviewed-by: Dave Stevenson <[email protected]> > >> Tested-by: Dave Stevenson <[email protected]> > >> > >>> --- > >>> Known users: Pixel 3 and 3a. > >>> --- > >>> drivers/media/i2c/imx355.c | 114 > >>> +++++++++++++++++++++------------------------ > >>> 1 file changed, 54 insertions(+), 60 deletions(-) > >>> > >>> diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c > >>> index 27a5c212a527f..f9ec13bb27d10 100644 > >>> --- a/drivers/media/i2c/imx355.c > >>> +++ b/drivers/media/i2c/imx355.c > >>> @@ -25,6 +25,11 @@ > >>> #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_VT_MUL 0x0306 > >>> +#define IMX355_REG_PLL_OP_MUL 0x030e > >>> + > >>> /* V_TIMING internal */ > >>> #define IMX355_REG_FLL 0x0340 > >>> #define IMX355_FLL_MAX 0xffff > >>> @@ -63,7 +68,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 +104,33 @@ 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_vt_mpy; /* VT system PLL multiplier */ > >>> + u16 pll_op_mpy; /* OP system PLL multiplier */ > >>> +}; > >>> + > >>> +/* > >>> + * All modes use the same PLL dividers (PREPLLCK_VT_DIV=2, > >>> PREPLLCK_OP_DIV=2), > >>> + * so the multipliers are adjusted to produce the same VCO frequencies: > >>> + * VT VCO = 1152 MHz, OP VCO = 720 MHz > >>> + */ > >>> +static const struct imx355_clk_params imx355_clk_params[] = { > >>> + { > >>> + .ext_clk = 19200000, > >>> + .extclk_freq = 0x1333, /* 19.2 MHz */ > >>> + .pll_vt_mpy = 120, /* 19.2 / 2 * 120 = 1152 MHz */ > >>> + .pll_op_mpy = 75, /* 19.2 / 2 * 75 = 720 MHz */ > >>> + }, > >>> + { > >>> + .ext_clk = 24000000, > >>> + .extclk_freq = 0x1800, /* 24.0 MHz */ > >>> + .pll_vt_mpy = 96, /* 24.0 / 2 * 96 = 1152 MHz */ > >>> + .pll_op_mpy = 60, /* 24.0 / 2 * 60 = 720 MHz */ > >>> + }, > >>> +}; > >>> + > >>> struct imx355_hwcfg { > >>> unsigned long link_freq_bitmap; > >>> }; > >>> @@ -125,6 +156,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 +176,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 }, > >>> @@ -231,12 +261,8 @@ static const struct imx355_reg mode_3268x2448_regs[] > >>> = { > >>> { 0x0301, 0x05 }, > >>> { 0x0303, 0x01 }, > >>> { 0x0305, 0x02 }, > >>> - { 0x0306, 0x00 }, > >>> - { 0x0307, 0x78 }, > >>> { 0x030b, 0x01 }, > >>> { 0x030d, 0x02 }, > >>> - { 0x030e, 0x00 }, > >>> - { 0x030f, 0x4b }, > >>> { 0x0310, 0x00 }, > >>> { 0x0700, 0x00 }, > >>> { 0x0701, 0x10 }, > >>> @@ -280,12 +306,8 @@ static const struct imx355_reg mode_3264x2448_regs[] > >>> = { > >>> { 0x0301, 0x05 }, > >>> { 0x0303, 0x01 }, > >>> { 0x0305, 0x02 }, > >>> - { 0x0306, 0x00 }, > >>> - { 0x0307, 0x78 }, > >>> { 0x030b, 0x01 }, > >>> { 0x030d, 0x02 }, > >>> - { 0x030e, 0x00 }, > >>> - { 0x030f, 0x4b }, > >>> { 0x0310, 0x00 }, > >>> { 0x0700, 0x00 }, > >>> { 0x0701, 0x10 }, > >>> @@ -329,12 +351,8 @@ static const struct imx355_reg mode_3280x2464_regs[] > >>> = { > >>> { 0x0301, 0x05 }, > >>> { 0x0303, 0x01 }, > >>> { 0x0305, 0x02 }, > >>> - { 0x0306, 0x00 }, > >>> - { 0x0307, 0x78 }, > >>> { 0x030b, 0x01 }, > >>> { 0x030d, 0x02 }, > >>> - { 0x030e, 0x00 }, > >>> - { 0x030f, 0x4b }, > >>> { 0x0310, 0x00 }, > >>> { 0x0700, 0x00 }, > >>> { 0x0701, 0x10 }, > >>> @@ -378,12 +396,8 @@ static const struct imx355_reg mode_1940x1096_regs[] > >>> = { > >>> { 0x0301, 0x05 }, > >>> { 0x0303, 0x01 }, > >>> { 0x0305, 0x02 }, > >>> - { 0x0306, 0x00 }, > >>> - { 0x0307, 0x78 }, > >>> { 0x030b, 0x01 }, > >>> { 0x030d, 0x02 }, > >>> - { 0x030e, 0x00 }, > >>> - { 0x030f, 0x4b }, > >>> { 0x0310, 0x00 }, > >>> { 0x0700, 0x00 }, > >>> { 0x0701, 0x10 }, > >>> @@ -427,12 +441,8 @@ static const struct imx355_reg mode_1936x1096_regs[] > >>> = { > >>> { 0x0301, 0x05 }, > >>> { 0x0303, 0x01 }, > >>> { 0x0305, 0x02 }, > >>> - { 0x0306, 0x00 }, > >>> - { 0x0307, 0x78 }, > >>> { 0x030b, 0x01 }, > >>> { 0x030d, 0x02 }, > >>> - { 0x030e, 0x00 }, > >>> - { 0x030f, 0x4b }, > >>> { 0x0310, 0x00 }, > >>> { 0x0700, 0x00 }, > >>> { 0x0701, 0x10 }, > >>> @@ -476,12 +486,8 @@ static const struct imx355_reg mode_1924x1080_regs[] > >>> = { > >>> { 0x0301, 0x05 }, > >>> { 0x0303, 0x01 }, > >>> { 0x0305, 0x02 }, > >>> - { 0x0306, 0x00 }, > >>> - { 0x0307, 0x78 }, > >>> { 0x030b, 0x01 }, > >>> { 0x030d, 0x02 }, > >>> - { 0x030e, 0x00 }, > >>> - { 0x030f, 0x4b }, > >>> { 0x0310, 0x00 }, > >>> { 0x0700, 0x00 }, > >>> { 0x0701, 0x10 }, > >>> @@ -525,12 +531,8 @@ static const struct imx355_reg mode_1920x1080_regs[] > >>> = { > >>> { 0x0301, 0x05 }, > >>> { 0x0303, 0x01 }, > >>> { 0x0305, 0x02 }, > >>> - { 0x0306, 0x00 }, > >>> - { 0x0307, 0x78 }, > >>> { 0x030b, 0x01 }, > >>> { 0x030d, 0x02 }, > >>> - { 0x030e, 0x00 }, > >>> - { 0x030f, 0x4b }, > >>> { 0x0310, 0x00 }, > >>> { 0x0700, 0x00 }, > >>> { 0x0701, 0x10 }, > >>> @@ -574,12 +576,8 @@ static const struct imx355_reg mode_1640x1232_regs[] > >>> = { > >>> { 0x0301, 0x05 }, > >>> { 0x0303, 0x01 }, > >>> { 0x0305, 0x02 }, > >>> - { 0x0306, 0x00 }, > >>> - { 0x0307, 0x78 }, > >>> { 0x030b, 0x01 }, > >>> { 0x030d, 0x02 }, > >>> - { 0x030e, 0x00 }, > >>> - { 0x030f, 0x4b }, > >>> { 0x0310, 0x00 }, > >>> { 0x0700, 0x00 }, > >>> { 0x0701, 0x10 }, > >>> @@ -623,12 +621,8 @@ static const struct imx355_reg mode_1640x922_regs[] > >>> = { > >>> { 0x0301, 0x05 }, > >>> { 0x0303, 0x01 }, > >>> { 0x0305, 0x02 }, > >>> - { 0x0306, 0x00 }, > >>> - { 0x0307, 0x78 }, > >>> { 0x030b, 0x01 }, > >>> { 0x030d, 0x02 }, > >>> - { 0x030e, 0x00 }, > >>> - { 0x030f, 0x4b }, > >>> { 0x0310, 0x00 }, > >>> { 0x0700, 0x00 }, > >>> { 0x0701, 0x10 }, > >>> @@ -672,12 +666,8 @@ static const struct imx355_reg mode_1300x736_regs[] > >>> = { > >>> { 0x0301, 0x05 }, > >>> { 0x0303, 0x01 }, > >>> { 0x0305, 0x02 }, > >>> - { 0x0306, 0x00 }, > >>> - { 0x0307, 0x78 }, > >>> { 0x030b, 0x01 }, > >>> { 0x030d, 0x02 }, > >>> - { 0x030e, 0x00 }, > >>> - { 0x030f, 0x4b }, > >>> { 0x0310, 0x00 }, > >>> { 0x0700, 0x00 }, > >>> { 0x0701, 0x10 }, > >>> @@ -721,12 +711,8 @@ static const struct imx355_reg mode_1296x736_regs[] > >>> = { > >>> { 0x0301, 0x05 }, > >>> { 0x0303, 0x01 }, > >>> { 0x0305, 0x02 }, > >>> - { 0x0306, 0x00 }, > >>> - { 0x0307, 0x78 }, > >>> { 0x030b, 0x01 }, > >>> { 0x030d, 0x02 }, > >>> - { 0x030e, 0x00 }, > >>> - { 0x030f, 0x4b }, > >>> { 0x0310, 0x00 }, > >>> { 0x0700, 0x00 }, > >>> { 0x0701, 0x10 }, > >>> @@ -770,12 +756,8 @@ static const struct imx355_reg mode_1284x720_regs[] > >>> = { > >>> { 0x0301, 0x05 }, > >>> { 0x0303, 0x01 }, > >>> { 0x0305, 0x02 }, > >>> - { 0x0306, 0x00 }, > >>> - { 0x0307, 0x78 }, > >>> { 0x030b, 0x01 }, > >>> { 0x030d, 0x02 }, > >>> - { 0x030e, 0x00 }, > >>> - { 0x030f, 0x4b }, > >>> { 0x0310, 0x00 }, > >>> { 0x0700, 0x00 }, > >>> { 0x0701, 0x10 }, > >>> @@ -819,12 +801,8 @@ static const struct imx355_reg mode_1280x720_regs[] > >>> = { > >>> { 0x0301, 0x05 }, > >>> { 0x0303, 0x01 }, > >>> { 0x0305, 0x02 }, > >>> - { 0x0306, 0x00 }, > >>> - { 0x0307, 0x78 }, > >>> { 0x030b, 0x01 }, > >>> { 0x030d, 0x02 }, > >>> - { 0x030e, 0x00 }, > >>> - { 0x030f, 0x4b }, > >>> { 0x0310, 0x00 }, > >>> { 0x0700, 0x00 }, > >>> { 0x0701, 0x10 }, > >>> @@ -868,12 +846,8 @@ static const struct imx355_reg mode_820x616_regs[] = > >>> { > >>> { 0x0301, 0x05 }, > >>> { 0x0303, 0x01 }, > >>> { 0x0305, 0x02 }, > >>> - { 0x0306, 0x00 }, > >>> - { 0x0307, 0x78 }, > >>> { 0x030b, 0x01 }, > >>> { 0x030d, 0x02 }, > >>> - { 0x030e, 0x00 }, > >>> - { 0x030f, 0x4b }, > >>> { 0x0310, 0x00 }, > >>> { 0x0700, 0x02 }, > >>> { 0x0701, 0x78 }, > >>> @@ -1422,6 +1396,20 @@ 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_VT_MUL, 2, > >>> + imx355->clk_params->pll_vt_mpy); > >>> + 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 +1737,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); > >>> > >>> --- > >>> base-commit: 66672af7a095d89f082c5327f3b15bc2f93d558e > >>> change-id: 20260414-imx355-24mhz-b8ccfab3adfb > >>> > >>> Best regards, > >>> -- > >>> David Heidelberg <[email protected]> > >>> > >>> > >>> > > -- > David Heidelberg >

