162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci// Copyright (C) 2018 Intel Corporation
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <asm/unaligned.h>
562306a36Sopenharmony_ci#include <linux/acpi.h>
662306a36Sopenharmony_ci#include <linux/i2c.h>
762306a36Sopenharmony_ci#include <linux/module.h>
862306a36Sopenharmony_ci#include <linux/pm_runtime.h>
962306a36Sopenharmony_ci#include <media/v4l2-ctrls.h>
1062306a36Sopenharmony_ci#include <media/v4l2-device.h>
1162306a36Sopenharmony_ci#include <media/v4l2-event.h>
1262306a36Sopenharmony_ci#include <media/v4l2-fwnode.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#define IMX355_REG_MODE_SELECT		0x0100
1562306a36Sopenharmony_ci#define IMX355_MODE_STANDBY		0x00
1662306a36Sopenharmony_ci#define IMX355_MODE_STREAMING		0x01
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci/* Chip ID */
1962306a36Sopenharmony_ci#define IMX355_REG_CHIP_ID		0x0016
2062306a36Sopenharmony_ci#define IMX355_CHIP_ID			0x0355
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci/* V_TIMING internal */
2362306a36Sopenharmony_ci#define IMX355_REG_FLL			0x0340
2462306a36Sopenharmony_ci#define IMX355_FLL_MAX			0xffff
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci/* Exposure control */
2762306a36Sopenharmony_ci#define IMX355_REG_EXPOSURE		0x0202
2862306a36Sopenharmony_ci#define IMX355_EXPOSURE_MIN		1
2962306a36Sopenharmony_ci#define IMX355_EXPOSURE_STEP		1
3062306a36Sopenharmony_ci#define IMX355_EXPOSURE_DEFAULT		0x0282
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/* Analog gain control */
3362306a36Sopenharmony_ci#define IMX355_REG_ANALOG_GAIN		0x0204
3462306a36Sopenharmony_ci#define IMX355_ANA_GAIN_MIN		0
3562306a36Sopenharmony_ci#define IMX355_ANA_GAIN_MAX		960
3662306a36Sopenharmony_ci#define IMX355_ANA_GAIN_STEP		1
3762306a36Sopenharmony_ci#define IMX355_ANA_GAIN_DEFAULT		0
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci/* Digital gain control */
4062306a36Sopenharmony_ci#define IMX355_REG_DPGA_USE_GLOBAL_GAIN	0x3070
4162306a36Sopenharmony_ci#define IMX355_REG_DIG_GAIN_GLOBAL	0x020e
4262306a36Sopenharmony_ci#define IMX355_DGTL_GAIN_MIN		256
4362306a36Sopenharmony_ci#define IMX355_DGTL_GAIN_MAX		4095
4462306a36Sopenharmony_ci#define IMX355_DGTL_GAIN_STEP		1
4562306a36Sopenharmony_ci#define IMX355_DGTL_GAIN_DEFAULT	256
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci/* Test Pattern Control */
4862306a36Sopenharmony_ci#define IMX355_REG_TEST_PATTERN		0x0600
4962306a36Sopenharmony_ci#define IMX355_TEST_PATTERN_DISABLED		0
5062306a36Sopenharmony_ci#define IMX355_TEST_PATTERN_SOLID_COLOR		1
5162306a36Sopenharmony_ci#define IMX355_TEST_PATTERN_COLOR_BARS		2
5262306a36Sopenharmony_ci#define IMX355_TEST_PATTERN_GRAY_COLOR_BARS	3
5362306a36Sopenharmony_ci#define IMX355_TEST_PATTERN_PN9			4
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci/* Flip Control */
5662306a36Sopenharmony_ci#define IMX355_REG_ORIENTATION		0x0101
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci/* default link frequency and external clock */
5962306a36Sopenharmony_ci#define IMX355_LINK_FREQ_DEFAULT	360000000
6062306a36Sopenharmony_ci#define IMX355_EXT_CLK			19200000
6162306a36Sopenharmony_ci#define IMX355_LINK_FREQ_INDEX		0
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistruct imx355_reg {
6462306a36Sopenharmony_ci	u16 address;
6562306a36Sopenharmony_ci	u8 val;
6662306a36Sopenharmony_ci};
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistruct imx355_reg_list {
6962306a36Sopenharmony_ci	u32 num_of_regs;
7062306a36Sopenharmony_ci	const struct imx355_reg *regs;
7162306a36Sopenharmony_ci};
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci/* Mode : resolution and related config&values */
7462306a36Sopenharmony_cistruct imx355_mode {
7562306a36Sopenharmony_ci	/* Frame width */
7662306a36Sopenharmony_ci	u32 width;
7762306a36Sopenharmony_ci	/* Frame height */
7862306a36Sopenharmony_ci	u32 height;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	/* V-timing */
8162306a36Sopenharmony_ci	u32 fll_def;
8262306a36Sopenharmony_ci	u32 fll_min;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	/* H-timing */
8562306a36Sopenharmony_ci	u32 llp;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	/* index of link frequency */
8862306a36Sopenharmony_ci	u32 link_freq_index;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	/* Default register values */
9162306a36Sopenharmony_ci	struct imx355_reg_list reg_list;
9262306a36Sopenharmony_ci};
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistruct imx355_hwcfg {
9562306a36Sopenharmony_ci	u32 ext_clk;			/* sensor external clk */
9662306a36Sopenharmony_ci	s64 *link_freqs;		/* CSI-2 link frequencies */
9762306a36Sopenharmony_ci	unsigned int nr_of_link_freqs;
9862306a36Sopenharmony_ci};
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistruct imx355 {
10162306a36Sopenharmony_ci	struct v4l2_subdev sd;
10262306a36Sopenharmony_ci	struct media_pad pad;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	struct v4l2_ctrl_handler ctrl_handler;
10562306a36Sopenharmony_ci	/* V4L2 Controls */
10662306a36Sopenharmony_ci	struct v4l2_ctrl *link_freq;
10762306a36Sopenharmony_ci	struct v4l2_ctrl *pixel_rate;
10862306a36Sopenharmony_ci	struct v4l2_ctrl *vblank;
10962306a36Sopenharmony_ci	struct v4l2_ctrl *hblank;
11062306a36Sopenharmony_ci	struct v4l2_ctrl *exposure;
11162306a36Sopenharmony_ci	struct v4l2_ctrl *vflip;
11262306a36Sopenharmony_ci	struct v4l2_ctrl *hflip;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	/* Current mode */
11562306a36Sopenharmony_ci	const struct imx355_mode *cur_mode;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	struct imx355_hwcfg *hwcfg;
11862306a36Sopenharmony_ci	s64 link_def_freq;	/* CSI-2 link default frequency */
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	/*
12162306a36Sopenharmony_ci	 * Mutex for serialized access:
12262306a36Sopenharmony_ci	 * Protect sensor set pad format and start/stop streaming safely.
12362306a36Sopenharmony_ci	 * Protect access to sensor v4l2 controls.
12462306a36Sopenharmony_ci	 */
12562306a36Sopenharmony_ci	struct mutex mutex;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	/* Streaming on/off */
12862306a36Sopenharmony_ci	bool streaming;
12962306a36Sopenharmony_ci};
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistatic const struct imx355_reg imx355_global_regs[] = {
13262306a36Sopenharmony_ci	{ 0x0136, 0x13 },
13362306a36Sopenharmony_ci	{ 0x0137, 0x33 },
13462306a36Sopenharmony_ci	{ 0x304e, 0x03 },
13562306a36Sopenharmony_ci	{ 0x4348, 0x16 },
13662306a36Sopenharmony_ci	{ 0x4350, 0x19 },
13762306a36Sopenharmony_ci	{ 0x4408, 0x0a },
13862306a36Sopenharmony_ci	{ 0x440c, 0x0b },
13962306a36Sopenharmony_ci	{ 0x4411, 0x5f },
14062306a36Sopenharmony_ci	{ 0x4412, 0x2c },
14162306a36Sopenharmony_ci	{ 0x4623, 0x00 },
14262306a36Sopenharmony_ci	{ 0x462c, 0x0f },
14362306a36Sopenharmony_ci	{ 0x462d, 0x00 },
14462306a36Sopenharmony_ci	{ 0x462e, 0x00 },
14562306a36Sopenharmony_ci	{ 0x4684, 0x54 },
14662306a36Sopenharmony_ci	{ 0x480a, 0x07 },
14762306a36Sopenharmony_ci	{ 0x4908, 0x07 },
14862306a36Sopenharmony_ci	{ 0x4909, 0x07 },
14962306a36Sopenharmony_ci	{ 0x490d, 0x0a },
15062306a36Sopenharmony_ci	{ 0x491e, 0x0f },
15162306a36Sopenharmony_ci	{ 0x4921, 0x06 },
15262306a36Sopenharmony_ci	{ 0x4923, 0x28 },
15362306a36Sopenharmony_ci	{ 0x4924, 0x28 },
15462306a36Sopenharmony_ci	{ 0x4925, 0x29 },
15562306a36Sopenharmony_ci	{ 0x4926, 0x29 },
15662306a36Sopenharmony_ci	{ 0x4927, 0x1f },
15762306a36Sopenharmony_ci	{ 0x4928, 0x20 },
15862306a36Sopenharmony_ci	{ 0x4929, 0x20 },
15962306a36Sopenharmony_ci	{ 0x492a, 0x20 },
16062306a36Sopenharmony_ci	{ 0x492c, 0x05 },
16162306a36Sopenharmony_ci	{ 0x492d, 0x06 },
16262306a36Sopenharmony_ci	{ 0x492e, 0x06 },
16362306a36Sopenharmony_ci	{ 0x492f, 0x06 },
16462306a36Sopenharmony_ci	{ 0x4930, 0x03 },
16562306a36Sopenharmony_ci	{ 0x4931, 0x04 },
16662306a36Sopenharmony_ci	{ 0x4932, 0x04 },
16762306a36Sopenharmony_ci	{ 0x4933, 0x05 },
16862306a36Sopenharmony_ci	{ 0x595e, 0x01 },
16962306a36Sopenharmony_ci	{ 0x5963, 0x01 },
17062306a36Sopenharmony_ci	{ 0x3030, 0x01 },
17162306a36Sopenharmony_ci	{ 0x3031, 0x01 },
17262306a36Sopenharmony_ci	{ 0x3045, 0x01 },
17362306a36Sopenharmony_ci	{ 0x4010, 0x00 },
17462306a36Sopenharmony_ci	{ 0x4011, 0x00 },
17562306a36Sopenharmony_ci	{ 0x4012, 0x00 },
17662306a36Sopenharmony_ci	{ 0x4013, 0x01 },
17762306a36Sopenharmony_ci	{ 0x68a8, 0xfe },
17862306a36Sopenharmony_ci	{ 0x68a9, 0xff },
17962306a36Sopenharmony_ci	{ 0x6888, 0x00 },
18062306a36Sopenharmony_ci	{ 0x6889, 0x00 },
18162306a36Sopenharmony_ci	{ 0x68b0, 0x00 },
18262306a36Sopenharmony_ci	{ 0x3058, 0x00 },
18362306a36Sopenharmony_ci	{ 0x305a, 0x00 },
18462306a36Sopenharmony_ci};
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_cistatic const struct imx355_reg_list imx355_global_setting = {
18762306a36Sopenharmony_ci	.num_of_regs = ARRAY_SIZE(imx355_global_regs),
18862306a36Sopenharmony_ci	.regs = imx355_global_regs,
18962306a36Sopenharmony_ci};
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_cistatic const struct imx355_reg mode_3268x2448_regs[] = {
19262306a36Sopenharmony_ci	{ 0x0112, 0x0a },
19362306a36Sopenharmony_ci	{ 0x0113, 0x0a },
19462306a36Sopenharmony_ci	{ 0x0114, 0x03 },
19562306a36Sopenharmony_ci	{ 0x0342, 0x0e },
19662306a36Sopenharmony_ci	{ 0x0343, 0x58 },
19762306a36Sopenharmony_ci	{ 0x0340, 0x0a },
19862306a36Sopenharmony_ci	{ 0x0341, 0x37 },
19962306a36Sopenharmony_ci	{ 0x0344, 0x00 },
20062306a36Sopenharmony_ci	{ 0x0345, 0x08 },
20162306a36Sopenharmony_ci	{ 0x0346, 0x00 },
20262306a36Sopenharmony_ci	{ 0x0347, 0x08 },
20362306a36Sopenharmony_ci	{ 0x0348, 0x0c },
20462306a36Sopenharmony_ci	{ 0x0349, 0xcb },
20562306a36Sopenharmony_ci	{ 0x034a, 0x09 },
20662306a36Sopenharmony_ci	{ 0x034b, 0x97 },
20762306a36Sopenharmony_ci	{ 0x0220, 0x00 },
20862306a36Sopenharmony_ci	{ 0x0222, 0x01 },
20962306a36Sopenharmony_ci	{ 0x0900, 0x00 },
21062306a36Sopenharmony_ci	{ 0x0901, 0x11 },
21162306a36Sopenharmony_ci	{ 0x0902, 0x00 },
21262306a36Sopenharmony_ci	{ 0x034c, 0x0c },
21362306a36Sopenharmony_ci	{ 0x034d, 0xc4 },
21462306a36Sopenharmony_ci	{ 0x034e, 0x09 },
21562306a36Sopenharmony_ci	{ 0x034f, 0x90 },
21662306a36Sopenharmony_ci	{ 0x0301, 0x05 },
21762306a36Sopenharmony_ci	{ 0x0303, 0x01 },
21862306a36Sopenharmony_ci	{ 0x0305, 0x02 },
21962306a36Sopenharmony_ci	{ 0x0306, 0x00 },
22062306a36Sopenharmony_ci	{ 0x0307, 0x78 },
22162306a36Sopenharmony_ci	{ 0x030b, 0x01 },
22262306a36Sopenharmony_ci	{ 0x030d, 0x02 },
22362306a36Sopenharmony_ci	{ 0x030e, 0x00 },
22462306a36Sopenharmony_ci	{ 0x030f, 0x4b },
22562306a36Sopenharmony_ci	{ 0x0310, 0x00 },
22662306a36Sopenharmony_ci	{ 0x0700, 0x00 },
22762306a36Sopenharmony_ci	{ 0x0701, 0x10 },
22862306a36Sopenharmony_ci	{ 0x0820, 0x0b },
22962306a36Sopenharmony_ci	{ 0x0821, 0x40 },
23062306a36Sopenharmony_ci	{ 0x3088, 0x04 },
23162306a36Sopenharmony_ci	{ 0x6813, 0x02 },
23262306a36Sopenharmony_ci	{ 0x6835, 0x07 },
23362306a36Sopenharmony_ci	{ 0x6836, 0x01 },
23462306a36Sopenharmony_ci	{ 0x6837, 0x04 },
23562306a36Sopenharmony_ci	{ 0x684d, 0x07 },
23662306a36Sopenharmony_ci	{ 0x684e, 0x01 },
23762306a36Sopenharmony_ci	{ 0x684f, 0x04 },
23862306a36Sopenharmony_ci};
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_cistatic const struct imx355_reg mode_3264x2448_regs[] = {
24162306a36Sopenharmony_ci	{ 0x0112, 0x0a },
24262306a36Sopenharmony_ci	{ 0x0113, 0x0a },
24362306a36Sopenharmony_ci	{ 0x0114, 0x03 },
24462306a36Sopenharmony_ci	{ 0x0342, 0x0e },
24562306a36Sopenharmony_ci	{ 0x0343, 0x58 },
24662306a36Sopenharmony_ci	{ 0x0340, 0x0a },
24762306a36Sopenharmony_ci	{ 0x0341, 0x37 },
24862306a36Sopenharmony_ci	{ 0x0344, 0x00 },
24962306a36Sopenharmony_ci	{ 0x0345, 0x08 },
25062306a36Sopenharmony_ci	{ 0x0346, 0x00 },
25162306a36Sopenharmony_ci	{ 0x0347, 0x08 },
25262306a36Sopenharmony_ci	{ 0x0348, 0x0c },
25362306a36Sopenharmony_ci	{ 0x0349, 0xc7 },
25462306a36Sopenharmony_ci	{ 0x034a, 0x09 },
25562306a36Sopenharmony_ci	{ 0x034b, 0x97 },
25662306a36Sopenharmony_ci	{ 0x0220, 0x00 },
25762306a36Sopenharmony_ci	{ 0x0222, 0x01 },
25862306a36Sopenharmony_ci	{ 0x0900, 0x00 },
25962306a36Sopenharmony_ci	{ 0x0901, 0x11 },
26062306a36Sopenharmony_ci	{ 0x0902, 0x00 },
26162306a36Sopenharmony_ci	{ 0x034c, 0x0c },
26262306a36Sopenharmony_ci	{ 0x034d, 0xc0 },
26362306a36Sopenharmony_ci	{ 0x034e, 0x09 },
26462306a36Sopenharmony_ci	{ 0x034f, 0x90 },
26562306a36Sopenharmony_ci	{ 0x0301, 0x05 },
26662306a36Sopenharmony_ci	{ 0x0303, 0x01 },
26762306a36Sopenharmony_ci	{ 0x0305, 0x02 },
26862306a36Sopenharmony_ci	{ 0x0306, 0x00 },
26962306a36Sopenharmony_ci	{ 0x0307, 0x78 },
27062306a36Sopenharmony_ci	{ 0x030b, 0x01 },
27162306a36Sopenharmony_ci	{ 0x030d, 0x02 },
27262306a36Sopenharmony_ci	{ 0x030e, 0x00 },
27362306a36Sopenharmony_ci	{ 0x030f, 0x4b },
27462306a36Sopenharmony_ci	{ 0x0310, 0x00 },
27562306a36Sopenharmony_ci	{ 0x0700, 0x00 },
27662306a36Sopenharmony_ci	{ 0x0701, 0x10 },
27762306a36Sopenharmony_ci	{ 0x0820, 0x0b },
27862306a36Sopenharmony_ci	{ 0x0821, 0x40 },
27962306a36Sopenharmony_ci	{ 0x3088, 0x04 },
28062306a36Sopenharmony_ci	{ 0x6813, 0x02 },
28162306a36Sopenharmony_ci	{ 0x6835, 0x07 },
28262306a36Sopenharmony_ci	{ 0x6836, 0x01 },
28362306a36Sopenharmony_ci	{ 0x6837, 0x04 },
28462306a36Sopenharmony_ci	{ 0x684d, 0x07 },
28562306a36Sopenharmony_ci	{ 0x684e, 0x01 },
28662306a36Sopenharmony_ci	{ 0x684f, 0x04 },
28762306a36Sopenharmony_ci};
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_cistatic const struct imx355_reg mode_3280x2464_regs[] = {
29062306a36Sopenharmony_ci	{ 0x0112, 0x0a },
29162306a36Sopenharmony_ci	{ 0x0113, 0x0a },
29262306a36Sopenharmony_ci	{ 0x0114, 0x03 },
29362306a36Sopenharmony_ci	{ 0x0342, 0x0e },
29462306a36Sopenharmony_ci	{ 0x0343, 0x58 },
29562306a36Sopenharmony_ci	{ 0x0340, 0x0a },
29662306a36Sopenharmony_ci	{ 0x0341, 0x37 },
29762306a36Sopenharmony_ci	{ 0x0344, 0x00 },
29862306a36Sopenharmony_ci	{ 0x0345, 0x00 },
29962306a36Sopenharmony_ci	{ 0x0346, 0x00 },
30062306a36Sopenharmony_ci	{ 0x0347, 0x00 },
30162306a36Sopenharmony_ci	{ 0x0348, 0x0c },
30262306a36Sopenharmony_ci	{ 0x0349, 0xcf },
30362306a36Sopenharmony_ci	{ 0x034a, 0x09 },
30462306a36Sopenharmony_ci	{ 0x034b, 0x9f },
30562306a36Sopenharmony_ci	{ 0x0220, 0x00 },
30662306a36Sopenharmony_ci	{ 0x0222, 0x01 },
30762306a36Sopenharmony_ci	{ 0x0900, 0x00 },
30862306a36Sopenharmony_ci	{ 0x0901, 0x11 },
30962306a36Sopenharmony_ci	{ 0x0902, 0x00 },
31062306a36Sopenharmony_ci	{ 0x034c, 0x0c },
31162306a36Sopenharmony_ci	{ 0x034d, 0xd0 },
31262306a36Sopenharmony_ci	{ 0x034e, 0x09 },
31362306a36Sopenharmony_ci	{ 0x034f, 0xa0 },
31462306a36Sopenharmony_ci	{ 0x0301, 0x05 },
31562306a36Sopenharmony_ci	{ 0x0303, 0x01 },
31662306a36Sopenharmony_ci	{ 0x0305, 0x02 },
31762306a36Sopenharmony_ci	{ 0x0306, 0x00 },
31862306a36Sopenharmony_ci	{ 0x0307, 0x78 },
31962306a36Sopenharmony_ci	{ 0x030b, 0x01 },
32062306a36Sopenharmony_ci	{ 0x030d, 0x02 },
32162306a36Sopenharmony_ci	{ 0x030e, 0x00 },
32262306a36Sopenharmony_ci	{ 0x030f, 0x4b },
32362306a36Sopenharmony_ci	{ 0x0310, 0x00 },
32462306a36Sopenharmony_ci	{ 0x0700, 0x00 },
32562306a36Sopenharmony_ci	{ 0x0701, 0x10 },
32662306a36Sopenharmony_ci	{ 0x0820, 0x0b },
32762306a36Sopenharmony_ci	{ 0x0821, 0x40 },
32862306a36Sopenharmony_ci	{ 0x3088, 0x04 },
32962306a36Sopenharmony_ci	{ 0x6813, 0x02 },
33062306a36Sopenharmony_ci	{ 0x6835, 0x07 },
33162306a36Sopenharmony_ci	{ 0x6836, 0x01 },
33262306a36Sopenharmony_ci	{ 0x6837, 0x04 },
33362306a36Sopenharmony_ci	{ 0x684d, 0x07 },
33462306a36Sopenharmony_ci	{ 0x684e, 0x01 },
33562306a36Sopenharmony_ci	{ 0x684f, 0x04 },
33662306a36Sopenharmony_ci};
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_cistatic const struct imx355_reg mode_1940x1096_regs[] = {
33962306a36Sopenharmony_ci	{ 0x0112, 0x0a },
34062306a36Sopenharmony_ci	{ 0x0113, 0x0a },
34162306a36Sopenharmony_ci	{ 0x0114, 0x03 },
34262306a36Sopenharmony_ci	{ 0x0342, 0x0e },
34362306a36Sopenharmony_ci	{ 0x0343, 0x58 },
34462306a36Sopenharmony_ci	{ 0x0340, 0x05 },
34562306a36Sopenharmony_ci	{ 0x0341, 0x1a },
34662306a36Sopenharmony_ci	{ 0x0344, 0x02 },
34762306a36Sopenharmony_ci	{ 0x0345, 0xa0 },
34862306a36Sopenharmony_ci	{ 0x0346, 0x02 },
34962306a36Sopenharmony_ci	{ 0x0347, 0xac },
35062306a36Sopenharmony_ci	{ 0x0348, 0x0a },
35162306a36Sopenharmony_ci	{ 0x0349, 0x33 },
35262306a36Sopenharmony_ci	{ 0x034a, 0x06 },
35362306a36Sopenharmony_ci	{ 0x034b, 0xf3 },
35462306a36Sopenharmony_ci	{ 0x0220, 0x00 },
35562306a36Sopenharmony_ci	{ 0x0222, 0x01 },
35662306a36Sopenharmony_ci	{ 0x0900, 0x00 },
35762306a36Sopenharmony_ci	{ 0x0901, 0x11 },
35862306a36Sopenharmony_ci	{ 0x0902, 0x00 },
35962306a36Sopenharmony_ci	{ 0x034c, 0x07 },
36062306a36Sopenharmony_ci	{ 0x034d, 0x94 },
36162306a36Sopenharmony_ci	{ 0x034e, 0x04 },
36262306a36Sopenharmony_ci	{ 0x034f, 0x48 },
36362306a36Sopenharmony_ci	{ 0x0301, 0x05 },
36462306a36Sopenharmony_ci	{ 0x0303, 0x01 },
36562306a36Sopenharmony_ci	{ 0x0305, 0x02 },
36662306a36Sopenharmony_ci	{ 0x0306, 0x00 },
36762306a36Sopenharmony_ci	{ 0x0307, 0x78 },
36862306a36Sopenharmony_ci	{ 0x030b, 0x01 },
36962306a36Sopenharmony_ci	{ 0x030d, 0x02 },
37062306a36Sopenharmony_ci	{ 0x030e, 0x00 },
37162306a36Sopenharmony_ci	{ 0x030f, 0x4b },
37262306a36Sopenharmony_ci	{ 0x0310, 0x00 },
37362306a36Sopenharmony_ci	{ 0x0700, 0x00 },
37462306a36Sopenharmony_ci	{ 0x0701, 0x10 },
37562306a36Sopenharmony_ci	{ 0x0820, 0x0b },
37662306a36Sopenharmony_ci	{ 0x0821, 0x40 },
37762306a36Sopenharmony_ci	{ 0x3088, 0x04 },
37862306a36Sopenharmony_ci	{ 0x6813, 0x02 },
37962306a36Sopenharmony_ci	{ 0x6835, 0x07 },
38062306a36Sopenharmony_ci	{ 0x6836, 0x01 },
38162306a36Sopenharmony_ci	{ 0x6837, 0x04 },
38262306a36Sopenharmony_ci	{ 0x684d, 0x07 },
38362306a36Sopenharmony_ci	{ 0x684e, 0x01 },
38462306a36Sopenharmony_ci	{ 0x684f, 0x04 },
38562306a36Sopenharmony_ci};
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_cistatic const struct imx355_reg mode_1936x1096_regs[] = {
38862306a36Sopenharmony_ci	{ 0x0112, 0x0a },
38962306a36Sopenharmony_ci	{ 0x0113, 0x0a },
39062306a36Sopenharmony_ci	{ 0x0114, 0x03 },
39162306a36Sopenharmony_ci	{ 0x0342, 0x0e },
39262306a36Sopenharmony_ci	{ 0x0343, 0x58 },
39362306a36Sopenharmony_ci	{ 0x0340, 0x05 },
39462306a36Sopenharmony_ci	{ 0x0341, 0x1a },
39562306a36Sopenharmony_ci	{ 0x0344, 0x02 },
39662306a36Sopenharmony_ci	{ 0x0345, 0xa0 },
39762306a36Sopenharmony_ci	{ 0x0346, 0x02 },
39862306a36Sopenharmony_ci	{ 0x0347, 0xac },
39962306a36Sopenharmony_ci	{ 0x0348, 0x0a },
40062306a36Sopenharmony_ci	{ 0x0349, 0x2f },
40162306a36Sopenharmony_ci	{ 0x034a, 0x06 },
40262306a36Sopenharmony_ci	{ 0x034b, 0xf3 },
40362306a36Sopenharmony_ci	{ 0x0220, 0x00 },
40462306a36Sopenharmony_ci	{ 0x0222, 0x01 },
40562306a36Sopenharmony_ci	{ 0x0900, 0x00 },
40662306a36Sopenharmony_ci	{ 0x0901, 0x11 },
40762306a36Sopenharmony_ci	{ 0x0902, 0x00 },
40862306a36Sopenharmony_ci	{ 0x034c, 0x07 },
40962306a36Sopenharmony_ci	{ 0x034d, 0x90 },
41062306a36Sopenharmony_ci	{ 0x034e, 0x04 },
41162306a36Sopenharmony_ci	{ 0x034f, 0x48 },
41262306a36Sopenharmony_ci	{ 0x0301, 0x05 },
41362306a36Sopenharmony_ci	{ 0x0303, 0x01 },
41462306a36Sopenharmony_ci	{ 0x0305, 0x02 },
41562306a36Sopenharmony_ci	{ 0x0306, 0x00 },
41662306a36Sopenharmony_ci	{ 0x0307, 0x78 },
41762306a36Sopenharmony_ci	{ 0x030b, 0x01 },
41862306a36Sopenharmony_ci	{ 0x030d, 0x02 },
41962306a36Sopenharmony_ci	{ 0x030e, 0x00 },
42062306a36Sopenharmony_ci	{ 0x030f, 0x4b },
42162306a36Sopenharmony_ci	{ 0x0310, 0x00 },
42262306a36Sopenharmony_ci	{ 0x0700, 0x00 },
42362306a36Sopenharmony_ci	{ 0x0701, 0x10 },
42462306a36Sopenharmony_ci	{ 0x0820, 0x0b },
42562306a36Sopenharmony_ci	{ 0x0821, 0x40 },
42662306a36Sopenharmony_ci	{ 0x3088, 0x04 },
42762306a36Sopenharmony_ci	{ 0x6813, 0x02 },
42862306a36Sopenharmony_ci	{ 0x6835, 0x07 },
42962306a36Sopenharmony_ci	{ 0x6836, 0x01 },
43062306a36Sopenharmony_ci	{ 0x6837, 0x04 },
43162306a36Sopenharmony_ci	{ 0x684d, 0x07 },
43262306a36Sopenharmony_ci	{ 0x684e, 0x01 },
43362306a36Sopenharmony_ci	{ 0x684f, 0x04 },
43462306a36Sopenharmony_ci};
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_cistatic const struct imx355_reg mode_1924x1080_regs[] = {
43762306a36Sopenharmony_ci	{ 0x0112, 0x0a },
43862306a36Sopenharmony_ci	{ 0x0113, 0x0a },
43962306a36Sopenharmony_ci	{ 0x0114, 0x03 },
44062306a36Sopenharmony_ci	{ 0x0342, 0x0e },
44162306a36Sopenharmony_ci	{ 0x0343, 0x58 },
44262306a36Sopenharmony_ci	{ 0x0340, 0x05 },
44362306a36Sopenharmony_ci	{ 0x0341, 0x1a },
44462306a36Sopenharmony_ci	{ 0x0344, 0x02 },
44562306a36Sopenharmony_ci	{ 0x0345, 0xa8 },
44662306a36Sopenharmony_ci	{ 0x0346, 0x02 },
44762306a36Sopenharmony_ci	{ 0x0347, 0xb4 },
44862306a36Sopenharmony_ci	{ 0x0348, 0x0a },
44962306a36Sopenharmony_ci	{ 0x0349, 0x2b },
45062306a36Sopenharmony_ci	{ 0x034a, 0x06 },
45162306a36Sopenharmony_ci	{ 0x034b, 0xeb },
45262306a36Sopenharmony_ci	{ 0x0220, 0x00 },
45362306a36Sopenharmony_ci	{ 0x0222, 0x01 },
45462306a36Sopenharmony_ci	{ 0x0900, 0x00 },
45562306a36Sopenharmony_ci	{ 0x0901, 0x11 },
45662306a36Sopenharmony_ci	{ 0x0902, 0x00 },
45762306a36Sopenharmony_ci	{ 0x034c, 0x07 },
45862306a36Sopenharmony_ci	{ 0x034d, 0x84 },
45962306a36Sopenharmony_ci	{ 0x034e, 0x04 },
46062306a36Sopenharmony_ci	{ 0x034f, 0x38 },
46162306a36Sopenharmony_ci	{ 0x0301, 0x05 },
46262306a36Sopenharmony_ci	{ 0x0303, 0x01 },
46362306a36Sopenharmony_ci	{ 0x0305, 0x02 },
46462306a36Sopenharmony_ci	{ 0x0306, 0x00 },
46562306a36Sopenharmony_ci	{ 0x0307, 0x78 },
46662306a36Sopenharmony_ci	{ 0x030b, 0x01 },
46762306a36Sopenharmony_ci	{ 0x030d, 0x02 },
46862306a36Sopenharmony_ci	{ 0x030e, 0x00 },
46962306a36Sopenharmony_ci	{ 0x030f, 0x4b },
47062306a36Sopenharmony_ci	{ 0x0310, 0x00 },
47162306a36Sopenharmony_ci	{ 0x0700, 0x00 },
47262306a36Sopenharmony_ci	{ 0x0701, 0x10 },
47362306a36Sopenharmony_ci	{ 0x0820, 0x0b },
47462306a36Sopenharmony_ci	{ 0x0821, 0x40 },
47562306a36Sopenharmony_ci	{ 0x3088, 0x04 },
47662306a36Sopenharmony_ci	{ 0x6813, 0x02 },
47762306a36Sopenharmony_ci	{ 0x6835, 0x07 },
47862306a36Sopenharmony_ci	{ 0x6836, 0x01 },
47962306a36Sopenharmony_ci	{ 0x6837, 0x04 },
48062306a36Sopenharmony_ci	{ 0x684d, 0x07 },
48162306a36Sopenharmony_ci	{ 0x684e, 0x01 },
48262306a36Sopenharmony_ci	{ 0x684f, 0x04 },
48362306a36Sopenharmony_ci};
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_cistatic const struct imx355_reg mode_1920x1080_regs[] = {
48662306a36Sopenharmony_ci	{ 0x0112, 0x0a },
48762306a36Sopenharmony_ci	{ 0x0113, 0x0a },
48862306a36Sopenharmony_ci	{ 0x0114, 0x03 },
48962306a36Sopenharmony_ci	{ 0x0342, 0x0e },
49062306a36Sopenharmony_ci	{ 0x0343, 0x58 },
49162306a36Sopenharmony_ci	{ 0x0340, 0x05 },
49262306a36Sopenharmony_ci	{ 0x0341, 0x1a },
49362306a36Sopenharmony_ci	{ 0x0344, 0x02 },
49462306a36Sopenharmony_ci	{ 0x0345, 0xa8 },
49562306a36Sopenharmony_ci	{ 0x0346, 0x02 },
49662306a36Sopenharmony_ci	{ 0x0347, 0xb4 },
49762306a36Sopenharmony_ci	{ 0x0348, 0x0a },
49862306a36Sopenharmony_ci	{ 0x0349, 0x27 },
49962306a36Sopenharmony_ci	{ 0x034a, 0x06 },
50062306a36Sopenharmony_ci	{ 0x034b, 0xeb },
50162306a36Sopenharmony_ci	{ 0x0220, 0x00 },
50262306a36Sopenharmony_ci	{ 0x0222, 0x01 },
50362306a36Sopenharmony_ci	{ 0x0900, 0x00 },
50462306a36Sopenharmony_ci	{ 0x0901, 0x11 },
50562306a36Sopenharmony_ci	{ 0x0902, 0x00 },
50662306a36Sopenharmony_ci	{ 0x034c, 0x07 },
50762306a36Sopenharmony_ci	{ 0x034d, 0x80 },
50862306a36Sopenharmony_ci	{ 0x034e, 0x04 },
50962306a36Sopenharmony_ci	{ 0x034f, 0x38 },
51062306a36Sopenharmony_ci	{ 0x0301, 0x05 },
51162306a36Sopenharmony_ci	{ 0x0303, 0x01 },
51262306a36Sopenharmony_ci	{ 0x0305, 0x02 },
51362306a36Sopenharmony_ci	{ 0x0306, 0x00 },
51462306a36Sopenharmony_ci	{ 0x0307, 0x78 },
51562306a36Sopenharmony_ci	{ 0x030b, 0x01 },
51662306a36Sopenharmony_ci	{ 0x030d, 0x02 },
51762306a36Sopenharmony_ci	{ 0x030e, 0x00 },
51862306a36Sopenharmony_ci	{ 0x030f, 0x4b },
51962306a36Sopenharmony_ci	{ 0x0310, 0x00 },
52062306a36Sopenharmony_ci	{ 0x0700, 0x00 },
52162306a36Sopenharmony_ci	{ 0x0701, 0x10 },
52262306a36Sopenharmony_ci	{ 0x0820, 0x0b },
52362306a36Sopenharmony_ci	{ 0x0821, 0x40 },
52462306a36Sopenharmony_ci	{ 0x3088, 0x04 },
52562306a36Sopenharmony_ci	{ 0x6813, 0x02 },
52662306a36Sopenharmony_ci	{ 0x6835, 0x07 },
52762306a36Sopenharmony_ci	{ 0x6836, 0x01 },
52862306a36Sopenharmony_ci	{ 0x6837, 0x04 },
52962306a36Sopenharmony_ci	{ 0x684d, 0x07 },
53062306a36Sopenharmony_ci	{ 0x684e, 0x01 },
53162306a36Sopenharmony_ci	{ 0x684f, 0x04 },
53262306a36Sopenharmony_ci};
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_cistatic const struct imx355_reg mode_1640x1232_regs[] = {
53562306a36Sopenharmony_ci	{ 0x0112, 0x0a },
53662306a36Sopenharmony_ci	{ 0x0113, 0x0a },
53762306a36Sopenharmony_ci	{ 0x0114, 0x03 },
53862306a36Sopenharmony_ci	{ 0x0342, 0x07 },
53962306a36Sopenharmony_ci	{ 0x0343, 0x2c },
54062306a36Sopenharmony_ci	{ 0x0340, 0x05 },
54162306a36Sopenharmony_ci	{ 0x0341, 0x1a },
54262306a36Sopenharmony_ci	{ 0x0344, 0x00 },
54362306a36Sopenharmony_ci	{ 0x0345, 0x00 },
54462306a36Sopenharmony_ci	{ 0x0346, 0x00 },
54562306a36Sopenharmony_ci	{ 0x0347, 0x00 },
54662306a36Sopenharmony_ci	{ 0x0348, 0x0c },
54762306a36Sopenharmony_ci	{ 0x0349, 0xcf },
54862306a36Sopenharmony_ci	{ 0x034a, 0x09 },
54962306a36Sopenharmony_ci	{ 0x034b, 0x9f },
55062306a36Sopenharmony_ci	{ 0x0220, 0x00 },
55162306a36Sopenharmony_ci	{ 0x0222, 0x01 },
55262306a36Sopenharmony_ci	{ 0x0900, 0x01 },
55362306a36Sopenharmony_ci	{ 0x0901, 0x22 },
55462306a36Sopenharmony_ci	{ 0x0902, 0x00 },
55562306a36Sopenharmony_ci	{ 0x034c, 0x06 },
55662306a36Sopenharmony_ci	{ 0x034d, 0x68 },
55762306a36Sopenharmony_ci	{ 0x034e, 0x04 },
55862306a36Sopenharmony_ci	{ 0x034f, 0xd0 },
55962306a36Sopenharmony_ci	{ 0x0301, 0x05 },
56062306a36Sopenharmony_ci	{ 0x0303, 0x01 },
56162306a36Sopenharmony_ci	{ 0x0305, 0x02 },
56262306a36Sopenharmony_ci	{ 0x0306, 0x00 },
56362306a36Sopenharmony_ci	{ 0x0307, 0x78 },
56462306a36Sopenharmony_ci	{ 0x030b, 0x01 },
56562306a36Sopenharmony_ci	{ 0x030d, 0x02 },
56662306a36Sopenharmony_ci	{ 0x030e, 0x00 },
56762306a36Sopenharmony_ci	{ 0x030f, 0x4b },
56862306a36Sopenharmony_ci	{ 0x0310, 0x00 },
56962306a36Sopenharmony_ci	{ 0x0700, 0x00 },
57062306a36Sopenharmony_ci	{ 0x0701, 0x10 },
57162306a36Sopenharmony_ci	{ 0x0820, 0x0b },
57262306a36Sopenharmony_ci	{ 0x0821, 0x40 },
57362306a36Sopenharmony_ci	{ 0x3088, 0x04 },
57462306a36Sopenharmony_ci	{ 0x6813, 0x02 },
57562306a36Sopenharmony_ci	{ 0x6835, 0x07 },
57662306a36Sopenharmony_ci	{ 0x6836, 0x01 },
57762306a36Sopenharmony_ci	{ 0x6837, 0x04 },
57862306a36Sopenharmony_ci	{ 0x684d, 0x07 },
57962306a36Sopenharmony_ci	{ 0x684e, 0x01 },
58062306a36Sopenharmony_ci	{ 0x684f, 0x04 },
58162306a36Sopenharmony_ci};
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_cistatic const struct imx355_reg mode_1640x922_regs[] = {
58462306a36Sopenharmony_ci	{ 0x0112, 0x0a },
58562306a36Sopenharmony_ci	{ 0x0113, 0x0a },
58662306a36Sopenharmony_ci	{ 0x0114, 0x03 },
58762306a36Sopenharmony_ci	{ 0x0342, 0x07 },
58862306a36Sopenharmony_ci	{ 0x0343, 0x2c },
58962306a36Sopenharmony_ci	{ 0x0340, 0x05 },
59062306a36Sopenharmony_ci	{ 0x0341, 0x1a },
59162306a36Sopenharmony_ci	{ 0x0344, 0x00 },
59262306a36Sopenharmony_ci	{ 0x0345, 0x00 },
59362306a36Sopenharmony_ci	{ 0x0346, 0x01 },
59462306a36Sopenharmony_ci	{ 0x0347, 0x30 },
59562306a36Sopenharmony_ci	{ 0x0348, 0x0c },
59662306a36Sopenharmony_ci	{ 0x0349, 0xcf },
59762306a36Sopenharmony_ci	{ 0x034a, 0x08 },
59862306a36Sopenharmony_ci	{ 0x034b, 0x63 },
59962306a36Sopenharmony_ci	{ 0x0220, 0x00 },
60062306a36Sopenharmony_ci	{ 0x0222, 0x01 },
60162306a36Sopenharmony_ci	{ 0x0900, 0x01 },
60262306a36Sopenharmony_ci	{ 0x0901, 0x22 },
60362306a36Sopenharmony_ci	{ 0x0902, 0x00 },
60462306a36Sopenharmony_ci	{ 0x034c, 0x06 },
60562306a36Sopenharmony_ci	{ 0x034d, 0x68 },
60662306a36Sopenharmony_ci	{ 0x034e, 0x03 },
60762306a36Sopenharmony_ci	{ 0x034f, 0x9a },
60862306a36Sopenharmony_ci	{ 0x0301, 0x05 },
60962306a36Sopenharmony_ci	{ 0x0303, 0x01 },
61062306a36Sopenharmony_ci	{ 0x0305, 0x02 },
61162306a36Sopenharmony_ci	{ 0x0306, 0x00 },
61262306a36Sopenharmony_ci	{ 0x0307, 0x78 },
61362306a36Sopenharmony_ci	{ 0x030b, 0x01 },
61462306a36Sopenharmony_ci	{ 0x030d, 0x02 },
61562306a36Sopenharmony_ci	{ 0x030e, 0x00 },
61662306a36Sopenharmony_ci	{ 0x030f, 0x4b },
61762306a36Sopenharmony_ci	{ 0x0310, 0x00 },
61862306a36Sopenharmony_ci	{ 0x0700, 0x00 },
61962306a36Sopenharmony_ci	{ 0x0701, 0x10 },
62062306a36Sopenharmony_ci	{ 0x0820, 0x0b },
62162306a36Sopenharmony_ci	{ 0x0821, 0x40 },
62262306a36Sopenharmony_ci	{ 0x3088, 0x04 },
62362306a36Sopenharmony_ci	{ 0x6813, 0x02 },
62462306a36Sopenharmony_ci	{ 0x6835, 0x07 },
62562306a36Sopenharmony_ci	{ 0x6836, 0x01 },
62662306a36Sopenharmony_ci	{ 0x6837, 0x04 },
62762306a36Sopenharmony_ci	{ 0x684d, 0x07 },
62862306a36Sopenharmony_ci	{ 0x684e, 0x01 },
62962306a36Sopenharmony_ci	{ 0x684f, 0x04 },
63062306a36Sopenharmony_ci};
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_cistatic const struct imx355_reg mode_1300x736_regs[] = {
63362306a36Sopenharmony_ci	{ 0x0112, 0x0a },
63462306a36Sopenharmony_ci	{ 0x0113, 0x0a },
63562306a36Sopenharmony_ci	{ 0x0114, 0x03 },
63662306a36Sopenharmony_ci	{ 0x0342, 0x07 },
63762306a36Sopenharmony_ci	{ 0x0343, 0x2c },
63862306a36Sopenharmony_ci	{ 0x0340, 0x05 },
63962306a36Sopenharmony_ci	{ 0x0341, 0x1a },
64062306a36Sopenharmony_ci	{ 0x0344, 0x01 },
64162306a36Sopenharmony_ci	{ 0x0345, 0x58 },
64262306a36Sopenharmony_ci	{ 0x0346, 0x01 },
64362306a36Sopenharmony_ci	{ 0x0347, 0xf0 },
64462306a36Sopenharmony_ci	{ 0x0348, 0x0b },
64562306a36Sopenharmony_ci	{ 0x0349, 0x7f },
64662306a36Sopenharmony_ci	{ 0x034a, 0x07 },
64762306a36Sopenharmony_ci	{ 0x034b, 0xaf },
64862306a36Sopenharmony_ci	{ 0x0220, 0x00 },
64962306a36Sopenharmony_ci	{ 0x0222, 0x01 },
65062306a36Sopenharmony_ci	{ 0x0900, 0x01 },
65162306a36Sopenharmony_ci	{ 0x0901, 0x22 },
65262306a36Sopenharmony_ci	{ 0x0902, 0x00 },
65362306a36Sopenharmony_ci	{ 0x034c, 0x05 },
65462306a36Sopenharmony_ci	{ 0x034d, 0x14 },
65562306a36Sopenharmony_ci	{ 0x034e, 0x02 },
65662306a36Sopenharmony_ci	{ 0x034f, 0xe0 },
65762306a36Sopenharmony_ci	{ 0x0301, 0x05 },
65862306a36Sopenharmony_ci	{ 0x0303, 0x01 },
65962306a36Sopenharmony_ci	{ 0x0305, 0x02 },
66062306a36Sopenharmony_ci	{ 0x0306, 0x00 },
66162306a36Sopenharmony_ci	{ 0x0307, 0x78 },
66262306a36Sopenharmony_ci	{ 0x030b, 0x01 },
66362306a36Sopenharmony_ci	{ 0x030d, 0x02 },
66462306a36Sopenharmony_ci	{ 0x030e, 0x00 },
66562306a36Sopenharmony_ci	{ 0x030f, 0x4b },
66662306a36Sopenharmony_ci	{ 0x0310, 0x00 },
66762306a36Sopenharmony_ci	{ 0x0700, 0x00 },
66862306a36Sopenharmony_ci	{ 0x0701, 0x10 },
66962306a36Sopenharmony_ci	{ 0x0820, 0x0b },
67062306a36Sopenharmony_ci	{ 0x0821, 0x40 },
67162306a36Sopenharmony_ci	{ 0x3088, 0x04 },
67262306a36Sopenharmony_ci	{ 0x6813, 0x02 },
67362306a36Sopenharmony_ci	{ 0x6835, 0x07 },
67462306a36Sopenharmony_ci	{ 0x6836, 0x01 },
67562306a36Sopenharmony_ci	{ 0x6837, 0x04 },
67662306a36Sopenharmony_ci	{ 0x684d, 0x07 },
67762306a36Sopenharmony_ci	{ 0x684e, 0x01 },
67862306a36Sopenharmony_ci	{ 0x684f, 0x04 },
67962306a36Sopenharmony_ci};
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_cistatic const struct imx355_reg mode_1296x736_regs[] = {
68262306a36Sopenharmony_ci	{ 0x0112, 0x0a },
68362306a36Sopenharmony_ci	{ 0x0113, 0x0a },
68462306a36Sopenharmony_ci	{ 0x0114, 0x03 },
68562306a36Sopenharmony_ci	{ 0x0342, 0x07 },
68662306a36Sopenharmony_ci	{ 0x0343, 0x2c },
68762306a36Sopenharmony_ci	{ 0x0340, 0x05 },
68862306a36Sopenharmony_ci	{ 0x0341, 0x1a },
68962306a36Sopenharmony_ci	{ 0x0344, 0x01 },
69062306a36Sopenharmony_ci	{ 0x0345, 0x58 },
69162306a36Sopenharmony_ci	{ 0x0346, 0x01 },
69262306a36Sopenharmony_ci	{ 0x0347, 0xf0 },
69362306a36Sopenharmony_ci	{ 0x0348, 0x0b },
69462306a36Sopenharmony_ci	{ 0x0349, 0x77 },
69562306a36Sopenharmony_ci	{ 0x034a, 0x07 },
69662306a36Sopenharmony_ci	{ 0x034b, 0xaf },
69762306a36Sopenharmony_ci	{ 0x0220, 0x00 },
69862306a36Sopenharmony_ci	{ 0x0222, 0x01 },
69962306a36Sopenharmony_ci	{ 0x0900, 0x01 },
70062306a36Sopenharmony_ci	{ 0x0901, 0x22 },
70162306a36Sopenharmony_ci	{ 0x0902, 0x00 },
70262306a36Sopenharmony_ci	{ 0x034c, 0x05 },
70362306a36Sopenharmony_ci	{ 0x034d, 0x10 },
70462306a36Sopenharmony_ci	{ 0x034e, 0x02 },
70562306a36Sopenharmony_ci	{ 0x034f, 0xe0 },
70662306a36Sopenharmony_ci	{ 0x0301, 0x05 },
70762306a36Sopenharmony_ci	{ 0x0303, 0x01 },
70862306a36Sopenharmony_ci	{ 0x0305, 0x02 },
70962306a36Sopenharmony_ci	{ 0x0306, 0x00 },
71062306a36Sopenharmony_ci	{ 0x0307, 0x78 },
71162306a36Sopenharmony_ci	{ 0x030b, 0x01 },
71262306a36Sopenharmony_ci	{ 0x030d, 0x02 },
71362306a36Sopenharmony_ci	{ 0x030e, 0x00 },
71462306a36Sopenharmony_ci	{ 0x030f, 0x4b },
71562306a36Sopenharmony_ci	{ 0x0310, 0x00 },
71662306a36Sopenharmony_ci	{ 0x0700, 0x00 },
71762306a36Sopenharmony_ci	{ 0x0701, 0x10 },
71862306a36Sopenharmony_ci	{ 0x0820, 0x0b },
71962306a36Sopenharmony_ci	{ 0x0821, 0x40 },
72062306a36Sopenharmony_ci	{ 0x3088, 0x04 },
72162306a36Sopenharmony_ci	{ 0x6813, 0x02 },
72262306a36Sopenharmony_ci	{ 0x6835, 0x07 },
72362306a36Sopenharmony_ci	{ 0x6836, 0x01 },
72462306a36Sopenharmony_ci	{ 0x6837, 0x04 },
72562306a36Sopenharmony_ci	{ 0x684d, 0x07 },
72662306a36Sopenharmony_ci	{ 0x684e, 0x01 },
72762306a36Sopenharmony_ci	{ 0x684f, 0x04 },
72862306a36Sopenharmony_ci};
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_cistatic const struct imx355_reg mode_1284x720_regs[] = {
73162306a36Sopenharmony_ci	{ 0x0112, 0x0a },
73262306a36Sopenharmony_ci	{ 0x0113, 0x0a },
73362306a36Sopenharmony_ci	{ 0x0114, 0x03 },
73462306a36Sopenharmony_ci	{ 0x0342, 0x07 },
73562306a36Sopenharmony_ci	{ 0x0343, 0x2c },
73662306a36Sopenharmony_ci	{ 0x0340, 0x05 },
73762306a36Sopenharmony_ci	{ 0x0341, 0x1a },
73862306a36Sopenharmony_ci	{ 0x0344, 0x01 },
73962306a36Sopenharmony_ci	{ 0x0345, 0x68 },
74062306a36Sopenharmony_ci	{ 0x0346, 0x02 },
74162306a36Sopenharmony_ci	{ 0x0347, 0x00 },
74262306a36Sopenharmony_ci	{ 0x0348, 0x0b },
74362306a36Sopenharmony_ci	{ 0x0349, 0x6f },
74462306a36Sopenharmony_ci	{ 0x034a, 0x07 },
74562306a36Sopenharmony_ci	{ 0x034b, 0x9f },
74662306a36Sopenharmony_ci	{ 0x0220, 0x00 },
74762306a36Sopenharmony_ci	{ 0x0222, 0x01 },
74862306a36Sopenharmony_ci	{ 0x0900, 0x01 },
74962306a36Sopenharmony_ci	{ 0x0901, 0x22 },
75062306a36Sopenharmony_ci	{ 0x0902, 0x00 },
75162306a36Sopenharmony_ci	{ 0x034c, 0x05 },
75262306a36Sopenharmony_ci	{ 0x034d, 0x04 },
75362306a36Sopenharmony_ci	{ 0x034e, 0x02 },
75462306a36Sopenharmony_ci	{ 0x034f, 0xd0 },
75562306a36Sopenharmony_ci	{ 0x0301, 0x05 },
75662306a36Sopenharmony_ci	{ 0x0303, 0x01 },
75762306a36Sopenharmony_ci	{ 0x0305, 0x02 },
75862306a36Sopenharmony_ci	{ 0x0306, 0x00 },
75962306a36Sopenharmony_ci	{ 0x0307, 0x78 },
76062306a36Sopenharmony_ci	{ 0x030b, 0x01 },
76162306a36Sopenharmony_ci	{ 0x030d, 0x02 },
76262306a36Sopenharmony_ci	{ 0x030e, 0x00 },
76362306a36Sopenharmony_ci	{ 0x030f, 0x4b },
76462306a36Sopenharmony_ci	{ 0x0310, 0x00 },
76562306a36Sopenharmony_ci	{ 0x0700, 0x00 },
76662306a36Sopenharmony_ci	{ 0x0701, 0x10 },
76762306a36Sopenharmony_ci	{ 0x0820, 0x0b },
76862306a36Sopenharmony_ci	{ 0x0821, 0x40 },
76962306a36Sopenharmony_ci	{ 0x3088, 0x04 },
77062306a36Sopenharmony_ci	{ 0x6813, 0x02 },
77162306a36Sopenharmony_ci	{ 0x6835, 0x07 },
77262306a36Sopenharmony_ci	{ 0x6836, 0x01 },
77362306a36Sopenharmony_ci	{ 0x6837, 0x04 },
77462306a36Sopenharmony_ci	{ 0x684d, 0x07 },
77562306a36Sopenharmony_ci	{ 0x684e, 0x01 },
77662306a36Sopenharmony_ci	{ 0x684f, 0x04 },
77762306a36Sopenharmony_ci};
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_cistatic const struct imx355_reg mode_1280x720_regs[] = {
78062306a36Sopenharmony_ci	{ 0x0112, 0x0a },
78162306a36Sopenharmony_ci	{ 0x0113, 0x0a },
78262306a36Sopenharmony_ci	{ 0x0114, 0x03 },
78362306a36Sopenharmony_ci	{ 0x0342, 0x07 },
78462306a36Sopenharmony_ci	{ 0x0343, 0x2c },
78562306a36Sopenharmony_ci	{ 0x0340, 0x05 },
78662306a36Sopenharmony_ci	{ 0x0341, 0x1a },
78762306a36Sopenharmony_ci	{ 0x0344, 0x01 },
78862306a36Sopenharmony_ci	{ 0x0345, 0x68 },
78962306a36Sopenharmony_ci	{ 0x0346, 0x02 },
79062306a36Sopenharmony_ci	{ 0x0347, 0x00 },
79162306a36Sopenharmony_ci	{ 0x0348, 0x0b },
79262306a36Sopenharmony_ci	{ 0x0349, 0x67 },
79362306a36Sopenharmony_ci	{ 0x034a, 0x07 },
79462306a36Sopenharmony_ci	{ 0x034b, 0x9f },
79562306a36Sopenharmony_ci	{ 0x0220, 0x00 },
79662306a36Sopenharmony_ci	{ 0x0222, 0x01 },
79762306a36Sopenharmony_ci	{ 0x0900, 0x01 },
79862306a36Sopenharmony_ci	{ 0x0901, 0x22 },
79962306a36Sopenharmony_ci	{ 0x0902, 0x00 },
80062306a36Sopenharmony_ci	{ 0x034c, 0x05 },
80162306a36Sopenharmony_ci	{ 0x034d, 0x00 },
80262306a36Sopenharmony_ci	{ 0x034e, 0x02 },
80362306a36Sopenharmony_ci	{ 0x034f, 0xd0 },
80462306a36Sopenharmony_ci	{ 0x0301, 0x05 },
80562306a36Sopenharmony_ci	{ 0x0303, 0x01 },
80662306a36Sopenharmony_ci	{ 0x0305, 0x02 },
80762306a36Sopenharmony_ci	{ 0x0306, 0x00 },
80862306a36Sopenharmony_ci	{ 0x0307, 0x78 },
80962306a36Sopenharmony_ci	{ 0x030b, 0x01 },
81062306a36Sopenharmony_ci	{ 0x030d, 0x02 },
81162306a36Sopenharmony_ci	{ 0x030e, 0x00 },
81262306a36Sopenharmony_ci	{ 0x030f, 0x4b },
81362306a36Sopenharmony_ci	{ 0x0310, 0x00 },
81462306a36Sopenharmony_ci	{ 0x0700, 0x00 },
81562306a36Sopenharmony_ci	{ 0x0701, 0x10 },
81662306a36Sopenharmony_ci	{ 0x0820, 0x0b },
81762306a36Sopenharmony_ci	{ 0x0821, 0x40 },
81862306a36Sopenharmony_ci	{ 0x3088, 0x04 },
81962306a36Sopenharmony_ci	{ 0x6813, 0x02 },
82062306a36Sopenharmony_ci	{ 0x6835, 0x07 },
82162306a36Sopenharmony_ci	{ 0x6836, 0x01 },
82262306a36Sopenharmony_ci	{ 0x6837, 0x04 },
82362306a36Sopenharmony_ci	{ 0x684d, 0x07 },
82462306a36Sopenharmony_ci	{ 0x684e, 0x01 },
82562306a36Sopenharmony_ci	{ 0x684f, 0x04 },
82662306a36Sopenharmony_ci};
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_cistatic const struct imx355_reg mode_820x616_regs[] = {
82962306a36Sopenharmony_ci	{ 0x0112, 0x0a },
83062306a36Sopenharmony_ci	{ 0x0113, 0x0a },
83162306a36Sopenharmony_ci	{ 0x0114, 0x03 },
83262306a36Sopenharmony_ci	{ 0x0342, 0x0e },
83362306a36Sopenharmony_ci	{ 0x0343, 0x58 },
83462306a36Sopenharmony_ci	{ 0x0340, 0x02 },
83562306a36Sopenharmony_ci	{ 0x0341, 0x8c },
83662306a36Sopenharmony_ci	{ 0x0344, 0x00 },
83762306a36Sopenharmony_ci	{ 0x0345, 0x00 },
83862306a36Sopenharmony_ci	{ 0x0346, 0x00 },
83962306a36Sopenharmony_ci	{ 0x0347, 0x00 },
84062306a36Sopenharmony_ci	{ 0x0348, 0x0c },
84162306a36Sopenharmony_ci	{ 0x0349, 0xcf },
84262306a36Sopenharmony_ci	{ 0x034a, 0x09 },
84362306a36Sopenharmony_ci	{ 0x034b, 0x9f },
84462306a36Sopenharmony_ci	{ 0x0220, 0x00 },
84562306a36Sopenharmony_ci	{ 0x0222, 0x01 },
84662306a36Sopenharmony_ci	{ 0x0900, 0x01 },
84762306a36Sopenharmony_ci	{ 0x0901, 0x44 },
84862306a36Sopenharmony_ci	{ 0x0902, 0x00 },
84962306a36Sopenharmony_ci	{ 0x034c, 0x03 },
85062306a36Sopenharmony_ci	{ 0x034d, 0x34 },
85162306a36Sopenharmony_ci	{ 0x034e, 0x02 },
85262306a36Sopenharmony_ci	{ 0x034f, 0x68 },
85362306a36Sopenharmony_ci	{ 0x0301, 0x05 },
85462306a36Sopenharmony_ci	{ 0x0303, 0x01 },
85562306a36Sopenharmony_ci	{ 0x0305, 0x02 },
85662306a36Sopenharmony_ci	{ 0x0306, 0x00 },
85762306a36Sopenharmony_ci	{ 0x0307, 0x78 },
85862306a36Sopenharmony_ci	{ 0x030b, 0x01 },
85962306a36Sopenharmony_ci	{ 0x030d, 0x02 },
86062306a36Sopenharmony_ci	{ 0x030e, 0x00 },
86162306a36Sopenharmony_ci	{ 0x030f, 0x4b },
86262306a36Sopenharmony_ci	{ 0x0310, 0x00 },
86362306a36Sopenharmony_ci	{ 0x0700, 0x02 },
86462306a36Sopenharmony_ci	{ 0x0701, 0x78 },
86562306a36Sopenharmony_ci	{ 0x0820, 0x0b },
86662306a36Sopenharmony_ci	{ 0x0821, 0x40 },
86762306a36Sopenharmony_ci	{ 0x3088, 0x04 },
86862306a36Sopenharmony_ci	{ 0x6813, 0x02 },
86962306a36Sopenharmony_ci	{ 0x6835, 0x07 },
87062306a36Sopenharmony_ci	{ 0x6836, 0x01 },
87162306a36Sopenharmony_ci	{ 0x6837, 0x04 },
87262306a36Sopenharmony_ci	{ 0x684d, 0x07 },
87362306a36Sopenharmony_ci	{ 0x684e, 0x01 },
87462306a36Sopenharmony_ci	{ 0x684f, 0x04 },
87562306a36Sopenharmony_ci};
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_cistatic const char * const imx355_test_pattern_menu[] = {
87862306a36Sopenharmony_ci	"Disabled",
87962306a36Sopenharmony_ci	"Solid Colour",
88062306a36Sopenharmony_ci	"Eight Vertical Colour Bars",
88162306a36Sopenharmony_ci	"Colour Bars With Fade to Grey",
88262306a36Sopenharmony_ci	"Pseudorandom Sequence (PN9)",
88362306a36Sopenharmony_ci};
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci/* supported link frequencies */
88662306a36Sopenharmony_cistatic const s64 link_freq_menu_items[] = {
88762306a36Sopenharmony_ci	IMX355_LINK_FREQ_DEFAULT,
88862306a36Sopenharmony_ci};
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci/* Mode configs */
89162306a36Sopenharmony_cistatic const struct imx355_mode supported_modes[] = {
89262306a36Sopenharmony_ci	{
89362306a36Sopenharmony_ci		.width = 3280,
89462306a36Sopenharmony_ci		.height = 2464,
89562306a36Sopenharmony_ci		.fll_def = 2615,
89662306a36Sopenharmony_ci		.fll_min = 2615,
89762306a36Sopenharmony_ci		.llp = 3672,
89862306a36Sopenharmony_ci		.link_freq_index = IMX355_LINK_FREQ_INDEX,
89962306a36Sopenharmony_ci		.reg_list = {
90062306a36Sopenharmony_ci			.num_of_regs = ARRAY_SIZE(mode_3280x2464_regs),
90162306a36Sopenharmony_ci			.regs = mode_3280x2464_regs,
90262306a36Sopenharmony_ci		},
90362306a36Sopenharmony_ci	},
90462306a36Sopenharmony_ci	{
90562306a36Sopenharmony_ci		.width = 3268,
90662306a36Sopenharmony_ci		.height = 2448,
90762306a36Sopenharmony_ci		.fll_def = 2615,
90862306a36Sopenharmony_ci		.fll_min = 2615,
90962306a36Sopenharmony_ci		.llp = 3672,
91062306a36Sopenharmony_ci		.link_freq_index = IMX355_LINK_FREQ_INDEX,
91162306a36Sopenharmony_ci		.reg_list = {
91262306a36Sopenharmony_ci			.num_of_regs = ARRAY_SIZE(mode_3268x2448_regs),
91362306a36Sopenharmony_ci			.regs = mode_3268x2448_regs,
91462306a36Sopenharmony_ci		},
91562306a36Sopenharmony_ci	},
91662306a36Sopenharmony_ci	{
91762306a36Sopenharmony_ci		.width = 3264,
91862306a36Sopenharmony_ci		.height = 2448,
91962306a36Sopenharmony_ci		.fll_def = 2615,
92062306a36Sopenharmony_ci		.fll_min = 2615,
92162306a36Sopenharmony_ci		.llp = 3672,
92262306a36Sopenharmony_ci		.link_freq_index = IMX355_LINK_FREQ_INDEX,
92362306a36Sopenharmony_ci		.reg_list = {
92462306a36Sopenharmony_ci			.num_of_regs = ARRAY_SIZE(mode_3264x2448_regs),
92562306a36Sopenharmony_ci			.regs = mode_3264x2448_regs,
92662306a36Sopenharmony_ci		},
92762306a36Sopenharmony_ci	},
92862306a36Sopenharmony_ci	{
92962306a36Sopenharmony_ci		.width = 1940,
93062306a36Sopenharmony_ci		.height = 1096,
93162306a36Sopenharmony_ci		.fll_def = 1306,
93262306a36Sopenharmony_ci		.fll_min = 1306,
93362306a36Sopenharmony_ci		.llp = 3672,
93462306a36Sopenharmony_ci		.link_freq_index = IMX355_LINK_FREQ_INDEX,
93562306a36Sopenharmony_ci		.reg_list = {
93662306a36Sopenharmony_ci			.num_of_regs = ARRAY_SIZE(mode_1940x1096_regs),
93762306a36Sopenharmony_ci			.regs = mode_1940x1096_regs,
93862306a36Sopenharmony_ci		},
93962306a36Sopenharmony_ci	},
94062306a36Sopenharmony_ci	{
94162306a36Sopenharmony_ci		.width = 1936,
94262306a36Sopenharmony_ci		.height = 1096,
94362306a36Sopenharmony_ci		.fll_def = 1306,
94462306a36Sopenharmony_ci		.fll_min = 1306,
94562306a36Sopenharmony_ci		.llp = 3672,
94662306a36Sopenharmony_ci		.link_freq_index = IMX355_LINK_FREQ_INDEX,
94762306a36Sopenharmony_ci		.reg_list = {
94862306a36Sopenharmony_ci			.num_of_regs = ARRAY_SIZE(mode_1936x1096_regs),
94962306a36Sopenharmony_ci			.regs = mode_1936x1096_regs,
95062306a36Sopenharmony_ci		},
95162306a36Sopenharmony_ci	},
95262306a36Sopenharmony_ci	{
95362306a36Sopenharmony_ci		.width = 1924,
95462306a36Sopenharmony_ci		.height = 1080,
95562306a36Sopenharmony_ci		.fll_def = 1306,
95662306a36Sopenharmony_ci		.fll_min = 1306,
95762306a36Sopenharmony_ci		.llp = 3672,
95862306a36Sopenharmony_ci		.link_freq_index = IMX355_LINK_FREQ_INDEX,
95962306a36Sopenharmony_ci		.reg_list = {
96062306a36Sopenharmony_ci			.num_of_regs = ARRAY_SIZE(mode_1924x1080_regs),
96162306a36Sopenharmony_ci			.regs = mode_1924x1080_regs,
96262306a36Sopenharmony_ci		},
96362306a36Sopenharmony_ci	},
96462306a36Sopenharmony_ci	{
96562306a36Sopenharmony_ci		.width = 1920,
96662306a36Sopenharmony_ci		.height = 1080,
96762306a36Sopenharmony_ci		.fll_def = 1306,
96862306a36Sopenharmony_ci		.fll_min = 1306,
96962306a36Sopenharmony_ci		.llp = 3672,
97062306a36Sopenharmony_ci		.link_freq_index = IMX355_LINK_FREQ_INDEX,
97162306a36Sopenharmony_ci		.reg_list = {
97262306a36Sopenharmony_ci			.num_of_regs = ARRAY_SIZE(mode_1920x1080_regs),
97362306a36Sopenharmony_ci			.regs = mode_1920x1080_regs,
97462306a36Sopenharmony_ci		},
97562306a36Sopenharmony_ci	},
97662306a36Sopenharmony_ci	{
97762306a36Sopenharmony_ci		.width = 1640,
97862306a36Sopenharmony_ci		.height = 1232,
97962306a36Sopenharmony_ci		.fll_def = 1306,
98062306a36Sopenharmony_ci		.fll_min = 1306,
98162306a36Sopenharmony_ci		.llp = 1836,
98262306a36Sopenharmony_ci		.link_freq_index = IMX355_LINK_FREQ_INDEX,
98362306a36Sopenharmony_ci		.reg_list = {
98462306a36Sopenharmony_ci			.num_of_regs = ARRAY_SIZE(mode_1640x1232_regs),
98562306a36Sopenharmony_ci			.regs = mode_1640x1232_regs,
98662306a36Sopenharmony_ci		},
98762306a36Sopenharmony_ci	},
98862306a36Sopenharmony_ci	{
98962306a36Sopenharmony_ci		.width = 1640,
99062306a36Sopenharmony_ci		.height = 922,
99162306a36Sopenharmony_ci		.fll_def = 1306,
99262306a36Sopenharmony_ci		.fll_min = 1306,
99362306a36Sopenharmony_ci		.llp = 1836,
99462306a36Sopenharmony_ci		.link_freq_index = IMX355_LINK_FREQ_INDEX,
99562306a36Sopenharmony_ci		.reg_list = {
99662306a36Sopenharmony_ci			.num_of_regs = ARRAY_SIZE(mode_1640x922_regs),
99762306a36Sopenharmony_ci			.regs = mode_1640x922_regs,
99862306a36Sopenharmony_ci		},
99962306a36Sopenharmony_ci	},
100062306a36Sopenharmony_ci	{
100162306a36Sopenharmony_ci		.width = 1300,
100262306a36Sopenharmony_ci		.height = 736,
100362306a36Sopenharmony_ci		.fll_def = 1306,
100462306a36Sopenharmony_ci		.fll_min = 1306,
100562306a36Sopenharmony_ci		.llp = 1836,
100662306a36Sopenharmony_ci		.link_freq_index = IMX355_LINK_FREQ_INDEX,
100762306a36Sopenharmony_ci		.reg_list = {
100862306a36Sopenharmony_ci			.num_of_regs = ARRAY_SIZE(mode_1300x736_regs),
100962306a36Sopenharmony_ci			.regs = mode_1300x736_regs,
101062306a36Sopenharmony_ci		},
101162306a36Sopenharmony_ci	},
101262306a36Sopenharmony_ci	{
101362306a36Sopenharmony_ci		.width = 1296,
101462306a36Sopenharmony_ci		.height = 736,
101562306a36Sopenharmony_ci		.fll_def = 1306,
101662306a36Sopenharmony_ci		.fll_min = 1306,
101762306a36Sopenharmony_ci		.llp = 1836,
101862306a36Sopenharmony_ci		.link_freq_index = IMX355_LINK_FREQ_INDEX,
101962306a36Sopenharmony_ci		.reg_list = {
102062306a36Sopenharmony_ci			.num_of_regs = ARRAY_SIZE(mode_1296x736_regs),
102162306a36Sopenharmony_ci			.regs = mode_1296x736_regs,
102262306a36Sopenharmony_ci		},
102362306a36Sopenharmony_ci	},
102462306a36Sopenharmony_ci	{
102562306a36Sopenharmony_ci		.width = 1284,
102662306a36Sopenharmony_ci		.height = 720,
102762306a36Sopenharmony_ci		.fll_def = 1306,
102862306a36Sopenharmony_ci		.fll_min = 1306,
102962306a36Sopenharmony_ci		.llp = 1836,
103062306a36Sopenharmony_ci		.link_freq_index = IMX355_LINK_FREQ_INDEX,
103162306a36Sopenharmony_ci		.reg_list = {
103262306a36Sopenharmony_ci			.num_of_regs = ARRAY_SIZE(mode_1284x720_regs),
103362306a36Sopenharmony_ci			.regs = mode_1284x720_regs,
103462306a36Sopenharmony_ci		},
103562306a36Sopenharmony_ci	},
103662306a36Sopenharmony_ci	{
103762306a36Sopenharmony_ci		.width = 1280,
103862306a36Sopenharmony_ci		.height = 720,
103962306a36Sopenharmony_ci		.fll_def = 1306,
104062306a36Sopenharmony_ci		.fll_min = 1306,
104162306a36Sopenharmony_ci		.llp = 1836,
104262306a36Sopenharmony_ci		.link_freq_index = IMX355_LINK_FREQ_INDEX,
104362306a36Sopenharmony_ci		.reg_list = {
104462306a36Sopenharmony_ci			.num_of_regs = ARRAY_SIZE(mode_1280x720_regs),
104562306a36Sopenharmony_ci			.regs = mode_1280x720_regs,
104662306a36Sopenharmony_ci		},
104762306a36Sopenharmony_ci	},
104862306a36Sopenharmony_ci	{
104962306a36Sopenharmony_ci		.width = 820,
105062306a36Sopenharmony_ci		.height = 616,
105162306a36Sopenharmony_ci		.fll_def = 652,
105262306a36Sopenharmony_ci		.fll_min = 652,
105362306a36Sopenharmony_ci		.llp = 3672,
105462306a36Sopenharmony_ci		.link_freq_index = IMX355_LINK_FREQ_INDEX,
105562306a36Sopenharmony_ci		.reg_list = {
105662306a36Sopenharmony_ci			.num_of_regs = ARRAY_SIZE(mode_820x616_regs),
105762306a36Sopenharmony_ci			.regs = mode_820x616_regs,
105862306a36Sopenharmony_ci		},
105962306a36Sopenharmony_ci	},
106062306a36Sopenharmony_ci};
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_cistatic inline struct imx355 *to_imx355(struct v4l2_subdev *_sd)
106362306a36Sopenharmony_ci{
106462306a36Sopenharmony_ci	return container_of(_sd, struct imx355, sd);
106562306a36Sopenharmony_ci}
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci/* Get bayer order based on flip setting. */
106862306a36Sopenharmony_cistatic u32 imx355_get_format_code(struct imx355 *imx355)
106962306a36Sopenharmony_ci{
107062306a36Sopenharmony_ci	/*
107162306a36Sopenharmony_ci	 * Only one bayer order is supported.
107262306a36Sopenharmony_ci	 * It depends on the flip settings.
107362306a36Sopenharmony_ci	 */
107462306a36Sopenharmony_ci	u32 code;
107562306a36Sopenharmony_ci	static const u32 codes[2][2] = {
107662306a36Sopenharmony_ci		{ MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SGRBG10_1X10, },
107762306a36Sopenharmony_ci		{ MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SBGGR10_1X10, },
107862306a36Sopenharmony_ci	};
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	lockdep_assert_held(&imx355->mutex);
108162306a36Sopenharmony_ci	code = codes[imx355->vflip->val][imx355->hflip->val];
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	return code;
108462306a36Sopenharmony_ci}
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci/* Read registers up to 4 at a time */
108762306a36Sopenharmony_cistatic int imx355_read_reg(struct imx355 *imx355, u16 reg, u32 len, u32 *val)
108862306a36Sopenharmony_ci{
108962306a36Sopenharmony_ci	struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd);
109062306a36Sopenharmony_ci	struct i2c_msg msgs[2];
109162306a36Sopenharmony_ci	u8 addr_buf[2];
109262306a36Sopenharmony_ci	u8 data_buf[4] = { 0 };
109362306a36Sopenharmony_ci	int ret;
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci	if (len > 4)
109662306a36Sopenharmony_ci		return -EINVAL;
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci	put_unaligned_be16(reg, addr_buf);
109962306a36Sopenharmony_ci	/* Write register address */
110062306a36Sopenharmony_ci	msgs[0].addr = client->addr;
110162306a36Sopenharmony_ci	msgs[0].flags = 0;
110262306a36Sopenharmony_ci	msgs[0].len = ARRAY_SIZE(addr_buf);
110362306a36Sopenharmony_ci	msgs[0].buf = addr_buf;
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	/* Read data from register */
110662306a36Sopenharmony_ci	msgs[1].addr = client->addr;
110762306a36Sopenharmony_ci	msgs[1].flags = I2C_M_RD;
110862306a36Sopenharmony_ci	msgs[1].len = len;
110962306a36Sopenharmony_ci	msgs[1].buf = &data_buf[4 - len];
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
111262306a36Sopenharmony_ci	if (ret != ARRAY_SIZE(msgs))
111362306a36Sopenharmony_ci		return -EIO;
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	*val = get_unaligned_be32(data_buf);
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	return 0;
111862306a36Sopenharmony_ci}
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci/* Write registers up to 4 at a time */
112162306a36Sopenharmony_cistatic int imx355_write_reg(struct imx355 *imx355, u16 reg, u32 len, u32 val)
112262306a36Sopenharmony_ci{
112362306a36Sopenharmony_ci	struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd);
112462306a36Sopenharmony_ci	u8 buf[6];
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci	if (len > 4)
112762306a36Sopenharmony_ci		return -EINVAL;
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	put_unaligned_be16(reg, buf);
113062306a36Sopenharmony_ci	put_unaligned_be32(val << (8 * (4 - len)), buf + 2);
113162306a36Sopenharmony_ci	if (i2c_master_send(client, buf, len + 2) != len + 2)
113262306a36Sopenharmony_ci		return -EIO;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	return 0;
113562306a36Sopenharmony_ci}
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci/* Write a list of registers */
113862306a36Sopenharmony_cistatic int imx355_write_regs(struct imx355 *imx355,
113962306a36Sopenharmony_ci			     const struct imx355_reg *regs, u32 len)
114062306a36Sopenharmony_ci{
114162306a36Sopenharmony_ci	struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd);
114262306a36Sopenharmony_ci	int ret;
114362306a36Sopenharmony_ci	u32 i;
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	for (i = 0; i < len; i++) {
114662306a36Sopenharmony_ci		ret = imx355_write_reg(imx355, regs[i].address, 1, regs[i].val);
114762306a36Sopenharmony_ci		if (ret) {
114862306a36Sopenharmony_ci			dev_err_ratelimited(&client->dev,
114962306a36Sopenharmony_ci					    "write reg 0x%4.4x return err %d",
115062306a36Sopenharmony_ci					    regs[i].address, ret);
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci			return ret;
115362306a36Sopenharmony_ci		}
115462306a36Sopenharmony_ci	}
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci	return 0;
115762306a36Sopenharmony_ci}
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci/* Open sub-device */
116062306a36Sopenharmony_cistatic int imx355_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
116162306a36Sopenharmony_ci{
116262306a36Sopenharmony_ci	struct imx355 *imx355 = to_imx355(sd);
116362306a36Sopenharmony_ci	struct v4l2_mbus_framefmt *try_fmt =
116462306a36Sopenharmony_ci		v4l2_subdev_get_try_format(sd, fh->state, 0);
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci	mutex_lock(&imx355->mutex);
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	/* Initialize try_fmt */
116962306a36Sopenharmony_ci	try_fmt->width = imx355->cur_mode->width;
117062306a36Sopenharmony_ci	try_fmt->height = imx355->cur_mode->height;
117162306a36Sopenharmony_ci	try_fmt->code = imx355_get_format_code(imx355);
117262306a36Sopenharmony_ci	try_fmt->field = V4L2_FIELD_NONE;
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci	mutex_unlock(&imx355->mutex);
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci	return 0;
117762306a36Sopenharmony_ci}
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_cistatic int imx355_set_ctrl(struct v4l2_ctrl *ctrl)
118062306a36Sopenharmony_ci{
118162306a36Sopenharmony_ci	struct imx355 *imx355 = container_of(ctrl->handler,
118262306a36Sopenharmony_ci					     struct imx355, ctrl_handler);
118362306a36Sopenharmony_ci	struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd);
118462306a36Sopenharmony_ci	s64 max;
118562306a36Sopenharmony_ci	int ret;
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci	/* Propagate change of current control to all related controls */
118862306a36Sopenharmony_ci	switch (ctrl->id) {
118962306a36Sopenharmony_ci	case V4L2_CID_VBLANK:
119062306a36Sopenharmony_ci		/* Update max exposure while meeting expected vblanking */
119162306a36Sopenharmony_ci		max = imx355->cur_mode->height + ctrl->val - 10;
119262306a36Sopenharmony_ci		__v4l2_ctrl_modify_range(imx355->exposure,
119362306a36Sopenharmony_ci					 imx355->exposure->minimum,
119462306a36Sopenharmony_ci					 max, imx355->exposure->step, max);
119562306a36Sopenharmony_ci		break;
119662306a36Sopenharmony_ci	}
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci	/*
119962306a36Sopenharmony_ci	 * Applying V4L2 control value only happens
120062306a36Sopenharmony_ci	 * when power is up for streaming
120162306a36Sopenharmony_ci	 */
120262306a36Sopenharmony_ci	if (!pm_runtime_get_if_in_use(&client->dev))
120362306a36Sopenharmony_ci		return 0;
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	switch (ctrl->id) {
120662306a36Sopenharmony_ci	case V4L2_CID_ANALOGUE_GAIN:
120762306a36Sopenharmony_ci		/* Analog gain = 1024/(1024 - ctrl->val) times */
120862306a36Sopenharmony_ci		ret = imx355_write_reg(imx355, IMX355_REG_ANALOG_GAIN, 2,
120962306a36Sopenharmony_ci				       ctrl->val);
121062306a36Sopenharmony_ci		break;
121162306a36Sopenharmony_ci	case V4L2_CID_DIGITAL_GAIN:
121262306a36Sopenharmony_ci		ret = imx355_write_reg(imx355, IMX355_REG_DIG_GAIN_GLOBAL, 2,
121362306a36Sopenharmony_ci				       ctrl->val);
121462306a36Sopenharmony_ci		break;
121562306a36Sopenharmony_ci	case V4L2_CID_EXPOSURE:
121662306a36Sopenharmony_ci		ret = imx355_write_reg(imx355, IMX355_REG_EXPOSURE, 2,
121762306a36Sopenharmony_ci				       ctrl->val);
121862306a36Sopenharmony_ci		break;
121962306a36Sopenharmony_ci	case V4L2_CID_VBLANK:
122062306a36Sopenharmony_ci		/* Update FLL that meets expected vertical blanking */
122162306a36Sopenharmony_ci		ret = imx355_write_reg(imx355, IMX355_REG_FLL, 2,
122262306a36Sopenharmony_ci				       imx355->cur_mode->height + ctrl->val);
122362306a36Sopenharmony_ci		break;
122462306a36Sopenharmony_ci	case V4L2_CID_TEST_PATTERN:
122562306a36Sopenharmony_ci		ret = imx355_write_reg(imx355, IMX355_REG_TEST_PATTERN,
122662306a36Sopenharmony_ci				       2, ctrl->val);
122762306a36Sopenharmony_ci		break;
122862306a36Sopenharmony_ci	case V4L2_CID_HFLIP:
122962306a36Sopenharmony_ci	case V4L2_CID_VFLIP:
123062306a36Sopenharmony_ci		ret = imx355_write_reg(imx355, IMX355_REG_ORIENTATION, 1,
123162306a36Sopenharmony_ci				       imx355->hflip->val |
123262306a36Sopenharmony_ci				       imx355->vflip->val << 1);
123362306a36Sopenharmony_ci		break;
123462306a36Sopenharmony_ci	default:
123562306a36Sopenharmony_ci		ret = -EINVAL;
123662306a36Sopenharmony_ci		dev_info(&client->dev, "ctrl(id:0x%x,val:0x%x) is not handled",
123762306a36Sopenharmony_ci			 ctrl->id, ctrl->val);
123862306a36Sopenharmony_ci		break;
123962306a36Sopenharmony_ci	}
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	pm_runtime_put(&client->dev);
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	return ret;
124462306a36Sopenharmony_ci}
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_cistatic const struct v4l2_ctrl_ops imx355_ctrl_ops = {
124762306a36Sopenharmony_ci	.s_ctrl = imx355_set_ctrl,
124862306a36Sopenharmony_ci};
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_cistatic int imx355_enum_mbus_code(struct v4l2_subdev *sd,
125162306a36Sopenharmony_ci				 struct v4l2_subdev_state *sd_state,
125262306a36Sopenharmony_ci				 struct v4l2_subdev_mbus_code_enum *code)
125362306a36Sopenharmony_ci{
125462306a36Sopenharmony_ci	struct imx355 *imx355 = to_imx355(sd);
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci	if (code->index > 0)
125762306a36Sopenharmony_ci		return -EINVAL;
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	mutex_lock(&imx355->mutex);
126062306a36Sopenharmony_ci	code->code = imx355_get_format_code(imx355);
126162306a36Sopenharmony_ci	mutex_unlock(&imx355->mutex);
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	return 0;
126462306a36Sopenharmony_ci}
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_cistatic int imx355_enum_frame_size(struct v4l2_subdev *sd,
126762306a36Sopenharmony_ci				  struct v4l2_subdev_state *sd_state,
126862306a36Sopenharmony_ci				  struct v4l2_subdev_frame_size_enum *fse)
126962306a36Sopenharmony_ci{
127062306a36Sopenharmony_ci	struct imx355 *imx355 = to_imx355(sd);
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci	if (fse->index >= ARRAY_SIZE(supported_modes))
127362306a36Sopenharmony_ci		return -EINVAL;
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	mutex_lock(&imx355->mutex);
127662306a36Sopenharmony_ci	if (fse->code != imx355_get_format_code(imx355)) {
127762306a36Sopenharmony_ci		mutex_unlock(&imx355->mutex);
127862306a36Sopenharmony_ci		return -EINVAL;
127962306a36Sopenharmony_ci	}
128062306a36Sopenharmony_ci	mutex_unlock(&imx355->mutex);
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci	fse->min_width = supported_modes[fse->index].width;
128362306a36Sopenharmony_ci	fse->max_width = fse->min_width;
128462306a36Sopenharmony_ci	fse->min_height = supported_modes[fse->index].height;
128562306a36Sopenharmony_ci	fse->max_height = fse->min_height;
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	return 0;
128862306a36Sopenharmony_ci}
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_cistatic void imx355_update_pad_format(struct imx355 *imx355,
129162306a36Sopenharmony_ci				     const struct imx355_mode *mode,
129262306a36Sopenharmony_ci				     struct v4l2_subdev_format *fmt)
129362306a36Sopenharmony_ci{
129462306a36Sopenharmony_ci	fmt->format.width = mode->width;
129562306a36Sopenharmony_ci	fmt->format.height = mode->height;
129662306a36Sopenharmony_ci	fmt->format.code = imx355_get_format_code(imx355);
129762306a36Sopenharmony_ci	fmt->format.field = V4L2_FIELD_NONE;
129862306a36Sopenharmony_ci}
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_cistatic int imx355_do_get_pad_format(struct imx355 *imx355,
130162306a36Sopenharmony_ci				    struct v4l2_subdev_state *sd_state,
130262306a36Sopenharmony_ci				    struct v4l2_subdev_format *fmt)
130362306a36Sopenharmony_ci{
130462306a36Sopenharmony_ci	struct v4l2_mbus_framefmt *framefmt;
130562306a36Sopenharmony_ci	struct v4l2_subdev *sd = &imx355->sd;
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
130862306a36Sopenharmony_ci		framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
130962306a36Sopenharmony_ci		fmt->format = *framefmt;
131062306a36Sopenharmony_ci	} else {
131162306a36Sopenharmony_ci		imx355_update_pad_format(imx355, imx355->cur_mode, fmt);
131262306a36Sopenharmony_ci	}
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_ci	return 0;
131562306a36Sopenharmony_ci}
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_cistatic int imx355_get_pad_format(struct v4l2_subdev *sd,
131862306a36Sopenharmony_ci				 struct v4l2_subdev_state *sd_state,
131962306a36Sopenharmony_ci				 struct v4l2_subdev_format *fmt)
132062306a36Sopenharmony_ci{
132162306a36Sopenharmony_ci	struct imx355 *imx355 = to_imx355(sd);
132262306a36Sopenharmony_ci	int ret;
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci	mutex_lock(&imx355->mutex);
132562306a36Sopenharmony_ci	ret = imx355_do_get_pad_format(imx355, sd_state, fmt);
132662306a36Sopenharmony_ci	mutex_unlock(&imx355->mutex);
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	return ret;
132962306a36Sopenharmony_ci}
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_cistatic int
133262306a36Sopenharmony_ciimx355_set_pad_format(struct v4l2_subdev *sd,
133362306a36Sopenharmony_ci		      struct v4l2_subdev_state *sd_state,
133462306a36Sopenharmony_ci		      struct v4l2_subdev_format *fmt)
133562306a36Sopenharmony_ci{
133662306a36Sopenharmony_ci	struct imx355 *imx355 = to_imx355(sd);
133762306a36Sopenharmony_ci	const struct imx355_mode *mode;
133862306a36Sopenharmony_ci	struct v4l2_mbus_framefmt *framefmt;
133962306a36Sopenharmony_ci	s32 vblank_def;
134062306a36Sopenharmony_ci	s32 vblank_min;
134162306a36Sopenharmony_ci	s64 h_blank;
134262306a36Sopenharmony_ci	u64 pixel_rate;
134362306a36Sopenharmony_ci	u32 height;
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	mutex_lock(&imx355->mutex);
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	/*
134862306a36Sopenharmony_ci	 * Only one bayer order is supported.
134962306a36Sopenharmony_ci	 * It depends on the flip settings.
135062306a36Sopenharmony_ci	 */
135162306a36Sopenharmony_ci	fmt->format.code = imx355_get_format_code(imx355);
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci	mode = v4l2_find_nearest_size(supported_modes,
135462306a36Sopenharmony_ci				      ARRAY_SIZE(supported_modes),
135562306a36Sopenharmony_ci				      width, height,
135662306a36Sopenharmony_ci				      fmt->format.width, fmt->format.height);
135762306a36Sopenharmony_ci	imx355_update_pad_format(imx355, mode, fmt);
135862306a36Sopenharmony_ci	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
135962306a36Sopenharmony_ci		framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
136062306a36Sopenharmony_ci		*framefmt = fmt->format;
136162306a36Sopenharmony_ci	} else {
136262306a36Sopenharmony_ci		imx355->cur_mode = mode;
136362306a36Sopenharmony_ci		pixel_rate = imx355->link_def_freq * 2 * 4;
136462306a36Sopenharmony_ci		do_div(pixel_rate, 10);
136562306a36Sopenharmony_ci		__v4l2_ctrl_s_ctrl_int64(imx355->pixel_rate, pixel_rate);
136662306a36Sopenharmony_ci		/* Update limits and set FPS to default */
136762306a36Sopenharmony_ci		height = imx355->cur_mode->height;
136862306a36Sopenharmony_ci		vblank_def = imx355->cur_mode->fll_def - height;
136962306a36Sopenharmony_ci		vblank_min = imx355->cur_mode->fll_min - height;
137062306a36Sopenharmony_ci		height = IMX355_FLL_MAX - height;
137162306a36Sopenharmony_ci		__v4l2_ctrl_modify_range(imx355->vblank, vblank_min, height, 1,
137262306a36Sopenharmony_ci					 vblank_def);
137362306a36Sopenharmony_ci		__v4l2_ctrl_s_ctrl(imx355->vblank, vblank_def);
137462306a36Sopenharmony_ci		h_blank = mode->llp - imx355->cur_mode->width;
137562306a36Sopenharmony_ci		/*
137662306a36Sopenharmony_ci		 * Currently hblank is not changeable.
137762306a36Sopenharmony_ci		 * So FPS control is done only by vblank.
137862306a36Sopenharmony_ci		 */
137962306a36Sopenharmony_ci		__v4l2_ctrl_modify_range(imx355->hblank, h_blank,
138062306a36Sopenharmony_ci					 h_blank, 1, h_blank);
138162306a36Sopenharmony_ci	}
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci	mutex_unlock(&imx355->mutex);
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci	return 0;
138662306a36Sopenharmony_ci}
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci/* Start streaming */
138962306a36Sopenharmony_cistatic int imx355_start_streaming(struct imx355 *imx355)
139062306a36Sopenharmony_ci{
139162306a36Sopenharmony_ci	struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd);
139262306a36Sopenharmony_ci	const struct imx355_reg_list *reg_list;
139362306a36Sopenharmony_ci	int ret;
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	/* Global Setting */
139662306a36Sopenharmony_ci	reg_list = &imx355_global_setting;
139762306a36Sopenharmony_ci	ret = imx355_write_regs(imx355, reg_list->regs, reg_list->num_of_regs);
139862306a36Sopenharmony_ci	if (ret) {
139962306a36Sopenharmony_ci		dev_err(&client->dev, "failed to set global settings");
140062306a36Sopenharmony_ci		return ret;
140162306a36Sopenharmony_ci	}
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci	/* Apply default values of current mode */
140462306a36Sopenharmony_ci	reg_list = &imx355->cur_mode->reg_list;
140562306a36Sopenharmony_ci	ret = imx355_write_regs(imx355, reg_list->regs, reg_list->num_of_regs);
140662306a36Sopenharmony_ci	if (ret) {
140762306a36Sopenharmony_ci		dev_err(&client->dev, "failed to set mode");
140862306a36Sopenharmony_ci		return ret;
140962306a36Sopenharmony_ci	}
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci	/* set digital gain control to all color mode */
141262306a36Sopenharmony_ci	ret = imx355_write_reg(imx355, IMX355_REG_DPGA_USE_GLOBAL_GAIN, 1, 1);
141362306a36Sopenharmony_ci	if (ret)
141462306a36Sopenharmony_ci		return ret;
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci	/* Apply customized values from user */
141762306a36Sopenharmony_ci	ret =  __v4l2_ctrl_handler_setup(imx355->sd.ctrl_handler);
141862306a36Sopenharmony_ci	if (ret)
141962306a36Sopenharmony_ci		return ret;
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci	return imx355_write_reg(imx355, IMX355_REG_MODE_SELECT,
142262306a36Sopenharmony_ci				1, IMX355_MODE_STREAMING);
142362306a36Sopenharmony_ci}
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci/* Stop streaming */
142662306a36Sopenharmony_cistatic int imx355_stop_streaming(struct imx355 *imx355)
142762306a36Sopenharmony_ci{
142862306a36Sopenharmony_ci	return imx355_write_reg(imx355, IMX355_REG_MODE_SELECT,
142962306a36Sopenharmony_ci				1, IMX355_MODE_STANDBY);
143062306a36Sopenharmony_ci}
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_cistatic int imx355_set_stream(struct v4l2_subdev *sd, int enable)
143362306a36Sopenharmony_ci{
143462306a36Sopenharmony_ci	struct imx355 *imx355 = to_imx355(sd);
143562306a36Sopenharmony_ci	struct i2c_client *client = v4l2_get_subdevdata(sd);
143662306a36Sopenharmony_ci	int ret = 0;
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_ci	mutex_lock(&imx355->mutex);
143962306a36Sopenharmony_ci	if (imx355->streaming == enable) {
144062306a36Sopenharmony_ci		mutex_unlock(&imx355->mutex);
144162306a36Sopenharmony_ci		return 0;
144262306a36Sopenharmony_ci	}
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	if (enable) {
144562306a36Sopenharmony_ci		ret = pm_runtime_resume_and_get(&client->dev);
144662306a36Sopenharmony_ci		if (ret < 0)
144762306a36Sopenharmony_ci			goto err_unlock;
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci		/*
145062306a36Sopenharmony_ci		 * Apply default & customized values
145162306a36Sopenharmony_ci		 * and then start streaming.
145262306a36Sopenharmony_ci		 */
145362306a36Sopenharmony_ci		ret = imx355_start_streaming(imx355);
145462306a36Sopenharmony_ci		if (ret)
145562306a36Sopenharmony_ci			goto err_rpm_put;
145662306a36Sopenharmony_ci	} else {
145762306a36Sopenharmony_ci		imx355_stop_streaming(imx355);
145862306a36Sopenharmony_ci		pm_runtime_put(&client->dev);
145962306a36Sopenharmony_ci	}
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci	imx355->streaming = enable;
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	/* vflip and hflip cannot change during streaming */
146462306a36Sopenharmony_ci	__v4l2_ctrl_grab(imx355->vflip, enable);
146562306a36Sopenharmony_ci	__v4l2_ctrl_grab(imx355->hflip, enable);
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci	mutex_unlock(&imx355->mutex);
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci	return ret;
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_cierr_rpm_put:
147262306a36Sopenharmony_ci	pm_runtime_put(&client->dev);
147362306a36Sopenharmony_cierr_unlock:
147462306a36Sopenharmony_ci	mutex_unlock(&imx355->mutex);
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci	return ret;
147762306a36Sopenharmony_ci}
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_cistatic int __maybe_unused imx355_suspend(struct device *dev)
148062306a36Sopenharmony_ci{
148162306a36Sopenharmony_ci	struct v4l2_subdev *sd = dev_get_drvdata(dev);
148262306a36Sopenharmony_ci	struct imx355 *imx355 = to_imx355(sd);
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci	if (imx355->streaming)
148562306a36Sopenharmony_ci		imx355_stop_streaming(imx355);
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci	return 0;
148862306a36Sopenharmony_ci}
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_cistatic int __maybe_unused imx355_resume(struct device *dev)
149162306a36Sopenharmony_ci{
149262306a36Sopenharmony_ci	struct v4l2_subdev *sd = dev_get_drvdata(dev);
149362306a36Sopenharmony_ci	struct imx355 *imx355 = to_imx355(sd);
149462306a36Sopenharmony_ci	int ret;
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci	if (imx355->streaming) {
149762306a36Sopenharmony_ci		ret = imx355_start_streaming(imx355);
149862306a36Sopenharmony_ci		if (ret)
149962306a36Sopenharmony_ci			goto error;
150062306a36Sopenharmony_ci	}
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci	return 0;
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_cierror:
150562306a36Sopenharmony_ci	imx355_stop_streaming(imx355);
150662306a36Sopenharmony_ci	imx355->streaming = 0;
150762306a36Sopenharmony_ci	return ret;
150862306a36Sopenharmony_ci}
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_ci/* Verify chip ID */
151162306a36Sopenharmony_cistatic int imx355_identify_module(struct imx355 *imx355)
151262306a36Sopenharmony_ci{
151362306a36Sopenharmony_ci	struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd);
151462306a36Sopenharmony_ci	int ret;
151562306a36Sopenharmony_ci	u32 val;
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	ret = imx355_read_reg(imx355, IMX355_REG_CHIP_ID, 2, &val);
151862306a36Sopenharmony_ci	if (ret)
151962306a36Sopenharmony_ci		return ret;
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	if (val != IMX355_CHIP_ID) {
152262306a36Sopenharmony_ci		dev_err(&client->dev, "chip id mismatch: %x!=%x",
152362306a36Sopenharmony_ci			IMX355_CHIP_ID, val);
152462306a36Sopenharmony_ci		return -EIO;
152562306a36Sopenharmony_ci	}
152662306a36Sopenharmony_ci	return 0;
152762306a36Sopenharmony_ci}
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_cistatic const struct v4l2_subdev_core_ops imx355_subdev_core_ops = {
153062306a36Sopenharmony_ci	.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
153162306a36Sopenharmony_ci	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
153262306a36Sopenharmony_ci};
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_cistatic const struct v4l2_subdev_video_ops imx355_video_ops = {
153562306a36Sopenharmony_ci	.s_stream = imx355_set_stream,
153662306a36Sopenharmony_ci};
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_cistatic const struct v4l2_subdev_pad_ops imx355_pad_ops = {
153962306a36Sopenharmony_ci	.enum_mbus_code = imx355_enum_mbus_code,
154062306a36Sopenharmony_ci	.get_fmt = imx355_get_pad_format,
154162306a36Sopenharmony_ci	.set_fmt = imx355_set_pad_format,
154262306a36Sopenharmony_ci	.enum_frame_size = imx355_enum_frame_size,
154362306a36Sopenharmony_ci};
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_cistatic const struct v4l2_subdev_ops imx355_subdev_ops = {
154662306a36Sopenharmony_ci	.core = &imx355_subdev_core_ops,
154762306a36Sopenharmony_ci	.video = &imx355_video_ops,
154862306a36Sopenharmony_ci	.pad = &imx355_pad_ops,
154962306a36Sopenharmony_ci};
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_cistatic const struct media_entity_operations imx355_subdev_entity_ops = {
155262306a36Sopenharmony_ci	.link_validate = v4l2_subdev_link_validate,
155362306a36Sopenharmony_ci};
155462306a36Sopenharmony_ci
155562306a36Sopenharmony_cistatic const struct v4l2_subdev_internal_ops imx355_internal_ops = {
155662306a36Sopenharmony_ci	.open = imx355_open,
155762306a36Sopenharmony_ci};
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ci/* Initialize control handlers */
156062306a36Sopenharmony_cistatic int imx355_init_controls(struct imx355 *imx355)
156162306a36Sopenharmony_ci{
156262306a36Sopenharmony_ci	struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd);
156362306a36Sopenharmony_ci	struct v4l2_ctrl_handler *ctrl_hdlr;
156462306a36Sopenharmony_ci	s64 exposure_max;
156562306a36Sopenharmony_ci	s64 vblank_def;
156662306a36Sopenharmony_ci	s64 vblank_min;
156762306a36Sopenharmony_ci	s64 hblank;
156862306a36Sopenharmony_ci	u64 pixel_rate;
156962306a36Sopenharmony_ci	const struct imx355_mode *mode;
157062306a36Sopenharmony_ci	u32 max;
157162306a36Sopenharmony_ci	int ret;
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci	ctrl_hdlr = &imx355->ctrl_handler;
157462306a36Sopenharmony_ci	ret = v4l2_ctrl_handler_init(ctrl_hdlr, 10);
157562306a36Sopenharmony_ci	if (ret)
157662306a36Sopenharmony_ci		return ret;
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci	ctrl_hdlr->lock = &imx355->mutex;
157962306a36Sopenharmony_ci	max = ARRAY_SIZE(link_freq_menu_items) - 1;
158062306a36Sopenharmony_ci	imx355->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx355_ctrl_ops,
158162306a36Sopenharmony_ci						   V4L2_CID_LINK_FREQ, max, 0,
158262306a36Sopenharmony_ci						   link_freq_menu_items);
158362306a36Sopenharmony_ci	if (imx355->link_freq)
158462306a36Sopenharmony_ci		imx355->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci	/* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */
158762306a36Sopenharmony_ci	pixel_rate = imx355->link_def_freq * 2 * 4;
158862306a36Sopenharmony_ci	do_div(pixel_rate, 10);
158962306a36Sopenharmony_ci	/* By default, PIXEL_RATE is read only */
159062306a36Sopenharmony_ci	imx355->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops,
159162306a36Sopenharmony_ci					       V4L2_CID_PIXEL_RATE, pixel_rate,
159262306a36Sopenharmony_ci					       pixel_rate, 1, pixel_rate);
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci	/* Initialize vblank/hblank/exposure parameters based on current mode */
159562306a36Sopenharmony_ci	mode = imx355->cur_mode;
159662306a36Sopenharmony_ci	vblank_def = mode->fll_def - mode->height;
159762306a36Sopenharmony_ci	vblank_min = mode->fll_min - mode->height;
159862306a36Sopenharmony_ci	imx355->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops,
159962306a36Sopenharmony_ci					   V4L2_CID_VBLANK, vblank_min,
160062306a36Sopenharmony_ci					   IMX355_FLL_MAX - mode->height,
160162306a36Sopenharmony_ci					   1, vblank_def);
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci	hblank = mode->llp - mode->width;
160462306a36Sopenharmony_ci	imx355->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops,
160562306a36Sopenharmony_ci					   V4L2_CID_HBLANK, hblank, hblank,
160662306a36Sopenharmony_ci					   1, hblank);
160762306a36Sopenharmony_ci	if (imx355->hblank)
160862306a36Sopenharmony_ci		imx355->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
160962306a36Sopenharmony_ci
161062306a36Sopenharmony_ci	/* fll >= exposure time + adjust parameter (default value is 10) */
161162306a36Sopenharmony_ci	exposure_max = mode->fll_def - 10;
161262306a36Sopenharmony_ci	imx355->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops,
161362306a36Sopenharmony_ci					     V4L2_CID_EXPOSURE,
161462306a36Sopenharmony_ci					     IMX355_EXPOSURE_MIN, exposure_max,
161562306a36Sopenharmony_ci					     IMX355_EXPOSURE_STEP,
161662306a36Sopenharmony_ci					     IMX355_EXPOSURE_DEFAULT);
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_ci	imx355->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops,
161962306a36Sopenharmony_ci					  V4L2_CID_HFLIP, 0, 1, 1, 0);
162062306a36Sopenharmony_ci	if (imx355->hflip)
162162306a36Sopenharmony_ci		imx355->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
162262306a36Sopenharmony_ci	imx355->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops,
162362306a36Sopenharmony_ci					  V4L2_CID_VFLIP, 0, 1, 1, 0);
162462306a36Sopenharmony_ci	if (imx355->vflip)
162562306a36Sopenharmony_ci		imx355->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ci	v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
162862306a36Sopenharmony_ci			  IMX355_ANA_GAIN_MIN, IMX355_ANA_GAIN_MAX,
162962306a36Sopenharmony_ci			  IMX355_ANA_GAIN_STEP, IMX355_ANA_GAIN_DEFAULT);
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci	/* Digital gain */
163262306a36Sopenharmony_ci	v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
163362306a36Sopenharmony_ci			  IMX355_DGTL_GAIN_MIN, IMX355_DGTL_GAIN_MAX,
163462306a36Sopenharmony_ci			  IMX355_DGTL_GAIN_STEP, IMX355_DGTL_GAIN_DEFAULT);
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_ci	v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx355_ctrl_ops,
163762306a36Sopenharmony_ci				     V4L2_CID_TEST_PATTERN,
163862306a36Sopenharmony_ci				     ARRAY_SIZE(imx355_test_pattern_menu) - 1,
163962306a36Sopenharmony_ci				     0, 0, imx355_test_pattern_menu);
164062306a36Sopenharmony_ci	if (ctrl_hdlr->error) {
164162306a36Sopenharmony_ci		ret = ctrl_hdlr->error;
164262306a36Sopenharmony_ci		dev_err(&client->dev, "control init failed: %d", ret);
164362306a36Sopenharmony_ci		goto error;
164462306a36Sopenharmony_ci	}
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_ci	imx355->sd.ctrl_handler = ctrl_hdlr;
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci	return 0;
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_cierror:
165162306a36Sopenharmony_ci	v4l2_ctrl_handler_free(ctrl_hdlr);
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_ci	return ret;
165462306a36Sopenharmony_ci}
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_cistatic struct imx355_hwcfg *imx355_get_hwcfg(struct device *dev)
165762306a36Sopenharmony_ci{
165862306a36Sopenharmony_ci	struct imx355_hwcfg *cfg;
165962306a36Sopenharmony_ci	struct v4l2_fwnode_endpoint bus_cfg = {
166062306a36Sopenharmony_ci		.bus_type = V4L2_MBUS_CSI2_DPHY
166162306a36Sopenharmony_ci	};
166262306a36Sopenharmony_ci	struct fwnode_handle *ep;
166362306a36Sopenharmony_ci	struct fwnode_handle *fwnode = dev_fwnode(dev);
166462306a36Sopenharmony_ci	unsigned int i;
166562306a36Sopenharmony_ci	int ret;
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ci	if (!fwnode)
166862306a36Sopenharmony_ci		return NULL;
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_ci	ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
167162306a36Sopenharmony_ci	if (!ep)
167262306a36Sopenharmony_ci		return NULL;
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_ci	ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
167562306a36Sopenharmony_ci	if (ret)
167662306a36Sopenharmony_ci		goto out_err;
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci	cfg = devm_kzalloc(dev, sizeof(*cfg), GFP_KERNEL);
167962306a36Sopenharmony_ci	if (!cfg)
168062306a36Sopenharmony_ci		goto out_err;
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_ci	ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency",
168362306a36Sopenharmony_ci				       &cfg->ext_clk);
168462306a36Sopenharmony_ci	if (ret) {
168562306a36Sopenharmony_ci		dev_err(dev, "can't get clock frequency");
168662306a36Sopenharmony_ci		goto out_err;
168762306a36Sopenharmony_ci	}
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci	dev_dbg(dev, "ext clk: %d", cfg->ext_clk);
169062306a36Sopenharmony_ci	if (cfg->ext_clk != IMX355_EXT_CLK) {
169162306a36Sopenharmony_ci		dev_err(dev, "external clock %d is not supported",
169262306a36Sopenharmony_ci			cfg->ext_clk);
169362306a36Sopenharmony_ci		goto out_err;
169462306a36Sopenharmony_ci	}
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ci	dev_dbg(dev, "num of link freqs: %d", bus_cfg.nr_of_link_frequencies);
169762306a36Sopenharmony_ci	if (!bus_cfg.nr_of_link_frequencies) {
169862306a36Sopenharmony_ci		dev_warn(dev, "no link frequencies defined");
169962306a36Sopenharmony_ci		goto out_err;
170062306a36Sopenharmony_ci	}
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_ci	cfg->nr_of_link_freqs = bus_cfg.nr_of_link_frequencies;
170362306a36Sopenharmony_ci	cfg->link_freqs = devm_kcalloc(dev,
170462306a36Sopenharmony_ci				       bus_cfg.nr_of_link_frequencies + 1,
170562306a36Sopenharmony_ci				       sizeof(*cfg->link_freqs), GFP_KERNEL);
170662306a36Sopenharmony_ci	if (!cfg->link_freqs)
170762306a36Sopenharmony_ci		goto out_err;
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_ci	for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) {
171062306a36Sopenharmony_ci		cfg->link_freqs[i] = bus_cfg.link_frequencies[i];
171162306a36Sopenharmony_ci		dev_dbg(dev, "link_freq[%d] = %lld", i, cfg->link_freqs[i]);
171262306a36Sopenharmony_ci	}
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_ci	v4l2_fwnode_endpoint_free(&bus_cfg);
171562306a36Sopenharmony_ci	fwnode_handle_put(ep);
171662306a36Sopenharmony_ci	return cfg;
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_ciout_err:
171962306a36Sopenharmony_ci	v4l2_fwnode_endpoint_free(&bus_cfg);
172062306a36Sopenharmony_ci	fwnode_handle_put(ep);
172162306a36Sopenharmony_ci	return NULL;
172262306a36Sopenharmony_ci}
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_cistatic int imx355_probe(struct i2c_client *client)
172562306a36Sopenharmony_ci{
172662306a36Sopenharmony_ci	struct imx355 *imx355;
172762306a36Sopenharmony_ci	int ret;
172862306a36Sopenharmony_ci	u32 i;
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_ci	imx355 = devm_kzalloc(&client->dev, sizeof(*imx355), GFP_KERNEL);
173162306a36Sopenharmony_ci	if (!imx355)
173262306a36Sopenharmony_ci		return -ENOMEM;
173362306a36Sopenharmony_ci
173462306a36Sopenharmony_ci	mutex_init(&imx355->mutex);
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_ci	/* Initialize subdev */
173762306a36Sopenharmony_ci	v4l2_i2c_subdev_init(&imx355->sd, client, &imx355_subdev_ops);
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ci	/* Check module identity */
174062306a36Sopenharmony_ci	ret = imx355_identify_module(imx355);
174162306a36Sopenharmony_ci	if (ret) {
174262306a36Sopenharmony_ci		dev_err(&client->dev, "failed to find sensor: %d", ret);
174362306a36Sopenharmony_ci		goto error_probe;
174462306a36Sopenharmony_ci	}
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_ci	imx355->hwcfg = imx355_get_hwcfg(&client->dev);
174762306a36Sopenharmony_ci	if (!imx355->hwcfg) {
174862306a36Sopenharmony_ci		dev_err(&client->dev, "failed to get hwcfg");
174962306a36Sopenharmony_ci		ret = -ENODEV;
175062306a36Sopenharmony_ci		goto error_probe;
175162306a36Sopenharmony_ci	}
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_ci	imx355->link_def_freq = link_freq_menu_items[IMX355_LINK_FREQ_INDEX];
175462306a36Sopenharmony_ci	for (i = 0; i < imx355->hwcfg->nr_of_link_freqs; i++) {
175562306a36Sopenharmony_ci		if (imx355->hwcfg->link_freqs[i] == imx355->link_def_freq) {
175662306a36Sopenharmony_ci			dev_dbg(&client->dev, "link freq index %d matched", i);
175762306a36Sopenharmony_ci			break;
175862306a36Sopenharmony_ci		}
175962306a36Sopenharmony_ci	}
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_ci	if (i == imx355->hwcfg->nr_of_link_freqs) {
176262306a36Sopenharmony_ci		dev_err(&client->dev, "no link frequency supported");
176362306a36Sopenharmony_ci		ret = -EINVAL;
176462306a36Sopenharmony_ci		goto error_probe;
176562306a36Sopenharmony_ci	}
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_ci	/* Set default mode to max resolution */
176862306a36Sopenharmony_ci	imx355->cur_mode = &supported_modes[0];
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_ci	ret = imx355_init_controls(imx355);
177162306a36Sopenharmony_ci	if (ret) {
177262306a36Sopenharmony_ci		dev_err(&client->dev, "failed to init controls: %d", ret);
177362306a36Sopenharmony_ci		goto error_probe;
177462306a36Sopenharmony_ci	}
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_ci	/* Initialize subdev */
177762306a36Sopenharmony_ci	imx355->sd.internal_ops = &imx355_internal_ops;
177862306a36Sopenharmony_ci	imx355->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
177962306a36Sopenharmony_ci		V4L2_SUBDEV_FL_HAS_EVENTS;
178062306a36Sopenharmony_ci	imx355->sd.entity.ops = &imx355_subdev_entity_ops;
178162306a36Sopenharmony_ci	imx355->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ci	/* Initialize source pad */
178462306a36Sopenharmony_ci	imx355->pad.flags = MEDIA_PAD_FL_SOURCE;
178562306a36Sopenharmony_ci	ret = media_entity_pads_init(&imx355->sd.entity, 1, &imx355->pad);
178662306a36Sopenharmony_ci	if (ret) {
178762306a36Sopenharmony_ci		dev_err(&client->dev, "failed to init entity pads: %d", ret);
178862306a36Sopenharmony_ci		goto error_handler_free;
178962306a36Sopenharmony_ci	}
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_ci	/*
179262306a36Sopenharmony_ci	 * Device is already turned on by i2c-core with ACPI domain PM.
179362306a36Sopenharmony_ci	 * Enable runtime PM and turn off the device.
179462306a36Sopenharmony_ci	 */
179562306a36Sopenharmony_ci	pm_runtime_set_active(&client->dev);
179662306a36Sopenharmony_ci	pm_runtime_enable(&client->dev);
179762306a36Sopenharmony_ci	pm_runtime_idle(&client->dev);
179862306a36Sopenharmony_ci
179962306a36Sopenharmony_ci	ret = v4l2_async_register_subdev_sensor(&imx355->sd);
180062306a36Sopenharmony_ci	if (ret < 0)
180162306a36Sopenharmony_ci		goto error_media_entity_runtime_pm;
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ci	return 0;
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_cierror_media_entity_runtime_pm:
180662306a36Sopenharmony_ci	pm_runtime_disable(&client->dev);
180762306a36Sopenharmony_ci	pm_runtime_set_suspended(&client->dev);
180862306a36Sopenharmony_ci	media_entity_cleanup(&imx355->sd.entity);
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_cierror_handler_free:
181162306a36Sopenharmony_ci	v4l2_ctrl_handler_free(imx355->sd.ctrl_handler);
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_cierror_probe:
181462306a36Sopenharmony_ci	mutex_destroy(&imx355->mutex);
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_ci	return ret;
181762306a36Sopenharmony_ci}
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_cistatic void imx355_remove(struct i2c_client *client)
182062306a36Sopenharmony_ci{
182162306a36Sopenharmony_ci	struct v4l2_subdev *sd = i2c_get_clientdata(client);
182262306a36Sopenharmony_ci	struct imx355 *imx355 = to_imx355(sd);
182362306a36Sopenharmony_ci
182462306a36Sopenharmony_ci	v4l2_async_unregister_subdev(sd);
182562306a36Sopenharmony_ci	media_entity_cleanup(&sd->entity);
182662306a36Sopenharmony_ci	v4l2_ctrl_handler_free(sd->ctrl_handler);
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_ci	pm_runtime_disable(&client->dev);
182962306a36Sopenharmony_ci	pm_runtime_set_suspended(&client->dev);
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_ci	mutex_destroy(&imx355->mutex);
183262306a36Sopenharmony_ci}
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_cistatic const struct dev_pm_ops imx355_pm_ops = {
183562306a36Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(imx355_suspend, imx355_resume)
183662306a36Sopenharmony_ci};
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_cistatic const struct acpi_device_id imx355_acpi_ids[] __maybe_unused = {
183962306a36Sopenharmony_ci	{ "SONY355A" },
184062306a36Sopenharmony_ci	{ /* sentinel */ }
184162306a36Sopenharmony_ci};
184262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, imx355_acpi_ids);
184362306a36Sopenharmony_ci
184462306a36Sopenharmony_cistatic struct i2c_driver imx355_i2c_driver = {
184562306a36Sopenharmony_ci	.driver = {
184662306a36Sopenharmony_ci		.name = "imx355",
184762306a36Sopenharmony_ci		.pm = &imx355_pm_ops,
184862306a36Sopenharmony_ci		.acpi_match_table = ACPI_PTR(imx355_acpi_ids),
184962306a36Sopenharmony_ci	},
185062306a36Sopenharmony_ci	.probe = imx355_probe,
185162306a36Sopenharmony_ci	.remove = imx355_remove,
185262306a36Sopenharmony_ci};
185362306a36Sopenharmony_cimodule_i2c_driver(imx355_i2c_driver);
185462306a36Sopenharmony_ci
185562306a36Sopenharmony_ciMODULE_AUTHOR("Qiu, Tianshu <tian.shu.qiu@intel.com>");
185662306a36Sopenharmony_ciMODULE_AUTHOR("Rapolu, Chiranjeevi");
185762306a36Sopenharmony_ciMODULE_AUTHOR("Bingbu Cao <bingbu.cao@intel.com>");
185862306a36Sopenharmony_ciMODULE_AUTHOR("Yang, Hyungwoo");
185962306a36Sopenharmony_ciMODULE_DESCRIPTION("Sony imx355 sensor driver");
186062306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
1861