1df0b5c4aSBingbu Cao // SPDX-License-Identifier: GPL-2.0 2df0b5c4aSBingbu Cao // Copyright (C) 2018 Intel Corporation 3df0b5c4aSBingbu Cao 4df0b5c4aSBingbu Cao #include <asm/unaligned.h> 5df0b5c4aSBingbu Cao #include <linux/acpi.h> 6df0b5c4aSBingbu Cao #include <linux/i2c.h> 7df0b5c4aSBingbu Cao #include <linux/module.h> 8df0b5c4aSBingbu Cao #include <linux/pm_runtime.h> 9df0b5c4aSBingbu Cao #include <media/v4l2-ctrls.h> 10df0b5c4aSBingbu Cao #include <media/v4l2-device.h> 11df0b5c4aSBingbu Cao #include <media/v4l2-event.h> 12df0b5c4aSBingbu Cao #include <media/v4l2-fwnode.h> 13df0b5c4aSBingbu Cao 14df0b5c4aSBingbu Cao #define IMX355_REG_MODE_SELECT 0x0100 15df0b5c4aSBingbu Cao #define IMX355_MODE_STANDBY 0x00 16df0b5c4aSBingbu Cao #define IMX355_MODE_STREAMING 0x01 17df0b5c4aSBingbu Cao 18df0b5c4aSBingbu Cao /* Chip ID */ 19df0b5c4aSBingbu Cao #define IMX355_REG_CHIP_ID 0x0016 20df0b5c4aSBingbu Cao #define IMX355_CHIP_ID 0x0355 21df0b5c4aSBingbu Cao 22df0b5c4aSBingbu Cao /* V_TIMING internal */ 23df0b5c4aSBingbu Cao #define IMX355_REG_FLL 0x0340 24df0b5c4aSBingbu Cao #define IMX355_FLL_MAX 0xffff 25df0b5c4aSBingbu Cao 26df0b5c4aSBingbu Cao /* Exposure control */ 27df0b5c4aSBingbu Cao #define IMX355_REG_EXPOSURE 0x0202 28df0b5c4aSBingbu Cao #define IMX355_EXPOSURE_MIN 1 29df0b5c4aSBingbu Cao #define IMX355_EXPOSURE_STEP 1 30df0b5c4aSBingbu Cao #define IMX355_EXPOSURE_DEFAULT 0x0282 31df0b5c4aSBingbu Cao 32df0b5c4aSBingbu Cao /* Analog gain control */ 33df0b5c4aSBingbu Cao #define IMX355_REG_ANALOG_GAIN 0x0204 34df0b5c4aSBingbu Cao #define IMX355_ANA_GAIN_MIN 0 35df0b5c4aSBingbu Cao #define IMX355_ANA_GAIN_MAX 960 36df0b5c4aSBingbu Cao #define IMX355_ANA_GAIN_STEP 1 37df0b5c4aSBingbu Cao #define IMX355_ANA_GAIN_DEFAULT 0 38df0b5c4aSBingbu Cao 39df0b5c4aSBingbu Cao /* Digital gain control */ 40df0b5c4aSBingbu Cao #define IMX355_REG_DPGA_USE_GLOBAL_GAIN 0x3070 41df0b5c4aSBingbu Cao #define IMX355_REG_DIG_GAIN_GLOBAL 0x020e 42df0b5c4aSBingbu Cao #define IMX355_DGTL_GAIN_MIN 256 43df0b5c4aSBingbu Cao #define IMX355_DGTL_GAIN_MAX 4095 44df0b5c4aSBingbu Cao #define IMX355_DGTL_GAIN_STEP 1 45df0b5c4aSBingbu Cao #define IMX355_DGTL_GAIN_DEFAULT 256 46df0b5c4aSBingbu Cao 47df0b5c4aSBingbu Cao /* Test Pattern Control */ 48df0b5c4aSBingbu Cao #define IMX355_REG_TEST_PATTERN 0x0600 49df0b5c4aSBingbu Cao #define IMX355_TEST_PATTERN_DISABLED 0 50df0b5c4aSBingbu Cao #define IMX355_TEST_PATTERN_SOLID_COLOR 1 51df0b5c4aSBingbu Cao #define IMX355_TEST_PATTERN_COLOR_BARS 2 52df0b5c4aSBingbu Cao #define IMX355_TEST_PATTERN_GRAY_COLOR_BARS 3 53df0b5c4aSBingbu Cao #define IMX355_TEST_PATTERN_PN9 4 54df0b5c4aSBingbu Cao 55df0b5c4aSBingbu Cao /* Flip Control */ 56df0b5c4aSBingbu Cao #define IMX355_REG_ORIENTATION 0x0101 57df0b5c4aSBingbu Cao 58df0b5c4aSBingbu Cao /* default link frequency and external clock */ 59df0b5c4aSBingbu Cao #define IMX355_LINK_FREQ_DEFAULT 360000000 60df0b5c4aSBingbu Cao #define IMX355_EXT_CLK 19200000 61df0b5c4aSBingbu Cao #define IMX355_LINK_FREQ_INDEX 0 62df0b5c4aSBingbu Cao 63df0b5c4aSBingbu Cao struct imx355_reg { 64df0b5c4aSBingbu Cao u16 address; 65df0b5c4aSBingbu Cao u8 val; 66df0b5c4aSBingbu Cao }; 67df0b5c4aSBingbu Cao 68df0b5c4aSBingbu Cao struct imx355_reg_list { 69df0b5c4aSBingbu Cao u32 num_of_regs; 70df0b5c4aSBingbu Cao const struct imx355_reg *regs; 71df0b5c4aSBingbu Cao }; 72df0b5c4aSBingbu Cao 73df0b5c4aSBingbu Cao /* Mode : resolution and related config&values */ 74df0b5c4aSBingbu Cao struct imx355_mode { 75df0b5c4aSBingbu Cao /* Frame width */ 76df0b5c4aSBingbu Cao u32 width; 77df0b5c4aSBingbu Cao /* Frame height */ 78df0b5c4aSBingbu Cao u32 height; 79df0b5c4aSBingbu Cao 80df0b5c4aSBingbu Cao /* V-timing */ 81df0b5c4aSBingbu Cao u32 fll_def; 82df0b5c4aSBingbu Cao u32 fll_min; 83df0b5c4aSBingbu Cao 84df0b5c4aSBingbu Cao /* H-timing */ 85df0b5c4aSBingbu Cao u32 llp; 86df0b5c4aSBingbu Cao 87df0b5c4aSBingbu Cao /* index of link frequency */ 88df0b5c4aSBingbu Cao u32 link_freq_index; 89df0b5c4aSBingbu Cao 90df0b5c4aSBingbu Cao /* Default register values */ 91df0b5c4aSBingbu Cao struct imx355_reg_list reg_list; 92df0b5c4aSBingbu Cao }; 93df0b5c4aSBingbu Cao 94df0b5c4aSBingbu Cao struct imx355_hwcfg { 95df0b5c4aSBingbu Cao u32 ext_clk; /* sensor external clk */ 96df0b5c4aSBingbu Cao s64 *link_freqs; /* CSI-2 link frequencies */ 97df0b5c4aSBingbu Cao unsigned int nr_of_link_freqs; 98df0b5c4aSBingbu Cao }; 99df0b5c4aSBingbu Cao 100df0b5c4aSBingbu Cao struct imx355 { 101df0b5c4aSBingbu Cao struct v4l2_subdev sd; 102df0b5c4aSBingbu Cao struct media_pad pad; 103df0b5c4aSBingbu Cao 104df0b5c4aSBingbu Cao struct v4l2_ctrl_handler ctrl_handler; 105df0b5c4aSBingbu Cao /* V4L2 Controls */ 106df0b5c4aSBingbu Cao struct v4l2_ctrl *link_freq; 107df0b5c4aSBingbu Cao struct v4l2_ctrl *pixel_rate; 108df0b5c4aSBingbu Cao struct v4l2_ctrl *vblank; 109df0b5c4aSBingbu Cao struct v4l2_ctrl *hblank; 110df0b5c4aSBingbu Cao struct v4l2_ctrl *exposure; 111df0b5c4aSBingbu Cao struct v4l2_ctrl *vflip; 112df0b5c4aSBingbu Cao struct v4l2_ctrl *hflip; 113df0b5c4aSBingbu Cao 114df0b5c4aSBingbu Cao /* Current mode */ 115df0b5c4aSBingbu Cao const struct imx355_mode *cur_mode; 116df0b5c4aSBingbu Cao 117df0b5c4aSBingbu Cao struct imx355_hwcfg *hwcfg; 118df0b5c4aSBingbu Cao s64 link_def_freq; /* CSI-2 link default frequency */ 119df0b5c4aSBingbu Cao 120df0b5c4aSBingbu Cao /* 121df0b5c4aSBingbu Cao * Mutex for serialized access: 122df0b5c4aSBingbu Cao * Protect sensor set pad format and start/stop streaming safely. 123df0b5c4aSBingbu Cao * Protect access to sensor v4l2 controls. 124df0b5c4aSBingbu Cao */ 125df0b5c4aSBingbu Cao struct mutex mutex; 126df0b5c4aSBingbu Cao 127df0b5c4aSBingbu Cao /* Streaming on/off */ 128df0b5c4aSBingbu Cao bool streaming; 129df0b5c4aSBingbu Cao }; 130df0b5c4aSBingbu Cao 131df0b5c4aSBingbu Cao static const struct imx355_reg imx355_global_regs[] = { 132df0b5c4aSBingbu Cao { 0x0136, 0x13 }, 133df0b5c4aSBingbu Cao { 0x0137, 0x33 }, 134df0b5c4aSBingbu Cao { 0x304e, 0x03 }, 135df0b5c4aSBingbu Cao { 0x4348, 0x16 }, 136df0b5c4aSBingbu Cao { 0x4350, 0x19 }, 137df0b5c4aSBingbu Cao { 0x4408, 0x0a }, 138df0b5c4aSBingbu Cao { 0x440c, 0x0b }, 139df0b5c4aSBingbu Cao { 0x4411, 0x5f }, 140df0b5c4aSBingbu Cao { 0x4412, 0x2c }, 141df0b5c4aSBingbu Cao { 0x4623, 0x00 }, 142df0b5c4aSBingbu Cao { 0x462c, 0x0f }, 143df0b5c4aSBingbu Cao { 0x462d, 0x00 }, 144df0b5c4aSBingbu Cao { 0x462e, 0x00 }, 145df0b5c4aSBingbu Cao { 0x4684, 0x54 }, 146df0b5c4aSBingbu Cao { 0x480a, 0x07 }, 147df0b5c4aSBingbu Cao { 0x4908, 0x07 }, 148df0b5c4aSBingbu Cao { 0x4909, 0x07 }, 149df0b5c4aSBingbu Cao { 0x490d, 0x0a }, 150df0b5c4aSBingbu Cao { 0x491e, 0x0f }, 151df0b5c4aSBingbu Cao { 0x4921, 0x06 }, 152df0b5c4aSBingbu Cao { 0x4923, 0x28 }, 153df0b5c4aSBingbu Cao { 0x4924, 0x28 }, 154df0b5c4aSBingbu Cao { 0x4925, 0x29 }, 155df0b5c4aSBingbu Cao { 0x4926, 0x29 }, 156df0b5c4aSBingbu Cao { 0x4927, 0x1f }, 157df0b5c4aSBingbu Cao { 0x4928, 0x20 }, 158df0b5c4aSBingbu Cao { 0x4929, 0x20 }, 159df0b5c4aSBingbu Cao { 0x492a, 0x20 }, 160df0b5c4aSBingbu Cao { 0x492c, 0x05 }, 161df0b5c4aSBingbu Cao { 0x492d, 0x06 }, 162df0b5c4aSBingbu Cao { 0x492e, 0x06 }, 163df0b5c4aSBingbu Cao { 0x492f, 0x06 }, 164df0b5c4aSBingbu Cao { 0x4930, 0x03 }, 165df0b5c4aSBingbu Cao { 0x4931, 0x04 }, 166df0b5c4aSBingbu Cao { 0x4932, 0x04 }, 167df0b5c4aSBingbu Cao { 0x4933, 0x05 }, 168df0b5c4aSBingbu Cao { 0x595e, 0x01 }, 169df0b5c4aSBingbu Cao { 0x5963, 0x01 }, 170df0b5c4aSBingbu Cao { 0x3030, 0x01 }, 171df0b5c4aSBingbu Cao { 0x3031, 0x01 }, 172df0b5c4aSBingbu Cao { 0x3045, 0x01 }, 173df0b5c4aSBingbu Cao { 0x4010, 0x00 }, 174df0b5c4aSBingbu Cao { 0x4011, 0x00 }, 175df0b5c4aSBingbu Cao { 0x4012, 0x00 }, 176df0b5c4aSBingbu Cao { 0x4013, 0x01 }, 177df0b5c4aSBingbu Cao { 0x68a8, 0xfe }, 178df0b5c4aSBingbu Cao { 0x68a9, 0xff }, 179df0b5c4aSBingbu Cao { 0x6888, 0x00 }, 180df0b5c4aSBingbu Cao { 0x6889, 0x00 }, 181df0b5c4aSBingbu Cao { 0x68b0, 0x00 }, 182df0b5c4aSBingbu Cao { 0x3058, 0x00 }, 183df0b5c4aSBingbu Cao { 0x305a, 0x00 }, 184df0b5c4aSBingbu Cao }; 185df0b5c4aSBingbu Cao 186df0b5c4aSBingbu Cao static const struct imx355_reg_list imx355_global_setting = { 187df0b5c4aSBingbu Cao .num_of_regs = ARRAY_SIZE(imx355_global_regs), 188df0b5c4aSBingbu Cao .regs = imx355_global_regs, 189df0b5c4aSBingbu Cao }; 190df0b5c4aSBingbu Cao 191df0b5c4aSBingbu Cao static const struct imx355_reg mode_3268x2448_regs[] = { 192df0b5c4aSBingbu Cao { 0x0112, 0x0a }, 193df0b5c4aSBingbu Cao { 0x0113, 0x0a }, 194df0b5c4aSBingbu Cao { 0x0114, 0x03 }, 195df0b5c4aSBingbu Cao { 0x0342, 0x0e }, 196df0b5c4aSBingbu Cao { 0x0343, 0x58 }, 197df0b5c4aSBingbu Cao { 0x0340, 0x0a }, 198df0b5c4aSBingbu Cao { 0x0341, 0x37 }, 199df0b5c4aSBingbu Cao { 0x0344, 0x00 }, 200df0b5c4aSBingbu Cao { 0x0345, 0x08 }, 201df0b5c4aSBingbu Cao { 0x0346, 0x00 }, 202df0b5c4aSBingbu Cao { 0x0347, 0x08 }, 203df0b5c4aSBingbu Cao { 0x0348, 0x0c }, 204df0b5c4aSBingbu Cao { 0x0349, 0xcb }, 205df0b5c4aSBingbu Cao { 0x034a, 0x09 }, 206df0b5c4aSBingbu Cao { 0x034b, 0x97 }, 207df0b5c4aSBingbu Cao { 0x0220, 0x00 }, 208df0b5c4aSBingbu Cao { 0x0222, 0x01 }, 209df0b5c4aSBingbu Cao { 0x0900, 0x00 }, 210df0b5c4aSBingbu Cao { 0x0901, 0x11 }, 211df0b5c4aSBingbu Cao { 0x0902, 0x00 }, 212df0b5c4aSBingbu Cao { 0x034c, 0x0c }, 213df0b5c4aSBingbu Cao { 0x034d, 0xc4 }, 214df0b5c4aSBingbu Cao { 0x034e, 0x09 }, 215df0b5c4aSBingbu Cao { 0x034f, 0x90 }, 216df0b5c4aSBingbu Cao { 0x0301, 0x05 }, 217df0b5c4aSBingbu Cao { 0x0303, 0x01 }, 218df0b5c4aSBingbu Cao { 0x0305, 0x02 }, 219df0b5c4aSBingbu Cao { 0x0306, 0x00 }, 220df0b5c4aSBingbu Cao { 0x0307, 0x78 }, 221df0b5c4aSBingbu Cao { 0x030b, 0x01 }, 222df0b5c4aSBingbu Cao { 0x030d, 0x02 }, 223df0b5c4aSBingbu Cao { 0x030e, 0x00 }, 224df0b5c4aSBingbu Cao { 0x030f, 0x4b }, 225df0b5c4aSBingbu Cao { 0x0310, 0x00 }, 226df0b5c4aSBingbu Cao { 0x0700, 0x00 }, 227df0b5c4aSBingbu Cao { 0x0701, 0x10 }, 228df0b5c4aSBingbu Cao { 0x0820, 0x0b }, 229df0b5c4aSBingbu Cao { 0x0821, 0x40 }, 230df0b5c4aSBingbu Cao { 0x3088, 0x04 }, 231df0b5c4aSBingbu Cao { 0x6813, 0x02 }, 232df0b5c4aSBingbu Cao { 0x6835, 0x07 }, 233df0b5c4aSBingbu Cao { 0x6836, 0x01 }, 234df0b5c4aSBingbu Cao { 0x6837, 0x04 }, 235df0b5c4aSBingbu Cao { 0x684d, 0x07 }, 236df0b5c4aSBingbu Cao { 0x684e, 0x01 }, 237df0b5c4aSBingbu Cao { 0x684f, 0x04 }, 238df0b5c4aSBingbu Cao }; 239df0b5c4aSBingbu Cao 240df0b5c4aSBingbu Cao static const struct imx355_reg mode_3264x2448_regs[] = { 241df0b5c4aSBingbu Cao { 0x0112, 0x0a }, 242df0b5c4aSBingbu Cao { 0x0113, 0x0a }, 243df0b5c4aSBingbu Cao { 0x0114, 0x03 }, 244df0b5c4aSBingbu Cao { 0x0342, 0x0e }, 245df0b5c4aSBingbu Cao { 0x0343, 0x58 }, 246df0b5c4aSBingbu Cao { 0x0340, 0x0a }, 247df0b5c4aSBingbu Cao { 0x0341, 0x37 }, 248df0b5c4aSBingbu Cao { 0x0344, 0x00 }, 249df0b5c4aSBingbu Cao { 0x0345, 0x08 }, 250df0b5c4aSBingbu Cao { 0x0346, 0x00 }, 251df0b5c4aSBingbu Cao { 0x0347, 0x08 }, 252df0b5c4aSBingbu Cao { 0x0348, 0x0c }, 253df0b5c4aSBingbu Cao { 0x0349, 0xc7 }, 254df0b5c4aSBingbu Cao { 0x034a, 0x09 }, 255df0b5c4aSBingbu Cao { 0x034b, 0x97 }, 256df0b5c4aSBingbu Cao { 0x0220, 0x00 }, 257df0b5c4aSBingbu Cao { 0x0222, 0x01 }, 258df0b5c4aSBingbu Cao { 0x0900, 0x00 }, 259df0b5c4aSBingbu Cao { 0x0901, 0x11 }, 260df0b5c4aSBingbu Cao { 0x0902, 0x00 }, 261df0b5c4aSBingbu Cao { 0x034c, 0x0c }, 262df0b5c4aSBingbu Cao { 0x034d, 0xc0 }, 263df0b5c4aSBingbu Cao { 0x034e, 0x09 }, 264df0b5c4aSBingbu Cao { 0x034f, 0x90 }, 265df0b5c4aSBingbu Cao { 0x0301, 0x05 }, 266df0b5c4aSBingbu Cao { 0x0303, 0x01 }, 267df0b5c4aSBingbu Cao { 0x0305, 0x02 }, 268df0b5c4aSBingbu Cao { 0x0306, 0x00 }, 269df0b5c4aSBingbu Cao { 0x0307, 0x78 }, 270df0b5c4aSBingbu Cao { 0x030b, 0x01 }, 271df0b5c4aSBingbu Cao { 0x030d, 0x02 }, 272df0b5c4aSBingbu Cao { 0x030e, 0x00 }, 273df0b5c4aSBingbu Cao { 0x030f, 0x4b }, 274df0b5c4aSBingbu Cao { 0x0310, 0x00 }, 275df0b5c4aSBingbu Cao { 0x0700, 0x00 }, 276df0b5c4aSBingbu Cao { 0x0701, 0x10 }, 277df0b5c4aSBingbu Cao { 0x0820, 0x0b }, 278df0b5c4aSBingbu Cao { 0x0821, 0x40 }, 279df0b5c4aSBingbu Cao { 0x3088, 0x04 }, 280df0b5c4aSBingbu Cao { 0x6813, 0x02 }, 281df0b5c4aSBingbu Cao { 0x6835, 0x07 }, 282df0b5c4aSBingbu Cao { 0x6836, 0x01 }, 283df0b5c4aSBingbu Cao { 0x6837, 0x04 }, 284df0b5c4aSBingbu Cao { 0x684d, 0x07 }, 285df0b5c4aSBingbu Cao { 0x684e, 0x01 }, 286df0b5c4aSBingbu Cao { 0x684f, 0x04 }, 287df0b5c4aSBingbu Cao }; 288df0b5c4aSBingbu Cao 289df0b5c4aSBingbu Cao static const struct imx355_reg mode_3280x2464_regs[] = { 290df0b5c4aSBingbu Cao { 0x0112, 0x0a }, 291df0b5c4aSBingbu Cao { 0x0113, 0x0a }, 292df0b5c4aSBingbu Cao { 0x0114, 0x03 }, 293df0b5c4aSBingbu Cao { 0x0342, 0x0e }, 294df0b5c4aSBingbu Cao { 0x0343, 0x58 }, 295df0b5c4aSBingbu Cao { 0x0340, 0x0a }, 296df0b5c4aSBingbu Cao { 0x0341, 0x37 }, 297df0b5c4aSBingbu Cao { 0x0344, 0x00 }, 298df0b5c4aSBingbu Cao { 0x0345, 0x00 }, 299df0b5c4aSBingbu Cao { 0x0346, 0x00 }, 300df0b5c4aSBingbu Cao { 0x0347, 0x00 }, 301df0b5c4aSBingbu Cao { 0x0348, 0x0c }, 302df0b5c4aSBingbu Cao { 0x0349, 0xcf }, 303df0b5c4aSBingbu Cao { 0x034a, 0x09 }, 304df0b5c4aSBingbu Cao { 0x034b, 0x9f }, 305df0b5c4aSBingbu Cao { 0x0220, 0x00 }, 306df0b5c4aSBingbu Cao { 0x0222, 0x01 }, 307df0b5c4aSBingbu Cao { 0x0900, 0x00 }, 308df0b5c4aSBingbu Cao { 0x0901, 0x11 }, 309df0b5c4aSBingbu Cao { 0x0902, 0x00 }, 310df0b5c4aSBingbu Cao { 0x034c, 0x0c }, 311df0b5c4aSBingbu Cao { 0x034d, 0xd0 }, 312df0b5c4aSBingbu Cao { 0x034e, 0x09 }, 313df0b5c4aSBingbu Cao { 0x034f, 0xa0 }, 314df0b5c4aSBingbu Cao { 0x0301, 0x05 }, 315df0b5c4aSBingbu Cao { 0x0303, 0x01 }, 316df0b5c4aSBingbu Cao { 0x0305, 0x02 }, 317df0b5c4aSBingbu Cao { 0x0306, 0x00 }, 318df0b5c4aSBingbu Cao { 0x0307, 0x78 }, 319df0b5c4aSBingbu Cao { 0x030b, 0x01 }, 320df0b5c4aSBingbu Cao { 0x030d, 0x02 }, 321df0b5c4aSBingbu Cao { 0x030e, 0x00 }, 322df0b5c4aSBingbu Cao { 0x030f, 0x4b }, 323df0b5c4aSBingbu Cao { 0x0310, 0x00 }, 324df0b5c4aSBingbu Cao { 0x0700, 0x00 }, 325df0b5c4aSBingbu Cao { 0x0701, 0x10 }, 326df0b5c4aSBingbu Cao { 0x0820, 0x0b }, 327df0b5c4aSBingbu Cao { 0x0821, 0x40 }, 328df0b5c4aSBingbu Cao { 0x3088, 0x04 }, 329df0b5c4aSBingbu Cao { 0x6813, 0x02 }, 330df0b5c4aSBingbu Cao { 0x6835, 0x07 }, 331df0b5c4aSBingbu Cao { 0x6836, 0x01 }, 332df0b5c4aSBingbu Cao { 0x6837, 0x04 }, 333df0b5c4aSBingbu Cao { 0x684d, 0x07 }, 334df0b5c4aSBingbu Cao { 0x684e, 0x01 }, 335df0b5c4aSBingbu Cao { 0x684f, 0x04 }, 336df0b5c4aSBingbu Cao }; 337df0b5c4aSBingbu Cao 338df0b5c4aSBingbu Cao static const struct imx355_reg mode_1940x1096_regs[] = { 339df0b5c4aSBingbu Cao { 0x0112, 0x0a }, 340df0b5c4aSBingbu Cao { 0x0113, 0x0a }, 341df0b5c4aSBingbu Cao { 0x0114, 0x03 }, 342df0b5c4aSBingbu Cao { 0x0342, 0x0e }, 343df0b5c4aSBingbu Cao { 0x0343, 0x58 }, 344df0b5c4aSBingbu Cao { 0x0340, 0x05 }, 345df0b5c4aSBingbu Cao { 0x0341, 0x1a }, 346df0b5c4aSBingbu Cao { 0x0344, 0x02 }, 347df0b5c4aSBingbu Cao { 0x0345, 0xa0 }, 348df0b5c4aSBingbu Cao { 0x0346, 0x02 }, 349df0b5c4aSBingbu Cao { 0x0347, 0xac }, 350df0b5c4aSBingbu Cao { 0x0348, 0x0a }, 351df0b5c4aSBingbu Cao { 0x0349, 0x33 }, 352df0b5c4aSBingbu Cao { 0x034a, 0x06 }, 353df0b5c4aSBingbu Cao { 0x034b, 0xf3 }, 354df0b5c4aSBingbu Cao { 0x0220, 0x00 }, 355df0b5c4aSBingbu Cao { 0x0222, 0x01 }, 356df0b5c4aSBingbu Cao { 0x0900, 0x00 }, 357df0b5c4aSBingbu Cao { 0x0901, 0x11 }, 358df0b5c4aSBingbu Cao { 0x0902, 0x00 }, 359df0b5c4aSBingbu Cao { 0x034c, 0x07 }, 360df0b5c4aSBingbu Cao { 0x034d, 0x94 }, 361df0b5c4aSBingbu Cao { 0x034e, 0x04 }, 362df0b5c4aSBingbu Cao { 0x034f, 0x48 }, 363df0b5c4aSBingbu Cao { 0x0301, 0x05 }, 364df0b5c4aSBingbu Cao { 0x0303, 0x01 }, 365df0b5c4aSBingbu Cao { 0x0305, 0x02 }, 366df0b5c4aSBingbu Cao { 0x0306, 0x00 }, 367df0b5c4aSBingbu Cao { 0x0307, 0x78 }, 368df0b5c4aSBingbu Cao { 0x030b, 0x01 }, 369df0b5c4aSBingbu Cao { 0x030d, 0x02 }, 370df0b5c4aSBingbu Cao { 0x030e, 0x00 }, 371df0b5c4aSBingbu Cao { 0x030f, 0x4b }, 372df0b5c4aSBingbu Cao { 0x0310, 0x00 }, 373df0b5c4aSBingbu Cao { 0x0700, 0x00 }, 374df0b5c4aSBingbu Cao { 0x0701, 0x10 }, 375df0b5c4aSBingbu Cao { 0x0820, 0x0b }, 376df0b5c4aSBingbu Cao { 0x0821, 0x40 }, 377df0b5c4aSBingbu Cao { 0x3088, 0x04 }, 378df0b5c4aSBingbu Cao { 0x6813, 0x02 }, 379df0b5c4aSBingbu Cao { 0x6835, 0x07 }, 380df0b5c4aSBingbu Cao { 0x6836, 0x01 }, 381df0b5c4aSBingbu Cao { 0x6837, 0x04 }, 382df0b5c4aSBingbu Cao { 0x684d, 0x07 }, 383df0b5c4aSBingbu Cao { 0x684e, 0x01 }, 384df0b5c4aSBingbu Cao { 0x684f, 0x04 }, 385df0b5c4aSBingbu Cao }; 386df0b5c4aSBingbu Cao 387df0b5c4aSBingbu Cao static const struct imx355_reg mode_1936x1096_regs[] = { 388df0b5c4aSBingbu Cao { 0x0112, 0x0a }, 389df0b5c4aSBingbu Cao { 0x0113, 0x0a }, 390df0b5c4aSBingbu Cao { 0x0114, 0x03 }, 391df0b5c4aSBingbu Cao { 0x0342, 0x0e }, 392df0b5c4aSBingbu Cao { 0x0343, 0x58 }, 393df0b5c4aSBingbu Cao { 0x0340, 0x05 }, 394df0b5c4aSBingbu Cao { 0x0341, 0x1a }, 395df0b5c4aSBingbu Cao { 0x0344, 0x02 }, 396df0b5c4aSBingbu Cao { 0x0345, 0xa0 }, 397df0b5c4aSBingbu Cao { 0x0346, 0x02 }, 398df0b5c4aSBingbu Cao { 0x0347, 0xac }, 399df0b5c4aSBingbu Cao { 0x0348, 0x0a }, 400df0b5c4aSBingbu Cao { 0x0349, 0x2f }, 401df0b5c4aSBingbu Cao { 0x034a, 0x06 }, 402df0b5c4aSBingbu Cao { 0x034b, 0xf3 }, 403df0b5c4aSBingbu Cao { 0x0220, 0x00 }, 404df0b5c4aSBingbu Cao { 0x0222, 0x01 }, 405df0b5c4aSBingbu Cao { 0x0900, 0x00 }, 406df0b5c4aSBingbu Cao { 0x0901, 0x11 }, 407df0b5c4aSBingbu Cao { 0x0902, 0x00 }, 408df0b5c4aSBingbu Cao { 0x034c, 0x07 }, 409df0b5c4aSBingbu Cao { 0x034d, 0x90 }, 410df0b5c4aSBingbu Cao { 0x034e, 0x04 }, 411df0b5c4aSBingbu Cao { 0x034f, 0x48 }, 412df0b5c4aSBingbu Cao { 0x0301, 0x05 }, 413df0b5c4aSBingbu Cao { 0x0303, 0x01 }, 414df0b5c4aSBingbu Cao { 0x0305, 0x02 }, 415df0b5c4aSBingbu Cao { 0x0306, 0x00 }, 416df0b5c4aSBingbu Cao { 0x0307, 0x78 }, 417df0b5c4aSBingbu Cao { 0x030b, 0x01 }, 418df0b5c4aSBingbu Cao { 0x030d, 0x02 }, 419df0b5c4aSBingbu Cao { 0x030e, 0x00 }, 420df0b5c4aSBingbu Cao { 0x030f, 0x4b }, 421df0b5c4aSBingbu Cao { 0x0310, 0x00 }, 422df0b5c4aSBingbu Cao { 0x0700, 0x00 }, 423df0b5c4aSBingbu Cao { 0x0701, 0x10 }, 424df0b5c4aSBingbu Cao { 0x0820, 0x0b }, 425df0b5c4aSBingbu Cao { 0x0821, 0x40 }, 426df0b5c4aSBingbu Cao { 0x3088, 0x04 }, 427df0b5c4aSBingbu Cao { 0x6813, 0x02 }, 428df0b5c4aSBingbu Cao { 0x6835, 0x07 }, 429df0b5c4aSBingbu Cao { 0x6836, 0x01 }, 430df0b5c4aSBingbu Cao { 0x6837, 0x04 }, 431df0b5c4aSBingbu Cao { 0x684d, 0x07 }, 432df0b5c4aSBingbu Cao { 0x684e, 0x01 }, 433df0b5c4aSBingbu Cao { 0x684f, 0x04 }, 434df0b5c4aSBingbu Cao }; 435df0b5c4aSBingbu Cao 436df0b5c4aSBingbu Cao static const struct imx355_reg mode_1924x1080_regs[] = { 437df0b5c4aSBingbu Cao { 0x0112, 0x0a }, 438df0b5c4aSBingbu Cao { 0x0113, 0x0a }, 439df0b5c4aSBingbu Cao { 0x0114, 0x03 }, 440df0b5c4aSBingbu Cao { 0x0342, 0x0e }, 441df0b5c4aSBingbu Cao { 0x0343, 0x58 }, 442df0b5c4aSBingbu Cao { 0x0340, 0x05 }, 443df0b5c4aSBingbu Cao { 0x0341, 0x1a }, 444df0b5c4aSBingbu Cao { 0x0344, 0x02 }, 445df0b5c4aSBingbu Cao { 0x0345, 0xa8 }, 446df0b5c4aSBingbu Cao { 0x0346, 0x02 }, 447df0b5c4aSBingbu Cao { 0x0347, 0xb4 }, 448df0b5c4aSBingbu Cao { 0x0348, 0x0a }, 449df0b5c4aSBingbu Cao { 0x0349, 0x2b }, 450df0b5c4aSBingbu Cao { 0x034a, 0x06 }, 451df0b5c4aSBingbu Cao { 0x034b, 0xeb }, 452df0b5c4aSBingbu Cao { 0x0220, 0x00 }, 453df0b5c4aSBingbu Cao { 0x0222, 0x01 }, 454df0b5c4aSBingbu Cao { 0x0900, 0x00 }, 455df0b5c4aSBingbu Cao { 0x0901, 0x11 }, 456df0b5c4aSBingbu Cao { 0x0902, 0x00 }, 457df0b5c4aSBingbu Cao { 0x034c, 0x07 }, 458df0b5c4aSBingbu Cao { 0x034d, 0x84 }, 459df0b5c4aSBingbu Cao { 0x034e, 0x04 }, 460df0b5c4aSBingbu Cao { 0x034f, 0x38 }, 461df0b5c4aSBingbu Cao { 0x0301, 0x05 }, 462df0b5c4aSBingbu Cao { 0x0303, 0x01 }, 463df0b5c4aSBingbu Cao { 0x0305, 0x02 }, 464df0b5c4aSBingbu Cao { 0x0306, 0x00 }, 465df0b5c4aSBingbu Cao { 0x0307, 0x78 }, 466df0b5c4aSBingbu Cao { 0x030b, 0x01 }, 467df0b5c4aSBingbu Cao { 0x030d, 0x02 }, 468df0b5c4aSBingbu Cao { 0x030e, 0x00 }, 469df0b5c4aSBingbu Cao { 0x030f, 0x4b }, 470df0b5c4aSBingbu Cao { 0x0310, 0x00 }, 471df0b5c4aSBingbu Cao { 0x0700, 0x00 }, 472df0b5c4aSBingbu Cao { 0x0701, 0x10 }, 473df0b5c4aSBingbu Cao { 0x0820, 0x0b }, 474df0b5c4aSBingbu Cao { 0x0821, 0x40 }, 475df0b5c4aSBingbu Cao { 0x3088, 0x04 }, 476df0b5c4aSBingbu Cao { 0x6813, 0x02 }, 477df0b5c4aSBingbu Cao { 0x6835, 0x07 }, 478df0b5c4aSBingbu Cao { 0x6836, 0x01 }, 479df0b5c4aSBingbu Cao { 0x6837, 0x04 }, 480df0b5c4aSBingbu Cao { 0x684d, 0x07 }, 481df0b5c4aSBingbu Cao { 0x684e, 0x01 }, 482df0b5c4aSBingbu Cao { 0x684f, 0x04 }, 483df0b5c4aSBingbu Cao }; 484df0b5c4aSBingbu Cao 485df0b5c4aSBingbu Cao static const struct imx355_reg mode_1920x1080_regs[] = { 486df0b5c4aSBingbu Cao { 0x0112, 0x0a }, 487df0b5c4aSBingbu Cao { 0x0113, 0x0a }, 488df0b5c4aSBingbu Cao { 0x0114, 0x03 }, 489df0b5c4aSBingbu Cao { 0x0342, 0x0e }, 490df0b5c4aSBingbu Cao { 0x0343, 0x58 }, 491df0b5c4aSBingbu Cao { 0x0340, 0x05 }, 492df0b5c4aSBingbu Cao { 0x0341, 0x1a }, 493df0b5c4aSBingbu Cao { 0x0344, 0x02 }, 494df0b5c4aSBingbu Cao { 0x0345, 0xa8 }, 495df0b5c4aSBingbu Cao { 0x0346, 0x02 }, 496df0b5c4aSBingbu Cao { 0x0347, 0xb4 }, 497df0b5c4aSBingbu Cao { 0x0348, 0x0a }, 498df0b5c4aSBingbu Cao { 0x0349, 0x27 }, 499df0b5c4aSBingbu Cao { 0x034a, 0x06 }, 500df0b5c4aSBingbu Cao { 0x034b, 0xeb }, 501df0b5c4aSBingbu Cao { 0x0220, 0x00 }, 502df0b5c4aSBingbu Cao { 0x0222, 0x01 }, 503df0b5c4aSBingbu Cao { 0x0900, 0x00 }, 504df0b5c4aSBingbu Cao { 0x0901, 0x11 }, 505df0b5c4aSBingbu Cao { 0x0902, 0x00 }, 506df0b5c4aSBingbu Cao { 0x034c, 0x07 }, 507df0b5c4aSBingbu Cao { 0x034d, 0x80 }, 508df0b5c4aSBingbu Cao { 0x034e, 0x04 }, 509df0b5c4aSBingbu Cao { 0x034f, 0x38 }, 510df0b5c4aSBingbu Cao { 0x0301, 0x05 }, 511df0b5c4aSBingbu Cao { 0x0303, 0x01 }, 512df0b5c4aSBingbu Cao { 0x0305, 0x02 }, 513df0b5c4aSBingbu Cao { 0x0306, 0x00 }, 514df0b5c4aSBingbu Cao { 0x0307, 0x78 }, 515df0b5c4aSBingbu Cao { 0x030b, 0x01 }, 516df0b5c4aSBingbu Cao { 0x030d, 0x02 }, 517df0b5c4aSBingbu Cao { 0x030e, 0x00 }, 518df0b5c4aSBingbu Cao { 0x030f, 0x4b }, 519df0b5c4aSBingbu Cao { 0x0310, 0x00 }, 520df0b5c4aSBingbu Cao { 0x0700, 0x00 }, 521df0b5c4aSBingbu Cao { 0x0701, 0x10 }, 522df0b5c4aSBingbu Cao { 0x0820, 0x0b }, 523df0b5c4aSBingbu Cao { 0x0821, 0x40 }, 524df0b5c4aSBingbu Cao { 0x3088, 0x04 }, 525df0b5c4aSBingbu Cao { 0x6813, 0x02 }, 526df0b5c4aSBingbu Cao { 0x6835, 0x07 }, 527df0b5c4aSBingbu Cao { 0x6836, 0x01 }, 528df0b5c4aSBingbu Cao { 0x6837, 0x04 }, 529df0b5c4aSBingbu Cao { 0x684d, 0x07 }, 530df0b5c4aSBingbu Cao { 0x684e, 0x01 }, 531df0b5c4aSBingbu Cao { 0x684f, 0x04 }, 532df0b5c4aSBingbu Cao }; 533df0b5c4aSBingbu Cao 534df0b5c4aSBingbu Cao static const struct imx355_reg mode_1640x1232_regs[] = { 535df0b5c4aSBingbu Cao { 0x0112, 0x0a }, 536df0b5c4aSBingbu Cao { 0x0113, 0x0a }, 537df0b5c4aSBingbu Cao { 0x0114, 0x03 }, 538df0b5c4aSBingbu Cao { 0x0342, 0x07 }, 539df0b5c4aSBingbu Cao { 0x0343, 0x2c }, 540df0b5c4aSBingbu Cao { 0x0340, 0x05 }, 541df0b5c4aSBingbu Cao { 0x0341, 0x1a }, 542df0b5c4aSBingbu Cao { 0x0344, 0x00 }, 543df0b5c4aSBingbu Cao { 0x0345, 0x00 }, 544df0b5c4aSBingbu Cao { 0x0346, 0x00 }, 545df0b5c4aSBingbu Cao { 0x0347, 0x00 }, 546df0b5c4aSBingbu Cao { 0x0348, 0x0c }, 547df0b5c4aSBingbu Cao { 0x0349, 0xcf }, 548df0b5c4aSBingbu Cao { 0x034a, 0x09 }, 549df0b5c4aSBingbu Cao { 0x034b, 0x9f }, 550df0b5c4aSBingbu Cao { 0x0220, 0x00 }, 551df0b5c4aSBingbu Cao { 0x0222, 0x01 }, 552df0b5c4aSBingbu Cao { 0x0900, 0x01 }, 553df0b5c4aSBingbu Cao { 0x0901, 0x22 }, 554df0b5c4aSBingbu Cao { 0x0902, 0x00 }, 555df0b5c4aSBingbu Cao { 0x034c, 0x06 }, 556df0b5c4aSBingbu Cao { 0x034d, 0x68 }, 557df0b5c4aSBingbu Cao { 0x034e, 0x04 }, 558df0b5c4aSBingbu Cao { 0x034f, 0xd0 }, 559df0b5c4aSBingbu Cao { 0x0301, 0x05 }, 560df0b5c4aSBingbu Cao { 0x0303, 0x01 }, 561df0b5c4aSBingbu Cao { 0x0305, 0x02 }, 562df0b5c4aSBingbu Cao { 0x0306, 0x00 }, 563df0b5c4aSBingbu Cao { 0x0307, 0x78 }, 564df0b5c4aSBingbu Cao { 0x030b, 0x01 }, 565df0b5c4aSBingbu Cao { 0x030d, 0x02 }, 566df0b5c4aSBingbu Cao { 0x030e, 0x00 }, 567df0b5c4aSBingbu Cao { 0x030f, 0x4b }, 568df0b5c4aSBingbu Cao { 0x0310, 0x00 }, 569df0b5c4aSBingbu Cao { 0x0700, 0x00 }, 570df0b5c4aSBingbu Cao { 0x0701, 0x10 }, 571df0b5c4aSBingbu Cao { 0x0820, 0x0b }, 572df0b5c4aSBingbu Cao { 0x0821, 0x40 }, 573df0b5c4aSBingbu Cao { 0x3088, 0x04 }, 574df0b5c4aSBingbu Cao { 0x6813, 0x02 }, 575df0b5c4aSBingbu Cao { 0x6835, 0x07 }, 576df0b5c4aSBingbu Cao { 0x6836, 0x01 }, 577df0b5c4aSBingbu Cao { 0x6837, 0x04 }, 578df0b5c4aSBingbu Cao { 0x684d, 0x07 }, 579df0b5c4aSBingbu Cao { 0x684e, 0x01 }, 580df0b5c4aSBingbu Cao { 0x684f, 0x04 }, 581df0b5c4aSBingbu Cao }; 582df0b5c4aSBingbu Cao 583df0b5c4aSBingbu Cao static const struct imx355_reg mode_1640x922_regs[] = { 584df0b5c4aSBingbu Cao { 0x0112, 0x0a }, 585df0b5c4aSBingbu Cao { 0x0113, 0x0a }, 586df0b5c4aSBingbu Cao { 0x0114, 0x03 }, 587df0b5c4aSBingbu Cao { 0x0342, 0x07 }, 588df0b5c4aSBingbu Cao { 0x0343, 0x2c }, 589df0b5c4aSBingbu Cao { 0x0340, 0x05 }, 590df0b5c4aSBingbu Cao { 0x0341, 0x1a }, 591df0b5c4aSBingbu Cao { 0x0344, 0x00 }, 592df0b5c4aSBingbu Cao { 0x0345, 0x00 }, 593df0b5c4aSBingbu Cao { 0x0346, 0x01 }, 594df0b5c4aSBingbu Cao { 0x0347, 0x30 }, 595df0b5c4aSBingbu Cao { 0x0348, 0x0c }, 596df0b5c4aSBingbu Cao { 0x0349, 0xcf }, 597df0b5c4aSBingbu Cao { 0x034a, 0x08 }, 598df0b5c4aSBingbu Cao { 0x034b, 0x63 }, 599df0b5c4aSBingbu Cao { 0x0220, 0x00 }, 600df0b5c4aSBingbu Cao { 0x0222, 0x01 }, 601df0b5c4aSBingbu Cao { 0x0900, 0x01 }, 602df0b5c4aSBingbu Cao { 0x0901, 0x22 }, 603df0b5c4aSBingbu Cao { 0x0902, 0x00 }, 604df0b5c4aSBingbu Cao { 0x034c, 0x06 }, 605df0b5c4aSBingbu Cao { 0x034d, 0x68 }, 606df0b5c4aSBingbu Cao { 0x034e, 0x03 }, 607df0b5c4aSBingbu Cao { 0x034f, 0x9a }, 608df0b5c4aSBingbu Cao { 0x0301, 0x05 }, 609df0b5c4aSBingbu Cao { 0x0303, 0x01 }, 610df0b5c4aSBingbu Cao { 0x0305, 0x02 }, 611df0b5c4aSBingbu Cao { 0x0306, 0x00 }, 612df0b5c4aSBingbu Cao { 0x0307, 0x78 }, 613df0b5c4aSBingbu Cao { 0x030b, 0x01 }, 614df0b5c4aSBingbu Cao { 0x030d, 0x02 }, 615df0b5c4aSBingbu Cao { 0x030e, 0x00 }, 616df0b5c4aSBingbu Cao { 0x030f, 0x4b }, 617df0b5c4aSBingbu Cao { 0x0310, 0x00 }, 618df0b5c4aSBingbu Cao { 0x0700, 0x00 }, 619df0b5c4aSBingbu Cao { 0x0701, 0x10 }, 620df0b5c4aSBingbu Cao { 0x0820, 0x0b }, 621df0b5c4aSBingbu Cao { 0x0821, 0x40 }, 622df0b5c4aSBingbu Cao { 0x3088, 0x04 }, 623df0b5c4aSBingbu Cao { 0x6813, 0x02 }, 624df0b5c4aSBingbu Cao { 0x6835, 0x07 }, 625df0b5c4aSBingbu Cao { 0x6836, 0x01 }, 626df0b5c4aSBingbu Cao { 0x6837, 0x04 }, 627df0b5c4aSBingbu Cao { 0x684d, 0x07 }, 628df0b5c4aSBingbu Cao { 0x684e, 0x01 }, 629df0b5c4aSBingbu Cao { 0x684f, 0x04 }, 630df0b5c4aSBingbu Cao }; 631df0b5c4aSBingbu Cao 632df0b5c4aSBingbu Cao static const struct imx355_reg mode_1300x736_regs[] = { 633df0b5c4aSBingbu Cao { 0x0112, 0x0a }, 634df0b5c4aSBingbu Cao { 0x0113, 0x0a }, 635df0b5c4aSBingbu Cao { 0x0114, 0x03 }, 636df0b5c4aSBingbu Cao { 0x0342, 0x07 }, 637df0b5c4aSBingbu Cao { 0x0343, 0x2c }, 638df0b5c4aSBingbu Cao { 0x0340, 0x05 }, 639df0b5c4aSBingbu Cao { 0x0341, 0x1a }, 640df0b5c4aSBingbu Cao { 0x0344, 0x01 }, 641df0b5c4aSBingbu Cao { 0x0345, 0x58 }, 642df0b5c4aSBingbu Cao { 0x0346, 0x01 }, 643df0b5c4aSBingbu Cao { 0x0347, 0xf0 }, 644df0b5c4aSBingbu Cao { 0x0348, 0x0b }, 645df0b5c4aSBingbu Cao { 0x0349, 0x7f }, 646df0b5c4aSBingbu Cao { 0x034a, 0x07 }, 647df0b5c4aSBingbu Cao { 0x034b, 0xaf }, 648df0b5c4aSBingbu Cao { 0x0220, 0x00 }, 649df0b5c4aSBingbu Cao { 0x0222, 0x01 }, 650df0b5c4aSBingbu Cao { 0x0900, 0x01 }, 651df0b5c4aSBingbu Cao { 0x0901, 0x22 }, 652df0b5c4aSBingbu Cao { 0x0902, 0x00 }, 653df0b5c4aSBingbu Cao { 0x034c, 0x05 }, 654df0b5c4aSBingbu Cao { 0x034d, 0x14 }, 655df0b5c4aSBingbu Cao { 0x034e, 0x02 }, 656df0b5c4aSBingbu Cao { 0x034f, 0xe0 }, 657df0b5c4aSBingbu Cao { 0x0301, 0x05 }, 658df0b5c4aSBingbu Cao { 0x0303, 0x01 }, 659df0b5c4aSBingbu Cao { 0x0305, 0x02 }, 660df0b5c4aSBingbu Cao { 0x0306, 0x00 }, 661df0b5c4aSBingbu Cao { 0x0307, 0x78 }, 662df0b5c4aSBingbu Cao { 0x030b, 0x01 }, 663df0b5c4aSBingbu Cao { 0x030d, 0x02 }, 664df0b5c4aSBingbu Cao { 0x030e, 0x00 }, 665df0b5c4aSBingbu Cao { 0x030f, 0x4b }, 666df0b5c4aSBingbu Cao { 0x0310, 0x00 }, 667df0b5c4aSBingbu Cao { 0x0700, 0x00 }, 668df0b5c4aSBingbu Cao { 0x0701, 0x10 }, 669df0b5c4aSBingbu Cao { 0x0820, 0x0b }, 670df0b5c4aSBingbu Cao { 0x0821, 0x40 }, 671df0b5c4aSBingbu Cao { 0x3088, 0x04 }, 672df0b5c4aSBingbu Cao { 0x6813, 0x02 }, 673df0b5c4aSBingbu Cao { 0x6835, 0x07 }, 674df0b5c4aSBingbu Cao { 0x6836, 0x01 }, 675df0b5c4aSBingbu Cao { 0x6837, 0x04 }, 676df0b5c4aSBingbu Cao { 0x684d, 0x07 }, 677df0b5c4aSBingbu Cao { 0x684e, 0x01 }, 678df0b5c4aSBingbu Cao { 0x684f, 0x04 }, 679df0b5c4aSBingbu Cao }; 680df0b5c4aSBingbu Cao 681df0b5c4aSBingbu Cao static const struct imx355_reg mode_1296x736_regs[] = { 682df0b5c4aSBingbu Cao { 0x0112, 0x0a }, 683df0b5c4aSBingbu Cao { 0x0113, 0x0a }, 684df0b5c4aSBingbu Cao { 0x0114, 0x03 }, 685df0b5c4aSBingbu Cao { 0x0342, 0x07 }, 686df0b5c4aSBingbu Cao { 0x0343, 0x2c }, 687df0b5c4aSBingbu Cao { 0x0340, 0x05 }, 688df0b5c4aSBingbu Cao { 0x0341, 0x1a }, 689df0b5c4aSBingbu Cao { 0x0344, 0x01 }, 690df0b5c4aSBingbu Cao { 0x0345, 0x58 }, 691df0b5c4aSBingbu Cao { 0x0346, 0x01 }, 692df0b5c4aSBingbu Cao { 0x0347, 0xf0 }, 693df0b5c4aSBingbu Cao { 0x0348, 0x0b }, 694df0b5c4aSBingbu Cao { 0x0349, 0x77 }, 695df0b5c4aSBingbu Cao { 0x034a, 0x07 }, 696df0b5c4aSBingbu Cao { 0x034b, 0xaf }, 697df0b5c4aSBingbu Cao { 0x0220, 0x00 }, 698df0b5c4aSBingbu Cao { 0x0222, 0x01 }, 699df0b5c4aSBingbu Cao { 0x0900, 0x01 }, 700df0b5c4aSBingbu Cao { 0x0901, 0x22 }, 701df0b5c4aSBingbu Cao { 0x0902, 0x00 }, 702df0b5c4aSBingbu Cao { 0x034c, 0x05 }, 703df0b5c4aSBingbu Cao { 0x034d, 0x10 }, 704df0b5c4aSBingbu Cao { 0x034e, 0x02 }, 705df0b5c4aSBingbu Cao { 0x034f, 0xe0 }, 706df0b5c4aSBingbu Cao { 0x0301, 0x05 }, 707df0b5c4aSBingbu Cao { 0x0303, 0x01 }, 708df0b5c4aSBingbu Cao { 0x0305, 0x02 }, 709df0b5c4aSBingbu Cao { 0x0306, 0x00 }, 710df0b5c4aSBingbu Cao { 0x0307, 0x78 }, 711df0b5c4aSBingbu Cao { 0x030b, 0x01 }, 712df0b5c4aSBingbu Cao { 0x030d, 0x02 }, 713df0b5c4aSBingbu Cao { 0x030e, 0x00 }, 714df0b5c4aSBingbu Cao { 0x030f, 0x4b }, 715df0b5c4aSBingbu Cao { 0x0310, 0x00 }, 716df0b5c4aSBingbu Cao { 0x0700, 0x00 }, 717df0b5c4aSBingbu Cao { 0x0701, 0x10 }, 718df0b5c4aSBingbu Cao { 0x0820, 0x0b }, 719df0b5c4aSBingbu Cao { 0x0821, 0x40 }, 720df0b5c4aSBingbu Cao { 0x3088, 0x04 }, 721df0b5c4aSBingbu Cao { 0x6813, 0x02 }, 722df0b5c4aSBingbu Cao { 0x6835, 0x07 }, 723df0b5c4aSBingbu Cao { 0x6836, 0x01 }, 724df0b5c4aSBingbu Cao { 0x6837, 0x04 }, 725df0b5c4aSBingbu Cao { 0x684d, 0x07 }, 726df0b5c4aSBingbu Cao { 0x684e, 0x01 }, 727df0b5c4aSBingbu Cao { 0x684f, 0x04 }, 728df0b5c4aSBingbu Cao }; 729df0b5c4aSBingbu Cao 730df0b5c4aSBingbu Cao static const struct imx355_reg mode_1284x720_regs[] = { 731df0b5c4aSBingbu Cao { 0x0112, 0x0a }, 732df0b5c4aSBingbu Cao { 0x0113, 0x0a }, 733df0b5c4aSBingbu Cao { 0x0114, 0x03 }, 734df0b5c4aSBingbu Cao { 0x0342, 0x07 }, 735df0b5c4aSBingbu Cao { 0x0343, 0x2c }, 736df0b5c4aSBingbu Cao { 0x0340, 0x05 }, 737df0b5c4aSBingbu Cao { 0x0341, 0x1a }, 738df0b5c4aSBingbu Cao { 0x0344, 0x01 }, 739df0b5c4aSBingbu Cao { 0x0345, 0x68 }, 740df0b5c4aSBingbu Cao { 0x0346, 0x02 }, 741df0b5c4aSBingbu Cao { 0x0347, 0x00 }, 742df0b5c4aSBingbu Cao { 0x0348, 0x0b }, 743df0b5c4aSBingbu Cao { 0x0349, 0x6f }, 744df0b5c4aSBingbu Cao { 0x034a, 0x07 }, 745df0b5c4aSBingbu Cao { 0x034b, 0x9f }, 746df0b5c4aSBingbu Cao { 0x0220, 0x00 }, 747df0b5c4aSBingbu Cao { 0x0222, 0x01 }, 748df0b5c4aSBingbu Cao { 0x0900, 0x01 }, 749df0b5c4aSBingbu Cao { 0x0901, 0x22 }, 750df0b5c4aSBingbu Cao { 0x0902, 0x00 }, 751df0b5c4aSBingbu Cao { 0x034c, 0x05 }, 752df0b5c4aSBingbu Cao { 0x034d, 0x04 }, 753df0b5c4aSBingbu Cao { 0x034e, 0x02 }, 754df0b5c4aSBingbu Cao { 0x034f, 0xd0 }, 755df0b5c4aSBingbu Cao { 0x0301, 0x05 }, 756df0b5c4aSBingbu Cao { 0x0303, 0x01 }, 757df0b5c4aSBingbu Cao { 0x0305, 0x02 }, 758df0b5c4aSBingbu Cao { 0x0306, 0x00 }, 759df0b5c4aSBingbu Cao { 0x0307, 0x78 }, 760df0b5c4aSBingbu Cao { 0x030b, 0x01 }, 761df0b5c4aSBingbu Cao { 0x030d, 0x02 }, 762df0b5c4aSBingbu Cao { 0x030e, 0x00 }, 763df0b5c4aSBingbu Cao { 0x030f, 0x4b }, 764df0b5c4aSBingbu Cao { 0x0310, 0x00 }, 765df0b5c4aSBingbu Cao { 0x0700, 0x00 }, 766df0b5c4aSBingbu Cao { 0x0701, 0x10 }, 767df0b5c4aSBingbu Cao { 0x0820, 0x0b }, 768df0b5c4aSBingbu Cao { 0x0821, 0x40 }, 769df0b5c4aSBingbu Cao { 0x3088, 0x04 }, 770df0b5c4aSBingbu Cao { 0x6813, 0x02 }, 771df0b5c4aSBingbu Cao { 0x6835, 0x07 }, 772df0b5c4aSBingbu Cao { 0x6836, 0x01 }, 773df0b5c4aSBingbu Cao { 0x6837, 0x04 }, 774df0b5c4aSBingbu Cao { 0x684d, 0x07 }, 775df0b5c4aSBingbu Cao { 0x684e, 0x01 }, 776df0b5c4aSBingbu Cao { 0x684f, 0x04 }, 777df0b5c4aSBingbu Cao }; 778df0b5c4aSBingbu Cao 779df0b5c4aSBingbu Cao static const struct imx355_reg mode_1280x720_regs[] = { 780df0b5c4aSBingbu Cao { 0x0112, 0x0a }, 781df0b5c4aSBingbu Cao { 0x0113, 0x0a }, 782df0b5c4aSBingbu Cao { 0x0114, 0x03 }, 783df0b5c4aSBingbu Cao { 0x0342, 0x07 }, 784df0b5c4aSBingbu Cao { 0x0343, 0x2c }, 785df0b5c4aSBingbu Cao { 0x0340, 0x05 }, 786df0b5c4aSBingbu Cao { 0x0341, 0x1a }, 787df0b5c4aSBingbu Cao { 0x0344, 0x01 }, 788df0b5c4aSBingbu Cao { 0x0345, 0x68 }, 789df0b5c4aSBingbu Cao { 0x0346, 0x02 }, 790df0b5c4aSBingbu Cao { 0x0347, 0x00 }, 791df0b5c4aSBingbu Cao { 0x0348, 0x0b }, 792df0b5c4aSBingbu Cao { 0x0349, 0x67 }, 793df0b5c4aSBingbu Cao { 0x034a, 0x07 }, 794df0b5c4aSBingbu Cao { 0x034b, 0x9f }, 795df0b5c4aSBingbu Cao { 0x0220, 0x00 }, 796df0b5c4aSBingbu Cao { 0x0222, 0x01 }, 797df0b5c4aSBingbu Cao { 0x0900, 0x01 }, 798df0b5c4aSBingbu Cao { 0x0901, 0x22 }, 799df0b5c4aSBingbu Cao { 0x0902, 0x00 }, 800df0b5c4aSBingbu Cao { 0x034c, 0x05 }, 801df0b5c4aSBingbu Cao { 0x034d, 0x00 }, 802df0b5c4aSBingbu Cao { 0x034e, 0x02 }, 803df0b5c4aSBingbu Cao { 0x034f, 0xd0 }, 804df0b5c4aSBingbu Cao { 0x0301, 0x05 }, 805df0b5c4aSBingbu Cao { 0x0303, 0x01 }, 806df0b5c4aSBingbu Cao { 0x0305, 0x02 }, 807df0b5c4aSBingbu Cao { 0x0306, 0x00 }, 808df0b5c4aSBingbu Cao { 0x0307, 0x78 }, 809df0b5c4aSBingbu Cao { 0x030b, 0x01 }, 810df0b5c4aSBingbu Cao { 0x030d, 0x02 }, 811df0b5c4aSBingbu Cao { 0x030e, 0x00 }, 812df0b5c4aSBingbu Cao { 0x030f, 0x4b }, 813df0b5c4aSBingbu Cao { 0x0310, 0x00 }, 814df0b5c4aSBingbu Cao { 0x0700, 0x00 }, 815df0b5c4aSBingbu Cao { 0x0701, 0x10 }, 816df0b5c4aSBingbu Cao { 0x0820, 0x0b }, 817df0b5c4aSBingbu Cao { 0x0821, 0x40 }, 818df0b5c4aSBingbu Cao { 0x3088, 0x04 }, 819df0b5c4aSBingbu Cao { 0x6813, 0x02 }, 820df0b5c4aSBingbu Cao { 0x6835, 0x07 }, 821df0b5c4aSBingbu Cao { 0x6836, 0x01 }, 822df0b5c4aSBingbu Cao { 0x6837, 0x04 }, 823df0b5c4aSBingbu Cao { 0x684d, 0x07 }, 824df0b5c4aSBingbu Cao { 0x684e, 0x01 }, 825df0b5c4aSBingbu Cao { 0x684f, 0x04 }, 826df0b5c4aSBingbu Cao }; 827df0b5c4aSBingbu Cao 828df0b5c4aSBingbu Cao static const struct imx355_reg mode_820x616_regs[] = { 829df0b5c4aSBingbu Cao { 0x0112, 0x0a }, 830df0b5c4aSBingbu Cao { 0x0113, 0x0a }, 831df0b5c4aSBingbu Cao { 0x0114, 0x03 }, 832df0b5c4aSBingbu Cao { 0x0342, 0x0e }, 833df0b5c4aSBingbu Cao { 0x0343, 0x58 }, 834df0b5c4aSBingbu Cao { 0x0340, 0x02 }, 835df0b5c4aSBingbu Cao { 0x0341, 0x8c }, 836df0b5c4aSBingbu Cao { 0x0344, 0x00 }, 837df0b5c4aSBingbu Cao { 0x0345, 0x00 }, 838df0b5c4aSBingbu Cao { 0x0346, 0x00 }, 839df0b5c4aSBingbu Cao { 0x0347, 0x00 }, 840df0b5c4aSBingbu Cao { 0x0348, 0x0c }, 841df0b5c4aSBingbu Cao { 0x0349, 0xcf }, 842df0b5c4aSBingbu Cao { 0x034a, 0x09 }, 843df0b5c4aSBingbu Cao { 0x034b, 0x9f }, 844df0b5c4aSBingbu Cao { 0x0220, 0x00 }, 845df0b5c4aSBingbu Cao { 0x0222, 0x01 }, 846df0b5c4aSBingbu Cao { 0x0900, 0x01 }, 847df0b5c4aSBingbu Cao { 0x0901, 0x44 }, 848df0b5c4aSBingbu Cao { 0x0902, 0x00 }, 849df0b5c4aSBingbu Cao { 0x034c, 0x03 }, 850df0b5c4aSBingbu Cao { 0x034d, 0x34 }, 851df0b5c4aSBingbu Cao { 0x034e, 0x02 }, 852df0b5c4aSBingbu Cao { 0x034f, 0x68 }, 853df0b5c4aSBingbu Cao { 0x0301, 0x05 }, 854df0b5c4aSBingbu Cao { 0x0303, 0x01 }, 855df0b5c4aSBingbu Cao { 0x0305, 0x02 }, 856df0b5c4aSBingbu Cao { 0x0306, 0x00 }, 857df0b5c4aSBingbu Cao { 0x0307, 0x78 }, 858df0b5c4aSBingbu Cao { 0x030b, 0x01 }, 859df0b5c4aSBingbu Cao { 0x030d, 0x02 }, 860df0b5c4aSBingbu Cao { 0x030e, 0x00 }, 861df0b5c4aSBingbu Cao { 0x030f, 0x4b }, 862df0b5c4aSBingbu Cao { 0x0310, 0x00 }, 863df0b5c4aSBingbu Cao { 0x0700, 0x02 }, 864df0b5c4aSBingbu Cao { 0x0701, 0x78 }, 865df0b5c4aSBingbu Cao { 0x0820, 0x0b }, 866df0b5c4aSBingbu Cao { 0x0821, 0x40 }, 867df0b5c4aSBingbu Cao { 0x3088, 0x04 }, 868df0b5c4aSBingbu Cao { 0x6813, 0x02 }, 869df0b5c4aSBingbu Cao { 0x6835, 0x07 }, 870df0b5c4aSBingbu Cao { 0x6836, 0x01 }, 871df0b5c4aSBingbu Cao { 0x6837, 0x04 }, 872df0b5c4aSBingbu Cao { 0x684d, 0x07 }, 873df0b5c4aSBingbu Cao { 0x684e, 0x01 }, 874df0b5c4aSBingbu Cao { 0x684f, 0x04 }, 875df0b5c4aSBingbu Cao }; 876df0b5c4aSBingbu Cao 877df0b5c4aSBingbu Cao static const char * const imx355_test_pattern_menu[] = { 878df0b5c4aSBingbu Cao "Disabled", 879ce6ebeacSBingbu Cao "Solid Colour", 880ce6ebeacSBingbu Cao "Eight Vertical Colour Bars", 881ce6ebeacSBingbu Cao "Colour Bars With Fade to Grey", 882ce6ebeacSBingbu Cao "Pseudorandom Sequence (PN9)", 883df0b5c4aSBingbu Cao }; 884df0b5c4aSBingbu Cao 885df0b5c4aSBingbu Cao /* supported link frequencies */ 886df0b5c4aSBingbu Cao static const s64 link_freq_menu_items[] = { 887df0b5c4aSBingbu Cao IMX355_LINK_FREQ_DEFAULT, 888df0b5c4aSBingbu Cao }; 889df0b5c4aSBingbu Cao 890df0b5c4aSBingbu Cao /* Mode configs */ 891df0b5c4aSBingbu Cao static const struct imx355_mode supported_modes[] = { 892df0b5c4aSBingbu Cao { 893df0b5c4aSBingbu Cao .width = 3280, 894df0b5c4aSBingbu Cao .height = 2464, 895df0b5c4aSBingbu Cao .fll_def = 2615, 896df0b5c4aSBingbu Cao .fll_min = 2615, 897df0b5c4aSBingbu Cao .llp = 3672, 898df0b5c4aSBingbu Cao .link_freq_index = IMX355_LINK_FREQ_INDEX, 899df0b5c4aSBingbu Cao .reg_list = { 900df0b5c4aSBingbu Cao .num_of_regs = ARRAY_SIZE(mode_3280x2464_regs), 901df0b5c4aSBingbu Cao .regs = mode_3280x2464_regs, 902df0b5c4aSBingbu Cao }, 903df0b5c4aSBingbu Cao }, 904df0b5c4aSBingbu Cao { 905df0b5c4aSBingbu Cao .width = 3268, 906df0b5c4aSBingbu Cao .height = 2448, 907df0b5c4aSBingbu Cao .fll_def = 2615, 908df0b5c4aSBingbu Cao .fll_min = 2615, 909df0b5c4aSBingbu Cao .llp = 3672, 910df0b5c4aSBingbu Cao .link_freq_index = IMX355_LINK_FREQ_INDEX, 911df0b5c4aSBingbu Cao .reg_list = { 912df0b5c4aSBingbu Cao .num_of_regs = ARRAY_SIZE(mode_3268x2448_regs), 913df0b5c4aSBingbu Cao .regs = mode_3268x2448_regs, 914df0b5c4aSBingbu Cao }, 915df0b5c4aSBingbu Cao }, 916df0b5c4aSBingbu Cao { 917df0b5c4aSBingbu Cao .width = 3264, 918df0b5c4aSBingbu Cao .height = 2448, 919df0b5c4aSBingbu Cao .fll_def = 2615, 920df0b5c4aSBingbu Cao .fll_min = 2615, 921df0b5c4aSBingbu Cao .llp = 3672, 922df0b5c4aSBingbu Cao .link_freq_index = IMX355_LINK_FREQ_INDEX, 923df0b5c4aSBingbu Cao .reg_list = { 924df0b5c4aSBingbu Cao .num_of_regs = ARRAY_SIZE(mode_3264x2448_regs), 925df0b5c4aSBingbu Cao .regs = mode_3264x2448_regs, 926df0b5c4aSBingbu Cao }, 927df0b5c4aSBingbu Cao }, 928df0b5c4aSBingbu Cao { 929df0b5c4aSBingbu Cao .width = 1940, 930df0b5c4aSBingbu Cao .height = 1096, 931df0b5c4aSBingbu Cao .fll_def = 1306, 932df0b5c4aSBingbu Cao .fll_min = 1306, 933df0b5c4aSBingbu Cao .llp = 3672, 934df0b5c4aSBingbu Cao .link_freq_index = IMX355_LINK_FREQ_INDEX, 935df0b5c4aSBingbu Cao .reg_list = { 936df0b5c4aSBingbu Cao .num_of_regs = ARRAY_SIZE(mode_1940x1096_regs), 937df0b5c4aSBingbu Cao .regs = mode_1940x1096_regs, 938df0b5c4aSBingbu Cao }, 939df0b5c4aSBingbu Cao }, 940df0b5c4aSBingbu Cao { 941df0b5c4aSBingbu Cao .width = 1936, 942df0b5c4aSBingbu Cao .height = 1096, 943df0b5c4aSBingbu Cao .fll_def = 1306, 944df0b5c4aSBingbu Cao .fll_min = 1306, 945df0b5c4aSBingbu Cao .llp = 3672, 946df0b5c4aSBingbu Cao .link_freq_index = IMX355_LINK_FREQ_INDEX, 947df0b5c4aSBingbu Cao .reg_list = { 948df0b5c4aSBingbu Cao .num_of_regs = ARRAY_SIZE(mode_1936x1096_regs), 949df0b5c4aSBingbu Cao .regs = mode_1936x1096_regs, 950df0b5c4aSBingbu Cao }, 951df0b5c4aSBingbu Cao }, 952df0b5c4aSBingbu Cao { 953df0b5c4aSBingbu Cao .width = 1924, 954df0b5c4aSBingbu Cao .height = 1080, 955df0b5c4aSBingbu Cao .fll_def = 1306, 956df0b5c4aSBingbu Cao .fll_min = 1306, 957df0b5c4aSBingbu Cao .llp = 3672, 958df0b5c4aSBingbu Cao .link_freq_index = IMX355_LINK_FREQ_INDEX, 959df0b5c4aSBingbu Cao .reg_list = { 960df0b5c4aSBingbu Cao .num_of_regs = ARRAY_SIZE(mode_1924x1080_regs), 961df0b5c4aSBingbu Cao .regs = mode_1924x1080_regs, 962df0b5c4aSBingbu Cao }, 963df0b5c4aSBingbu Cao }, 964df0b5c4aSBingbu Cao { 965df0b5c4aSBingbu Cao .width = 1920, 966df0b5c4aSBingbu Cao .height = 1080, 967df0b5c4aSBingbu Cao .fll_def = 1306, 968df0b5c4aSBingbu Cao .fll_min = 1306, 969df0b5c4aSBingbu Cao .llp = 3672, 970df0b5c4aSBingbu Cao .link_freq_index = IMX355_LINK_FREQ_INDEX, 971df0b5c4aSBingbu Cao .reg_list = { 972df0b5c4aSBingbu Cao .num_of_regs = ARRAY_SIZE(mode_1920x1080_regs), 973df0b5c4aSBingbu Cao .regs = mode_1920x1080_regs, 974df0b5c4aSBingbu Cao }, 975df0b5c4aSBingbu Cao }, 976df0b5c4aSBingbu Cao { 977df0b5c4aSBingbu Cao .width = 1640, 978df0b5c4aSBingbu Cao .height = 1232, 979df0b5c4aSBingbu Cao .fll_def = 1306, 980df0b5c4aSBingbu Cao .fll_min = 1306, 981df0b5c4aSBingbu Cao .llp = 1836, 982df0b5c4aSBingbu Cao .link_freq_index = IMX355_LINK_FREQ_INDEX, 983df0b5c4aSBingbu Cao .reg_list = { 984df0b5c4aSBingbu Cao .num_of_regs = ARRAY_SIZE(mode_1640x1232_regs), 985df0b5c4aSBingbu Cao .regs = mode_1640x1232_regs, 986df0b5c4aSBingbu Cao }, 987df0b5c4aSBingbu Cao }, 988df0b5c4aSBingbu Cao { 989df0b5c4aSBingbu Cao .width = 1640, 990df0b5c4aSBingbu Cao .height = 922, 991df0b5c4aSBingbu Cao .fll_def = 1306, 992df0b5c4aSBingbu Cao .fll_min = 1306, 993df0b5c4aSBingbu Cao .llp = 1836, 994df0b5c4aSBingbu Cao .link_freq_index = IMX355_LINK_FREQ_INDEX, 995df0b5c4aSBingbu Cao .reg_list = { 996df0b5c4aSBingbu Cao .num_of_regs = ARRAY_SIZE(mode_1640x922_regs), 997df0b5c4aSBingbu Cao .regs = mode_1640x922_regs, 998df0b5c4aSBingbu Cao }, 999df0b5c4aSBingbu Cao }, 1000df0b5c4aSBingbu Cao { 1001df0b5c4aSBingbu Cao .width = 1300, 1002df0b5c4aSBingbu Cao .height = 736, 1003df0b5c4aSBingbu Cao .fll_def = 1306, 1004df0b5c4aSBingbu Cao .fll_min = 1306, 1005df0b5c4aSBingbu Cao .llp = 1836, 1006df0b5c4aSBingbu Cao .link_freq_index = IMX355_LINK_FREQ_INDEX, 1007df0b5c4aSBingbu Cao .reg_list = { 1008df0b5c4aSBingbu Cao .num_of_regs = ARRAY_SIZE(mode_1300x736_regs), 1009df0b5c4aSBingbu Cao .regs = mode_1300x736_regs, 1010df0b5c4aSBingbu Cao }, 1011df0b5c4aSBingbu Cao }, 1012df0b5c4aSBingbu Cao { 1013df0b5c4aSBingbu Cao .width = 1296, 1014df0b5c4aSBingbu Cao .height = 736, 1015df0b5c4aSBingbu Cao .fll_def = 1306, 1016df0b5c4aSBingbu Cao .fll_min = 1306, 1017df0b5c4aSBingbu Cao .llp = 1836, 1018df0b5c4aSBingbu Cao .link_freq_index = IMX355_LINK_FREQ_INDEX, 1019df0b5c4aSBingbu Cao .reg_list = { 1020df0b5c4aSBingbu Cao .num_of_regs = ARRAY_SIZE(mode_1296x736_regs), 1021df0b5c4aSBingbu Cao .regs = mode_1296x736_regs, 1022df0b5c4aSBingbu Cao }, 1023df0b5c4aSBingbu Cao }, 1024df0b5c4aSBingbu Cao { 1025df0b5c4aSBingbu Cao .width = 1284, 1026df0b5c4aSBingbu Cao .height = 720, 1027df0b5c4aSBingbu Cao .fll_def = 1306, 1028df0b5c4aSBingbu Cao .fll_min = 1306, 1029df0b5c4aSBingbu Cao .llp = 1836, 1030df0b5c4aSBingbu Cao .link_freq_index = IMX355_LINK_FREQ_INDEX, 1031df0b5c4aSBingbu Cao .reg_list = { 1032df0b5c4aSBingbu Cao .num_of_regs = ARRAY_SIZE(mode_1284x720_regs), 1033df0b5c4aSBingbu Cao .regs = mode_1284x720_regs, 1034df0b5c4aSBingbu Cao }, 1035df0b5c4aSBingbu Cao }, 1036df0b5c4aSBingbu Cao { 1037df0b5c4aSBingbu Cao .width = 1280, 1038df0b5c4aSBingbu Cao .height = 720, 1039df0b5c4aSBingbu Cao .fll_def = 1306, 1040df0b5c4aSBingbu Cao .fll_min = 1306, 1041df0b5c4aSBingbu Cao .llp = 1836, 1042df0b5c4aSBingbu Cao .link_freq_index = IMX355_LINK_FREQ_INDEX, 1043df0b5c4aSBingbu Cao .reg_list = { 1044df0b5c4aSBingbu Cao .num_of_regs = ARRAY_SIZE(mode_1280x720_regs), 1045df0b5c4aSBingbu Cao .regs = mode_1280x720_regs, 1046df0b5c4aSBingbu Cao }, 1047df0b5c4aSBingbu Cao }, 1048df0b5c4aSBingbu Cao { 1049df0b5c4aSBingbu Cao .width = 820, 1050df0b5c4aSBingbu Cao .height = 616, 1051df0b5c4aSBingbu Cao .fll_def = 652, 1052df0b5c4aSBingbu Cao .fll_min = 652, 1053df0b5c4aSBingbu Cao .llp = 3672, 1054df0b5c4aSBingbu Cao .link_freq_index = IMX355_LINK_FREQ_INDEX, 1055df0b5c4aSBingbu Cao .reg_list = { 1056df0b5c4aSBingbu Cao .num_of_regs = ARRAY_SIZE(mode_820x616_regs), 1057df0b5c4aSBingbu Cao .regs = mode_820x616_regs, 1058df0b5c4aSBingbu Cao }, 1059df0b5c4aSBingbu Cao }, 1060df0b5c4aSBingbu Cao }; 1061df0b5c4aSBingbu Cao 1062df0b5c4aSBingbu Cao static inline struct imx355 *to_imx355(struct v4l2_subdev *_sd) 1063df0b5c4aSBingbu Cao { 1064df0b5c4aSBingbu Cao return container_of(_sd, struct imx355, sd); 1065df0b5c4aSBingbu Cao } 1066df0b5c4aSBingbu Cao 1067df0b5c4aSBingbu Cao /* Get bayer order based on flip setting. */ 1068df0b5c4aSBingbu Cao static u32 imx355_get_format_code(struct imx355 *imx355) 1069df0b5c4aSBingbu Cao { 1070df0b5c4aSBingbu Cao /* 1071df0b5c4aSBingbu Cao * Only one bayer order is supported. 1072df0b5c4aSBingbu Cao * It depends on the flip settings. 1073df0b5c4aSBingbu Cao */ 1074df0b5c4aSBingbu Cao u32 code; 1075df0b5c4aSBingbu Cao static const u32 codes[2][2] = { 1076df0b5c4aSBingbu Cao { MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SGRBG10_1X10, }, 1077df0b5c4aSBingbu Cao { MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SBGGR10_1X10, }, 1078df0b5c4aSBingbu Cao }; 1079df0b5c4aSBingbu Cao 1080df0b5c4aSBingbu Cao lockdep_assert_held(&imx355->mutex); 1081df0b5c4aSBingbu Cao code = codes[imx355->vflip->val][imx355->hflip->val]; 1082df0b5c4aSBingbu Cao 1083df0b5c4aSBingbu Cao return code; 1084df0b5c4aSBingbu Cao } 1085df0b5c4aSBingbu Cao 1086df0b5c4aSBingbu Cao /* Read registers up to 4 at a time */ 1087df0b5c4aSBingbu Cao static int imx355_read_reg(struct imx355 *imx355, u16 reg, u32 len, u32 *val) 1088df0b5c4aSBingbu Cao { 1089df0b5c4aSBingbu Cao struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd); 1090df0b5c4aSBingbu Cao struct i2c_msg msgs[2]; 1091df0b5c4aSBingbu Cao u8 addr_buf[2]; 1092df0b5c4aSBingbu Cao u8 data_buf[4] = { 0 }; 1093df0b5c4aSBingbu Cao int ret; 1094df0b5c4aSBingbu Cao 1095df0b5c4aSBingbu Cao if (len > 4) 1096df0b5c4aSBingbu Cao return -EINVAL; 1097df0b5c4aSBingbu Cao 1098df0b5c4aSBingbu Cao put_unaligned_be16(reg, addr_buf); 1099df0b5c4aSBingbu Cao /* Write register address */ 1100df0b5c4aSBingbu Cao msgs[0].addr = client->addr; 1101df0b5c4aSBingbu Cao msgs[0].flags = 0; 1102df0b5c4aSBingbu Cao msgs[0].len = ARRAY_SIZE(addr_buf); 1103df0b5c4aSBingbu Cao msgs[0].buf = addr_buf; 1104df0b5c4aSBingbu Cao 1105df0b5c4aSBingbu Cao /* Read data from register */ 1106df0b5c4aSBingbu Cao msgs[1].addr = client->addr; 1107df0b5c4aSBingbu Cao msgs[1].flags = I2C_M_RD; 1108df0b5c4aSBingbu Cao msgs[1].len = len; 1109df0b5c4aSBingbu Cao msgs[1].buf = &data_buf[4 - len]; 1110df0b5c4aSBingbu Cao 1111df0b5c4aSBingbu Cao ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 1112df0b5c4aSBingbu Cao if (ret != ARRAY_SIZE(msgs)) 1113df0b5c4aSBingbu Cao return -EIO; 1114df0b5c4aSBingbu Cao 1115df0b5c4aSBingbu Cao *val = get_unaligned_be32(data_buf); 1116df0b5c4aSBingbu Cao 1117df0b5c4aSBingbu Cao return 0; 1118df0b5c4aSBingbu Cao } 1119df0b5c4aSBingbu Cao 1120df0b5c4aSBingbu Cao /* Write registers up to 4 at a time */ 1121df0b5c4aSBingbu Cao static int imx355_write_reg(struct imx355 *imx355, u16 reg, u32 len, u32 val) 1122df0b5c4aSBingbu Cao { 1123df0b5c4aSBingbu Cao struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd); 1124df0b5c4aSBingbu Cao u8 buf[6]; 1125df0b5c4aSBingbu Cao 1126df0b5c4aSBingbu Cao if (len > 4) 1127df0b5c4aSBingbu Cao return -EINVAL; 1128df0b5c4aSBingbu Cao 1129df0b5c4aSBingbu Cao put_unaligned_be16(reg, buf); 1130df0b5c4aSBingbu Cao put_unaligned_be32(val << (8 * (4 - len)), buf + 2); 1131df0b5c4aSBingbu Cao if (i2c_master_send(client, buf, len + 2) != len + 2) 1132df0b5c4aSBingbu Cao return -EIO; 1133df0b5c4aSBingbu Cao 1134df0b5c4aSBingbu Cao return 0; 1135df0b5c4aSBingbu Cao } 1136df0b5c4aSBingbu Cao 1137df0b5c4aSBingbu Cao /* Write a list of registers */ 1138df0b5c4aSBingbu Cao static int imx355_write_regs(struct imx355 *imx355, 1139df0b5c4aSBingbu Cao const struct imx355_reg *regs, u32 len) 1140df0b5c4aSBingbu Cao { 1141df0b5c4aSBingbu Cao struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd); 1142df0b5c4aSBingbu Cao int ret; 1143df0b5c4aSBingbu Cao u32 i; 1144df0b5c4aSBingbu Cao 1145df0b5c4aSBingbu Cao for (i = 0; i < len; i++) { 1146df0b5c4aSBingbu Cao ret = imx355_write_reg(imx355, regs[i].address, 1, regs[i].val); 1147df0b5c4aSBingbu Cao if (ret) { 1148df0b5c4aSBingbu Cao dev_err_ratelimited(&client->dev, 1149df0b5c4aSBingbu Cao "write reg 0x%4.4x return err %d", 1150df0b5c4aSBingbu Cao regs[i].address, ret); 1151df0b5c4aSBingbu Cao 1152df0b5c4aSBingbu Cao return ret; 1153df0b5c4aSBingbu Cao } 1154df0b5c4aSBingbu Cao } 1155df0b5c4aSBingbu Cao 1156df0b5c4aSBingbu Cao return 0; 1157df0b5c4aSBingbu Cao } 1158df0b5c4aSBingbu Cao 1159df0b5c4aSBingbu Cao /* Open sub-device */ 1160df0b5c4aSBingbu Cao static int imx355_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) 1161df0b5c4aSBingbu Cao { 1162df0b5c4aSBingbu Cao struct imx355 *imx355 = to_imx355(sd); 1163df0b5c4aSBingbu Cao struct v4l2_mbus_framefmt *try_fmt = 11640d346d2aSTomi Valkeinen v4l2_subdev_get_try_format(sd, fh->state, 0); 1165df0b5c4aSBingbu Cao 1166df0b5c4aSBingbu Cao mutex_lock(&imx355->mutex); 1167df0b5c4aSBingbu Cao 1168df0b5c4aSBingbu Cao /* Initialize try_fmt */ 1169df0b5c4aSBingbu Cao try_fmt->width = imx355->cur_mode->width; 1170df0b5c4aSBingbu Cao try_fmt->height = imx355->cur_mode->height; 1171df0b5c4aSBingbu Cao try_fmt->code = imx355_get_format_code(imx355); 1172df0b5c4aSBingbu Cao try_fmt->field = V4L2_FIELD_NONE; 1173df0b5c4aSBingbu Cao 1174df0b5c4aSBingbu Cao mutex_unlock(&imx355->mutex); 1175df0b5c4aSBingbu Cao 1176df0b5c4aSBingbu Cao return 0; 1177df0b5c4aSBingbu Cao } 1178df0b5c4aSBingbu Cao 1179df0b5c4aSBingbu Cao static int imx355_set_ctrl(struct v4l2_ctrl *ctrl) 1180df0b5c4aSBingbu Cao { 1181df0b5c4aSBingbu Cao struct imx355 *imx355 = container_of(ctrl->handler, 1182df0b5c4aSBingbu Cao struct imx355, ctrl_handler); 1183df0b5c4aSBingbu Cao struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd); 1184df0b5c4aSBingbu Cao s64 max; 1185df0b5c4aSBingbu Cao int ret; 1186df0b5c4aSBingbu Cao 1187df0b5c4aSBingbu Cao /* Propagate change of current control to all related controls */ 1188df0b5c4aSBingbu Cao switch (ctrl->id) { 1189df0b5c4aSBingbu Cao case V4L2_CID_VBLANK: 1190df0b5c4aSBingbu Cao /* Update max exposure while meeting expected vblanking */ 1191df0b5c4aSBingbu Cao max = imx355->cur_mode->height + ctrl->val - 10; 1192df0b5c4aSBingbu Cao __v4l2_ctrl_modify_range(imx355->exposure, 1193df0b5c4aSBingbu Cao imx355->exposure->minimum, 1194df0b5c4aSBingbu Cao max, imx355->exposure->step, max); 1195df0b5c4aSBingbu Cao break; 1196df0b5c4aSBingbu Cao } 1197df0b5c4aSBingbu Cao 1198df0b5c4aSBingbu Cao /* 1199df0b5c4aSBingbu Cao * Applying V4L2 control value only happens 1200df0b5c4aSBingbu Cao * when power is up for streaming 1201df0b5c4aSBingbu Cao */ 1202df0b5c4aSBingbu Cao if (!pm_runtime_get_if_in_use(&client->dev)) 1203df0b5c4aSBingbu Cao return 0; 1204df0b5c4aSBingbu Cao 1205df0b5c4aSBingbu Cao switch (ctrl->id) { 1206df0b5c4aSBingbu Cao case V4L2_CID_ANALOGUE_GAIN: 1207df0b5c4aSBingbu Cao /* Analog gain = 1024/(1024 - ctrl->val) times */ 1208df0b5c4aSBingbu Cao ret = imx355_write_reg(imx355, IMX355_REG_ANALOG_GAIN, 2, 1209df0b5c4aSBingbu Cao ctrl->val); 1210df0b5c4aSBingbu Cao break; 1211df0b5c4aSBingbu Cao case V4L2_CID_DIGITAL_GAIN: 1212df0b5c4aSBingbu Cao ret = imx355_write_reg(imx355, IMX355_REG_DIG_GAIN_GLOBAL, 2, 1213df0b5c4aSBingbu Cao ctrl->val); 1214df0b5c4aSBingbu Cao break; 1215df0b5c4aSBingbu Cao case V4L2_CID_EXPOSURE: 1216df0b5c4aSBingbu Cao ret = imx355_write_reg(imx355, IMX355_REG_EXPOSURE, 2, 1217df0b5c4aSBingbu Cao ctrl->val); 1218df0b5c4aSBingbu Cao break; 1219df0b5c4aSBingbu Cao case V4L2_CID_VBLANK: 1220df0b5c4aSBingbu Cao /* Update FLL that meets expected vertical blanking */ 1221df0b5c4aSBingbu Cao ret = imx355_write_reg(imx355, IMX355_REG_FLL, 2, 1222df0b5c4aSBingbu Cao imx355->cur_mode->height + ctrl->val); 1223df0b5c4aSBingbu Cao break; 1224df0b5c4aSBingbu Cao case V4L2_CID_TEST_PATTERN: 1225df0b5c4aSBingbu Cao ret = imx355_write_reg(imx355, IMX355_REG_TEST_PATTERN, 1226df0b5c4aSBingbu Cao 2, ctrl->val); 1227df0b5c4aSBingbu Cao break; 1228df0b5c4aSBingbu Cao case V4L2_CID_HFLIP: 1229df0b5c4aSBingbu Cao case V4L2_CID_VFLIP: 1230df0b5c4aSBingbu Cao ret = imx355_write_reg(imx355, IMX355_REG_ORIENTATION, 1, 1231df0b5c4aSBingbu Cao imx355->hflip->val | 1232df0b5c4aSBingbu Cao imx355->vflip->val << 1); 1233df0b5c4aSBingbu Cao break; 1234df0b5c4aSBingbu Cao default: 1235df0b5c4aSBingbu Cao ret = -EINVAL; 1236df0b5c4aSBingbu Cao dev_info(&client->dev, "ctrl(id:0x%x,val:0x%x) is not handled", 1237df0b5c4aSBingbu Cao ctrl->id, ctrl->val); 1238df0b5c4aSBingbu Cao break; 1239df0b5c4aSBingbu Cao } 1240df0b5c4aSBingbu Cao 1241df0b5c4aSBingbu Cao pm_runtime_put(&client->dev); 1242df0b5c4aSBingbu Cao 1243df0b5c4aSBingbu Cao return ret; 1244df0b5c4aSBingbu Cao } 1245df0b5c4aSBingbu Cao 1246df0b5c4aSBingbu Cao static const struct v4l2_ctrl_ops imx355_ctrl_ops = { 1247df0b5c4aSBingbu Cao .s_ctrl = imx355_set_ctrl, 1248df0b5c4aSBingbu Cao }; 1249df0b5c4aSBingbu Cao 1250df0b5c4aSBingbu Cao static int imx355_enum_mbus_code(struct v4l2_subdev *sd, 12510d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 1252df0b5c4aSBingbu Cao struct v4l2_subdev_mbus_code_enum *code) 1253df0b5c4aSBingbu Cao { 1254df0b5c4aSBingbu Cao struct imx355 *imx355 = to_imx355(sd); 1255df0b5c4aSBingbu Cao 1256df0b5c4aSBingbu Cao if (code->index > 0) 1257df0b5c4aSBingbu Cao return -EINVAL; 1258df0b5c4aSBingbu Cao 1259df0b5c4aSBingbu Cao mutex_lock(&imx355->mutex); 1260df0b5c4aSBingbu Cao code->code = imx355_get_format_code(imx355); 1261df0b5c4aSBingbu Cao mutex_unlock(&imx355->mutex); 1262df0b5c4aSBingbu Cao 1263df0b5c4aSBingbu Cao return 0; 1264df0b5c4aSBingbu Cao } 1265df0b5c4aSBingbu Cao 1266df0b5c4aSBingbu Cao static int imx355_enum_frame_size(struct v4l2_subdev *sd, 12670d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 1268df0b5c4aSBingbu Cao struct v4l2_subdev_frame_size_enum *fse) 1269df0b5c4aSBingbu Cao { 1270df0b5c4aSBingbu Cao struct imx355 *imx355 = to_imx355(sd); 1271df0b5c4aSBingbu Cao 1272df0b5c4aSBingbu Cao if (fse->index >= ARRAY_SIZE(supported_modes)) 1273df0b5c4aSBingbu Cao return -EINVAL; 1274df0b5c4aSBingbu Cao 1275df0b5c4aSBingbu Cao mutex_lock(&imx355->mutex); 1276df0b5c4aSBingbu Cao if (fse->code != imx355_get_format_code(imx355)) { 1277df0b5c4aSBingbu Cao mutex_unlock(&imx355->mutex); 1278df0b5c4aSBingbu Cao return -EINVAL; 1279df0b5c4aSBingbu Cao } 1280df0b5c4aSBingbu Cao mutex_unlock(&imx355->mutex); 1281df0b5c4aSBingbu Cao 1282df0b5c4aSBingbu Cao fse->min_width = supported_modes[fse->index].width; 1283df0b5c4aSBingbu Cao fse->max_width = fse->min_width; 1284df0b5c4aSBingbu Cao fse->min_height = supported_modes[fse->index].height; 1285df0b5c4aSBingbu Cao fse->max_height = fse->min_height; 1286df0b5c4aSBingbu Cao 1287df0b5c4aSBingbu Cao return 0; 1288df0b5c4aSBingbu Cao } 1289df0b5c4aSBingbu Cao 1290df0b5c4aSBingbu Cao static void imx355_update_pad_format(struct imx355 *imx355, 1291df0b5c4aSBingbu Cao const struct imx355_mode *mode, 1292df0b5c4aSBingbu Cao struct v4l2_subdev_format *fmt) 1293df0b5c4aSBingbu Cao { 1294df0b5c4aSBingbu Cao fmt->format.width = mode->width; 1295df0b5c4aSBingbu Cao fmt->format.height = mode->height; 1296df0b5c4aSBingbu Cao fmt->format.code = imx355_get_format_code(imx355); 1297df0b5c4aSBingbu Cao fmt->format.field = V4L2_FIELD_NONE; 1298df0b5c4aSBingbu Cao } 1299df0b5c4aSBingbu Cao 1300df0b5c4aSBingbu Cao static int imx355_do_get_pad_format(struct imx355 *imx355, 13010d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 1302df0b5c4aSBingbu Cao struct v4l2_subdev_format *fmt) 1303df0b5c4aSBingbu Cao { 1304df0b5c4aSBingbu Cao struct v4l2_mbus_framefmt *framefmt; 1305df0b5c4aSBingbu Cao struct v4l2_subdev *sd = &imx355->sd; 1306df0b5c4aSBingbu Cao 1307df0b5c4aSBingbu Cao if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { 13080d346d2aSTomi Valkeinen framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); 1309df0b5c4aSBingbu Cao fmt->format = *framefmt; 1310df0b5c4aSBingbu Cao } else { 1311df0b5c4aSBingbu Cao imx355_update_pad_format(imx355, imx355->cur_mode, fmt); 1312df0b5c4aSBingbu Cao } 1313df0b5c4aSBingbu Cao 1314df0b5c4aSBingbu Cao return 0; 1315df0b5c4aSBingbu Cao } 1316df0b5c4aSBingbu Cao 1317df0b5c4aSBingbu Cao static int imx355_get_pad_format(struct v4l2_subdev *sd, 13180d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 1319df0b5c4aSBingbu Cao struct v4l2_subdev_format *fmt) 1320df0b5c4aSBingbu Cao { 1321df0b5c4aSBingbu Cao struct imx355 *imx355 = to_imx355(sd); 1322df0b5c4aSBingbu Cao int ret; 1323df0b5c4aSBingbu Cao 1324df0b5c4aSBingbu Cao mutex_lock(&imx355->mutex); 13250d346d2aSTomi Valkeinen ret = imx355_do_get_pad_format(imx355, sd_state, fmt); 1326df0b5c4aSBingbu Cao mutex_unlock(&imx355->mutex); 1327df0b5c4aSBingbu Cao 1328df0b5c4aSBingbu Cao return ret; 1329df0b5c4aSBingbu Cao } 1330df0b5c4aSBingbu Cao 1331df0b5c4aSBingbu Cao static int 1332df0b5c4aSBingbu Cao imx355_set_pad_format(struct v4l2_subdev *sd, 13330d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 1334df0b5c4aSBingbu Cao struct v4l2_subdev_format *fmt) 1335df0b5c4aSBingbu Cao { 1336df0b5c4aSBingbu Cao struct imx355 *imx355 = to_imx355(sd); 1337df0b5c4aSBingbu Cao const struct imx355_mode *mode; 1338df0b5c4aSBingbu Cao struct v4l2_mbus_framefmt *framefmt; 1339df0b5c4aSBingbu Cao s32 vblank_def; 1340df0b5c4aSBingbu Cao s32 vblank_min; 1341df0b5c4aSBingbu Cao s64 h_blank; 1342df0b5c4aSBingbu Cao u64 pixel_rate; 1343df0b5c4aSBingbu Cao u32 height; 1344df0b5c4aSBingbu Cao 1345df0b5c4aSBingbu Cao mutex_lock(&imx355->mutex); 1346df0b5c4aSBingbu Cao 1347df0b5c4aSBingbu Cao /* 1348df0b5c4aSBingbu Cao * Only one bayer order is supported. 1349df0b5c4aSBingbu Cao * It depends on the flip settings. 1350df0b5c4aSBingbu Cao */ 1351df0b5c4aSBingbu Cao fmt->format.code = imx355_get_format_code(imx355); 1352df0b5c4aSBingbu Cao 1353df0b5c4aSBingbu Cao mode = v4l2_find_nearest_size(supported_modes, 1354df0b5c4aSBingbu Cao ARRAY_SIZE(supported_modes), 1355df0b5c4aSBingbu Cao width, height, 1356df0b5c4aSBingbu Cao fmt->format.width, fmt->format.height); 1357df0b5c4aSBingbu Cao imx355_update_pad_format(imx355, mode, fmt); 1358df0b5c4aSBingbu Cao if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { 13590d346d2aSTomi Valkeinen framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); 1360df0b5c4aSBingbu Cao *framefmt = fmt->format; 1361df0b5c4aSBingbu Cao } else { 1362df0b5c4aSBingbu Cao imx355->cur_mode = mode; 1363df0b5c4aSBingbu Cao pixel_rate = imx355->link_def_freq * 2 * 4; 1364df0b5c4aSBingbu Cao do_div(pixel_rate, 10); 1365df0b5c4aSBingbu Cao __v4l2_ctrl_s_ctrl_int64(imx355->pixel_rate, pixel_rate); 1366df0b5c4aSBingbu Cao /* Update limits and set FPS to default */ 1367df0b5c4aSBingbu Cao height = imx355->cur_mode->height; 1368df0b5c4aSBingbu Cao vblank_def = imx355->cur_mode->fll_def - height; 1369df0b5c4aSBingbu Cao vblank_min = imx355->cur_mode->fll_min - height; 1370df0b5c4aSBingbu Cao height = IMX355_FLL_MAX - height; 1371df0b5c4aSBingbu Cao __v4l2_ctrl_modify_range(imx355->vblank, vblank_min, height, 1, 1372df0b5c4aSBingbu Cao vblank_def); 1373df0b5c4aSBingbu Cao __v4l2_ctrl_s_ctrl(imx355->vblank, vblank_def); 1374df0b5c4aSBingbu Cao h_blank = mode->llp - imx355->cur_mode->width; 1375df0b5c4aSBingbu Cao /* 1376df0b5c4aSBingbu Cao * Currently hblank is not changeable. 1377df0b5c4aSBingbu Cao * So FPS control is done only by vblank. 1378df0b5c4aSBingbu Cao */ 1379df0b5c4aSBingbu Cao __v4l2_ctrl_modify_range(imx355->hblank, h_blank, 1380df0b5c4aSBingbu Cao h_blank, 1, h_blank); 1381df0b5c4aSBingbu Cao } 1382df0b5c4aSBingbu Cao 1383df0b5c4aSBingbu Cao mutex_unlock(&imx355->mutex); 1384df0b5c4aSBingbu Cao 1385df0b5c4aSBingbu Cao return 0; 1386df0b5c4aSBingbu Cao } 1387df0b5c4aSBingbu Cao 1388df0b5c4aSBingbu Cao /* Start streaming */ 1389df0b5c4aSBingbu Cao static int imx355_start_streaming(struct imx355 *imx355) 1390df0b5c4aSBingbu Cao { 1391df0b5c4aSBingbu Cao struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd); 1392df0b5c4aSBingbu Cao const struct imx355_reg_list *reg_list; 1393df0b5c4aSBingbu Cao int ret; 1394df0b5c4aSBingbu Cao 1395df0b5c4aSBingbu Cao /* Global Setting */ 1396df0b5c4aSBingbu Cao reg_list = &imx355_global_setting; 1397df0b5c4aSBingbu Cao ret = imx355_write_regs(imx355, reg_list->regs, reg_list->num_of_regs); 1398df0b5c4aSBingbu Cao if (ret) { 1399df0b5c4aSBingbu Cao dev_err(&client->dev, "failed to set global settings"); 1400df0b5c4aSBingbu Cao return ret; 1401df0b5c4aSBingbu Cao } 1402df0b5c4aSBingbu Cao 1403df0b5c4aSBingbu Cao /* Apply default values of current mode */ 1404df0b5c4aSBingbu Cao reg_list = &imx355->cur_mode->reg_list; 1405df0b5c4aSBingbu Cao ret = imx355_write_regs(imx355, reg_list->regs, reg_list->num_of_regs); 1406df0b5c4aSBingbu Cao if (ret) { 1407df0b5c4aSBingbu Cao dev_err(&client->dev, "failed to set mode"); 1408df0b5c4aSBingbu Cao return ret; 1409df0b5c4aSBingbu Cao } 1410df0b5c4aSBingbu Cao 1411df0b5c4aSBingbu Cao /* set digital gain control to all color mode */ 1412df0b5c4aSBingbu Cao ret = imx355_write_reg(imx355, IMX355_REG_DPGA_USE_GLOBAL_GAIN, 1, 1); 1413df0b5c4aSBingbu Cao if (ret) 1414df0b5c4aSBingbu Cao return ret; 1415df0b5c4aSBingbu Cao 1416df0b5c4aSBingbu Cao /* Apply customized values from user */ 1417df0b5c4aSBingbu Cao ret = __v4l2_ctrl_handler_setup(imx355->sd.ctrl_handler); 1418df0b5c4aSBingbu Cao if (ret) 1419df0b5c4aSBingbu Cao return ret; 1420df0b5c4aSBingbu Cao 1421df0b5c4aSBingbu Cao return imx355_write_reg(imx355, IMX355_REG_MODE_SELECT, 1422df0b5c4aSBingbu Cao 1, IMX355_MODE_STREAMING); 1423df0b5c4aSBingbu Cao } 1424df0b5c4aSBingbu Cao 1425df0b5c4aSBingbu Cao /* Stop streaming */ 1426df0b5c4aSBingbu Cao static int imx355_stop_streaming(struct imx355 *imx355) 1427df0b5c4aSBingbu Cao { 1428df0b5c4aSBingbu Cao return imx355_write_reg(imx355, IMX355_REG_MODE_SELECT, 1429df0b5c4aSBingbu Cao 1, IMX355_MODE_STANDBY); 1430df0b5c4aSBingbu Cao } 1431df0b5c4aSBingbu Cao 1432df0b5c4aSBingbu Cao static int imx355_set_stream(struct v4l2_subdev *sd, int enable) 1433df0b5c4aSBingbu Cao { 1434df0b5c4aSBingbu Cao struct imx355 *imx355 = to_imx355(sd); 1435df0b5c4aSBingbu Cao struct i2c_client *client = v4l2_get_subdevdata(sd); 1436df0b5c4aSBingbu Cao int ret = 0; 1437df0b5c4aSBingbu Cao 1438df0b5c4aSBingbu Cao mutex_lock(&imx355->mutex); 1439df0b5c4aSBingbu Cao if (imx355->streaming == enable) { 1440df0b5c4aSBingbu Cao mutex_unlock(&imx355->mutex); 1441df0b5c4aSBingbu Cao return 0; 1442df0b5c4aSBingbu Cao } 1443df0b5c4aSBingbu Cao 1444df0b5c4aSBingbu Cao if (enable) { 14455f070f4dSMauro Carvalho Chehab ret = pm_runtime_resume_and_get(&client->dev); 14465f070f4dSMauro Carvalho Chehab if (ret < 0) 1447df0b5c4aSBingbu Cao goto err_unlock; 1448df0b5c4aSBingbu Cao 1449df0b5c4aSBingbu Cao /* 1450df0b5c4aSBingbu Cao * Apply default & customized values 1451df0b5c4aSBingbu Cao * and then start streaming. 1452df0b5c4aSBingbu Cao */ 1453df0b5c4aSBingbu Cao ret = imx355_start_streaming(imx355); 1454df0b5c4aSBingbu Cao if (ret) 1455df0b5c4aSBingbu Cao goto err_rpm_put; 1456df0b5c4aSBingbu Cao } else { 1457df0b5c4aSBingbu Cao imx355_stop_streaming(imx355); 1458df0b5c4aSBingbu Cao pm_runtime_put(&client->dev); 1459df0b5c4aSBingbu Cao } 1460df0b5c4aSBingbu Cao 1461df0b5c4aSBingbu Cao imx355->streaming = enable; 1462df0b5c4aSBingbu Cao 1463df0b5c4aSBingbu Cao /* vflip and hflip cannot change during streaming */ 1464df0b5c4aSBingbu Cao __v4l2_ctrl_grab(imx355->vflip, enable); 1465df0b5c4aSBingbu Cao __v4l2_ctrl_grab(imx355->hflip, enable); 1466df0b5c4aSBingbu Cao 1467df0b5c4aSBingbu Cao mutex_unlock(&imx355->mutex); 1468df0b5c4aSBingbu Cao 1469df0b5c4aSBingbu Cao return ret; 1470df0b5c4aSBingbu Cao 1471df0b5c4aSBingbu Cao err_rpm_put: 1472df0b5c4aSBingbu Cao pm_runtime_put(&client->dev); 1473df0b5c4aSBingbu Cao err_unlock: 1474df0b5c4aSBingbu Cao mutex_unlock(&imx355->mutex); 1475df0b5c4aSBingbu Cao 1476df0b5c4aSBingbu Cao return ret; 1477df0b5c4aSBingbu Cao } 1478df0b5c4aSBingbu Cao 1479df0b5c4aSBingbu Cao static int __maybe_unused imx355_suspend(struct device *dev) 1480df0b5c4aSBingbu Cao { 1481be0b9b63SKrzysztof Kozlowski struct v4l2_subdev *sd = dev_get_drvdata(dev); 1482df0b5c4aSBingbu Cao struct imx355 *imx355 = to_imx355(sd); 1483df0b5c4aSBingbu Cao 1484df0b5c4aSBingbu Cao if (imx355->streaming) 1485df0b5c4aSBingbu Cao imx355_stop_streaming(imx355); 1486df0b5c4aSBingbu Cao 1487df0b5c4aSBingbu Cao return 0; 1488df0b5c4aSBingbu Cao } 1489df0b5c4aSBingbu Cao 1490df0b5c4aSBingbu Cao static int __maybe_unused imx355_resume(struct device *dev) 1491df0b5c4aSBingbu Cao { 1492be0b9b63SKrzysztof Kozlowski struct v4l2_subdev *sd = dev_get_drvdata(dev); 1493df0b5c4aSBingbu Cao struct imx355 *imx355 = to_imx355(sd); 1494df0b5c4aSBingbu Cao int ret; 1495df0b5c4aSBingbu Cao 1496df0b5c4aSBingbu Cao if (imx355->streaming) { 1497df0b5c4aSBingbu Cao ret = imx355_start_streaming(imx355); 1498df0b5c4aSBingbu Cao if (ret) 1499df0b5c4aSBingbu Cao goto error; 1500df0b5c4aSBingbu Cao } 1501df0b5c4aSBingbu Cao 1502df0b5c4aSBingbu Cao return 0; 1503df0b5c4aSBingbu Cao 1504df0b5c4aSBingbu Cao error: 1505df0b5c4aSBingbu Cao imx355_stop_streaming(imx355); 1506df0b5c4aSBingbu Cao imx355->streaming = 0; 1507df0b5c4aSBingbu Cao return ret; 1508df0b5c4aSBingbu Cao } 1509df0b5c4aSBingbu Cao 1510df0b5c4aSBingbu Cao /* Verify chip ID */ 1511df0b5c4aSBingbu Cao static int imx355_identify_module(struct imx355 *imx355) 1512df0b5c4aSBingbu Cao { 1513df0b5c4aSBingbu Cao struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd); 1514df0b5c4aSBingbu Cao int ret; 1515df0b5c4aSBingbu Cao u32 val; 1516df0b5c4aSBingbu Cao 1517df0b5c4aSBingbu Cao ret = imx355_read_reg(imx355, IMX355_REG_CHIP_ID, 2, &val); 1518df0b5c4aSBingbu Cao if (ret) 1519df0b5c4aSBingbu Cao return ret; 1520df0b5c4aSBingbu Cao 1521df0b5c4aSBingbu Cao if (val != IMX355_CHIP_ID) { 1522df0b5c4aSBingbu Cao dev_err(&client->dev, "chip id mismatch: %x!=%x", 1523df0b5c4aSBingbu Cao IMX355_CHIP_ID, val); 1524df0b5c4aSBingbu Cao return -EIO; 1525df0b5c4aSBingbu Cao } 1526df0b5c4aSBingbu Cao return 0; 1527df0b5c4aSBingbu Cao } 1528df0b5c4aSBingbu Cao 1529df0b5c4aSBingbu Cao static const struct v4l2_subdev_core_ops imx355_subdev_core_ops = { 1530df0b5c4aSBingbu Cao .subscribe_event = v4l2_ctrl_subdev_subscribe_event, 1531df0b5c4aSBingbu Cao .unsubscribe_event = v4l2_event_subdev_unsubscribe, 1532df0b5c4aSBingbu Cao }; 1533df0b5c4aSBingbu Cao 1534df0b5c4aSBingbu Cao static const struct v4l2_subdev_video_ops imx355_video_ops = { 1535df0b5c4aSBingbu Cao .s_stream = imx355_set_stream, 1536df0b5c4aSBingbu Cao }; 1537df0b5c4aSBingbu Cao 1538df0b5c4aSBingbu Cao static const struct v4l2_subdev_pad_ops imx355_pad_ops = { 1539df0b5c4aSBingbu Cao .enum_mbus_code = imx355_enum_mbus_code, 1540df0b5c4aSBingbu Cao .get_fmt = imx355_get_pad_format, 1541df0b5c4aSBingbu Cao .set_fmt = imx355_set_pad_format, 1542df0b5c4aSBingbu Cao .enum_frame_size = imx355_enum_frame_size, 1543df0b5c4aSBingbu Cao }; 1544df0b5c4aSBingbu Cao 1545df0b5c4aSBingbu Cao static const struct v4l2_subdev_ops imx355_subdev_ops = { 1546df0b5c4aSBingbu Cao .core = &imx355_subdev_core_ops, 1547df0b5c4aSBingbu Cao .video = &imx355_video_ops, 1548df0b5c4aSBingbu Cao .pad = &imx355_pad_ops, 1549df0b5c4aSBingbu Cao }; 1550df0b5c4aSBingbu Cao 1551df0b5c4aSBingbu Cao static const struct media_entity_operations imx355_subdev_entity_ops = { 1552df0b5c4aSBingbu Cao .link_validate = v4l2_subdev_link_validate, 1553df0b5c4aSBingbu Cao }; 1554df0b5c4aSBingbu Cao 1555df0b5c4aSBingbu Cao static const struct v4l2_subdev_internal_ops imx355_internal_ops = { 1556df0b5c4aSBingbu Cao .open = imx355_open, 1557df0b5c4aSBingbu Cao }; 1558df0b5c4aSBingbu Cao 1559df0b5c4aSBingbu Cao /* Initialize control handlers */ 1560df0b5c4aSBingbu Cao static int imx355_init_controls(struct imx355 *imx355) 1561df0b5c4aSBingbu Cao { 1562df0b5c4aSBingbu Cao struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd); 1563df0b5c4aSBingbu Cao struct v4l2_ctrl_handler *ctrl_hdlr; 1564df0b5c4aSBingbu Cao s64 exposure_max; 1565df0b5c4aSBingbu Cao s64 vblank_def; 1566df0b5c4aSBingbu Cao s64 vblank_min; 1567df0b5c4aSBingbu Cao s64 hblank; 1568df0b5c4aSBingbu Cao u64 pixel_rate; 1569df0b5c4aSBingbu Cao const struct imx355_mode *mode; 1570df0b5c4aSBingbu Cao u32 max; 1571df0b5c4aSBingbu Cao int ret; 1572df0b5c4aSBingbu Cao 1573df0b5c4aSBingbu Cao ctrl_hdlr = &imx355->ctrl_handler; 1574df0b5c4aSBingbu Cao ret = v4l2_ctrl_handler_init(ctrl_hdlr, 10); 1575df0b5c4aSBingbu Cao if (ret) 1576df0b5c4aSBingbu Cao return ret; 1577df0b5c4aSBingbu Cao 1578df0b5c4aSBingbu Cao ctrl_hdlr->lock = &imx355->mutex; 1579df0b5c4aSBingbu Cao max = ARRAY_SIZE(link_freq_menu_items) - 1; 1580df0b5c4aSBingbu Cao imx355->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx355_ctrl_ops, 1581df0b5c4aSBingbu Cao V4L2_CID_LINK_FREQ, max, 0, 1582df0b5c4aSBingbu Cao link_freq_menu_items); 1583df0b5c4aSBingbu Cao if (imx355->link_freq) 1584df0b5c4aSBingbu Cao imx355->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; 1585df0b5c4aSBingbu Cao 1586df0b5c4aSBingbu Cao /* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ 1587df0b5c4aSBingbu Cao pixel_rate = imx355->link_def_freq * 2 * 4; 1588df0b5c4aSBingbu Cao do_div(pixel_rate, 10); 1589df0b5c4aSBingbu Cao /* By default, PIXEL_RATE is read only */ 1590df0b5c4aSBingbu Cao imx355->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, 1591df0b5c4aSBingbu Cao V4L2_CID_PIXEL_RATE, pixel_rate, 1592df0b5c4aSBingbu Cao pixel_rate, 1, pixel_rate); 1593df0b5c4aSBingbu Cao 1594df0b5c4aSBingbu Cao /* Initialize vblank/hblank/exposure parameters based on current mode */ 1595df0b5c4aSBingbu Cao mode = imx355->cur_mode; 1596df0b5c4aSBingbu Cao vblank_def = mode->fll_def - mode->height; 1597df0b5c4aSBingbu Cao vblank_min = mode->fll_min - mode->height; 1598df0b5c4aSBingbu Cao imx355->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, 1599df0b5c4aSBingbu Cao V4L2_CID_VBLANK, vblank_min, 1600df0b5c4aSBingbu Cao IMX355_FLL_MAX - mode->height, 1601df0b5c4aSBingbu Cao 1, vblank_def); 1602df0b5c4aSBingbu Cao 1603df0b5c4aSBingbu Cao hblank = mode->llp - mode->width; 1604df0b5c4aSBingbu Cao imx355->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, 1605df0b5c4aSBingbu Cao V4L2_CID_HBLANK, hblank, hblank, 1606df0b5c4aSBingbu Cao 1, hblank); 1607df0b5c4aSBingbu Cao if (imx355->hblank) 1608df0b5c4aSBingbu Cao imx355->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; 1609df0b5c4aSBingbu Cao 1610df0b5c4aSBingbu Cao /* fll >= exposure time + adjust parameter (default value is 10) */ 1611df0b5c4aSBingbu Cao exposure_max = mode->fll_def - 10; 1612df0b5c4aSBingbu Cao imx355->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, 1613df0b5c4aSBingbu Cao V4L2_CID_EXPOSURE, 1614df0b5c4aSBingbu Cao IMX355_EXPOSURE_MIN, exposure_max, 1615df0b5c4aSBingbu Cao IMX355_EXPOSURE_STEP, 1616df0b5c4aSBingbu Cao IMX355_EXPOSURE_DEFAULT); 1617df0b5c4aSBingbu Cao 1618df0b5c4aSBingbu Cao imx355->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, 1619df0b5c4aSBingbu Cao V4L2_CID_HFLIP, 0, 1, 1, 0); 1620*1dc33888SDave Stevenson if (imx355->hflip) 1621*1dc33888SDave Stevenson imx355->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; 1622df0b5c4aSBingbu Cao imx355->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, 1623df0b5c4aSBingbu Cao V4L2_CID_VFLIP, 0, 1, 1, 0); 1624*1dc33888SDave Stevenson if (imx355->vflip) 1625*1dc33888SDave Stevenson imx355->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; 1626df0b5c4aSBingbu Cao 1627df0b5c4aSBingbu Cao v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, 1628df0b5c4aSBingbu Cao IMX355_ANA_GAIN_MIN, IMX355_ANA_GAIN_MAX, 1629df0b5c4aSBingbu Cao IMX355_ANA_GAIN_STEP, IMX355_ANA_GAIN_DEFAULT); 1630df0b5c4aSBingbu Cao 1631df0b5c4aSBingbu Cao /* Digital gain */ 1632df0b5c4aSBingbu Cao v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, V4L2_CID_DIGITAL_GAIN, 1633df0b5c4aSBingbu Cao IMX355_DGTL_GAIN_MIN, IMX355_DGTL_GAIN_MAX, 1634df0b5c4aSBingbu Cao IMX355_DGTL_GAIN_STEP, IMX355_DGTL_GAIN_DEFAULT); 1635df0b5c4aSBingbu Cao 1636df0b5c4aSBingbu Cao v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx355_ctrl_ops, 1637df0b5c4aSBingbu Cao V4L2_CID_TEST_PATTERN, 1638df0b5c4aSBingbu Cao ARRAY_SIZE(imx355_test_pattern_menu) - 1, 1639df0b5c4aSBingbu Cao 0, 0, imx355_test_pattern_menu); 1640df0b5c4aSBingbu Cao if (ctrl_hdlr->error) { 1641df0b5c4aSBingbu Cao ret = ctrl_hdlr->error; 1642df0b5c4aSBingbu Cao dev_err(&client->dev, "control init failed: %d", ret); 1643df0b5c4aSBingbu Cao goto error; 1644df0b5c4aSBingbu Cao } 1645df0b5c4aSBingbu Cao 1646df0b5c4aSBingbu Cao imx355->sd.ctrl_handler = ctrl_hdlr; 1647df0b5c4aSBingbu Cao 1648df0b5c4aSBingbu Cao return 0; 1649df0b5c4aSBingbu Cao 1650df0b5c4aSBingbu Cao error: 1651df0b5c4aSBingbu Cao v4l2_ctrl_handler_free(ctrl_hdlr); 1652df0b5c4aSBingbu Cao 1653df0b5c4aSBingbu Cao return ret; 1654df0b5c4aSBingbu Cao } 1655df0b5c4aSBingbu Cao 1656df0b5c4aSBingbu Cao static struct imx355_hwcfg *imx355_get_hwcfg(struct device *dev) 1657df0b5c4aSBingbu Cao { 1658df0b5c4aSBingbu Cao struct imx355_hwcfg *cfg; 1659df0b5c4aSBingbu Cao struct v4l2_fwnode_endpoint bus_cfg = { 1660df0b5c4aSBingbu Cao .bus_type = V4L2_MBUS_CSI2_DPHY 1661df0b5c4aSBingbu Cao }; 1662df0b5c4aSBingbu Cao struct fwnode_handle *ep; 1663df0b5c4aSBingbu Cao struct fwnode_handle *fwnode = dev_fwnode(dev); 1664df0b5c4aSBingbu Cao unsigned int i; 1665df0b5c4aSBingbu Cao int ret; 1666df0b5c4aSBingbu Cao 1667df0b5c4aSBingbu Cao if (!fwnode) 1668df0b5c4aSBingbu Cao return NULL; 1669df0b5c4aSBingbu Cao 1670df0b5c4aSBingbu Cao ep = fwnode_graph_get_next_endpoint(fwnode, NULL); 1671df0b5c4aSBingbu Cao if (!ep) 1672df0b5c4aSBingbu Cao return NULL; 1673df0b5c4aSBingbu Cao 1674df0b5c4aSBingbu Cao ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); 1675df0b5c4aSBingbu Cao if (ret) 1676df0b5c4aSBingbu Cao goto out_err; 1677df0b5c4aSBingbu Cao 1678df0b5c4aSBingbu Cao cfg = devm_kzalloc(dev, sizeof(*cfg), GFP_KERNEL); 1679df0b5c4aSBingbu Cao if (!cfg) 1680df0b5c4aSBingbu Cao goto out_err; 1681df0b5c4aSBingbu Cao 1682df0b5c4aSBingbu Cao ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", 1683df0b5c4aSBingbu Cao &cfg->ext_clk); 1684df0b5c4aSBingbu Cao if (ret) { 1685df0b5c4aSBingbu Cao dev_err(dev, "can't get clock frequency"); 1686df0b5c4aSBingbu Cao goto out_err; 1687df0b5c4aSBingbu Cao } 1688df0b5c4aSBingbu Cao 1689df0b5c4aSBingbu Cao dev_dbg(dev, "ext clk: %d", cfg->ext_clk); 1690df0b5c4aSBingbu Cao if (cfg->ext_clk != IMX355_EXT_CLK) { 1691df0b5c4aSBingbu Cao dev_err(dev, "external clock %d is not supported", 1692df0b5c4aSBingbu Cao cfg->ext_clk); 1693df0b5c4aSBingbu Cao goto out_err; 1694df0b5c4aSBingbu Cao } 1695df0b5c4aSBingbu Cao 1696df0b5c4aSBingbu Cao dev_dbg(dev, "num of link freqs: %d", bus_cfg.nr_of_link_frequencies); 1697df0b5c4aSBingbu Cao if (!bus_cfg.nr_of_link_frequencies) { 1698df0b5c4aSBingbu Cao dev_warn(dev, "no link frequencies defined"); 1699df0b5c4aSBingbu Cao goto out_err; 1700df0b5c4aSBingbu Cao } 1701df0b5c4aSBingbu Cao 1702df0b5c4aSBingbu Cao cfg->nr_of_link_freqs = bus_cfg.nr_of_link_frequencies; 1703370d8e2aSMauro Carvalho Chehab cfg->link_freqs = devm_kcalloc(dev, 1704370d8e2aSMauro Carvalho Chehab bus_cfg.nr_of_link_frequencies + 1, 1705df0b5c4aSBingbu Cao sizeof(*cfg->link_freqs), GFP_KERNEL); 1706df0b5c4aSBingbu Cao if (!cfg->link_freqs) 1707df0b5c4aSBingbu Cao goto out_err; 1708df0b5c4aSBingbu Cao 1709df0b5c4aSBingbu Cao for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) { 1710df0b5c4aSBingbu Cao cfg->link_freqs[i] = bus_cfg.link_frequencies[i]; 1711df0b5c4aSBingbu Cao dev_dbg(dev, "link_freq[%d] = %lld", i, cfg->link_freqs[i]); 1712df0b5c4aSBingbu Cao } 1713df0b5c4aSBingbu Cao 1714df0b5c4aSBingbu Cao v4l2_fwnode_endpoint_free(&bus_cfg); 1715df0b5c4aSBingbu Cao fwnode_handle_put(ep); 1716df0b5c4aSBingbu Cao return cfg; 1717df0b5c4aSBingbu Cao 1718df0b5c4aSBingbu Cao out_err: 1719df0b5c4aSBingbu Cao v4l2_fwnode_endpoint_free(&bus_cfg); 1720df0b5c4aSBingbu Cao fwnode_handle_put(ep); 1721df0b5c4aSBingbu Cao return NULL; 1722df0b5c4aSBingbu Cao } 1723df0b5c4aSBingbu Cao 1724df0b5c4aSBingbu Cao static int imx355_probe(struct i2c_client *client) 1725df0b5c4aSBingbu Cao { 1726df0b5c4aSBingbu Cao struct imx355 *imx355; 1727df0b5c4aSBingbu Cao int ret; 1728df0b5c4aSBingbu Cao u32 i; 1729df0b5c4aSBingbu Cao 1730df0b5c4aSBingbu Cao imx355 = devm_kzalloc(&client->dev, sizeof(*imx355), GFP_KERNEL); 1731df0b5c4aSBingbu Cao if (!imx355) 1732df0b5c4aSBingbu Cao return -ENOMEM; 1733df0b5c4aSBingbu Cao 1734df0b5c4aSBingbu Cao mutex_init(&imx355->mutex); 1735df0b5c4aSBingbu Cao 1736df0b5c4aSBingbu Cao /* Initialize subdev */ 1737df0b5c4aSBingbu Cao v4l2_i2c_subdev_init(&imx355->sd, client, &imx355_subdev_ops); 1738df0b5c4aSBingbu Cao 1739df0b5c4aSBingbu Cao /* Check module identity */ 1740df0b5c4aSBingbu Cao ret = imx355_identify_module(imx355); 1741df0b5c4aSBingbu Cao if (ret) { 1742df0b5c4aSBingbu Cao dev_err(&client->dev, "failed to find sensor: %d", ret); 1743df0b5c4aSBingbu Cao goto error_probe; 1744df0b5c4aSBingbu Cao } 1745df0b5c4aSBingbu Cao 1746df0b5c4aSBingbu Cao imx355->hwcfg = imx355_get_hwcfg(&client->dev); 1747df0b5c4aSBingbu Cao if (!imx355->hwcfg) { 1748df0b5c4aSBingbu Cao dev_err(&client->dev, "failed to get hwcfg"); 1749df0b5c4aSBingbu Cao ret = -ENODEV; 1750df0b5c4aSBingbu Cao goto error_probe; 1751df0b5c4aSBingbu Cao } 1752df0b5c4aSBingbu Cao 1753df0b5c4aSBingbu Cao imx355->link_def_freq = link_freq_menu_items[IMX355_LINK_FREQ_INDEX]; 1754df0b5c4aSBingbu Cao for (i = 0; i < imx355->hwcfg->nr_of_link_freqs; i++) { 1755df0b5c4aSBingbu Cao if (imx355->hwcfg->link_freqs[i] == imx355->link_def_freq) { 1756df0b5c4aSBingbu Cao dev_dbg(&client->dev, "link freq index %d matched", i); 1757df0b5c4aSBingbu Cao break; 1758df0b5c4aSBingbu Cao } 1759df0b5c4aSBingbu Cao } 1760df0b5c4aSBingbu Cao 1761df0b5c4aSBingbu Cao if (i == imx355->hwcfg->nr_of_link_freqs) { 1762df0b5c4aSBingbu Cao dev_err(&client->dev, "no link frequency supported"); 1763df0b5c4aSBingbu Cao ret = -EINVAL; 1764df0b5c4aSBingbu Cao goto error_probe; 1765df0b5c4aSBingbu Cao } 1766df0b5c4aSBingbu Cao 1767df0b5c4aSBingbu Cao /* Set default mode to max resolution */ 1768df0b5c4aSBingbu Cao imx355->cur_mode = &supported_modes[0]; 1769df0b5c4aSBingbu Cao 1770df0b5c4aSBingbu Cao ret = imx355_init_controls(imx355); 1771df0b5c4aSBingbu Cao if (ret) { 1772df0b5c4aSBingbu Cao dev_err(&client->dev, "failed to init controls: %d", ret); 1773df0b5c4aSBingbu Cao goto error_probe; 1774df0b5c4aSBingbu Cao } 1775df0b5c4aSBingbu Cao 1776df0b5c4aSBingbu Cao /* Initialize subdev */ 1777df0b5c4aSBingbu Cao imx355->sd.internal_ops = &imx355_internal_ops; 1778df0b5c4aSBingbu Cao imx355->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | 1779df0b5c4aSBingbu Cao V4L2_SUBDEV_FL_HAS_EVENTS; 1780df0b5c4aSBingbu Cao imx355->sd.entity.ops = &imx355_subdev_entity_ops; 1781df0b5c4aSBingbu Cao imx355->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; 1782df0b5c4aSBingbu Cao 1783df0b5c4aSBingbu Cao /* Initialize source pad */ 1784df0b5c4aSBingbu Cao imx355->pad.flags = MEDIA_PAD_FL_SOURCE; 1785df0b5c4aSBingbu Cao ret = media_entity_pads_init(&imx355->sd.entity, 1, &imx355->pad); 1786df0b5c4aSBingbu Cao if (ret) { 1787df0b5c4aSBingbu Cao dev_err(&client->dev, "failed to init entity pads: %d", ret); 1788df0b5c4aSBingbu Cao goto error_handler_free; 1789df0b5c4aSBingbu Cao } 1790df0b5c4aSBingbu Cao 179115786f7bSSakari Ailus ret = v4l2_async_register_subdev_sensor(&imx355->sd); 1792df0b5c4aSBingbu Cao if (ret < 0) 1793df0b5c4aSBingbu Cao goto error_media_entity; 1794df0b5c4aSBingbu Cao 1795df0b5c4aSBingbu Cao /* 1796df0b5c4aSBingbu Cao * Device is already turned on by i2c-core with ACPI domain PM. 1797df0b5c4aSBingbu Cao * Enable runtime PM and turn off the device. 1798df0b5c4aSBingbu Cao */ 1799df0b5c4aSBingbu Cao pm_runtime_set_active(&client->dev); 1800df0b5c4aSBingbu Cao pm_runtime_enable(&client->dev); 1801df0b5c4aSBingbu Cao pm_runtime_idle(&client->dev); 1802df0b5c4aSBingbu Cao 1803df0b5c4aSBingbu Cao return 0; 1804df0b5c4aSBingbu Cao 1805df0b5c4aSBingbu Cao error_media_entity: 1806df0b5c4aSBingbu Cao media_entity_cleanup(&imx355->sd.entity); 1807df0b5c4aSBingbu Cao 1808df0b5c4aSBingbu Cao error_handler_free: 1809df0b5c4aSBingbu Cao v4l2_ctrl_handler_free(imx355->sd.ctrl_handler); 1810df0b5c4aSBingbu Cao 1811df0b5c4aSBingbu Cao error_probe: 1812df0b5c4aSBingbu Cao mutex_destroy(&imx355->mutex); 1813df0b5c4aSBingbu Cao 1814df0b5c4aSBingbu Cao return ret; 1815df0b5c4aSBingbu Cao } 1816df0b5c4aSBingbu Cao 1817ed5c2f5fSUwe Kleine-König static void imx355_remove(struct i2c_client *client) 1818df0b5c4aSBingbu Cao { 1819df0b5c4aSBingbu Cao struct v4l2_subdev *sd = i2c_get_clientdata(client); 1820df0b5c4aSBingbu Cao struct imx355 *imx355 = to_imx355(sd); 1821df0b5c4aSBingbu Cao 1822df0b5c4aSBingbu Cao v4l2_async_unregister_subdev(sd); 1823df0b5c4aSBingbu Cao media_entity_cleanup(&sd->entity); 1824df0b5c4aSBingbu Cao v4l2_ctrl_handler_free(sd->ctrl_handler); 1825df0b5c4aSBingbu Cao 1826df0b5c4aSBingbu Cao pm_runtime_disable(&client->dev); 1827df0b5c4aSBingbu Cao pm_runtime_set_suspended(&client->dev); 1828df0b5c4aSBingbu Cao 1829df0b5c4aSBingbu Cao mutex_destroy(&imx355->mutex); 1830df0b5c4aSBingbu Cao } 1831df0b5c4aSBingbu Cao 1832df0b5c4aSBingbu Cao static const struct dev_pm_ops imx355_pm_ops = { 1833df0b5c4aSBingbu Cao SET_SYSTEM_SLEEP_PM_OPS(imx355_suspend, imx355_resume) 1834df0b5c4aSBingbu Cao }; 1835df0b5c4aSBingbu Cao 1836bbaecc36SKrzysztof Kozlowski static const struct acpi_device_id imx355_acpi_ids[] __maybe_unused = { 1837df0b5c4aSBingbu Cao { "SONY355A" }, 1838df0b5c4aSBingbu Cao { /* sentinel */ } 1839df0b5c4aSBingbu Cao }; 1840df0b5c4aSBingbu Cao MODULE_DEVICE_TABLE(acpi, imx355_acpi_ids); 1841df0b5c4aSBingbu Cao 1842df0b5c4aSBingbu Cao static struct i2c_driver imx355_i2c_driver = { 1843df0b5c4aSBingbu Cao .driver = { 1844df0b5c4aSBingbu Cao .name = "imx355", 1845df0b5c4aSBingbu Cao .pm = &imx355_pm_ops, 1846df0b5c4aSBingbu Cao .acpi_match_table = ACPI_PTR(imx355_acpi_ids), 1847df0b5c4aSBingbu Cao }, 1848df0b5c4aSBingbu Cao .probe_new = imx355_probe, 1849df0b5c4aSBingbu Cao .remove = imx355_remove, 1850df0b5c4aSBingbu Cao }; 1851df0b5c4aSBingbu Cao module_i2c_driver(imx355_i2c_driver); 1852df0b5c4aSBingbu Cao 1853df0b5c4aSBingbu Cao MODULE_AUTHOR("Qiu, Tianshu <tian.shu.qiu@intel.com>"); 1854df0b5c4aSBingbu Cao MODULE_AUTHOR("Rapolu, Chiranjeevi <chiranjeevi.rapolu@intel.com>"); 1855df0b5c4aSBingbu Cao MODULE_AUTHOR("Bingbu Cao <bingbu.cao@intel.com>"); 18565fcec420SSakari Ailus MODULE_AUTHOR("Yang, Hyungwoo"); 1857df0b5c4aSBingbu Cao MODULE_DESCRIPTION("Sony imx355 sensor driver"); 1858df0b5c4aSBingbu Cao MODULE_LICENSE("GPL v2"); 1859