1*bf40cc53SJai Luthra // SPDX-License-Identifier: GPL-2.0 2*bf40cc53SJai Luthra /* 3*bf40cc53SJai Luthra * V4L2 driver for Sony IMX678 4*bf40cc53SJai Luthra * 5*bf40cc53SJai Luthra * Diagonal 8.86 mm (Type 1/1.8) CMOS image sensor with 8.40 M effective pixels. 6*bf40cc53SJai Luthra * 7*bf40cc53SJai Luthra * Copyright (C) 2026 Ideas On Board Oy. 8*bf40cc53SJai Luthra * 9*bf40cc53SJai Luthra * Based on Sony IMX678 driver prepared by Will Whang & Soho Enterprise Ltd. 10*bf40cc53SJai Luthra */ 11*bf40cc53SJai Luthra #include <linux/clk.h> 12*bf40cc53SJai Luthra #include <linux/delay.h> 13*bf40cc53SJai Luthra #include <linux/gpio/consumer.h> 14*bf40cc53SJai Luthra #include <linux/i2c.h> 15*bf40cc53SJai Luthra #include <linux/media-bus-format.h> 16*bf40cc53SJai Luthra #include <linux/module.h> 17*bf40cc53SJai Luthra #include <linux/property.h> 18*bf40cc53SJai Luthra #include <linux/pm_runtime.h> 19*bf40cc53SJai Luthra #include <linux/regulator/consumer.h> 20*bf40cc53SJai Luthra #include <media/v4l2-cci.h> 21*bf40cc53SJai Luthra #include <media/v4l2-ctrls.h> 22*bf40cc53SJai Luthra #include <media/v4l2-device.h> 23*bf40cc53SJai Luthra #include <media/v4l2-fwnode.h> 24*bf40cc53SJai Luthra #include <media/v4l2-mediabus.h> 25*bf40cc53SJai Luthra #include <media/v4l2-rect.h> 26*bf40cc53SJai Luthra #include <media/v4l2-subdev.h> 27*bf40cc53SJai Luthra 28*bf40cc53SJai Luthra /* Standby or streaming mode */ 29*bf40cc53SJai Luthra #define IMX678_REG_MODE_SELECT CCI_REG8(0x3000) 30*bf40cc53SJai Luthra #define IMX678_MODE_STANDBY 0x01 31*bf40cc53SJai Luthra #define IMX678_MODE_STREAMING 0x00 32*bf40cc53SJai Luthra #define IMX678_STREAM_DELAY_US 25000 33*bf40cc53SJai Luthra #define IMX678_STREAM_DELAY_RANGE_US 1000 34*bf40cc53SJai Luthra 35*bf40cc53SJai Luthra /* XVS/XHS sync control */ 36*bf40cc53SJai Luthra #define IMX678_REG_XMSTA CCI_REG8(0x3002) 37*bf40cc53SJai Luthra #define IMX678_REG_XXS_DRV CCI_REG8(0x30a6) 38*bf40cc53SJai Luthra #define IMX678_REG_XXS_OUTSEL CCI_REG8(0x30a4) 39*bf40cc53SJai Luthra 40*bf40cc53SJai Luthra /* Clk selection */ 41*bf40cc53SJai Luthra #define IMX678_REG_INCK_SEL CCI_REG8(0x3014) 42*bf40cc53SJai Luthra 43*bf40cc53SJai Luthra /* Link Speed */ 44*bf40cc53SJai Luthra #define IMX678_REG_DATARATE_SEL CCI_REG8(0x3015) 45*bf40cc53SJai Luthra 46*bf40cc53SJai Luthra /* Lane Count */ 47*bf40cc53SJai Luthra #define IMX678_REG_LANEMODE CCI_REG8(0x3040) 48*bf40cc53SJai Luthra 49*bf40cc53SJai Luthra /* 50*bf40cc53SJai Luthra * The internal readout clock runs at 74.25 MHz. In one cycle the AD reads 8 51*bf40cc53SJai Luthra * pixels, thus giving us a rate of 74.25 * 8 = 594 MPix/s 52*bf40cc53SJai Luthra */ 53*bf40cc53SJai Luthra #define IMX678_PIXEL_RATE 594000000 54*bf40cc53SJai Luthra #define IMX678_PIX_PER_CLK 8 55*bf40cc53SJai Luthra 56*bf40cc53SJai Luthra /* VMAX - Frame Length in Lines */ 57*bf40cc53SJai Luthra #define IMX678_REG_VMAX CCI_REG24_LE(0x3028) 58*bf40cc53SJai Luthra #define IMX678_VMAX_MAX 0xfffff 59*bf40cc53SJai Luthra #define IMX678_VMAX_DEFAULT 2250 60*bf40cc53SJai Luthra 61*bf40cc53SJai Luthra /* HMAX - Line Length in Cycles (8 Pixels) */ 62*bf40cc53SJai Luthra #define IMX678_REG_HMAX CCI_REG16_LE(0x302c) 63*bf40cc53SJai Luthra #define IMX678_HMAX_MAX 0xffff 64*bf40cc53SJai Luthra 65*bf40cc53SJai Luthra /* SHR internal */ 66*bf40cc53SJai Luthra #define IMX678_REG_SHR CCI_REG24_LE(0x3050) 67*bf40cc53SJai Luthra #define IMX678_SHR_MIN 8 68*bf40cc53SJai Luthra 69*bf40cc53SJai Luthra /* Exposure control */ 70*bf40cc53SJai Luthra #define IMX678_EXPOSURE_MIN 2 71*bf40cc53SJai Luthra #define IMX678_EXPOSURE_STEP 1 72*bf40cc53SJai Luthra #define IMX678_EXPOSURE_DEFAULT 1000 73*bf40cc53SJai Luthra 74*bf40cc53SJai Luthra /* 75*bf40cc53SJai Luthra * Analogue gain control 76*bf40cc53SJai Luthra * Range is from 0 to 100 (0dB - 30dB) with 0.3dB step size 77*bf40cc53SJai Luthra * Values from 101 to 240 are valid but correspond to additional digital gain 78*bf40cc53SJai Luthra * (0.3dB - 42dB) so don't expose it to userspace 79*bf40cc53SJai Luthra */ 80*bf40cc53SJai Luthra #define IMX678_REG_GAIN CCI_REG16_LE(0x3070) 81*bf40cc53SJai Luthra #define IMX678_ANA_GAIN_MIN_NORMAL 0 82*bf40cc53SJai Luthra #define IMX678_ANA_GAIN_MAX_NORMAL 100 83*bf40cc53SJai Luthra #define IMX678_ANA_GAIN_STEP 1 84*bf40cc53SJai Luthra #define IMX678_ANA_GAIN_DEFAULT 0 85*bf40cc53SJai Luthra 86*bf40cc53SJai Luthra /* Crop */ 87*bf40cc53SJai Luthra #define IMX678_REG_WINMODE CCI_REG8(0x3018) 88*bf40cc53SJai Luthra #define IMX678_REG_PIX_HST CCI_REG16_LE(0x303c) 89*bf40cc53SJai Luthra #define IMX678_REG_PIX_HWIDTH CCI_REG16_LE(0x303e) 90*bf40cc53SJai Luthra #define IMX678_REG_PIX_VST CCI_REG16_LE(0x3044) 91*bf40cc53SJai Luthra #define IMX678_REG_PIX_VWIDTH CCI_REG16_LE(0x3046) 92*bf40cc53SJai Luthra 93*bf40cc53SJai Luthra /* Flip */ 94*bf40cc53SJai Luthra #define IMX678_REG_WINMODEH CCI_REG8(0x3020) 95*bf40cc53SJai Luthra #define IMX678_REG_WINMODEV CCI_REG8(0x3021) 96*bf40cc53SJai Luthra 97*bf40cc53SJai Luthra /* Sensor Identification */ 98*bf40cc53SJai Luthra #define IMX678_REG_MONOCHROME CCI_REG8(0x4d18) 99*bf40cc53SJai Luthra #define IMX678_TYPE BIT(0) 100*bf40cc53SJai Luthra #define IMX678_REG_MODULE_ID CCI_REG16_LE(0x4d1c) 101*bf40cc53SJai Luthra #define IMX678_ID 0x02a6 102*bf40cc53SJai Luthra #define IMX678_MODULE_ID_DELAY 80000 103*bf40cc53SJai Luthra 104*bf40cc53SJai Luthra /* Common configuration registers */ 105*bf40cc53SJai Luthra #define IMX678_REG_WDMODE CCI_REG8(0x301a) 106*bf40cc53SJai Luthra #define IMX678_REG_ADDMODE CCI_REG8(0x301b) 107*bf40cc53SJai Luthra #define IMX678_REG_THIN_V_EN CCI_REG8(0x301c) 108*bf40cc53SJai Luthra #define IMX678_REG_VCMODE CCI_REG8(0x301e) 109*bf40cc53SJai Luthra #define IMX678_REG_ADBIT CCI_REG8(0x3022) 110*bf40cc53SJai Luthra #define IMX678_REG_MDBIT CCI_REG8(0x3023) 111*bf40cc53SJai Luthra #define IMX678_REG_GAIN_PGC_FIDMD CCI_REG8(0x3400) 112*bf40cc53SJai Luthra 113*bf40cc53SJai Luthra /* Test pattern generator */ 114*bf40cc53SJai Luthra #define IMX678_REG_TPG_EN_DUOUT CCI_REG8(0x30e0) 115*bf40cc53SJai Luthra #define IMX678_REG_TPG_PATSEL_DUOUT CCI_REG8(0x30e2) 116*bf40cc53SJai Luthra #define IMX678_TPG_ALL_000 0 117*bf40cc53SJai Luthra #define IMX678_TPG_ALL_FFF 1 118*bf40cc53SJai Luthra #define IMX678_TPG_ALL_555 2 119*bf40cc53SJai Luthra #define IMX678_TPG_ALL_AAA 3 120*bf40cc53SJai Luthra #define IMX678_TPG_TOG_555_AAA 4 121*bf40cc53SJai Luthra #define IMX678_TPG_TOG_AAA_555 5 122*bf40cc53SJai Luthra #define IMX678_TPG_TOG_000_555 6 123*bf40cc53SJai Luthra #define IMX678_TPG_TOG_555_000 7 124*bf40cc53SJai Luthra #define IMX678_TPG_TOG_000_FFF 8 125*bf40cc53SJai Luthra #define IMX678_TPG_TOG_FFF_000 9 126*bf40cc53SJai Luthra #define IMX678_TPG_H_COLOR_BARS 10 127*bf40cc53SJai Luthra #define IMX678_TPG_V_COLOR_BARS 11 128*bf40cc53SJai Luthra #define IMX678_REG_TPG_COLORWIDTH CCI_REG8(0x30e4) 129*bf40cc53SJai Luthra #define IMX678_TPG_COLORWIDTH_80PIX 0 130*bf40cc53SJai Luthra #define IMX678_TPG_COLORWIDTH_160PIX 1 131*bf40cc53SJai Luthra #define IMX678_TPG_COLORWIDTH_320PIX 2 132*bf40cc53SJai Luthra #define IMX678_TPG_COLORWIDTH_640PIX 3 133*bf40cc53SJai Luthra 134*bf40cc53SJai Luthra #define IMX678_REG_INTERFACE_SEL CCI_REG8(0x4e3c) 135*bf40cc53SJai Luthra #define IMX678_INTERFACE_2L_4L 0x07 136*bf40cc53SJai Luthra #define IMX678_INTERFACE_8L_2x4L 0x7f 137*bf40cc53SJai Luthra 138*bf40cc53SJai Luthra /* Minimum output resolution */ 139*bf40cc53SJai Luthra #define IMX678_PIXEL_ARRAY_MIN_WIDTH 1040 140*bf40cc53SJai Luthra #define IMX678_PIXEL_ARRAY_MIN_HEIGHT 956 141*bf40cc53SJai Luthra 142*bf40cc53SJai Luthra /* Sensor windowing register alignment */ 143*bf40cc53SJai Luthra #define IMX678_CROP_HWIDTH_ALIGN 16 144*bf40cc53SJai Luthra #define IMX678_CROP_VWIDTH_ALIGN 4 145*bf40cc53SJai Luthra #define IMX678_CROP_HST_ALIGN 4 146*bf40cc53SJai Luthra #define IMX678_CROP_VST_ALIGN 4 147*bf40cc53SJai Luthra 148*bf40cc53SJai Luthra /* Subdev pads */ 149*bf40cc53SJai Luthra #define IMX678_SOURCE_PAD 0 150*bf40cc53SJai Luthra 151*bf40cc53SJai Luthra /* IMX678 native and active pixel array size. */ 152*bf40cc53SJai Luthra static const struct v4l2_rect imx678_native_area = { 153*bf40cc53SJai Luthra .top = 0, 154*bf40cc53SJai Luthra .left = 0, 155*bf40cc53SJai Luthra .width = 3857, 156*bf40cc53SJai Luthra .height = 2201, 157*bf40cc53SJai Luthra }; 158*bf40cc53SJai Luthra 159*bf40cc53SJai Luthra static const struct v4l2_rect imx678_active_area = { 160*bf40cc53SJai Luthra .top = 20, 161*bf40cc53SJai Luthra .left = 0, 162*bf40cc53SJai Luthra .width = 3856, 163*bf40cc53SJai Luthra .height = 2180, 164*bf40cc53SJai Luthra }; 165*bf40cc53SJai Luthra 166*bf40cc53SJai Luthra enum imx678_type { 167*bf40cc53SJai Luthra IMX678_COLOR = 0, 168*bf40cc53SJai Luthra IMX678_MONOCHROME = 1, 169*bf40cc53SJai Luthra }; 170*bf40cc53SJai Luthra 171*bf40cc53SJai Luthra struct imx678_model_info { 172*bf40cc53SJai Luthra enum imx678_type type; 173*bf40cc53SJai Luthra const u32 *codes; 174*bf40cc53SJai Luthra unsigned int num_codes; 175*bf40cc53SJai Luthra }; 176*bf40cc53SJai Luthra 177*bf40cc53SJai Luthra enum imx678_lanemode { 178*bf40cc53SJai Luthra IMX678_LANEMODE_2L = 1, 179*bf40cc53SJai Luthra IMX678_LANEMODE_4L = 3, 180*bf40cc53SJai Luthra }; 181*bf40cc53SJai Luthra 182*bf40cc53SJai Luthra /* Link frequency setup (DDR: lane rate = 2 x link freq) */ 183*bf40cc53SJai Luthra enum { 184*bf40cc53SJai Luthra IMX678_LINK_FREQ_297MHZ, 185*bf40cc53SJai Luthra IMX678_LINK_FREQ_360MHZ, 186*bf40cc53SJai Luthra IMX678_LINK_FREQ_445MHZ, 187*bf40cc53SJai Luthra IMX678_LINK_FREQ_594MHZ, 188*bf40cc53SJai Luthra IMX678_LINK_FREQ_720MHZ, 189*bf40cc53SJai Luthra IMX678_LINK_FREQ_891MHZ, 190*bf40cc53SJai Luthra IMX678_LINK_FREQ_1039MHZ, 191*bf40cc53SJai Luthra IMX678_LINK_FREQ_1188MHZ, 192*bf40cc53SJai Luthra }; 193*bf40cc53SJai Luthra 194*bf40cc53SJai Luthra static const u8 link_freqs_reg_value[] = { 195*bf40cc53SJai Luthra [IMX678_LINK_FREQ_297MHZ] = 0x07, 196*bf40cc53SJai Luthra [IMX678_LINK_FREQ_360MHZ] = 0x06, 197*bf40cc53SJai Luthra [IMX678_LINK_FREQ_445MHZ] = 0x05, 198*bf40cc53SJai Luthra [IMX678_LINK_FREQ_594MHZ] = 0x04, 199*bf40cc53SJai Luthra [IMX678_LINK_FREQ_720MHZ] = 0x03, 200*bf40cc53SJai Luthra [IMX678_LINK_FREQ_891MHZ] = 0x02, 201*bf40cc53SJai Luthra [IMX678_LINK_FREQ_1039MHZ] = 0x01, 202*bf40cc53SJai Luthra [IMX678_LINK_FREQ_1188MHZ] = 0x00, 203*bf40cc53SJai Luthra }; 204*bf40cc53SJai Luthra 205*bf40cc53SJai Luthra static const u64 link_freqs[] = { 206*bf40cc53SJai Luthra [IMX678_LINK_FREQ_297MHZ] = 297000000, 207*bf40cc53SJai Luthra [IMX678_LINK_FREQ_360MHZ] = 360000000, 208*bf40cc53SJai Luthra [IMX678_LINK_FREQ_445MHZ] = 445500000, 209*bf40cc53SJai Luthra [IMX678_LINK_FREQ_594MHZ] = 594000000, 210*bf40cc53SJai Luthra [IMX678_LINK_FREQ_720MHZ] = 720000000, 211*bf40cc53SJai Luthra [IMX678_LINK_FREQ_891MHZ] = 891000000, 212*bf40cc53SJai Luthra [IMX678_LINK_FREQ_1039MHZ] = 1039500000, 213*bf40cc53SJai Luthra [IMX678_LINK_FREQ_1188MHZ] = 1188000000, 214*bf40cc53SJai Luthra }; 215*bf40cc53SJai Luthra 216*bf40cc53SJai Luthra static const u16 min_hmax_4lane[] = { 217*bf40cc53SJai Luthra [IMX678_LINK_FREQ_297MHZ] = 1584, 218*bf40cc53SJai Luthra [IMX678_LINK_FREQ_360MHZ] = 1320, 219*bf40cc53SJai Luthra [IMX678_LINK_FREQ_445MHZ] = 1100, 220*bf40cc53SJai Luthra [IMX678_LINK_FREQ_594MHZ] = 792, 221*bf40cc53SJai Luthra [IMX678_LINK_FREQ_720MHZ] = 660, 222*bf40cc53SJai Luthra [IMX678_LINK_FREQ_891MHZ] = 550, 223*bf40cc53SJai Luthra [IMX678_LINK_FREQ_1039MHZ] = 550, 224*bf40cc53SJai Luthra [IMX678_LINK_FREQ_1188MHZ] = 550, 225*bf40cc53SJai Luthra }; 226*bf40cc53SJai Luthra 227*bf40cc53SJai Luthra struct imx678_inck_cfg { 228*bf40cc53SJai Luthra u32 xclk_hz; /* platform clock rate */ 229*bf40cc53SJai Luthra u8 inck_sel; /* value for reg */ 230*bf40cc53SJai Luthra }; 231*bf40cc53SJai Luthra 232*bf40cc53SJai Luthra static const struct imx678_inck_cfg imx678_inck_table[] = { 233*bf40cc53SJai Luthra { 74250000, 0x00 }, 234*bf40cc53SJai Luthra { 37125000, 0x01 }, 235*bf40cc53SJai Luthra { 72000000, 0x02 }, 236*bf40cc53SJai Luthra { 27000000, 0x03 }, 237*bf40cc53SJai Luthra { 24000000, 0x04 }, 238*bf40cc53SJai Luthra { 36000000, 0x05 }, 239*bf40cc53SJai Luthra { 18000000, 0x06 }, 240*bf40cc53SJai Luthra { 13500000, 0x07 }, 241*bf40cc53SJai Luthra }; 242*bf40cc53SJai Luthra 243*bf40cc53SJai Luthra static const char * const imx678_tpg_menu[] = { 244*bf40cc53SJai Luthra "Disabled", 245*bf40cc53SJai Luthra "All 000h", 246*bf40cc53SJai Luthra "All FFFh", 247*bf40cc53SJai Luthra "All 555h", 248*bf40cc53SJai Luthra "All AAAh", 249*bf40cc53SJai Luthra "Toggle 555/AAAh", 250*bf40cc53SJai Luthra "Toggle AAA/555h", 251*bf40cc53SJai Luthra "Toggle 000/555h", 252*bf40cc53SJai Luthra "Toggle 555/000h", 253*bf40cc53SJai Luthra "Toggle 000/FFFh", 254*bf40cc53SJai Luthra "Toggle FFF/000h", 255*bf40cc53SJai Luthra "Horizontal color bars", 256*bf40cc53SJai Luthra "Vertical color bars", 257*bf40cc53SJai Luthra }; 258*bf40cc53SJai Luthra 259*bf40cc53SJai Luthra static const int imx678_tpg_val[] = { 260*bf40cc53SJai Luthra IMX678_TPG_ALL_000, 261*bf40cc53SJai Luthra IMX678_TPG_ALL_000, 262*bf40cc53SJai Luthra IMX678_TPG_ALL_FFF, 263*bf40cc53SJai Luthra IMX678_TPG_ALL_555, 264*bf40cc53SJai Luthra IMX678_TPG_ALL_AAA, 265*bf40cc53SJai Luthra IMX678_TPG_TOG_555_AAA, 266*bf40cc53SJai Luthra IMX678_TPG_TOG_AAA_555, 267*bf40cc53SJai Luthra IMX678_TPG_TOG_000_555, 268*bf40cc53SJai Luthra IMX678_TPG_TOG_555_000, 269*bf40cc53SJai Luthra IMX678_TPG_TOG_000_FFF, 270*bf40cc53SJai Luthra IMX678_TPG_TOG_FFF_000, 271*bf40cc53SJai Luthra IMX678_TPG_H_COLOR_BARS, 272*bf40cc53SJai Luthra IMX678_TPG_V_COLOR_BARS, 273*bf40cc53SJai Luthra }; 274*bf40cc53SJai Luthra 275*bf40cc53SJai Luthra /* Common configuration */ 276*bf40cc53SJai Luthra static const struct cci_reg_sequence common_regs[] = { 277*bf40cc53SJai Luthra { IMX678_REG_THIN_V_EN, 0x00 }, 278*bf40cc53SJai Luthra { IMX678_REG_VCMODE, 0x01 }, 279*bf40cc53SJai Luthra { CCI_REG8(0x306b), 0x00 }, 280*bf40cc53SJai Luthra { IMX678_REG_GAIN_PGC_FIDMD, 0x01 }, 281*bf40cc53SJai Luthra { CCI_REG8(0x3460), 0x22 }, 282*bf40cc53SJai Luthra { CCI_REG8(0x355a), 0x64 }, 283*bf40cc53SJai Luthra { CCI_REG8(0x3a02), 0x7a }, 284*bf40cc53SJai Luthra { CCI_REG8(0x3a10), 0xec }, 285*bf40cc53SJai Luthra { CCI_REG8(0x3a12), 0x71 }, 286*bf40cc53SJai Luthra { CCI_REG8(0x3a14), 0xde }, 287*bf40cc53SJai Luthra { CCI_REG8(0x3a20), 0x2b }, 288*bf40cc53SJai Luthra { CCI_REG8(0x3a24), 0x22 }, 289*bf40cc53SJai Luthra { CCI_REG8(0x3a25), 0x25 }, 290*bf40cc53SJai Luthra { CCI_REG8(0x3a26), 0x2a }, 291*bf40cc53SJai Luthra { CCI_REG8(0x3a27), 0x2c }, 292*bf40cc53SJai Luthra { CCI_REG8(0x3a28), 0x39 }, 293*bf40cc53SJai Luthra { CCI_REG8(0x3a29), 0x38 }, 294*bf40cc53SJai Luthra { CCI_REG8(0x3a30), 0x04 }, 295*bf40cc53SJai Luthra { CCI_REG8(0x3a31), 0x04 }, 296*bf40cc53SJai Luthra { CCI_REG8(0x3a32), 0x03 }, 297*bf40cc53SJai Luthra { CCI_REG8(0x3a33), 0x03 }, 298*bf40cc53SJai Luthra { CCI_REG8(0x3a34), 0x09 }, 299*bf40cc53SJai Luthra { CCI_REG8(0x3a35), 0x06 }, 300*bf40cc53SJai Luthra { CCI_REG8(0x3a38), 0xcd }, 301*bf40cc53SJai Luthra { CCI_REG8(0x3a3a), 0x4c }, 302*bf40cc53SJai Luthra { CCI_REG8(0x3a3c), 0xb9 }, 303*bf40cc53SJai Luthra { CCI_REG8(0x3a3e), 0x30 }, 304*bf40cc53SJai Luthra { CCI_REG8(0x3a40), 0x2c }, 305*bf40cc53SJai Luthra { CCI_REG8(0x3a42), 0x39 }, 306*bf40cc53SJai Luthra { CCI_REG8(0x3a4e), 0x00 }, 307*bf40cc53SJai Luthra { CCI_REG8(0x3a52), 0x00 }, 308*bf40cc53SJai Luthra { CCI_REG8(0x3a56), 0x00 }, 309*bf40cc53SJai Luthra { CCI_REG8(0x3a5a), 0x00 }, 310*bf40cc53SJai Luthra { CCI_REG8(0x3a5e), 0x00 }, 311*bf40cc53SJai Luthra { CCI_REG8(0x3a62), 0x00 }, 312*bf40cc53SJai Luthra { CCI_REG8(0x3a64), 0x00 }, 313*bf40cc53SJai Luthra { CCI_REG8(0x3a6e), 0xa0 }, 314*bf40cc53SJai Luthra { CCI_REG8(0x3a70), 0x50 }, 315*bf40cc53SJai Luthra { CCI_REG8(0x3a8c), 0x04 }, 316*bf40cc53SJai Luthra { CCI_REG8(0x3a8d), 0x03 }, 317*bf40cc53SJai Luthra { CCI_REG8(0x3a8e), 0x09 }, 318*bf40cc53SJai Luthra { CCI_REG8(0x3a90), 0x38 }, 319*bf40cc53SJai Luthra { CCI_REG8(0x3a91), 0x42 }, 320*bf40cc53SJai Luthra { CCI_REG8(0x3a92), 0x3c }, 321*bf40cc53SJai Luthra { CCI_REG8(0x3b0e), 0xf3 }, 322*bf40cc53SJai Luthra { CCI_REG8(0x3b12), 0xe5 }, 323*bf40cc53SJai Luthra { CCI_REG8(0x3b27), 0xc0 }, 324*bf40cc53SJai Luthra { CCI_REG8(0x3b2e), 0xef }, 325*bf40cc53SJai Luthra { CCI_REG8(0x3b30), 0x6a }, 326*bf40cc53SJai Luthra { CCI_REG8(0x3b32), 0xf6 }, 327*bf40cc53SJai Luthra { CCI_REG8(0x3b36), 0xe1 }, 328*bf40cc53SJai Luthra { CCI_REG8(0x3b3a), 0xe8 }, 329*bf40cc53SJai Luthra { CCI_REG8(0x3b5a), 0x17 }, 330*bf40cc53SJai Luthra { CCI_REG8(0x3b5e), 0xef }, 331*bf40cc53SJai Luthra { CCI_REG8(0x3b60), 0x6a }, 332*bf40cc53SJai Luthra { CCI_REG8(0x3b62), 0xf6 }, 333*bf40cc53SJai Luthra { CCI_REG8(0x3b66), 0xe1 }, 334*bf40cc53SJai Luthra { CCI_REG8(0x3b6a), 0xe8 }, 335*bf40cc53SJai Luthra { CCI_REG8(0x3b88), 0xec }, 336*bf40cc53SJai Luthra { CCI_REG8(0x3b8a), 0xed }, 337*bf40cc53SJai Luthra { CCI_REG8(0x3b94), 0x71 }, 338*bf40cc53SJai Luthra { CCI_REG8(0x3b96), 0x72 }, 339*bf40cc53SJai Luthra { CCI_REG8(0x3b98), 0xde }, 340*bf40cc53SJai Luthra { CCI_REG8(0x3b9a), 0xdf }, 341*bf40cc53SJai Luthra { CCI_REG8(0x3c0f), 0x06 }, 342*bf40cc53SJai Luthra { CCI_REG8(0x3c10), 0x06 }, 343*bf40cc53SJai Luthra { CCI_REG8(0x3c11), 0x06 }, 344*bf40cc53SJai Luthra { CCI_REG8(0x3c12), 0x06 }, 345*bf40cc53SJai Luthra { CCI_REG8(0x3c13), 0x06 }, 346*bf40cc53SJai Luthra { CCI_REG8(0x3c18), 0x20 }, 347*bf40cc53SJai Luthra { CCI_REG8(0x3c37), 0x10 }, 348*bf40cc53SJai Luthra { CCI_REG8(0x3c3a), 0x7a }, 349*bf40cc53SJai Luthra { CCI_REG8(0x3c40), 0xf4 }, 350*bf40cc53SJai Luthra { CCI_REG8(0x3c48), 0xe6 }, 351*bf40cc53SJai Luthra { CCI_REG8(0x3c54), 0xce }, 352*bf40cc53SJai Luthra { CCI_REG8(0x3c56), 0xd0 }, 353*bf40cc53SJai Luthra { CCI_REG8(0x3c6c), 0x53 }, 354*bf40cc53SJai Luthra { CCI_REG8(0x3c6e), 0x55 }, 355*bf40cc53SJai Luthra { CCI_REG8(0x3c70), 0xc0 }, 356*bf40cc53SJai Luthra { CCI_REG8(0x3c72), 0xc2 }, 357*bf40cc53SJai Luthra { CCI_REG8(0x3c7e), 0xce }, 358*bf40cc53SJai Luthra { CCI_REG8(0x3c8c), 0xcf }, 359*bf40cc53SJai Luthra { CCI_REG8(0x3c8e), 0xeb }, 360*bf40cc53SJai Luthra { CCI_REG8(0x3c98), 0x54 }, 361*bf40cc53SJai Luthra { CCI_REG8(0x3c9a), 0x70 }, 362*bf40cc53SJai Luthra { CCI_REG8(0x3c9c), 0xc1 }, 363*bf40cc53SJai Luthra { CCI_REG8(0x3c9e), 0xdd }, 364*bf40cc53SJai Luthra { CCI_REG8(0x3cb0), 0x7a }, 365*bf40cc53SJai Luthra { CCI_REG8(0x3cb2), 0xba }, 366*bf40cc53SJai Luthra { CCI_REG8(0x3cc8), 0xbc }, 367*bf40cc53SJai Luthra { CCI_REG8(0x3cca), 0x7c }, 368*bf40cc53SJai Luthra { CCI_REG8(0x3cd4), 0xea }, 369*bf40cc53SJai Luthra { CCI_REG8(0x3cd5), 0x01 }, 370*bf40cc53SJai Luthra { CCI_REG8(0x3cd6), 0x4a }, 371*bf40cc53SJai Luthra { CCI_REG8(0x3cd8), 0x00 }, 372*bf40cc53SJai Luthra { CCI_REG8(0x3cd9), 0x00 }, 373*bf40cc53SJai Luthra { CCI_REG8(0x3cda), 0xff }, 374*bf40cc53SJai Luthra { CCI_REG8(0x3cdb), 0x03 }, 375*bf40cc53SJai Luthra { CCI_REG8(0x3cdc), 0x00 }, 376*bf40cc53SJai Luthra { CCI_REG8(0x3cdd), 0x00 }, 377*bf40cc53SJai Luthra { CCI_REG8(0x3cde), 0xff }, 378*bf40cc53SJai Luthra { CCI_REG8(0x3cdf), 0x03 }, 379*bf40cc53SJai Luthra { CCI_REG8(0x3ce4), 0x4c }, 380*bf40cc53SJai Luthra { CCI_REG8(0x3ce6), 0xec }, 381*bf40cc53SJai Luthra { CCI_REG8(0x3ce7), 0x01 }, 382*bf40cc53SJai Luthra { CCI_REG8(0x3ce8), 0xff }, 383*bf40cc53SJai Luthra { CCI_REG8(0x3ce9), 0x03 }, 384*bf40cc53SJai Luthra { CCI_REG8(0x3cea), 0x00 }, 385*bf40cc53SJai Luthra { CCI_REG8(0x3ceb), 0x00 }, 386*bf40cc53SJai Luthra { CCI_REG8(0x3cec), 0xff }, 387*bf40cc53SJai Luthra { CCI_REG8(0x3ced), 0x03 }, 388*bf40cc53SJai Luthra { CCI_REG8(0x3cee), 0x00 }, 389*bf40cc53SJai Luthra { CCI_REG8(0x3cef), 0x00 }, 390*bf40cc53SJai Luthra { CCI_REG8(0x3cf2), 0xff }, 391*bf40cc53SJai Luthra { CCI_REG8(0x3cf3), 0x03 }, 392*bf40cc53SJai Luthra { CCI_REG8(0x3cf4), 0x00 }, 393*bf40cc53SJai Luthra { CCI_REG8(0x3e28), 0x82 }, 394*bf40cc53SJai Luthra { CCI_REG8(0x3e2a), 0x80 }, 395*bf40cc53SJai Luthra { CCI_REG8(0x3e30), 0x85 }, 396*bf40cc53SJai Luthra { CCI_REG8(0x3e32), 0x7d }, 397*bf40cc53SJai Luthra { CCI_REG8(0x3e5c), 0xce }, 398*bf40cc53SJai Luthra { CCI_REG8(0x3e5e), 0xd3 }, 399*bf40cc53SJai Luthra { CCI_REG8(0x3e70), 0x53 }, 400*bf40cc53SJai Luthra { CCI_REG8(0x3e72), 0x58 }, 401*bf40cc53SJai Luthra { CCI_REG8(0x3e74), 0xc0 }, 402*bf40cc53SJai Luthra { CCI_REG8(0x3e76), 0xc5 }, 403*bf40cc53SJai Luthra { CCI_REG8(0x3e78), 0xc0 }, 404*bf40cc53SJai Luthra { CCI_REG8(0x3e79), 0x01 }, 405*bf40cc53SJai Luthra { CCI_REG8(0x3e7a), 0xd4 }, 406*bf40cc53SJai Luthra { CCI_REG8(0x3e7b), 0x01 }, 407*bf40cc53SJai Luthra { CCI_REG8(0x3eb4), 0x0b }, 408*bf40cc53SJai Luthra { CCI_REG8(0x3eb5), 0x02 }, 409*bf40cc53SJai Luthra { CCI_REG8(0x3eb6), 0x4d }, 410*bf40cc53SJai Luthra { CCI_REG8(0x3eb7), 0x42 }, 411*bf40cc53SJai Luthra { CCI_REG8(0x3eec), 0xf3 }, 412*bf40cc53SJai Luthra { CCI_REG8(0x3eee), 0xe7 }, 413*bf40cc53SJai Luthra { CCI_REG8(0x3f01), 0x01 }, 414*bf40cc53SJai Luthra { CCI_REG8(0x3f24), 0x10 }, 415*bf40cc53SJai Luthra { CCI_REG8(0x3f28), 0x2d }, 416*bf40cc53SJai Luthra { CCI_REG8(0x3f2a), 0x2d }, 417*bf40cc53SJai Luthra { CCI_REG8(0x3f2c), 0x2d }, 418*bf40cc53SJai Luthra { CCI_REG8(0x3f2e), 0x2d }, 419*bf40cc53SJai Luthra { CCI_REG8(0x3f30), 0x23 }, 420*bf40cc53SJai Luthra { CCI_REG8(0x3f38), 0x2d }, 421*bf40cc53SJai Luthra { CCI_REG8(0x3f3a), 0x2d }, 422*bf40cc53SJai Luthra { CCI_REG8(0x3f3c), 0x2d }, 423*bf40cc53SJai Luthra { CCI_REG8(0x3f3e), 0x28 }, 424*bf40cc53SJai Luthra { CCI_REG8(0x3f40), 0x1e }, 425*bf40cc53SJai Luthra { CCI_REG8(0x3f48), 0x2d }, 426*bf40cc53SJai Luthra { CCI_REG8(0x3f4a), 0x2d }, 427*bf40cc53SJai Luthra { CCI_REG8(0x3f4c), 0x00 }, 428*bf40cc53SJai Luthra { CCI_REG8(0x4004), 0xe4 }, 429*bf40cc53SJai Luthra { CCI_REG8(0x4006), 0xff }, 430*bf40cc53SJai Luthra { CCI_REG8(0x4018), 0x69 }, 431*bf40cc53SJai Luthra { CCI_REG8(0x401a), 0x84 }, 432*bf40cc53SJai Luthra { CCI_REG8(0x401c), 0xd6 }, 433*bf40cc53SJai Luthra { CCI_REG8(0x401e), 0xf1 }, 434*bf40cc53SJai Luthra { CCI_REG8(0x4038), 0xde }, 435*bf40cc53SJai Luthra { CCI_REG8(0x403a), 0x00 }, 436*bf40cc53SJai Luthra { CCI_REG8(0x403b), 0x01 }, 437*bf40cc53SJai Luthra { CCI_REG8(0x404c), 0x63 }, 438*bf40cc53SJai Luthra { CCI_REG8(0x404e), 0x85 }, 439*bf40cc53SJai Luthra { CCI_REG8(0x4050), 0xd0 }, 440*bf40cc53SJai Luthra { CCI_REG8(0x4052), 0xf2 }, 441*bf40cc53SJai Luthra { CCI_REG8(0x4108), 0xdd }, 442*bf40cc53SJai Luthra { CCI_REG8(0x410a), 0xf7 }, 443*bf40cc53SJai Luthra { CCI_REG8(0x411c), 0x62 }, 444*bf40cc53SJai Luthra { CCI_REG8(0x411e), 0x7c }, 445*bf40cc53SJai Luthra { CCI_REG8(0x4120), 0xcf }, 446*bf40cc53SJai Luthra { CCI_REG8(0x4122), 0xe9 }, 447*bf40cc53SJai Luthra { CCI_REG8(0x4138), 0xe6 }, 448*bf40cc53SJai Luthra { CCI_REG8(0x413a), 0xf1 }, 449*bf40cc53SJai Luthra { CCI_REG8(0x414c), 0x6b }, 450*bf40cc53SJai Luthra { CCI_REG8(0x414e), 0x76 }, 451*bf40cc53SJai Luthra { CCI_REG8(0x4150), 0xd8 }, 452*bf40cc53SJai Luthra { CCI_REG8(0x4152), 0xe3 }, 453*bf40cc53SJai Luthra { CCI_REG8(0x417e), 0x03 }, 454*bf40cc53SJai Luthra { CCI_REG8(0x417f), 0x01 }, 455*bf40cc53SJai Luthra { CCI_REG8(0x4186), 0xe0 }, 456*bf40cc53SJai Luthra { CCI_REG8(0x4190), 0xf3 }, 457*bf40cc53SJai Luthra { CCI_REG8(0x4192), 0xf7 }, 458*bf40cc53SJai Luthra { CCI_REG8(0x419c), 0x78 }, 459*bf40cc53SJai Luthra { CCI_REG8(0x419e), 0x7c }, 460*bf40cc53SJai Luthra { CCI_REG8(0x41a0), 0xe5 }, 461*bf40cc53SJai Luthra { CCI_REG8(0x41a2), 0xe9 }, 462*bf40cc53SJai Luthra { CCI_REG8(0x41c8), 0xe2 }, 463*bf40cc53SJai Luthra { CCI_REG8(0x41ca), 0xfd }, 464*bf40cc53SJai Luthra { CCI_REG8(0x41dc), 0x67 }, 465*bf40cc53SJai Luthra { CCI_REG8(0x41de), 0x82 }, 466*bf40cc53SJai Luthra { CCI_REG8(0x41e0), 0xd4 }, 467*bf40cc53SJai Luthra { CCI_REG8(0x41e2), 0xef }, 468*bf40cc53SJai Luthra { CCI_REG8(0x4200), 0xde }, 469*bf40cc53SJai Luthra { CCI_REG8(0x4202), 0xda }, 470*bf40cc53SJai Luthra { CCI_REG8(0x4218), 0x63 }, 471*bf40cc53SJai Luthra { CCI_REG8(0x421a), 0x5f }, 472*bf40cc53SJai Luthra { CCI_REG8(0x421c), 0xd0 }, 473*bf40cc53SJai Luthra { CCI_REG8(0x421e), 0xcc }, 474*bf40cc53SJai Luthra { CCI_REG8(0x425a), 0x82 }, 475*bf40cc53SJai Luthra { CCI_REG8(0x425c), 0xef }, 476*bf40cc53SJai Luthra { CCI_REG8(0x4348), 0xfe }, 477*bf40cc53SJai Luthra { CCI_REG8(0x4349), 0x06 }, 478*bf40cc53SJai Luthra { CCI_REG8(0x4352), 0xce }, 479*bf40cc53SJai Luthra { CCI_REG8(0x4420), 0x0b }, 480*bf40cc53SJai Luthra { CCI_REG8(0x4421), 0x02 }, 481*bf40cc53SJai Luthra { CCI_REG8(0x4422), 0x4d }, 482*bf40cc53SJai Luthra { CCI_REG8(0x4423), 0x0a }, 483*bf40cc53SJai Luthra { CCI_REG8(0x4426), 0xf5 }, 484*bf40cc53SJai Luthra { CCI_REG8(0x442a), 0xe7 }, 485*bf40cc53SJai Luthra { CCI_REG8(0x4432), 0xf5 }, 486*bf40cc53SJai Luthra { CCI_REG8(0x4436), 0xe7 }, 487*bf40cc53SJai Luthra { CCI_REG8(0x4466), 0xb4 }, 488*bf40cc53SJai Luthra { CCI_REG8(0x446e), 0x32 }, 489*bf40cc53SJai Luthra { CCI_REG8(0x449f), 0x1c }, 490*bf40cc53SJai Luthra { CCI_REG8(0x44a4), 0x2c }, 491*bf40cc53SJai Luthra { CCI_REG8(0x44a6), 0x2c }, 492*bf40cc53SJai Luthra { CCI_REG8(0x44a8), 0x2c }, 493*bf40cc53SJai Luthra { CCI_REG8(0x44aa), 0x2c }, 494*bf40cc53SJai Luthra { CCI_REG8(0x44b4), 0x2c }, 495*bf40cc53SJai Luthra { CCI_REG8(0x44b6), 0x2c }, 496*bf40cc53SJai Luthra { CCI_REG8(0x44b8), 0x2c }, 497*bf40cc53SJai Luthra { CCI_REG8(0x44ba), 0x2c }, 498*bf40cc53SJai Luthra { CCI_REG8(0x44c4), 0x2c }, 499*bf40cc53SJai Luthra { CCI_REG8(0x44c6), 0x2c }, 500*bf40cc53SJai Luthra { CCI_REG8(0x44c8), 0x2c }, 501*bf40cc53SJai Luthra { CCI_REG8(0x4506), 0xf3 }, 502*bf40cc53SJai Luthra { CCI_REG8(0x450e), 0xe5 }, 503*bf40cc53SJai Luthra { CCI_REG8(0x4516), 0xf3 }, 504*bf40cc53SJai Luthra { CCI_REG8(0x4522), 0xe5 }, 505*bf40cc53SJai Luthra { CCI_REG8(0x4524), 0xf3 }, 506*bf40cc53SJai Luthra { CCI_REG8(0x452c), 0xe5 }, 507*bf40cc53SJai Luthra { CCI_REG8(0x453c), 0x22 }, 508*bf40cc53SJai Luthra { CCI_REG8(0x453d), 0x1b }, 509*bf40cc53SJai Luthra { CCI_REG8(0x453e), 0x1b }, 510*bf40cc53SJai Luthra { CCI_REG8(0x453f), 0x15 }, 511*bf40cc53SJai Luthra { CCI_REG8(0x4540), 0x15 }, 512*bf40cc53SJai Luthra { CCI_REG8(0x4541), 0x15 }, 513*bf40cc53SJai Luthra { CCI_REG8(0x4542), 0x15 }, 514*bf40cc53SJai Luthra { CCI_REG8(0x4543), 0x15 }, 515*bf40cc53SJai Luthra { CCI_REG8(0x4544), 0x15 }, 516*bf40cc53SJai Luthra { CCI_REG8(0x4548), 0x00 }, 517*bf40cc53SJai Luthra { CCI_REG8(0x4549), 0x01 }, 518*bf40cc53SJai Luthra { CCI_REG8(0x454a), 0x01 }, 519*bf40cc53SJai Luthra { CCI_REG8(0x454b), 0x06 }, 520*bf40cc53SJai Luthra { CCI_REG8(0x454c), 0x06 }, 521*bf40cc53SJai Luthra { CCI_REG8(0x454d), 0x06 }, 522*bf40cc53SJai Luthra { CCI_REG8(0x454e), 0x06 }, 523*bf40cc53SJai Luthra { CCI_REG8(0x454f), 0x06 }, 524*bf40cc53SJai Luthra { CCI_REG8(0x4550), 0x06 }, 525*bf40cc53SJai Luthra { CCI_REG8(0x4554), 0x55 }, 526*bf40cc53SJai Luthra { CCI_REG8(0x4555), 0x02 }, 527*bf40cc53SJai Luthra { CCI_REG8(0x4556), 0x42 }, 528*bf40cc53SJai Luthra { CCI_REG8(0x4557), 0x05 }, 529*bf40cc53SJai Luthra { CCI_REG8(0x4558), 0xfd }, 530*bf40cc53SJai Luthra { CCI_REG8(0x4559), 0x05 }, 531*bf40cc53SJai Luthra { CCI_REG8(0x455a), 0x94 }, 532*bf40cc53SJai Luthra { CCI_REG8(0x455b), 0x06 }, 533*bf40cc53SJai Luthra { CCI_REG8(0x455d), 0x06 }, 534*bf40cc53SJai Luthra { CCI_REG8(0x455e), 0x49 }, 535*bf40cc53SJai Luthra { CCI_REG8(0x455f), 0x07 }, 536*bf40cc53SJai Luthra { CCI_REG8(0x4560), 0x7f }, 537*bf40cc53SJai Luthra { CCI_REG8(0x4561), 0x07 }, 538*bf40cc53SJai Luthra { CCI_REG8(0x4562), 0xa5 }, 539*bf40cc53SJai Luthra { CCI_REG8(0x4564), 0x55 }, 540*bf40cc53SJai Luthra { CCI_REG8(0x4565), 0x02 }, 541*bf40cc53SJai Luthra { CCI_REG8(0x4566), 0x42 }, 542*bf40cc53SJai Luthra { CCI_REG8(0x4567), 0x05 }, 543*bf40cc53SJai Luthra { CCI_REG8(0x4568), 0xfd }, 544*bf40cc53SJai Luthra { CCI_REG8(0x4569), 0x05 }, 545*bf40cc53SJai Luthra { CCI_REG8(0x456a), 0x94 }, 546*bf40cc53SJai Luthra { CCI_REG8(0x456b), 0x06 }, 547*bf40cc53SJai Luthra { CCI_REG8(0x456d), 0x06 }, 548*bf40cc53SJai Luthra { CCI_REG8(0x456e), 0x49 }, 549*bf40cc53SJai Luthra { CCI_REG8(0x456f), 0x07 }, 550*bf40cc53SJai Luthra { CCI_REG8(0x4572), 0xa5 }, 551*bf40cc53SJai Luthra { CCI_REG8(0x460c), 0x7d }, 552*bf40cc53SJai Luthra { CCI_REG8(0x460e), 0xb1 }, 553*bf40cc53SJai Luthra { CCI_REG8(0x4614), 0xa8 }, 554*bf40cc53SJai Luthra { CCI_REG8(0x4616), 0xb2 }, 555*bf40cc53SJai Luthra { CCI_REG8(0x461c), 0x7e }, 556*bf40cc53SJai Luthra { CCI_REG8(0x461e), 0xa7 }, 557*bf40cc53SJai Luthra { CCI_REG8(0x4624), 0xa8 }, 558*bf40cc53SJai Luthra { CCI_REG8(0x4626), 0xb2 }, 559*bf40cc53SJai Luthra { CCI_REG8(0x462c), 0x7e }, 560*bf40cc53SJai Luthra { CCI_REG8(0x462e), 0x8a }, 561*bf40cc53SJai Luthra { CCI_REG8(0x4630), 0x94 }, 562*bf40cc53SJai Luthra { CCI_REG8(0x4632), 0xa7 }, 563*bf40cc53SJai Luthra { CCI_REG8(0x4634), 0xfb }, 564*bf40cc53SJai Luthra { CCI_REG8(0x4636), 0x2f }, 565*bf40cc53SJai Luthra { CCI_REG8(0x4638), 0x81 }, 566*bf40cc53SJai Luthra { CCI_REG8(0x4639), 0x01 }, 567*bf40cc53SJai Luthra { CCI_REG8(0x463a), 0xb5 }, 568*bf40cc53SJai Luthra { CCI_REG8(0x463b), 0x01 }, 569*bf40cc53SJai Luthra { CCI_REG8(0x463c), 0x26 }, 570*bf40cc53SJai Luthra { CCI_REG8(0x463e), 0x30 }, 571*bf40cc53SJai Luthra { CCI_REG8(0x4640), 0xac }, 572*bf40cc53SJai Luthra { CCI_REG8(0x4641), 0x01 }, 573*bf40cc53SJai Luthra { CCI_REG8(0x4642), 0xb6 }, 574*bf40cc53SJai Luthra { CCI_REG8(0x4643), 0x01 }, 575*bf40cc53SJai Luthra { CCI_REG8(0x4644), 0xfc }, 576*bf40cc53SJai Luthra { CCI_REG8(0x4646), 0x25 }, 577*bf40cc53SJai Luthra { CCI_REG8(0x4648), 0x82 }, 578*bf40cc53SJai Luthra { CCI_REG8(0x4649), 0x01 }, 579*bf40cc53SJai Luthra { CCI_REG8(0x464a), 0xab }, 580*bf40cc53SJai Luthra { CCI_REG8(0x464b), 0x01 }, 581*bf40cc53SJai Luthra { CCI_REG8(0x464c), 0x26 }, 582*bf40cc53SJai Luthra { CCI_REG8(0x464e), 0x30 }, 583*bf40cc53SJai Luthra { CCI_REG8(0x4654), 0xfc }, 584*bf40cc53SJai Luthra { CCI_REG8(0x4656), 0x08 }, 585*bf40cc53SJai Luthra { CCI_REG8(0x4658), 0x12 }, 586*bf40cc53SJai Luthra { CCI_REG8(0x465a), 0x25 }, 587*bf40cc53SJai Luthra { CCI_REG8(0x4662), 0xfc }, 588*bf40cc53SJai Luthra { CCI_REG8(0x46a2), 0xfb }, 589*bf40cc53SJai Luthra { CCI_REG8(0x46d6), 0xf3 }, 590*bf40cc53SJai Luthra { CCI_REG8(0x46e6), 0x00 }, 591*bf40cc53SJai Luthra { CCI_REG8(0x46e8), 0xff }, 592*bf40cc53SJai Luthra { CCI_REG8(0x46e9), 0x03 }, 593*bf40cc53SJai Luthra { CCI_REG8(0x46ec), 0x7a }, 594*bf40cc53SJai Luthra { CCI_REG8(0x46ee), 0xe5 }, 595*bf40cc53SJai Luthra { CCI_REG8(0x46f4), 0xee }, 596*bf40cc53SJai Luthra { CCI_REG8(0x46f6), 0xf2 }, 597*bf40cc53SJai Luthra { CCI_REG8(0x470c), 0xff }, 598*bf40cc53SJai Luthra { CCI_REG8(0x470d), 0x03 }, 599*bf40cc53SJai Luthra { CCI_REG8(0x470e), 0x00 }, 600*bf40cc53SJai Luthra { CCI_REG8(0x4714), 0xe0 }, 601*bf40cc53SJai Luthra { CCI_REG8(0x4716), 0xe4 }, 602*bf40cc53SJai Luthra { CCI_REG8(0x471e), 0xed }, 603*bf40cc53SJai Luthra { CCI_REG8(0x472e), 0x00 }, 604*bf40cc53SJai Luthra { CCI_REG8(0x4730), 0xff }, 605*bf40cc53SJai Luthra { CCI_REG8(0x4731), 0x03 }, 606*bf40cc53SJai Luthra { CCI_REG8(0x4734), 0x7b }, 607*bf40cc53SJai Luthra { CCI_REG8(0x4736), 0xdf }, 608*bf40cc53SJai Luthra { CCI_REG8(0x4754), 0x7d }, 609*bf40cc53SJai Luthra { CCI_REG8(0x4756), 0x8b }, 610*bf40cc53SJai Luthra { CCI_REG8(0x4758), 0x93 }, 611*bf40cc53SJai Luthra { CCI_REG8(0x475a), 0xb1 }, 612*bf40cc53SJai Luthra { CCI_REG8(0x475c), 0xfb }, 613*bf40cc53SJai Luthra { CCI_REG8(0x475e), 0x09 }, 614*bf40cc53SJai Luthra { CCI_REG8(0x4760), 0x11 }, 615*bf40cc53SJai Luthra { CCI_REG8(0x4762), 0x2f }, 616*bf40cc53SJai Luthra { CCI_REG8(0x4766), 0xcc }, 617*bf40cc53SJai Luthra { CCI_REG8(0x4776), 0xcb }, 618*bf40cc53SJai Luthra { CCI_REG8(0x477e), 0x4a }, 619*bf40cc53SJai Luthra { CCI_REG8(0x478e), 0x49 }, 620*bf40cc53SJai Luthra { CCI_REG8(0x4794), 0x7c }, 621*bf40cc53SJai Luthra { CCI_REG8(0x4796), 0x8f }, 622*bf40cc53SJai Luthra { CCI_REG8(0x4798), 0xb3 }, 623*bf40cc53SJai Luthra { CCI_REG8(0x4799), 0x00 }, 624*bf40cc53SJai Luthra { CCI_REG8(0x479a), 0xcc }, 625*bf40cc53SJai Luthra { CCI_REG8(0x479c), 0xc1 }, 626*bf40cc53SJai Luthra { CCI_REG8(0x479e), 0xcb }, 627*bf40cc53SJai Luthra { CCI_REG8(0x47a4), 0x7d }, 628*bf40cc53SJai Luthra { CCI_REG8(0x47a6), 0x8e }, 629*bf40cc53SJai Luthra { CCI_REG8(0x47a8), 0xb4 }, 630*bf40cc53SJai Luthra { CCI_REG8(0x47a9), 0x00 }, 631*bf40cc53SJai Luthra { CCI_REG8(0x47aa), 0xc0 }, 632*bf40cc53SJai Luthra { CCI_REG8(0x47ac), 0xfa }, 633*bf40cc53SJai Luthra { CCI_REG8(0x47ae), 0x0d }, 634*bf40cc53SJai Luthra { CCI_REG8(0x47b0), 0x31 }, 635*bf40cc53SJai Luthra { CCI_REG8(0x47b1), 0x01 }, 636*bf40cc53SJai Luthra { CCI_REG8(0x47b2), 0x4a }, 637*bf40cc53SJai Luthra { CCI_REG8(0x47b3), 0x01 }, 638*bf40cc53SJai Luthra { CCI_REG8(0x47b4), 0x3f }, 639*bf40cc53SJai Luthra { CCI_REG8(0x47b6), 0x49 }, 640*bf40cc53SJai Luthra { CCI_REG8(0x47bc), 0xfb }, 641*bf40cc53SJai Luthra { CCI_REG8(0x47be), 0x0c }, 642*bf40cc53SJai Luthra { CCI_REG8(0x47c0), 0x32 }, 643*bf40cc53SJai Luthra { CCI_REG8(0x47c1), 0x01 }, 644*bf40cc53SJai Luthra { CCI_REG8(0x47c2), 0x3e }, 645*bf40cc53SJai Luthra { CCI_REG8(0x47c3), 0x01 }, 646*bf40cc53SJai Luthra { IMX678_REG_WDMODE, 0x00 }, 647*bf40cc53SJai Luthra { IMX678_REG_MDBIT, 0x01 }, 648*bf40cc53SJai Luthra { IMX678_REG_XXS_DRV, 0x00 }, 649*bf40cc53SJai Luthra }; 650*bf40cc53SJai Luthra 651*bf40cc53SJai Luthra static const u32 codes_bayer[] = { 652*bf40cc53SJai Luthra MEDIA_BUS_FMT_SRGGB12_1X12, 653*bf40cc53SJai Luthra }; 654*bf40cc53SJai Luthra 655*bf40cc53SJai Luthra static const u32 codes_monochrome[] = { 656*bf40cc53SJai Luthra MEDIA_BUS_FMT_Y12_1X12, 657*bf40cc53SJai Luthra }; 658*bf40cc53SJai Luthra 659*bf40cc53SJai Luthra static const struct imx678_model_info imx678_aaqr_info = { 660*bf40cc53SJai Luthra .type = IMX678_COLOR, 661*bf40cc53SJai Luthra .codes = codes_bayer, 662*bf40cc53SJai Luthra .num_codes = ARRAY_SIZE(codes_bayer), 663*bf40cc53SJai Luthra }; 664*bf40cc53SJai Luthra 665*bf40cc53SJai Luthra static const struct imx678_model_info imx678_aamr_info = { 666*bf40cc53SJai Luthra .type = IMX678_MONOCHROME, 667*bf40cc53SJai Luthra .codes = codes_monochrome, 668*bf40cc53SJai Luthra .num_codes = ARRAY_SIZE(codes_monochrome), 669*bf40cc53SJai Luthra }; 670*bf40cc53SJai Luthra 671*bf40cc53SJai Luthra static const char * const imx678_supply_name[] = { 672*bf40cc53SJai Luthra "avdd", /* Analog (3.3V) supply */ 673*bf40cc53SJai Luthra "dvdd", /* Digital Core (1.1V) supply */ 674*bf40cc53SJai Luthra "ovdd", /* IF (1.8V) supply */ 675*bf40cc53SJai Luthra }; 676*bf40cc53SJai Luthra 677*bf40cc53SJai Luthra struct imx678 { 678*bf40cc53SJai Luthra struct v4l2_subdev sd; 679*bf40cc53SJai Luthra struct media_pad pad; 680*bf40cc53SJai Luthra struct regmap *cci; 681*bf40cc53SJai Luthra 682*bf40cc53SJai Luthra const struct imx678_model_info *info; 683*bf40cc53SJai Luthra 684*bf40cc53SJai Luthra struct clk *xclk; 685*bf40cc53SJai Luthra u32 xclk_freq; 686*bf40cc53SJai Luthra 687*bf40cc53SJai Luthra /* chosen INCK_SEL register value */ 688*bf40cc53SJai Luthra u8 inck_sel_val; 689*bf40cc53SJai Luthra 690*bf40cc53SJai Luthra /* Link configurations */ 691*bf40cc53SJai Luthra enum imx678_lanemode lane_mode; 692*bf40cc53SJai Luthra unsigned long link_freq_bitmap; 693*bf40cc53SJai Luthra 694*bf40cc53SJai Luthra struct gpio_desc *reset_gpio; 695*bf40cc53SJai Luthra struct regulator_bulk_data supplies[ARRAY_SIZE(imx678_supply_name)]; 696*bf40cc53SJai Luthra 697*bf40cc53SJai Luthra struct v4l2_ctrl_handler ctrl_handler; 698*bf40cc53SJai Luthra 699*bf40cc53SJai Luthra /* V4L2 Controls */ 700*bf40cc53SJai Luthra struct v4l2_ctrl *exposure; 701*bf40cc53SJai Luthra struct v4l2_ctrl *vblank; 702*bf40cc53SJai Luthra struct v4l2_ctrl *hblank; 703*bf40cc53SJai Luthra 704*bf40cc53SJai Luthra /* Track VMAX for exposure updates */ 705*bf40cc53SJai Luthra u32 vmax; 706*bf40cc53SJai Luthra }; 707*bf40cc53SJai Luthra 708*bf40cc53SJai Luthra static inline struct imx678 *to_imx678(struct v4l2_subdev *_sd) 709*bf40cc53SJai Luthra { 710*bf40cc53SJai Luthra return container_of_const(_sd, struct imx678, sd); 711*bf40cc53SJai Luthra } 712*bf40cc53SJai Luthra 713*bf40cc53SJai Luthra static u32 imx678_default_mbus_code(struct imx678 *imx678) 714*bf40cc53SJai Luthra { 715*bf40cc53SJai Luthra return imx678->info->codes[0]; 716*bf40cc53SJai Luthra } 717*bf40cc53SJai Luthra 718*bf40cc53SJai Luthra static bool imx678_mbus_code_supported(struct imx678 *imx678, u32 code) 719*bf40cc53SJai Luthra { 720*bf40cc53SJai Luthra for (unsigned int i = 0; i < imx678->info->num_codes; i++) { 721*bf40cc53SJai Luthra if (imx678->info->codes[i] == code) 722*bf40cc53SJai Luthra return true; 723*bf40cc53SJai Luthra } 724*bf40cc53SJai Luthra 725*bf40cc53SJai Luthra return false; 726*bf40cc53SJai Luthra } 727*bf40cc53SJai Luthra 728*bf40cc53SJai Luthra static int imx678_set_ctrl(struct v4l2_ctrl *ctrl) 729*bf40cc53SJai Luthra { 730*bf40cc53SJai Luthra struct imx678 *imx678 = container_of_const(ctrl->handler, struct 731*bf40cc53SJai Luthra imx678, ctrl_handler); 732*bf40cc53SJai Luthra struct i2c_client *client = v4l2_get_subdevdata(&imx678->sd); 733*bf40cc53SJai Luthra const struct v4l2_mbus_framefmt *format; 734*bf40cc53SJai Luthra struct v4l2_subdev_state *state; 735*bf40cc53SJai Luthra int ret = 0; 736*bf40cc53SJai Luthra 737*bf40cc53SJai Luthra state = v4l2_subdev_get_locked_active_state(&imx678->sd); 738*bf40cc53SJai Luthra format = v4l2_subdev_state_get_format(state, IMX678_SOURCE_PAD); 739*bf40cc53SJai Luthra 740*bf40cc53SJai Luthra if (ctrl->id == V4L2_CID_VBLANK) { 741*bf40cc53SJai Luthra u32 current_exposure = imx678->exposure->cur.val; 742*bf40cc53SJai Luthra 743*bf40cc53SJai Luthra imx678->vmax = format->height + ctrl->val; 744*bf40cc53SJai Luthra 745*bf40cc53SJai Luthra current_exposure = clamp_t(u32, current_exposure, 746*bf40cc53SJai Luthra IMX678_EXPOSURE_MIN, 747*bf40cc53SJai Luthra imx678->vmax - IMX678_SHR_MIN); 748*bf40cc53SJai Luthra ret = __v4l2_ctrl_modify_range(imx678->exposure, 749*bf40cc53SJai Luthra IMX678_EXPOSURE_MIN, 750*bf40cc53SJai Luthra imx678->vmax - IMX678_SHR_MIN, 751*bf40cc53SJai Luthra 1, current_exposure); 752*bf40cc53SJai Luthra if (ret) 753*bf40cc53SJai Luthra return ret; 754*bf40cc53SJai Luthra } 755*bf40cc53SJai Luthra 756*bf40cc53SJai Luthra /* 757*bf40cc53SJai Luthra * Only apply control values when device is powered on (RPM ACTIVE) 758*bf40cc53SJai Luthra * and streaming (usage count != 0) 759*bf40cc53SJai Luthra */ 760*bf40cc53SJai Luthra if (!pm_runtime_get_if_in_use(&client->dev)) 761*bf40cc53SJai Luthra return 0; 762*bf40cc53SJai Luthra 763*bf40cc53SJai Luthra switch (ctrl->id) { 764*bf40cc53SJai Luthra case V4L2_CID_VBLANK: 765*bf40cc53SJai Luthra cci_write(imx678->cci, IMX678_REG_VMAX, imx678->vmax, &ret); 766*bf40cc53SJai Luthra fallthrough; /* SHR = VMAX - exposure, so update it */ 767*bf40cc53SJai Luthra case V4L2_CID_EXPOSURE: { 768*bf40cc53SJai Luthra u32 shr = imx678->vmax - imx678->exposure->val; 769*bf40cc53SJai Luthra 770*bf40cc53SJai Luthra cci_write(imx678->cci, IMX678_REG_SHR, shr, &ret); 771*bf40cc53SJai Luthra break; 772*bf40cc53SJai Luthra } 773*bf40cc53SJai Luthra case V4L2_CID_ANALOGUE_GAIN: 774*bf40cc53SJai Luthra cci_write(imx678->cci, IMX678_REG_GAIN, ctrl->val, &ret); 775*bf40cc53SJai Luthra break; 776*bf40cc53SJai Luthra case V4L2_CID_HBLANK: { 777*bf40cc53SJai Luthra u32 hmax = (format->width + ctrl->val) / IMX678_PIX_PER_CLK; 778*bf40cc53SJai Luthra 779*bf40cc53SJai Luthra cci_write(imx678->cci, IMX678_REG_HMAX, hmax, &ret); 780*bf40cc53SJai Luthra break; 781*bf40cc53SJai Luthra } 782*bf40cc53SJai Luthra case V4L2_CID_TEST_PATTERN: { 783*bf40cc53SJai Luthra cci_write(imx678->cci, IMX678_REG_TPG_COLORWIDTH, 784*bf40cc53SJai Luthra IMX678_TPG_COLORWIDTH_160PIX, &ret); 785*bf40cc53SJai Luthra cci_write(imx678->cci, IMX678_REG_TPG_PATSEL_DUOUT, 786*bf40cc53SJai Luthra imx678_tpg_val[ctrl->val], &ret); 787*bf40cc53SJai Luthra cci_write(imx678->cci, IMX678_REG_TPG_EN_DUOUT, 788*bf40cc53SJai Luthra (ctrl->val) ? 1 : 0, 789*bf40cc53SJai Luthra &ret); 790*bf40cc53SJai Luthra break; 791*bf40cc53SJai Luthra } 792*bf40cc53SJai Luthra case V4L2_CID_HFLIP: 793*bf40cc53SJai Luthra cci_write(imx678->cci, IMX678_REG_WINMODEH, ctrl->val, &ret); 794*bf40cc53SJai Luthra break; 795*bf40cc53SJai Luthra case V4L2_CID_VFLIP: 796*bf40cc53SJai Luthra cci_write(imx678->cci, IMX678_REG_WINMODEV, ctrl->val, &ret); 797*bf40cc53SJai Luthra break; 798*bf40cc53SJai Luthra default: 799*bf40cc53SJai Luthra dev_warn(&client->dev, 800*bf40cc53SJai Luthra "ctrl(id:0x%x,val:0x%x) is not handled\n", 801*bf40cc53SJai Luthra ctrl->id, ctrl->val); 802*bf40cc53SJai Luthra break; 803*bf40cc53SJai Luthra } 804*bf40cc53SJai Luthra 805*bf40cc53SJai Luthra pm_runtime_put(&client->dev); 806*bf40cc53SJai Luthra 807*bf40cc53SJai Luthra return ret; 808*bf40cc53SJai Luthra } 809*bf40cc53SJai Luthra 810*bf40cc53SJai Luthra static const struct v4l2_ctrl_ops imx678_ctrl_ops = { 811*bf40cc53SJai Luthra .s_ctrl = imx678_set_ctrl, 812*bf40cc53SJai Luthra }; 813*bf40cc53SJai Luthra 814*bf40cc53SJai Luthra static int imx678_enum_mbus_code(struct v4l2_subdev *sd, 815*bf40cc53SJai Luthra struct v4l2_subdev_state *sd_state, 816*bf40cc53SJai Luthra struct v4l2_subdev_mbus_code_enum *code) 817*bf40cc53SJai Luthra { 818*bf40cc53SJai Luthra struct imx678 *imx678 = to_imx678(sd); 819*bf40cc53SJai Luthra 820*bf40cc53SJai Luthra if (code->index >= imx678->info->num_codes) 821*bf40cc53SJai Luthra return -EINVAL; 822*bf40cc53SJai Luthra 823*bf40cc53SJai Luthra code->code = imx678->info->codes[code->index]; 824*bf40cc53SJai Luthra 825*bf40cc53SJai Luthra return 0; 826*bf40cc53SJai Luthra } 827*bf40cc53SJai Luthra 828*bf40cc53SJai Luthra static int imx678_enum_frame_size(struct v4l2_subdev *sd, 829*bf40cc53SJai Luthra struct v4l2_subdev_state *sd_state, 830*bf40cc53SJai Luthra struct v4l2_subdev_frame_size_enum *fse) 831*bf40cc53SJai Luthra { 832*bf40cc53SJai Luthra struct imx678 *imx678 = to_imx678(sd); 833*bf40cc53SJai Luthra const struct v4l2_rect *crop; 834*bf40cc53SJai Luthra 835*bf40cc53SJai Luthra if (fse->index) 836*bf40cc53SJai Luthra return -EINVAL; 837*bf40cc53SJai Luthra 838*bf40cc53SJai Luthra if (!imx678_mbus_code_supported(imx678, fse->code)) 839*bf40cc53SJai Luthra return -EINVAL; 840*bf40cc53SJai Luthra 841*bf40cc53SJai Luthra crop = v4l2_subdev_state_get_crop(sd_state, fse->pad); 842*bf40cc53SJai Luthra 843*bf40cc53SJai Luthra fse->min_width = crop->width; 844*bf40cc53SJai Luthra fse->max_width = fse->min_width; 845*bf40cc53SJai Luthra fse->min_height = crop->height; 846*bf40cc53SJai Luthra fse->max_height = fse->min_height; 847*bf40cc53SJai Luthra 848*bf40cc53SJai Luthra return 0; 849*bf40cc53SJai Luthra } 850*bf40cc53SJai Luthra 851*bf40cc53SJai Luthra static int imx678_get_selection(struct v4l2_subdev *sd, 852*bf40cc53SJai Luthra struct v4l2_subdev_state *sd_state, 853*bf40cc53SJai Luthra struct v4l2_subdev_selection *sel) 854*bf40cc53SJai Luthra { 855*bf40cc53SJai Luthra switch (sel->target) { 856*bf40cc53SJai Luthra case V4L2_SEL_TGT_CROP: 857*bf40cc53SJai Luthra sel->r = *v4l2_subdev_state_get_crop(sd_state, sel->pad); 858*bf40cc53SJai Luthra return 0; 859*bf40cc53SJai Luthra 860*bf40cc53SJai Luthra case V4L2_SEL_TGT_NATIVE_SIZE: 861*bf40cc53SJai Luthra sel->r = imx678_native_area; 862*bf40cc53SJai Luthra return 0; 863*bf40cc53SJai Luthra 864*bf40cc53SJai Luthra case V4L2_SEL_TGT_CROP_DEFAULT: 865*bf40cc53SJai Luthra case V4L2_SEL_TGT_CROP_BOUNDS: 866*bf40cc53SJai Luthra sel->r = imx678_active_area; 867*bf40cc53SJai Luthra return 0; 868*bf40cc53SJai Luthra } 869*bf40cc53SJai Luthra 870*bf40cc53SJai Luthra return -EINVAL; 871*bf40cc53SJai Luthra } 872*bf40cc53SJai Luthra 873*bf40cc53SJai Luthra static int imx678_init_state(struct v4l2_subdev *sd, 874*bf40cc53SJai Luthra struct v4l2_subdev_state *state) 875*bf40cc53SJai Luthra { 876*bf40cc53SJai Luthra struct imx678 *imx678 = to_imx678(sd); 877*bf40cc53SJai Luthra struct v4l2_mbus_framefmt *format; 878*bf40cc53SJai Luthra struct v4l2_rect *crop; 879*bf40cc53SJai Luthra 880*bf40cc53SJai Luthra crop = v4l2_subdev_state_get_crop(state, IMX678_SOURCE_PAD); 881*bf40cc53SJai Luthra *crop = imx678_active_area; 882*bf40cc53SJai Luthra 883*bf40cc53SJai Luthra format = v4l2_subdev_state_get_format(state, IMX678_SOURCE_PAD); 884*bf40cc53SJai Luthra format->code = imx678_default_mbus_code(imx678); 885*bf40cc53SJai Luthra format->width = imx678_active_area.width; 886*bf40cc53SJai Luthra format->height = imx678_active_area.height; 887*bf40cc53SJai Luthra format->field = V4L2_FIELD_NONE; 888*bf40cc53SJai Luthra format->colorspace = V4L2_COLORSPACE_RAW; 889*bf40cc53SJai Luthra format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; 890*bf40cc53SJai Luthra format->quantization = V4L2_QUANTIZATION_FULL_RANGE; 891*bf40cc53SJai Luthra format->xfer_func = V4L2_XFER_FUNC_NONE; 892*bf40cc53SJai Luthra 893*bf40cc53SJai Luthra return 0; 894*bf40cc53SJai Luthra } 895*bf40cc53SJai Luthra 896*bf40cc53SJai Luthra static int imx678_write_common(struct imx678 *imx678) 897*bf40cc53SJai Luthra { 898*bf40cc53SJai Luthra int ret = 0; 899*bf40cc53SJai Luthra 900*bf40cc53SJai Luthra cci_multi_reg_write(imx678->cci, common_regs, ARRAY_SIZE(common_regs), 901*bf40cc53SJai Luthra &ret); 902*bf40cc53SJai Luthra 903*bf40cc53SJai Luthra cci_write(imx678->cci, IMX678_REG_INCK_SEL, imx678->inck_sel_val, &ret); 904*bf40cc53SJai Luthra cci_write(imx678->cci, IMX678_REG_DATARATE_SEL, 905*bf40cc53SJai Luthra link_freqs_reg_value[__ffs(imx678->link_freq_bitmap)], &ret); 906*bf40cc53SJai Luthra cci_write(imx678->cci, IMX678_REG_LANEMODE, imx678->lane_mode, &ret); 907*bf40cc53SJai Luthra 908*bf40cc53SJai Luthra cci_write(imx678->cci, IMX678_REG_INTERFACE_SEL, IMX678_INTERFACE_2L_4L, 909*bf40cc53SJai Luthra &ret); 910*bf40cc53SJai Luthra 911*bf40cc53SJai Luthra return ret; 912*bf40cc53SJai Luthra } 913*bf40cc53SJai Luthra 914*bf40cc53SJai Luthra static int imx678_program_window(struct imx678 *imx678, 915*bf40cc53SJai Luthra const struct v4l2_rect *crop) 916*bf40cc53SJai Luthra { 917*bf40cc53SJai Luthra int ret = 0; 918*bf40cc53SJai Luthra 919*bf40cc53SJai Luthra cci_write(imx678->cci, IMX678_REG_ADDMODE, 0x00, &ret); 920*bf40cc53SJai Luthra cci_write(imx678->cci, IMX678_REG_WINMODE, 921*bf40cc53SJai Luthra v4l2_rect_equal(crop, &imx678_active_area) ? 0x00 : 0x04, 922*bf40cc53SJai Luthra &ret); 923*bf40cc53SJai Luthra cci_write(imx678->cci, IMX678_REG_PIX_HST, 924*bf40cc53SJai Luthra crop->left - imx678_active_area.left, &ret); 925*bf40cc53SJai Luthra cci_write(imx678->cci, IMX678_REG_PIX_HWIDTH, crop->width, &ret); 926*bf40cc53SJai Luthra cci_write(imx678->cci, IMX678_REG_PIX_VST, 927*bf40cc53SJai Luthra crop->top - imx678_active_area.top, &ret); 928*bf40cc53SJai Luthra cci_write(imx678->cci, IMX678_REG_PIX_VWIDTH, crop->height, &ret); 929*bf40cc53SJai Luthra cci_write(imx678->cci, IMX678_REG_ADBIT, 0x01, &ret); 930*bf40cc53SJai Luthra 931*bf40cc53SJai Luthra return ret; 932*bf40cc53SJai Luthra } 933*bf40cc53SJai Luthra 934*bf40cc53SJai Luthra static int imx678_enable_streams(struct v4l2_subdev *sd, 935*bf40cc53SJai Luthra struct v4l2_subdev_state *state, u32 pad, 936*bf40cc53SJai Luthra u64 mask) 937*bf40cc53SJai Luthra { 938*bf40cc53SJai Luthra struct i2c_client *client = v4l2_get_subdevdata(sd); 939*bf40cc53SJai Luthra struct imx678 *imx678 = to_imx678(sd); 940*bf40cc53SJai Luthra const struct v4l2_rect *crop; 941*bf40cc53SJai Luthra int ret; 942*bf40cc53SJai Luthra 943*bf40cc53SJai Luthra ret = pm_runtime_resume_and_get(&client->dev); 944*bf40cc53SJai Luthra if (ret < 0) 945*bf40cc53SJai Luthra return ret; 946*bf40cc53SJai Luthra 947*bf40cc53SJai Luthra crop = v4l2_subdev_state_get_crop(state, pad); 948*bf40cc53SJai Luthra ret = imx678_program_window(imx678, crop); 949*bf40cc53SJai Luthra if (ret) { 950*bf40cc53SJai Luthra dev_err(&client->dev, "%s failed to set mode\n", __func__); 951*bf40cc53SJai Luthra goto err_rpm_put; 952*bf40cc53SJai Luthra } 953*bf40cc53SJai Luthra 954*bf40cc53SJai Luthra ret = __v4l2_ctrl_handler_setup(imx678->sd.ctrl_handler); 955*bf40cc53SJai Luthra if (ret) { 956*bf40cc53SJai Luthra dev_err(&client->dev, "%s failed to apply user values\n", 957*bf40cc53SJai Luthra __func__); 958*bf40cc53SJai Luthra goto err_rpm_put; 959*bf40cc53SJai Luthra } 960*bf40cc53SJai Luthra 961*bf40cc53SJai Luthra cci_write(imx678->cci, IMX678_REG_MODE_SELECT, IMX678_MODE_STREAMING, 962*bf40cc53SJai Luthra &ret); 963*bf40cc53SJai Luthra usleep_range(IMX678_STREAM_DELAY_US, IMX678_STREAM_DELAY_US + 964*bf40cc53SJai Luthra IMX678_STREAM_DELAY_RANGE_US); 965*bf40cc53SJai Luthra cci_write(imx678->cci, IMX678_REG_XMSTA, 0x00, &ret); 966*bf40cc53SJai Luthra 967*bf40cc53SJai Luthra if (ret) { 968*bf40cc53SJai Luthra dev_err(&client->dev, "%s failed to start streaming\n", 969*bf40cc53SJai Luthra __func__); 970*bf40cc53SJai Luthra goto err_rpm_put; 971*bf40cc53SJai Luthra } 972*bf40cc53SJai Luthra 973*bf40cc53SJai Luthra return 0; 974*bf40cc53SJai Luthra 975*bf40cc53SJai Luthra err_rpm_put: 976*bf40cc53SJai Luthra pm_runtime_put(&client->dev); 977*bf40cc53SJai Luthra 978*bf40cc53SJai Luthra return ret; 979*bf40cc53SJai Luthra } 980*bf40cc53SJai Luthra 981*bf40cc53SJai Luthra static int imx678_disable_streams(struct v4l2_subdev *sd, 982*bf40cc53SJai Luthra struct v4l2_subdev_state *state, 983*bf40cc53SJai Luthra u32 pad, u64 mask) 984*bf40cc53SJai Luthra { 985*bf40cc53SJai Luthra struct i2c_client *client = v4l2_get_subdevdata(sd); 986*bf40cc53SJai Luthra struct imx678 *imx678 = to_imx678(sd); 987*bf40cc53SJai Luthra int ret = 0; 988*bf40cc53SJai Luthra 989*bf40cc53SJai Luthra /* Master mode disable */ 990*bf40cc53SJai Luthra cci_write(imx678->cci, IMX678_REG_XMSTA, 0x01, &ret); 991*bf40cc53SJai Luthra /* Standby */ 992*bf40cc53SJai Luthra cci_write(imx678->cci, IMX678_REG_MODE_SELECT, IMX678_MODE_STANDBY, 993*bf40cc53SJai Luthra &ret); 994*bf40cc53SJai Luthra if (ret) 995*bf40cc53SJai Luthra dev_err(&client->dev, "%s failed to stop stream\n", __func__); 996*bf40cc53SJai Luthra 997*bf40cc53SJai Luthra pm_runtime_put(&client->dev); 998*bf40cc53SJai Luthra 999*bf40cc53SJai Luthra return ret; 1000*bf40cc53SJai Luthra } 1001*bf40cc53SJai Luthra 1002*bf40cc53SJai Luthra static int imx678_power_on(struct device *dev) 1003*bf40cc53SJai Luthra { 1004*bf40cc53SJai Luthra struct i2c_client *client = to_i2c_client(dev); 1005*bf40cc53SJai Luthra struct v4l2_subdev *sd = i2c_get_clientdata(client); 1006*bf40cc53SJai Luthra struct imx678 *imx678 = to_imx678(sd); 1007*bf40cc53SJai Luthra int ret; 1008*bf40cc53SJai Luthra 1009*bf40cc53SJai Luthra ret = regulator_bulk_enable(ARRAY_SIZE(imx678_supply_name), 1010*bf40cc53SJai Luthra imx678->supplies); 1011*bf40cc53SJai Luthra if (ret) { 1012*bf40cc53SJai Luthra dev_err(&client->dev, "%s: failed to enable regulators\n", 1013*bf40cc53SJai Luthra __func__); 1014*bf40cc53SJai Luthra return ret; 1015*bf40cc53SJai Luthra } 1016*bf40cc53SJai Luthra 1017*bf40cc53SJai Luthra fsleep(1); /* Tlow > 500ns */ 1018*bf40cc53SJai Luthra 1019*bf40cc53SJai Luthra gpiod_set_value_cansleep(imx678->reset_gpio, 0); 1020*bf40cc53SJai Luthra 1021*bf40cc53SJai Luthra fsleep(1); /* T3 > 1us */ 1022*bf40cc53SJai Luthra 1023*bf40cc53SJai Luthra ret = clk_prepare_enable(imx678->xclk); 1024*bf40cc53SJai Luthra if (ret) { 1025*bf40cc53SJai Luthra dev_err(&client->dev, "%s: failed to enable clock\n", 1026*bf40cc53SJai Luthra __func__); 1027*bf40cc53SJai Luthra goto reg_off; 1028*bf40cc53SJai Luthra } 1029*bf40cc53SJai Luthra 1030*bf40cc53SJai Luthra fsleep(20); /* T4 > 20us */ 1031*bf40cc53SJai Luthra 1032*bf40cc53SJai Luthra ret = imx678_write_common(imx678); 1033*bf40cc53SJai Luthra if (ret) { 1034*bf40cc53SJai Luthra dev_err(&client->dev, "%s failed to write registers\n", 1035*bf40cc53SJai Luthra __func__); 1036*bf40cc53SJai Luthra goto clk_off; 1037*bf40cc53SJai Luthra } 1038*bf40cc53SJai Luthra 1039*bf40cc53SJai Luthra return 0; 1040*bf40cc53SJai Luthra 1041*bf40cc53SJai Luthra clk_off: 1042*bf40cc53SJai Luthra clk_disable_unprepare(imx678->xclk); 1043*bf40cc53SJai Luthra 1044*bf40cc53SJai Luthra reg_off: 1045*bf40cc53SJai Luthra gpiod_set_value_cansleep(imx678->reset_gpio, 1); 1046*bf40cc53SJai Luthra regulator_bulk_disable(ARRAY_SIZE(imx678_supply_name), 1047*bf40cc53SJai Luthra imx678->supplies); 1048*bf40cc53SJai Luthra 1049*bf40cc53SJai Luthra return ret; 1050*bf40cc53SJai Luthra } 1051*bf40cc53SJai Luthra 1052*bf40cc53SJai Luthra static int imx678_power_off(struct device *dev) 1053*bf40cc53SJai Luthra { 1054*bf40cc53SJai Luthra struct i2c_client *client = to_i2c_client(dev); 1055*bf40cc53SJai Luthra struct v4l2_subdev *sd = i2c_get_clientdata(client); 1056*bf40cc53SJai Luthra struct imx678 *imx678 = to_imx678(sd); 1057*bf40cc53SJai Luthra 1058*bf40cc53SJai Luthra clk_disable_unprepare(imx678->xclk); 1059*bf40cc53SJai Luthra gpiod_set_value_cansleep(imx678->reset_gpio, 1); 1060*bf40cc53SJai Luthra regulator_bulk_disable(ARRAY_SIZE(imx678_supply_name), 1061*bf40cc53SJai Luthra imx678->supplies); 1062*bf40cc53SJai Luthra 1063*bf40cc53SJai Luthra return 0; 1064*bf40cc53SJai Luthra } 1065*bf40cc53SJai Luthra 1066*bf40cc53SJai Luthra static int imx678_identify_model(struct imx678 *imx678) 1067*bf40cc53SJai Luthra { 1068*bf40cc53SJai Luthra struct i2c_client *client = v4l2_get_subdevdata(&imx678->sd); 1069*bf40cc53SJai Luthra const struct imx678_model_info *info; 1070*bf40cc53SJai Luthra enum imx678_type detected; 1071*bf40cc53SJai Luthra int ret = 0; 1072*bf40cc53SJai Luthra u64 val = 0; 1073*bf40cc53SJai Luthra 1074*bf40cc53SJai Luthra info = device_get_match_data(&client->dev); 1075*bf40cc53SJai Luthra 1076*bf40cc53SJai Luthra /* 1077*bf40cc53SJai Luthra * This sensor's ID registers become accessible 80ms after coming out 1078*bf40cc53SJai Luthra * of STANDBY mode. 1079*bf40cc53SJai Luthra */ 1080*bf40cc53SJai Luthra cci_write(imx678->cci, IMX678_REG_MODE_SELECT, 0, &ret); 1081*bf40cc53SJai Luthra fsleep(IMX678_MODULE_ID_DELAY); 1082*bf40cc53SJai Luthra 1083*bf40cc53SJai Luthra cci_read(imx678->cci, IMX678_REG_MODULE_ID, &val, &ret); 1084*bf40cc53SJai Luthra 1085*bf40cc53SJai Luthra if (ret) { 1086*bf40cc53SJai Luthra dev_err(&client->dev, 1087*bf40cc53SJai Luthra "I2C transaction failed ret = %d\n", ret); 1088*bf40cc53SJai Luthra return ret; 1089*bf40cc53SJai Luthra } 1090*bf40cc53SJai Luthra 1091*bf40cc53SJai Luthra if (val != IMX678_ID) { 1092*bf40cc53SJai Luthra dev_err(&client->dev, 1093*bf40cc53SJai Luthra "Chip ID mismatch: %x!=%llx\n", IMX678_ID, val); 1094*bf40cc53SJai Luthra return -ENXIO; 1095*bf40cc53SJai Luthra } 1096*bf40cc53SJai Luthra 1097*bf40cc53SJai Luthra cci_read(imx678->cci, IMX678_REG_MONOCHROME, &val, &ret); 1098*bf40cc53SJai Luthra 1099*bf40cc53SJai Luthra if (ret) { 1100*bf40cc53SJai Luthra dev_err(&client->dev, 1101*bf40cc53SJai Luthra "I2C transaction failed ret = %d\n", ret); 1102*bf40cc53SJai Luthra return ret; 1103*bf40cc53SJai Luthra } 1104*bf40cc53SJai Luthra 1105*bf40cc53SJai Luthra detected = val & IMX678_TYPE; 1106*bf40cc53SJai Luthra 1107*bf40cc53SJai Luthra /* Prefer to use sensor type specified in device tree */ 1108*bf40cc53SJai Luthra if (info) { 1109*bf40cc53SJai Luthra imx678->info = info; 1110*bf40cc53SJai Luthra if (detected != info->type) 1111*bf40cc53SJai Luthra dev_err(&client->dev, 1112*bf40cc53SJai Luthra "detected %s sensor, DT specifies %s; using DT value\n", 1113*bf40cc53SJai Luthra detected == IMX678_COLOR ? "color" : "mono", 1114*bf40cc53SJai Luthra info->type == IMX678_COLOR ? "color" : "mono"); 1115*bf40cc53SJai Luthra } else { 1116*bf40cc53SJai Luthra imx678->info = detected == IMX678_MONOCHROME ? 1117*bf40cc53SJai Luthra &imx678_aamr_info : &imx678_aaqr_info; 1118*bf40cc53SJai Luthra dev_info(&client->dev, 1119*bf40cc53SJai Luthra "sensor type missing in DT; detected %s sensor\n", 1120*bf40cc53SJai Luthra detected == IMX678_MONOCHROME ? "mono" : "color"); 1121*bf40cc53SJai Luthra } 1122*bf40cc53SJai Luthra 1123*bf40cc53SJai Luthra return 0; 1124*bf40cc53SJai Luthra } 1125*bf40cc53SJai Luthra 1126*bf40cc53SJai Luthra static const struct v4l2_subdev_video_ops imx678_video_ops = { 1127*bf40cc53SJai Luthra .s_stream = v4l2_subdev_s_stream_helper, 1128*bf40cc53SJai Luthra }; 1129*bf40cc53SJai Luthra 1130*bf40cc53SJai Luthra static const struct v4l2_subdev_pad_ops imx678_pad_ops = { 1131*bf40cc53SJai Luthra .enum_mbus_code = imx678_enum_mbus_code, 1132*bf40cc53SJai Luthra .get_fmt = v4l2_subdev_get_fmt, 1133*bf40cc53SJai Luthra .set_fmt = v4l2_subdev_get_fmt, 1134*bf40cc53SJai Luthra .get_selection = imx678_get_selection, 1135*bf40cc53SJai Luthra .enum_frame_size = imx678_enum_frame_size, 1136*bf40cc53SJai Luthra .enable_streams = imx678_enable_streams, 1137*bf40cc53SJai Luthra .disable_streams = imx678_disable_streams, 1138*bf40cc53SJai Luthra }; 1139*bf40cc53SJai Luthra 1140*bf40cc53SJai Luthra static const struct v4l2_subdev_ops imx678_subdev_ops = { 1141*bf40cc53SJai Luthra .video = &imx678_video_ops, 1142*bf40cc53SJai Luthra .pad = &imx678_pad_ops, 1143*bf40cc53SJai Luthra }; 1144*bf40cc53SJai Luthra 1145*bf40cc53SJai Luthra static const struct v4l2_subdev_internal_ops imx678_internal_ops = { 1146*bf40cc53SJai Luthra .init_state = imx678_init_state, 1147*bf40cc53SJai Luthra }; 1148*bf40cc53SJai Luthra 1149*bf40cc53SJai Luthra static int imx678_init_controls(struct imx678 *imx678) 1150*bf40cc53SJai Luthra { 1151*bf40cc53SJai Luthra struct v4l2_ctrl_handler *ctrl_hdlr; 1152*bf40cc53SJai Luthra const u32 hmax_4lane = min_hmax_4lane[__ffs(imx678->link_freq_bitmap)]; 1153*bf40cc53SJai Luthra const u32 lane_scale = imx678->lane_mode == IMX678_LANEMODE_2L ? 2 : 1; 1154*bf40cc53SJai Luthra struct i2c_client *client = v4l2_get_subdevdata(&imx678->sd); 1155*bf40cc53SJai Luthra struct v4l2_fwnode_device_properties props; 1156*bf40cc53SJai Luthra struct v4l2_ctrl *link_freq; 1157*bf40cc53SJai Luthra s32 hblank, max_hblank, vblank, max_vblank; 1158*bf40cc53SJai Luthra u32 hmax; 1159*bf40cc53SJai Luthra int ret; 1160*bf40cc53SJai Luthra 1161*bf40cc53SJai Luthra ret = v4l2_fwnode_device_parse(&client->dev, &props); 1162*bf40cc53SJai Luthra if (ret < 0) 1163*bf40cc53SJai Luthra return ret; 1164*bf40cc53SJai Luthra 1165*bf40cc53SJai Luthra ctrl_hdlr = &imx678->ctrl_handler; 1166*bf40cc53SJai Luthra ret = v4l2_ctrl_handler_init(ctrl_hdlr, 11); 1167*bf40cc53SJai Luthra if (ret) 1168*bf40cc53SJai Luthra return ret; 1169*bf40cc53SJai Luthra 1170*bf40cc53SJai Luthra imx678->vmax = IMX678_VMAX_DEFAULT; 1171*bf40cc53SJai Luthra hmax = hmax_4lane * lane_scale; 1172*bf40cc53SJai Luthra 1173*bf40cc53SJai Luthra /* PIXEL_RATE is fixed and read-only */ 1174*bf40cc53SJai Luthra v4l2_ctrl_new_std(ctrl_hdlr, &imx678_ctrl_ops, V4L2_CID_PIXEL_RATE, 1175*bf40cc53SJai Luthra IMX678_PIXEL_RATE, IMX678_PIXEL_RATE, 1, 1176*bf40cc53SJai Luthra IMX678_PIXEL_RATE); 1177*bf40cc53SJai Luthra 1178*bf40cc53SJai Luthra /* LINK_FREQ is also read only */ 1179*bf40cc53SJai Luthra link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx678_ctrl_ops, 1180*bf40cc53SJai Luthra V4L2_CID_LINK_FREQ, 1181*bf40cc53SJai Luthra ARRAY_SIZE(link_freqs) - 1, 1182*bf40cc53SJai Luthra __ffs(imx678->link_freq_bitmap), 1183*bf40cc53SJai Luthra link_freqs); 1184*bf40cc53SJai Luthra 1185*bf40cc53SJai Luthra if (link_freq) 1186*bf40cc53SJai Luthra link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; 1187*bf40cc53SJai Luthra 1188*bf40cc53SJai Luthra vblank = imx678->vmax - imx678_active_area.height; 1189*bf40cc53SJai Luthra max_vblank = IMX678_VMAX_MAX - imx678_active_area.height; 1190*bf40cc53SJai Luthra imx678->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx678_ctrl_ops, 1191*bf40cc53SJai Luthra V4L2_CID_VBLANK, vblank, max_vblank, 1192*bf40cc53SJai Luthra 2, vblank); 1193*bf40cc53SJai Luthra 1194*bf40cc53SJai Luthra hblank = hmax * IMX678_PIX_PER_CLK - imx678_active_area.width; 1195*bf40cc53SJai Luthra max_hblank = IMX678_HMAX_MAX * IMX678_PIX_PER_CLK - 1196*bf40cc53SJai Luthra imx678_active_area.width; 1197*bf40cc53SJai Luthra imx678->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx678_ctrl_ops, 1198*bf40cc53SJai Luthra V4L2_CID_HBLANK, hblank, max_hblank, 1199*bf40cc53SJai Luthra IMX678_PIX_PER_CLK, hblank); 1200*bf40cc53SJai Luthra 1201*bf40cc53SJai Luthra imx678->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx678_ctrl_ops, 1202*bf40cc53SJai Luthra V4L2_CID_EXPOSURE, 1203*bf40cc53SJai Luthra IMX678_EXPOSURE_MIN, 1204*bf40cc53SJai Luthra IMX678_VMAX_DEFAULT - 1205*bf40cc53SJai Luthra IMX678_SHR_MIN, 1206*bf40cc53SJai Luthra IMX678_EXPOSURE_STEP, 1207*bf40cc53SJai Luthra IMX678_EXPOSURE_DEFAULT); 1208*bf40cc53SJai Luthra 1209*bf40cc53SJai Luthra v4l2_ctrl_new_std(ctrl_hdlr, &imx678_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, 1210*bf40cc53SJai Luthra IMX678_ANA_GAIN_MIN_NORMAL, 1211*bf40cc53SJai Luthra IMX678_ANA_GAIN_MAX_NORMAL, IMX678_ANA_GAIN_STEP, 1212*bf40cc53SJai Luthra IMX678_ANA_GAIN_DEFAULT); 1213*bf40cc53SJai Luthra 1214*bf40cc53SJai Luthra v4l2_ctrl_new_std(ctrl_hdlr, &imx678_ctrl_ops, V4L2_CID_HFLIP, 1215*bf40cc53SJai Luthra 0, 1, 1, 0); 1216*bf40cc53SJai Luthra v4l2_ctrl_new_std(ctrl_hdlr, &imx678_ctrl_ops, V4L2_CID_VFLIP, 1217*bf40cc53SJai Luthra 0, 1, 1, 0); 1218*bf40cc53SJai Luthra 1219*bf40cc53SJai Luthra v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx678_ctrl_ops, 1220*bf40cc53SJai Luthra V4L2_CID_TEST_PATTERN, 1221*bf40cc53SJai Luthra ARRAY_SIZE(imx678_tpg_menu) - 1, 0, 0, 1222*bf40cc53SJai Luthra imx678_tpg_menu); 1223*bf40cc53SJai Luthra 1224*bf40cc53SJai Luthra v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx678_ctrl_ops, &props); 1225*bf40cc53SJai Luthra 1226*bf40cc53SJai Luthra if (ctrl_hdlr->error) { 1227*bf40cc53SJai Luthra ret = ctrl_hdlr->error; 1228*bf40cc53SJai Luthra dev_err(&client->dev, "%s control init failed (%d)\n", 1229*bf40cc53SJai Luthra __func__, ret); 1230*bf40cc53SJai Luthra v4l2_ctrl_handler_free(ctrl_hdlr); 1231*bf40cc53SJai Luthra return ret; 1232*bf40cc53SJai Luthra } 1233*bf40cc53SJai Luthra 1234*bf40cc53SJai Luthra imx678->sd.ctrl_handler = ctrl_hdlr; 1235*bf40cc53SJai Luthra 1236*bf40cc53SJai Luthra return 0; 1237*bf40cc53SJai Luthra } 1238*bf40cc53SJai Luthra 1239*bf40cc53SJai Luthra static int imx678_check_hwcfg(struct device *dev, struct imx678 *imx678) 1240*bf40cc53SJai Luthra { 1241*bf40cc53SJai Luthra struct fwnode_handle *endpoint; 1242*bf40cc53SJai Luthra struct v4l2_fwnode_endpoint ep_cfg = { 1243*bf40cc53SJai Luthra .bus_type = V4L2_MBUS_CSI2_DPHY 1244*bf40cc53SJai Luthra }; 1245*bf40cc53SJai Luthra int ret = -EINVAL; 1246*bf40cc53SJai Luthra 1247*bf40cc53SJai Luthra endpoint = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, 0); 1248*bf40cc53SJai Luthra if (!endpoint) { 1249*bf40cc53SJai Luthra dev_err(dev, "endpoint node not found\n"); 1250*bf40cc53SJai Luthra return -EINVAL; 1251*bf40cc53SJai Luthra } 1252*bf40cc53SJai Luthra 1253*bf40cc53SJai Luthra if (v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep_cfg)) { 1254*bf40cc53SJai Luthra dev_err(dev, "could not parse endpoint\n"); 1255*bf40cc53SJai Luthra goto error_out; 1256*bf40cc53SJai Luthra } 1257*bf40cc53SJai Luthra 1258*bf40cc53SJai Luthra switch (ep_cfg.bus.mipi_csi2.num_data_lanes) { 1259*bf40cc53SJai Luthra case 2: 1260*bf40cc53SJai Luthra imx678->lane_mode = IMX678_LANEMODE_2L; 1261*bf40cc53SJai Luthra break; 1262*bf40cc53SJai Luthra case 4: 1263*bf40cc53SJai Luthra imx678->lane_mode = IMX678_LANEMODE_4L; 1264*bf40cc53SJai Luthra break; 1265*bf40cc53SJai Luthra default: 1266*bf40cc53SJai Luthra dev_err(dev, 1267*bf40cc53SJai Luthra "only 2 or 4 CSI2 data lanes are currently supported\n"); 1268*bf40cc53SJai Luthra goto error_out; 1269*bf40cc53SJai Luthra } 1270*bf40cc53SJai Luthra 1271*bf40cc53SJai Luthra ret = v4l2_link_freq_to_bitmap(dev, ep_cfg.link_frequencies, 1272*bf40cc53SJai Luthra ep_cfg.nr_of_link_frequencies, 1273*bf40cc53SJai Luthra link_freqs, ARRAY_SIZE(link_freqs), 1274*bf40cc53SJai Luthra &imx678->link_freq_bitmap); 1275*bf40cc53SJai Luthra 1276*bf40cc53SJai Luthra error_out: 1277*bf40cc53SJai Luthra v4l2_fwnode_endpoint_free(&ep_cfg); 1278*bf40cc53SJai Luthra fwnode_handle_put(endpoint); 1279*bf40cc53SJai Luthra 1280*bf40cc53SJai Luthra return ret; 1281*bf40cc53SJai Luthra } 1282*bf40cc53SJai Luthra 1283*bf40cc53SJai Luthra static int imx678_probe(struct i2c_client *client) 1284*bf40cc53SJai Luthra { 1285*bf40cc53SJai Luthra struct device *dev = &client->dev; 1286*bf40cc53SJai Luthra struct imx678 *imx678; 1287*bf40cc53SJai Luthra int ret, i; 1288*bf40cc53SJai Luthra 1289*bf40cc53SJai Luthra imx678 = devm_kzalloc(&client->dev, sizeof(*imx678), GFP_KERNEL); 1290*bf40cc53SJai Luthra if (!imx678) 1291*bf40cc53SJai Luthra return -ENOMEM; 1292*bf40cc53SJai Luthra 1293*bf40cc53SJai Luthra v4l2_i2c_subdev_init(&imx678->sd, client, &imx678_subdev_ops); 1294*bf40cc53SJai Luthra 1295*bf40cc53SJai Luthra imx678->cci = devm_cci_regmap_init_i2c(client, 16); 1296*bf40cc53SJai Luthra if (IS_ERR(imx678->cci)) 1297*bf40cc53SJai Luthra return dev_err_probe(dev, PTR_ERR(imx678->cci), 1298*bf40cc53SJai Luthra "failed to init CCI\n"); 1299*bf40cc53SJai Luthra 1300*bf40cc53SJai Luthra if (imx678_check_hwcfg(dev, imx678)) 1301*bf40cc53SJai Luthra return -EINVAL; 1302*bf40cc53SJai Luthra 1303*bf40cc53SJai Luthra imx678->xclk = devm_v4l2_sensor_clk_get(dev, NULL); 1304*bf40cc53SJai Luthra if (IS_ERR(imx678->xclk)) 1305*bf40cc53SJai Luthra return dev_err_probe(dev, PTR_ERR(imx678->xclk), 1306*bf40cc53SJai Luthra "failed to get xclk\n"); 1307*bf40cc53SJai Luthra 1308*bf40cc53SJai Luthra imx678->xclk_freq = clk_get_rate(imx678->xclk); 1309*bf40cc53SJai Luthra 1310*bf40cc53SJai Luthra for (i = 0; i < ARRAY_SIZE(imx678_inck_table); ++i) { 1311*bf40cc53SJai Luthra if (imx678_inck_table[i].xclk_hz == imx678->xclk_freq) { 1312*bf40cc53SJai Luthra imx678->inck_sel_val = imx678_inck_table[i].inck_sel; 1313*bf40cc53SJai Luthra break; 1314*bf40cc53SJai Luthra } 1315*bf40cc53SJai Luthra } 1316*bf40cc53SJai Luthra 1317*bf40cc53SJai Luthra if (i == ARRAY_SIZE(imx678_inck_table)) 1318*bf40cc53SJai Luthra return dev_err_probe(dev, -EINVAL, 1319*bf40cc53SJai Luthra "unsupported XCLK rate %u Hz\n", 1320*bf40cc53SJai Luthra imx678->xclk_freq); 1321*bf40cc53SJai Luthra 1322*bf40cc53SJai Luthra for (i = 0; i < ARRAY_SIZE(imx678_supply_name); i++) 1323*bf40cc53SJai Luthra imx678->supplies[i].supply = imx678_supply_name[i]; 1324*bf40cc53SJai Luthra 1325*bf40cc53SJai Luthra ret = devm_regulator_bulk_get(&client->dev, 1326*bf40cc53SJai Luthra ARRAY_SIZE(imx678_supply_name), 1327*bf40cc53SJai Luthra imx678->supplies); 1328*bf40cc53SJai Luthra if (ret) 1329*bf40cc53SJai Luthra return dev_err_probe(dev, ret, "failed to get regulators\n"); 1330*bf40cc53SJai Luthra 1331*bf40cc53SJai Luthra imx678->reset_gpio = devm_gpiod_get_optional(dev, "reset", 1332*bf40cc53SJai Luthra GPIOD_OUT_HIGH); 1333*bf40cc53SJai Luthra if (IS_ERR(imx678->reset_gpio)) 1334*bf40cc53SJai Luthra return dev_err_probe(dev, PTR_ERR(imx678->reset_gpio), 1335*bf40cc53SJai Luthra "failed to get reset GPIO\n"); 1336*bf40cc53SJai Luthra 1337*bf40cc53SJai Luthra ret = imx678_power_on(dev); 1338*bf40cc53SJai Luthra if (ret) 1339*bf40cc53SJai Luthra return ret; 1340*bf40cc53SJai Luthra 1341*bf40cc53SJai Luthra ret = imx678_identify_model(imx678); 1342*bf40cc53SJai Luthra if (ret) 1343*bf40cc53SJai Luthra goto error_power_off; 1344*bf40cc53SJai Luthra 1345*bf40cc53SJai Luthra pm_runtime_set_active(dev); 1346*bf40cc53SJai Luthra pm_runtime_enable(dev); 1347*bf40cc53SJai Luthra 1348*bf40cc53SJai Luthra ret = imx678_init_controls(imx678); 1349*bf40cc53SJai Luthra if (ret) 1350*bf40cc53SJai Luthra goto error_pm_runtime; 1351*bf40cc53SJai Luthra 1352*bf40cc53SJai Luthra imx678->sd.internal_ops = &imx678_internal_ops; 1353*bf40cc53SJai Luthra imx678->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 1354*bf40cc53SJai Luthra imx678->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; 1355*bf40cc53SJai Luthra 1356*bf40cc53SJai Luthra imx678->pad.flags = MEDIA_PAD_FL_SOURCE; 1357*bf40cc53SJai Luthra 1358*bf40cc53SJai Luthra ret = media_entity_pads_init(&imx678->sd.entity, 1, &imx678->pad); 1359*bf40cc53SJai Luthra if (ret) { 1360*bf40cc53SJai Luthra dev_err_probe(dev, ret, "failed to init entity pads\n"); 1361*bf40cc53SJai Luthra goto error_handler_free; 1362*bf40cc53SJai Luthra } 1363*bf40cc53SJai Luthra 1364*bf40cc53SJai Luthra imx678->sd.state_lock = imx678->ctrl_handler.lock; 1365*bf40cc53SJai Luthra ret = v4l2_subdev_init_finalize(&imx678->sd); 1366*bf40cc53SJai Luthra if (ret < 0) { 1367*bf40cc53SJai Luthra dev_err_probe(dev, ret, "subdev init error\n"); 1368*bf40cc53SJai Luthra goto error_media_entity; 1369*bf40cc53SJai Luthra } 1370*bf40cc53SJai Luthra 1371*bf40cc53SJai Luthra ret = v4l2_async_register_subdev_sensor(&imx678->sd); 1372*bf40cc53SJai Luthra if (ret < 0) { 1373*bf40cc53SJai Luthra dev_err_probe(dev, ret, 1374*bf40cc53SJai Luthra "failed to register sensor sub-device\n"); 1375*bf40cc53SJai Luthra goto error_subdev_cleanup; 1376*bf40cc53SJai Luthra } 1377*bf40cc53SJai Luthra 1378*bf40cc53SJai Luthra pm_runtime_idle(dev); 1379*bf40cc53SJai Luthra 1380*bf40cc53SJai Luthra return 0; 1381*bf40cc53SJai Luthra 1382*bf40cc53SJai Luthra error_subdev_cleanup: 1383*bf40cc53SJai Luthra v4l2_subdev_cleanup(&imx678->sd); 1384*bf40cc53SJai Luthra 1385*bf40cc53SJai Luthra error_media_entity: 1386*bf40cc53SJai Luthra media_entity_cleanup(&imx678->sd.entity); 1387*bf40cc53SJai Luthra 1388*bf40cc53SJai Luthra error_handler_free: 1389*bf40cc53SJai Luthra v4l2_ctrl_handler_free(imx678->sd.ctrl_handler); 1390*bf40cc53SJai Luthra 1391*bf40cc53SJai Luthra error_pm_runtime: 1392*bf40cc53SJai Luthra pm_runtime_disable(&client->dev); 1393*bf40cc53SJai Luthra pm_runtime_set_suspended(&client->dev); 1394*bf40cc53SJai Luthra 1395*bf40cc53SJai Luthra error_power_off: 1396*bf40cc53SJai Luthra imx678_power_off(&client->dev); 1397*bf40cc53SJai Luthra 1398*bf40cc53SJai Luthra return ret; 1399*bf40cc53SJai Luthra } 1400*bf40cc53SJai Luthra 1401*bf40cc53SJai Luthra static void imx678_remove(struct i2c_client *client) 1402*bf40cc53SJai Luthra { 1403*bf40cc53SJai Luthra struct v4l2_subdev *sd = i2c_get_clientdata(client); 1404*bf40cc53SJai Luthra struct imx678 *imx678 = to_imx678(sd); 1405*bf40cc53SJai Luthra 1406*bf40cc53SJai Luthra v4l2_async_unregister_subdev(sd); 1407*bf40cc53SJai Luthra v4l2_subdev_cleanup(sd); 1408*bf40cc53SJai Luthra media_entity_cleanup(&sd->entity); 1409*bf40cc53SJai Luthra v4l2_ctrl_handler_free(imx678->sd.ctrl_handler); 1410*bf40cc53SJai Luthra 1411*bf40cc53SJai Luthra pm_runtime_disable(&client->dev); 1412*bf40cc53SJai Luthra if (!pm_runtime_status_suspended(&client->dev)) 1413*bf40cc53SJai Luthra imx678_power_off(&client->dev); 1414*bf40cc53SJai Luthra pm_runtime_set_suspended(&client->dev); 1415*bf40cc53SJai Luthra } 1416*bf40cc53SJai Luthra 1417*bf40cc53SJai Luthra static const struct dev_pm_ops imx678_pm_ops = { 1418*bf40cc53SJai Luthra SET_RUNTIME_PM_OPS(imx678_power_off, imx678_power_on, NULL) 1419*bf40cc53SJai Luthra }; 1420*bf40cc53SJai Luthra 1421*bf40cc53SJai Luthra static const struct of_device_id imx678_of_match[] = { 1422*bf40cc53SJai Luthra { .compatible = "sony,imx678-aamr", .data = &imx678_aamr_info }, 1423*bf40cc53SJai Luthra { .compatible = "sony,imx678-aaqr", .data = &imx678_aaqr_info }, 1424*bf40cc53SJai Luthra /* for non-conforming DTs that rely on runtime check */ 1425*bf40cc53SJai Luthra { .compatible = "sony,imx678" }, 1426*bf40cc53SJai Luthra { /* sentinel */ } 1427*bf40cc53SJai Luthra }; 1428*bf40cc53SJai Luthra 1429*bf40cc53SJai Luthra MODULE_DEVICE_TABLE(of, imx678_of_match); 1430*bf40cc53SJai Luthra 1431*bf40cc53SJai Luthra static struct i2c_driver imx678_i2c_driver = { 1432*bf40cc53SJai Luthra .driver = { 1433*bf40cc53SJai Luthra .name = "imx678", 1434*bf40cc53SJai Luthra .of_match_table = imx678_of_match, 1435*bf40cc53SJai Luthra .pm = pm_ptr(&imx678_pm_ops), 1436*bf40cc53SJai Luthra }, 1437*bf40cc53SJai Luthra .probe = imx678_probe, 1438*bf40cc53SJai Luthra .remove = imx678_remove, 1439*bf40cc53SJai Luthra }; 1440*bf40cc53SJai Luthra 1441*bf40cc53SJai Luthra module_i2c_driver(imx678_i2c_driver); 1442*bf40cc53SJai Luthra 1443*bf40cc53SJai Luthra MODULE_AUTHOR("Will Whang <will@willwhang.com>"); 1444*bf40cc53SJai Luthra MODULE_AUTHOR("Tetsuya NOMURA <tetsuya.nomura@soho-enterprise.com>"); 1445*bf40cc53SJai Luthra MODULE_AUTHOR("Jai Luthra <jai.luthra@ideasonboard.com>"); 1446*bf40cc53SJai Luthra MODULE_DESCRIPTION("Sony imx678 sensor driver"); 1447*bf40cc53SJai Luthra MODULE_LICENSE("GPL"); 1448