2024-01-25 15:49:41

by Umang Jain

[permalink] [raw]
Subject: [PATCH 0/4] imx335: Support additional link-freq and TPG

This series adds support for additional link frequency and
test pattern generator on IMX335.

Patch 1/4 is a drive-by patch which drops setting of a reserved
register.

Patch 2/4 is also a prep-up patch for TPG introduction(in 4/4), as the test
pattern needs sensor to be powered up to apply the test pattern.

Patch 3/4 supports for additional link-frequency supported by IMX335

Matthias Fend (1):
media: i2c: imx335: Add support for test pattern generator

Umang Jain (3):
media: i2c: imx335: Drop setting of 0x3a00 register
media: i2c: imx335: Refactor power sequence to set controls
media: i2c: imx335: Support multiple link frequency

drivers/media/i2c/imx335.c | 227 ++++++++++++++++++++++++++++++++-----
1 file changed, 197 insertions(+), 30 deletions(-)

--
2.41.0



2024-01-25 15:49:57

by Umang Jain

[permalink] [raw]
Subject: [PATCH 1/4] media: i2c: imx335: Drop setting of 0x3a00 register

Register 0x3a00 is a reserved field as per the IMX335 datasheet,
hence shouldn't be set by the driver.

Signed-off-by: Umang Jain <[email protected]>
---
drivers/media/i2c/imx335.c | 1 -
1 file changed, 1 deletion(-)

diff --git a/drivers/media/i2c/imx335.c b/drivers/media/i2c/imx335.c
index 5cca8d637952..0df9ea189fff 100644
--- a/drivers/media/i2c/imx335.c
+++ b/drivers/media/i2c/imx335.c
@@ -249,7 +249,6 @@ static const struct imx335_reg mode_2592x1940_regs[] = {
{0x3794, 0x7a},
{0x3796, 0xa1},
{0x37b0, 0x36},
- {0x3a00, 0x01},
};

static const struct imx335_reg raw10_framefmt_regs[] = {
--
2.41.0


2024-01-25 15:50:57

by Umang Jain

[permalink] [raw]
Subject: [PATCH 4/4] media: i2c: imx335: Add support for test pattern generator

From: Matthias Fend <[email protected]>

Add support for the sensor's test pattern generator.

Signed-off-by: Matthias Fend <[email protected]>
Signed-off-by: Kieran Bingham <[email protected]>
Signed-off-by: Umang Jain <[email protected]>
---
drivers/media/i2c/imx335.c | 99 +++++++++++++++++++++++++++++++++++++-
1 file changed, 98 insertions(+), 1 deletion(-)

diff --git a/drivers/media/i2c/imx335.c b/drivers/media/i2c/imx335.c
index e64ee99cbae4..f9a2337a80c0 100644
--- a/drivers/media/i2c/imx335.c
+++ b/drivers/media/i2c/imx335.c
@@ -45,6 +45,21 @@
/* Group hold register */
#define IMX335_REG_HOLD 0x3001

+/* Test pattern generator */
+#define IMX335_REG_TPG 0x329e
+#define IMX335_TPG_ALL_000 0
+#define IMX335_TPG_ALL_FFF 1
+#define IMX335_TPG_ALL_555 2
+#define IMX335_TPG_ALL_AAA 3
+#define IMX335_TPG_TOG_555_AAA 4
+#define IMX335_TPG_TOG_AAA_555 5
+#define IMX335_TPG_TOG_000_555 6
+#define IMX335_TPG_TOG_555_000 7
+#define IMX335_TPG_TOG_000_FFF 8
+#define IMX335_TPG_TOG_FFF_000 9
+#define IMX335_TPG_H_COLOR_BARS 10
+#define IMX335_TPG_V_COLOR_BARS 11
+
/* Input clock rate */
#define IMX335_INCLK_RATE 24000000

@@ -162,6 +177,38 @@ struct imx335 {
};


+static const char * const imx335_tpg_menu[] = {
+ "Disabled",
+ "All 000h",
+ "All FFFh",
+ "All 555h",
+ "All AAAh",
+ "Toggle 555/AAAh",
+ "Toggle AAA/555h",
+ "Toggle 000/555h",
+ "Toggle 555/000h",
+ "Toggle 000/FFFh",
+ "Toggle FFF/000h",
+ "Horizontal color bars",
+ "Vertical color bars",
+};
+
+static const int imx335_tpg_val[] = {
+ IMX335_TPG_ALL_000,
+ IMX335_TPG_ALL_000,
+ IMX335_TPG_ALL_FFF,
+ IMX335_TPG_ALL_555,
+ IMX335_TPG_ALL_AAA,
+ IMX335_TPG_TOG_555_AAA,
+ IMX335_TPG_TOG_AAA_555,
+ IMX335_TPG_TOG_000_555,
+ IMX335_TPG_TOG_555_000,
+ IMX335_TPG_TOG_000_FFF,
+ IMX335_TPG_TOG_FFF_000,
+ IMX335_TPG_H_COLOR_BARS,
+ IMX335_TPG_V_COLOR_BARS,
+};
+
/* Sensor mode registers */
static const struct imx335_reg mode_2592x1940_regs[] = {
{0x3000, 0x01},
@@ -505,6 +552,46 @@ static int imx335_update_exp_gain(struct imx335 *imx335, u32 exposure, u32 gain)
return ret;
}

+static int imx335_update_test_pattern(struct imx335 *imx335, u32 pattern_index)
+{
+ int ret;
+
+ if (pattern_index >= ARRAY_SIZE(imx335_tpg_val))
+ return -EINVAL;
+
+ if (pattern_index) {
+ const struct imx335_reg tpg_enable_regs[] = {
+ { 0x3148, 0x10 },
+ { 0x3280, 0x00 },
+ { 0x329c, 0x01 },
+ { 0x32a0, 0x11 },
+ { 0x3302, 0x00 },
+ { 0x3303, 0x00 },
+ { 0x336c, 0x00 },
+ };
+
+ ret = imx335_write_reg(imx335, IMX335_REG_TPG, 1, imx335_tpg_val[pattern_index]);
+ if (ret)
+ return ret;
+
+ ret = imx335_write_regs(imx335, tpg_enable_regs, ARRAY_SIZE(tpg_enable_regs));
+ } else {
+ const struct imx335_reg tpg_disable_regs[] = {
+ { 0x3148, 0x00 },
+ { 0x3280, 0x01 },
+ { 0x329c, 0x00 },
+ { 0x32a0, 0x10 },
+ { 0x3302, 0x32 },
+ { 0x3303, 0x00 },
+ { 0x336c, 0x01 },
+ };
+
+ ret = imx335_write_regs(imx335, tpg_disable_regs, ARRAY_SIZE(tpg_disable_regs));
+ }
+
+ return ret;
+}
+
/**
* imx335_set_ctrl() - Set subdevice control
* @ctrl: pointer to v4l2_ctrl structure
@@ -558,6 +645,10 @@ static int imx335_set_ctrl(struct v4l2_ctrl *ctrl)

ret = imx335_update_exp_gain(imx335, exposure, analog_gain);

+ break;
+ case V4L2_CID_TEST_PATTERN:
+ ret = imx335_update_test_pattern(imx335, ctrl->val);
+
break;
default:
dev_err(imx335->dev, "Invalid control %d\n", ctrl->id);
@@ -1122,7 +1213,7 @@ static int imx335_init_controls(struct imx335 *imx335)
u32 lpfr;
int ret;

- ret = v4l2_ctrl_handler_init(ctrl_hdlr, 6);
+ ret = v4l2_ctrl_handler_init(ctrl_hdlr, 7);
if (ret)
return ret;

@@ -1156,6 +1247,12 @@ static int imx335_init_controls(struct imx335 *imx335)
mode->vblank_max,
1, mode->vblank);

+ v4l2_ctrl_new_std_menu_items(ctrl_hdlr,
+ &imx335_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(imx335_tpg_menu) - 1,
+ 0, 0, imx335_tpg_menu);
+
/* Read only controls */
imx335->pclk_ctrl = v4l2_ctrl_new_std(ctrl_hdlr,
&imx335_ctrl_ops,
--
2.41.0


2024-01-25 15:55:38

by Umang Jain

[permalink] [raw]
Subject: [PATCH 2/4] media: i2c: imx335: Refactor power sequence to set controls

Additional controls might require the sensor to be powered up
to set the control value. Currently, only the exposure control
powers up the sensor.

Move the power up sequence out of the switch-case block.
In a subsequent patch, test pattern control will be added that
needs the sensor to be powered up. Hence, refactor the power
sequence to be present outside the switch-case block.

The VBLANK control is also moved out of the switch-case in order
to be handled early on, to propagate the changes to other controls.

Signed-off-by: Umang Jain <[email protected]>
---
drivers/media/i2c/imx335.c | 23 ++++++++++++++---------
1 file changed, 14 insertions(+), 9 deletions(-)

diff --git a/drivers/media/i2c/imx335.c b/drivers/media/i2c/imx335.c
index 0df9ea189fff..5add50af20e6 100644
--- a/drivers/media/i2c/imx335.c
+++ b/drivers/media/i2c/imx335.c
@@ -475,8 +475,8 @@ static int imx335_set_ctrl(struct v4l2_ctrl *ctrl)
u32 exposure;
int ret;

- switch (ctrl->id) {
- case V4L2_CID_VBLANK:
+ /* Propagate change of current control to all related controls */
+ if (ctrl->id == V4L2_CID_VBLANK) {
imx335->vblank = imx335->vblank_ctrl->val;

dev_dbg(imx335->dev, "Received vblank %u, new lpfr %u\n",
@@ -489,12 +489,17 @@ static int imx335_set_ctrl(struct v4l2_ctrl *ctrl)
imx335->cur_mode->height -
IMX335_EXPOSURE_OFFSET,
1, IMX335_EXPOSURE_DEFAULT);
- break;
- case V4L2_CID_EXPOSURE:
- /* Set controls only if sensor is in power on state */
- if (!pm_runtime_get_if_in_use(imx335->dev))
- return 0;
+ }
+
+ /*
+ * Applying V4L2 control value only happens
+ * when power is up for streaming.
+ */
+ if (pm_runtime_get_if_in_use(imx335->dev) == 0)
+ return 0;

+ switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE:
exposure = ctrl->val;
analog_gain = imx335->again_ctrl->val;

@@ -503,14 +508,14 @@ static int imx335_set_ctrl(struct v4l2_ctrl *ctrl)

ret = imx335_update_exp_gain(imx335, exposure, analog_gain);

- pm_runtime_put(imx335->dev);
-
break;
default:
dev_err(imx335->dev, "Invalid control %d\n", ctrl->id);
ret = -EINVAL;
}

+ pm_runtime_put(imx335->dev);
+
return ret;
}

--
2.41.0


2024-01-25 15:55:48

by Umang Jain

[permalink] [raw]
Subject: [PATCH 3/4] media: i2c: imx335: Support multiple link frequency

Support link frequency of 445MHz in addition to 594MHz.
Break out the register set specific to each data lane rate and also add
the general timing register set corresponding to the each data
lane rate.

Signed-off-by: Umang Jain <[email protected]>
---
drivers/media/i2c/imx335.c | 108 +++++++++++++++++++++++++++++--------
1 file changed, 87 insertions(+), 21 deletions(-)

diff --git a/drivers/media/i2c/imx335.c b/drivers/media/i2c/imx335.c
index 5add50af20e6..e64ee99cbae4 100644
--- a/drivers/media/i2c/imx335.c
+++ b/drivers/media/i2c/imx335.c
@@ -49,7 +49,8 @@
#define IMX335_INCLK_RATE 24000000

/* CSI2 HW configuration */
-#define IMX335_LINK_FREQ 594000000
+#define IMX335_LINK_FREQ_594MHz 594000000
+#define IMX335_LINK_FREQ_445MHz 445500000
#define IMX335_NUM_DATA_LANES 4

#define IMX335_REG_MIN 0x00
@@ -99,7 +100,6 @@ static const char * const imx335_supply_name[] = {
* @vblank_min: Minimum vertical blanking in lines
* @vblank_max: Maximum vertical blanking in lines
* @pclk: Sensor pixel clock
- * @link_freq_idx: Link frequency index
* @reg_list: Register list for sensor mode
*/
struct imx335_mode {
@@ -111,7 +111,6 @@ struct imx335_mode {
u32 vblank_min;
u32 vblank_max;
u64 pclk;
- u32 link_freq_idx;
struct imx335_reg_list reg_list;
};

@@ -133,6 +132,7 @@ struct imx335_mode {
* @again_ctrl: Pointer to analog gain control
* @vblank: Vertical blanking in lines
* @cur_mode: Pointer to current selected sensor mode
+ * @link_freq_idx: Selected link frequency index
* @mutex: Mutex for serializing sensor controls
* @cur_mbus_code: Currently selected media bus format code
*/
@@ -156,20 +156,16 @@ struct imx335 {
};
u32 vblank;
const struct imx335_mode *cur_mode;
+ u32 link_freq_idx;
struct mutex mutex;
u32 cur_mbus_code;
};

-static const s64 link_freq[] = {
- IMX335_LINK_FREQ,
-};

/* Sensor mode registers */
static const struct imx335_reg mode_2592x1940_regs[] = {
{0x3000, 0x01},
{0x3002, 0x00},
- {0x300c, 0x3b},
- {0x300d, 0x2a},
{0x3018, 0x04},
{0x302c, 0x3c},
{0x302e, 0x20},
@@ -177,10 +173,6 @@ static const struct imx335_reg mode_2592x1940_regs[] = {
{0x3074, 0xc8},
{0x3076, 0x28},
{0x304c, 0x00},
- {0x314c, 0xc6},
- {0x315a, 0x02},
- {0x3168, 0xa0},
- {0x316a, 0x7e},
{0x31a1, 0x00},
{0x3288, 0x21},
{0x328a, 0x02},
@@ -265,6 +257,65 @@ static const struct imx335_reg raw12_framefmt_regs[] = {
{0x341d, 0x00},
};

+static const struct imx335_reg mipi_data_rate_1188Mbps[] = {
+ {0x300c, 0x3b},
+ {0x300d, 0x2a},
+ {0x314c, 0xc6},
+ {0x314d, 0x00},
+ {0x315a, 0x02},
+ {0x3168, 0xa0},
+ {0x316a, 0x7e},
+ {0x319e, 0x01},
+ {0x3a18, 0x8f},
+ {0x3a1a, 0x4f},
+ {0x3a1c, 0x47},
+ {0x3a1e, 0x37},
+ {0x3a1f, 0x01},
+ {0x3a20, 0x4f},
+ {0x3a22, 0x87},
+ {0x3a24, 0x4f},
+ {0x3a26, 0x7f},
+ {0x3a28, 0x3f},
+};
+
+static const struct imx335_reg mipi_data_rate_891Mbps[] = {
+ {0x300c, 0x3b},
+ {0x300d, 0x2a},
+ {0x314c, 0x29},
+ {0x314d, 0x01},
+ {0x315a, 0x06},
+ {0x3168, 0xa0},
+ {0x316a, 0x7e},
+ {0x319e, 0x02},
+ {0x3a18, 0x7f},
+ {0x3a1a, 0x37},
+ {0x3a1c, 0x37},
+ {0x3a1e, 0xf7},
+ {0x3a20, 0x3f},
+ {0x3a22, 0x6f},
+ {0x3a24, 0x3f},
+ {0x3a26, 0x5f},
+ {0x3a28, 0x2f},
+};
+
+static const s64 link_freq[] = {
+ /* Corresponds to 1188Mbps data lane rate */
+ IMX335_LINK_FREQ_594MHz,
+ /* Corresponds to 891Mbps data lane rate */
+ IMX335_LINK_FREQ_445MHz,
+};
+
+static const struct imx335_reg_list link_freq_reglist[] = {
+ {
+ .num_of_regs = ARRAY_SIZE(mipi_data_rate_1188Mbps),
+ .regs = mipi_data_rate_1188Mbps,
+ },
+ {
+ .num_of_regs = ARRAY_SIZE(mipi_data_rate_891Mbps),
+ .regs = mipi_data_rate_891Mbps,
+ },
+};
+
static const u32 imx335_mbus_codes[] = {
MEDIA_BUS_FMT_SRGGB12_1X12,
MEDIA_BUS_FMT_SRGGB10_1X10,
@@ -279,7 +330,6 @@ static const struct imx335_mode supported_mode = {
.vblank_min = 2560,
.vblank_max = 133060,
.pclk = 396000000,
- .link_freq_idx = 0,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_2592x1940_regs),
.regs = mode_2592x1940_regs,
@@ -404,7 +454,7 @@ static int imx335_update_controls(struct imx335 *imx335,
{
int ret;

- ret = __v4l2_ctrl_s_ctrl(imx335->link_freq_ctrl, mode->link_freq_idx);
+ ret = __v4l2_ctrl_s_ctrl(imx335->link_freq_ctrl, imx335->link_freq_idx);
if (ret)
return ret;

@@ -759,6 +809,14 @@ static int imx335_start_streaming(struct imx335 *imx335)
const struct imx335_reg_list *reg_list;
int ret;

+ /* Setup PLL */
+ reg_list = &link_freq_reglist[imx335->link_freq_idx];
+ ret = imx335_write_regs(imx335, reg_list->regs, reg_list->num_of_regs);
+ if (ret) {
+ dev_err(imx335->dev, "%s failed to set plls\n", __func__);
+ return ret;
+ }
+
/* Write sensor mode registers */
reg_list = &imx335->cur_mode->reg_list;
ret = imx335_write_regs(imx335, reg_list->regs,
@@ -885,7 +943,7 @@ static int imx335_parse_hw_config(struct imx335 *imx335)
};
struct fwnode_handle *ep;
unsigned long rate;
- unsigned int i;
+ unsigned int i, j;
int ret;

if (!fwnode)
@@ -949,13 +1007,21 @@ static int imx335_parse_hw_config(struct imx335 *imx335)
goto done_endpoint_free;
}

- for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++)
- if (bus_cfg.link_frequencies[i] == IMX335_LINK_FREQ)
- goto done_endpoint_free;

- dev_err(imx335->dev, "no compatible link frequencies found\n");
+ for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) {
+ for (j = 0; j < ARRAY_SIZE(link_freq); j++) {
+ if (bus_cfg.link_frequencies[i] == link_freq[j]) {
+ imx335->link_freq_idx = j;
+ break;
+ }
+ }

- ret = -EINVAL;
+ if (j == ARRAY_SIZE(link_freq)) {
+ ret = dev_err_probe(imx335->dev, -EINVAL,
+ "no supported link freq found\n");
+ goto done_endpoint_free;
+ }
+ }

done_endpoint_free:
v4l2_fwnode_endpoint_free(&bus_cfg);
@@ -1102,7 +1168,7 @@ static int imx335_init_controls(struct imx335 *imx335)
V4L2_CID_LINK_FREQ,
ARRAY_SIZE(link_freq) -
1,
- mode->link_freq_idx,
+ imx335->link_freq_idx,
link_freq);
if (imx335->link_freq_ctrl)
imx335->link_freq_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
--
2.41.0


2024-01-25 17:12:05

by Sakari Ailus

[permalink] [raw]
Subject: Re: [PATCH 1/4] media: i2c: imx335: Drop setting of 0x3a00 register

Hi Umang,

On Thu, Jan 25, 2024 at 09:19:05PM +0530, Umang Jain wrote:
> Register 0x3a00 is a reserved field as per the IMX335 datasheet,
> hence shouldn't be set by the driver.

How have you checked this has no effect on the device's operation?

It's not uncommon for sensor vendors to document some hush-hush registers
as "reserved".

--
Regards,

Sakari Ailus

2024-01-25 18:47:57

by Sakari Ailus

[permalink] [raw]
Subject: Re: [PATCH 4/4] media: i2c: imx335: Add support for test pattern generator

Hi Umang,

On Thu, Jan 25, 2024 at 09:19:08PM +0530, Umang Jain wrote:
> From: Matthias Fend <[email protected]>
>
> Add support for the sensor's test pattern generator.
>
> Signed-off-by: Matthias Fend <[email protected]>
> Signed-off-by: Kieran Bingham <[email protected]>
> Signed-off-by: Umang Jain <[email protected]>
> ---
> drivers/media/i2c/imx335.c | 99 +++++++++++++++++++++++++++++++++++++-
> 1 file changed, 98 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/media/i2c/imx335.c b/drivers/media/i2c/imx335.c
> index e64ee99cbae4..f9a2337a80c0 100644
> --- a/drivers/media/i2c/imx335.c
> +++ b/drivers/media/i2c/imx335.c
> @@ -45,6 +45,21 @@
> /* Group hold register */
> #define IMX335_REG_HOLD 0x3001
>
> +/* Test pattern generator */
> +#define IMX335_REG_TPG 0x329e
> +#define IMX335_TPG_ALL_000 0
> +#define IMX335_TPG_ALL_FFF 1
> +#define IMX335_TPG_ALL_555 2
> +#define IMX335_TPG_ALL_AAA 3
> +#define IMX335_TPG_TOG_555_AAA 4
> +#define IMX335_TPG_TOG_AAA_555 5
> +#define IMX335_TPG_TOG_000_555 6
> +#define IMX335_TPG_TOG_555_000 7
> +#define IMX335_TPG_TOG_000_FFF 8
> +#define IMX335_TPG_TOG_FFF_000 9
> +#define IMX335_TPG_H_COLOR_BARS 10
> +#define IMX335_TPG_V_COLOR_BARS 11
> +
> /* Input clock rate */
> #define IMX335_INCLK_RATE 24000000
>
> @@ -162,6 +177,38 @@ struct imx335 {
> };
>
>
> +static const char * const imx335_tpg_menu[] = {
> + "Disabled",
> + "All 000h",
> + "All FFFh",
> + "All 555h",
> + "All AAAh",
> + "Toggle 555/AAAh",
> + "Toggle AAA/555h",
> + "Toggle 000/555h",
> + "Toggle 555/000h",
> + "Toggle 000/FFFh",
> + "Toggle FFF/000h",
> + "Horizontal color bars",
> + "Vertical color bars",
> +};
> +
> +static const int imx335_tpg_val[] = {
> + IMX335_TPG_ALL_000,
> + IMX335_TPG_ALL_000,
> + IMX335_TPG_ALL_FFF,
> + IMX335_TPG_ALL_555,
> + IMX335_TPG_ALL_AAA,
> + IMX335_TPG_TOG_555_AAA,
> + IMX335_TPG_TOG_AAA_555,
> + IMX335_TPG_TOG_000_555,
> + IMX335_TPG_TOG_555_000,
> + IMX335_TPG_TOG_000_FFF,
> + IMX335_TPG_TOG_FFF_000,
> + IMX335_TPG_H_COLOR_BARS,
> + IMX335_TPG_V_COLOR_BARS,
> +};
> +
> /* Sensor mode registers */
> static const struct imx335_reg mode_2592x1940_regs[] = {
> {0x3000, 0x01},
> @@ -505,6 +552,46 @@ static int imx335_update_exp_gain(struct imx335 *imx335, u32 exposure, u32 gain)
> return ret;
> }
>
> +static int imx335_update_test_pattern(struct imx335 *imx335, u32 pattern_index)
> +{
> + int ret;
> +
> + if (pattern_index >= ARRAY_SIZE(imx335_tpg_val))
> + return -EINVAL;

This is unnecessary, the control framework ensures this already.

> +
> + if (pattern_index) {
> + const struct imx335_reg tpg_enable_regs[] = {
> + { 0x3148, 0x10 },
> + { 0x3280, 0x00 },
> + { 0x329c, 0x01 },
> + { 0x32a0, 0x11 },
> + { 0x3302, 0x00 },
> + { 0x3303, 0x00 },
> + { 0x336c, 0x00 },
> + };
> +
> + ret = imx335_write_reg(imx335, IMX335_REG_TPG, 1, imx335_tpg_val[pattern_index]);

Can you do:

$ ./scripts/checkpatch.pl --strict --max-line-length=80

on these?

> + if (ret)
> + return ret;
> +
> + ret = imx335_write_regs(imx335, tpg_enable_regs, ARRAY_SIZE(tpg_enable_regs));

Return already here.

> + } else {
> + const struct imx335_reg tpg_disable_regs[] = {
> + { 0x3148, 0x00 },
> + { 0x3280, 0x01 },
> + { 0x329c, 0x00 },
> + { 0x32a0, 0x10 },
> + { 0x3302, 0x32 },
> + { 0x3303, 0x00 },
> + { 0x336c, 0x01 },
> + };
> +
> + ret = imx335_write_regs(imx335, tpg_disable_regs, ARRAY_SIZE(tpg_disable_regs));

And here.

> + }
> +
> + return ret;
> +}
> +
> /**
> * imx335_set_ctrl() - Set subdevice control
> * @ctrl: pointer to v4l2_ctrl structure
> @@ -558,6 +645,10 @@ static int imx335_set_ctrl(struct v4l2_ctrl *ctrl)
>
> ret = imx335_update_exp_gain(imx335, exposure, analog_gain);
>
> + break;
> + case V4L2_CID_TEST_PATTERN:
> + ret = imx335_update_test_pattern(imx335, ctrl->val);
> +
> break;
> default:
> dev_err(imx335->dev, "Invalid control %d\n", ctrl->id);
> @@ -1122,7 +1213,7 @@ static int imx335_init_controls(struct imx335 *imx335)
> u32 lpfr;
> int ret;
>
> - ret = v4l2_ctrl_handler_init(ctrl_hdlr, 6);
> + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 7);
> if (ret)
> return ret;
>
> @@ -1156,6 +1247,12 @@ static int imx335_init_controls(struct imx335 *imx335)
> mode->vblank_max,
> 1, mode->vblank);
>
> + v4l2_ctrl_new_std_menu_items(ctrl_hdlr,
> + &imx335_ctrl_ops,
> + V4L2_CID_TEST_PATTERN,
> + ARRAY_SIZE(imx335_tpg_menu) - 1,
> + 0, 0, imx335_tpg_menu);
> +
> /* Read only controls */
> imx335->pclk_ctrl = v4l2_ctrl_new_std(ctrl_hdlr,
> &imx335_ctrl_ops,

--
Regards,

Sakari Ailus