1e6213840SShawn Tu // SPDX-License-Identifier: GPL-2.0 2e6213840SShawn Tu // Copyright (c) 2019 Intel Corporation. 3e6213840SShawn Tu 4e6213840SShawn Tu #include <asm/unaligned.h> 5e6213840SShawn Tu #include <linux/acpi.h> 6e6213840SShawn Tu #include <linux/delay.h> 7e6213840SShawn Tu #include <linux/i2c.h> 8e6213840SShawn Tu #include <linux/module.h> 9e6213840SShawn Tu #include <linux/pm_runtime.h> 10e6213840SShawn Tu #include <media/v4l2-ctrls.h> 11e6213840SShawn Tu #include <media/v4l2-device.h> 12e6213840SShawn Tu #include <media/v4l2-fwnode.h> 13e6213840SShawn Tu 14e6213840SShawn Tu #define HI556_REG_VALUE_08BIT 1 15e6213840SShawn Tu #define HI556_REG_VALUE_16BIT 2 16e6213840SShawn Tu #define HI556_REG_VALUE_24BIT 3 17e6213840SShawn Tu 18e6213840SShawn Tu #define HI556_LINK_FREQ_437MHZ 437000000ULL 19e6213840SShawn Tu #define HI556_MCLK 19200000 20e6213840SShawn Tu #define HI556_DATA_LANES 2 21e6213840SShawn Tu #define HI556_RGB_DEPTH 10 22e6213840SShawn Tu 23e6213840SShawn Tu #define HI556_REG_CHIP_ID 0x0f16 24e6213840SShawn Tu #define HI556_CHIP_ID 0x0556 25e6213840SShawn Tu 26e6213840SShawn Tu #define HI556_REG_MODE_SELECT 0x0a00 27e6213840SShawn Tu #define HI556_MODE_STANDBY 0x0000 28e6213840SShawn Tu #define HI556_MODE_STREAMING 0x0100 29e6213840SShawn Tu 30e6213840SShawn Tu /* vertical-timings from sensor */ 31e6213840SShawn Tu #define HI556_REG_FLL 0x0006 32e6213840SShawn Tu #define HI556_FLL_30FPS 0x0814 33e6213840SShawn Tu #define HI556_FLL_30FPS_MIN 0x0814 34e6213840SShawn Tu #define HI556_FLL_MAX 0x7fff 35e6213840SShawn Tu 36e6213840SShawn Tu /* horizontal-timings from sensor */ 37e6213840SShawn Tu #define HI556_REG_LLP 0x0008 38e6213840SShawn Tu 39e6213840SShawn Tu /* Exposure controls from sensor */ 40e6213840SShawn Tu #define HI556_REG_EXPOSURE 0x0074 41e6213840SShawn Tu #define HI556_EXPOSURE_MIN 6 42e6213840SShawn Tu #define HI556_EXPOSURE_MAX_MARGIN 2 43e6213840SShawn Tu #define HI556_EXPOSURE_STEP 1 44e6213840SShawn Tu 45e6213840SShawn Tu /* Analog gain controls from sensor */ 46e6213840SShawn Tu #define HI556_REG_ANALOG_GAIN 0x0077 47e6213840SShawn Tu #define HI556_ANAL_GAIN_MIN 0 48e6213840SShawn Tu #define HI556_ANAL_GAIN_MAX 240 49e6213840SShawn Tu #define HI556_ANAL_GAIN_STEP 1 50e6213840SShawn Tu 51e6213840SShawn Tu /* Digital gain controls from sensor */ 52e6213840SShawn Tu #define HI556_REG_MWB_GR_GAIN 0x0078 53e6213840SShawn Tu #define HI556_REG_MWB_GB_GAIN 0x007a 54e6213840SShawn Tu #define HI556_REG_MWB_R_GAIN 0x007c 55e6213840SShawn Tu #define HI556_REG_MWB_B_GAIN 0x007e 56e6213840SShawn Tu #define HI556_DGTL_GAIN_MIN 0 57e6213840SShawn Tu #define HI556_DGTL_GAIN_MAX 2048 58e6213840SShawn Tu #define HI556_DGTL_GAIN_STEP 1 59e6213840SShawn Tu #define HI556_DGTL_GAIN_DEFAULT 256 60e6213840SShawn Tu 61e6213840SShawn Tu /* Test Pattern Control */ 62e6213840SShawn Tu #define HI556_REG_ISP 0X0a05 63e6213840SShawn Tu #define HI556_REG_ISP_TPG_EN 0x01 64e6213840SShawn Tu #define HI556_REG_TEST_PATTERN 0x0201 65e6213840SShawn Tu 66e6213840SShawn Tu enum { 67e6213840SShawn Tu HI556_LINK_FREQ_437MHZ_INDEX, 68e6213840SShawn Tu }; 69e6213840SShawn Tu 70e6213840SShawn Tu struct hi556_reg { 71e6213840SShawn Tu u16 address; 72e6213840SShawn Tu u16 val; 73e6213840SShawn Tu }; 74e6213840SShawn Tu 75e6213840SShawn Tu struct hi556_reg_list { 76e6213840SShawn Tu u32 num_of_regs; 77e6213840SShawn Tu const struct hi556_reg *regs; 78e6213840SShawn Tu }; 79e6213840SShawn Tu 80e6213840SShawn Tu struct hi556_link_freq_config { 81e6213840SShawn Tu const struct hi556_reg_list reg_list; 82e6213840SShawn Tu }; 83e6213840SShawn Tu 84e6213840SShawn Tu struct hi556_mode { 85e6213840SShawn Tu /* Frame width in pixels */ 86e6213840SShawn Tu u32 width; 87e6213840SShawn Tu 88e6213840SShawn Tu /* Frame height in pixels */ 89e6213840SShawn Tu u32 height; 90e6213840SShawn Tu 91e6213840SShawn Tu /* Horizontal timining size */ 92e6213840SShawn Tu u32 llp; 93e6213840SShawn Tu 94e6213840SShawn Tu /* Default vertical timining size */ 95e6213840SShawn Tu u32 fll_def; 96e6213840SShawn Tu 97e6213840SShawn Tu /* Min vertical timining size */ 98e6213840SShawn Tu u32 fll_min; 99e6213840SShawn Tu 100e6213840SShawn Tu /* Link frequency needed for this resolution */ 101e6213840SShawn Tu u32 link_freq_index; 102e6213840SShawn Tu 103e6213840SShawn Tu /* Sensor register settings for this resolution */ 104e6213840SShawn Tu const struct hi556_reg_list reg_list; 105e6213840SShawn Tu }; 106e6213840SShawn Tu 107e6213840SShawn Tu #define to_hi556(_sd) container_of(_sd, struct hi556, sd) 108e6213840SShawn Tu 109e6213840SShawn Tu //SENSOR_INITIALIZATION 110e6213840SShawn Tu static const struct hi556_reg mipi_data_rate_874mbps[] = { 111e6213840SShawn Tu {0x0e00, 0x0102}, 112e6213840SShawn Tu {0x0e02, 0x0102}, 113e6213840SShawn Tu {0x0e0c, 0x0100}, 114e6213840SShawn Tu {0x2000, 0x7400}, 115e6213840SShawn Tu {0x2002, 0x001c}, 116e6213840SShawn Tu {0x2004, 0x0242}, 117e6213840SShawn Tu {0x2006, 0x0942}, 118e6213840SShawn Tu {0x2008, 0x7007}, 119e6213840SShawn Tu {0x200a, 0x0fd9}, 120e6213840SShawn Tu {0x200c, 0x0259}, 121e6213840SShawn Tu {0x200e, 0x7008}, 122e6213840SShawn Tu {0x2010, 0x160e}, 123e6213840SShawn Tu {0x2012, 0x0047}, 124e6213840SShawn Tu {0x2014, 0x2118}, 125e6213840SShawn Tu {0x2016, 0x0041}, 126e6213840SShawn Tu {0x2018, 0x00d8}, 127e6213840SShawn Tu {0x201a, 0x0145}, 128e6213840SShawn Tu {0x201c, 0x0006}, 129e6213840SShawn Tu {0x201e, 0x0181}, 130e6213840SShawn Tu {0x2020, 0x13cc}, 131e6213840SShawn Tu {0x2022, 0x2057}, 132e6213840SShawn Tu {0x2024, 0x7001}, 133e6213840SShawn Tu {0x2026, 0x0fca}, 134e6213840SShawn Tu {0x2028, 0x00cb}, 135e6213840SShawn Tu {0x202a, 0x009f}, 136e6213840SShawn Tu {0x202c, 0x7002}, 137e6213840SShawn Tu {0x202e, 0x13cc}, 138e6213840SShawn Tu {0x2030, 0x019b}, 139e6213840SShawn Tu {0x2032, 0x014d}, 140e6213840SShawn Tu {0x2034, 0x2987}, 141e6213840SShawn Tu {0x2036, 0x2766}, 142e6213840SShawn Tu {0x2038, 0x0020}, 143e6213840SShawn Tu {0x203a, 0x2060}, 144e6213840SShawn Tu {0x203c, 0x0e5d}, 145e6213840SShawn Tu {0x203e, 0x181d}, 146e6213840SShawn Tu {0x2040, 0x2066}, 147e6213840SShawn Tu {0x2042, 0x20c4}, 148e6213840SShawn Tu {0x2044, 0x5000}, 149e6213840SShawn Tu {0x2046, 0x0005}, 150e6213840SShawn Tu {0x2048, 0x0000}, 151e6213840SShawn Tu {0x204a, 0x01db}, 152e6213840SShawn Tu {0x204c, 0x025a}, 153e6213840SShawn Tu {0x204e, 0x00c0}, 154e6213840SShawn Tu {0x2050, 0x0005}, 155e6213840SShawn Tu {0x2052, 0x0006}, 156e6213840SShawn Tu {0x2054, 0x0ad9}, 157e6213840SShawn Tu {0x2056, 0x0259}, 158e6213840SShawn Tu {0x2058, 0x0618}, 159e6213840SShawn Tu {0x205a, 0x0258}, 160e6213840SShawn Tu {0x205c, 0x2266}, 161e6213840SShawn Tu {0x205e, 0x20c8}, 162e6213840SShawn Tu {0x2060, 0x2060}, 163e6213840SShawn Tu {0x2062, 0x707b}, 164e6213840SShawn Tu {0x2064, 0x0fdd}, 165e6213840SShawn Tu {0x2066, 0x81b8}, 166e6213840SShawn Tu {0x2068, 0x5040}, 167e6213840SShawn Tu {0x206a, 0x0020}, 168e6213840SShawn Tu {0x206c, 0x5060}, 169e6213840SShawn Tu {0x206e, 0x3143}, 170e6213840SShawn Tu {0x2070, 0x5081}, 171e6213840SShawn Tu {0x2072, 0x025c}, 172e6213840SShawn Tu {0x2074, 0x7800}, 173e6213840SShawn Tu {0x2076, 0x7400}, 174e6213840SShawn Tu {0x2078, 0x001c}, 175e6213840SShawn Tu {0x207a, 0x0242}, 176e6213840SShawn Tu {0x207c, 0x0942}, 177e6213840SShawn Tu {0x207e, 0x0bd9}, 178e6213840SShawn Tu {0x2080, 0x0259}, 179e6213840SShawn Tu {0x2082, 0x7008}, 180e6213840SShawn Tu {0x2084, 0x160e}, 181e6213840SShawn Tu {0x2086, 0x0047}, 182e6213840SShawn Tu {0x2088, 0x2118}, 183e6213840SShawn Tu {0x208a, 0x0041}, 184e6213840SShawn Tu {0x208c, 0x00d8}, 185e6213840SShawn Tu {0x208e, 0x0145}, 186e6213840SShawn Tu {0x2090, 0x0006}, 187e6213840SShawn Tu {0x2092, 0x0181}, 188e6213840SShawn Tu {0x2094, 0x13cc}, 189e6213840SShawn Tu {0x2096, 0x2057}, 190e6213840SShawn Tu {0x2098, 0x7001}, 191e6213840SShawn Tu {0x209a, 0x0fca}, 192e6213840SShawn Tu {0x209c, 0x00cb}, 193e6213840SShawn Tu {0x209e, 0x009f}, 194e6213840SShawn Tu {0x20a0, 0x7002}, 195e6213840SShawn Tu {0x20a2, 0x13cc}, 196e6213840SShawn Tu {0x20a4, 0x019b}, 197e6213840SShawn Tu {0x20a6, 0x014d}, 198e6213840SShawn Tu {0x20a8, 0x2987}, 199e6213840SShawn Tu {0x20aa, 0x2766}, 200e6213840SShawn Tu {0x20ac, 0x0020}, 201e6213840SShawn Tu {0x20ae, 0x2060}, 202e6213840SShawn Tu {0x20b0, 0x0e5d}, 203e6213840SShawn Tu {0x20b2, 0x181d}, 204e6213840SShawn Tu {0x20b4, 0x2066}, 205e6213840SShawn Tu {0x20b6, 0x20c4}, 206e6213840SShawn Tu {0x20b8, 0x50a0}, 207e6213840SShawn Tu {0x20ba, 0x0005}, 208e6213840SShawn Tu {0x20bc, 0x0000}, 209e6213840SShawn Tu {0x20be, 0x01db}, 210e6213840SShawn Tu {0x20c0, 0x025a}, 211e6213840SShawn Tu {0x20c2, 0x00c0}, 212e6213840SShawn Tu {0x20c4, 0x0005}, 213e6213840SShawn Tu {0x20c6, 0x0006}, 214e6213840SShawn Tu {0x20c8, 0x0ad9}, 215e6213840SShawn Tu {0x20ca, 0x0259}, 216e6213840SShawn Tu {0x20cc, 0x0618}, 217e6213840SShawn Tu {0x20ce, 0x0258}, 218e6213840SShawn Tu {0x20d0, 0x2266}, 219e6213840SShawn Tu {0x20d2, 0x20c8}, 220e6213840SShawn Tu {0x20d4, 0x2060}, 221e6213840SShawn Tu {0x20d6, 0x707b}, 222e6213840SShawn Tu {0x20d8, 0x0fdd}, 223e6213840SShawn Tu {0x20da, 0x86b8}, 224e6213840SShawn Tu {0x20dc, 0x50e0}, 225e6213840SShawn Tu {0x20de, 0x0020}, 226e6213840SShawn Tu {0x20e0, 0x5100}, 227e6213840SShawn Tu {0x20e2, 0x3143}, 228e6213840SShawn Tu {0x20e4, 0x5121}, 229e6213840SShawn Tu {0x20e6, 0x7800}, 230e6213840SShawn Tu {0x20e8, 0x3140}, 231e6213840SShawn Tu {0x20ea, 0x01c4}, 232e6213840SShawn Tu {0x20ec, 0x01c1}, 233e6213840SShawn Tu {0x20ee, 0x01c0}, 234e6213840SShawn Tu {0x20f0, 0x01c4}, 235e6213840SShawn Tu {0x20f2, 0x2700}, 236e6213840SShawn Tu {0x20f4, 0x3d40}, 237e6213840SShawn Tu {0x20f6, 0x7800}, 238e6213840SShawn Tu {0x20f8, 0xffff}, 239e6213840SShawn Tu {0x27fe, 0xe000}, 240e6213840SShawn Tu {0x3000, 0x60f8}, 241e6213840SShawn Tu {0x3002, 0x187f}, 242e6213840SShawn Tu {0x3004, 0x7060}, 243e6213840SShawn Tu {0x3006, 0x0114}, 244e6213840SShawn Tu {0x3008, 0x60b0}, 245e6213840SShawn Tu {0x300a, 0x1473}, 246e6213840SShawn Tu {0x300c, 0x0013}, 247e6213840SShawn Tu {0x300e, 0x140f}, 248e6213840SShawn Tu {0x3010, 0x0040}, 249e6213840SShawn Tu {0x3012, 0x100f}, 250e6213840SShawn Tu {0x3014, 0x60f8}, 251e6213840SShawn Tu {0x3016, 0x187f}, 252e6213840SShawn Tu {0x3018, 0x7060}, 253e6213840SShawn Tu {0x301a, 0x0114}, 254e6213840SShawn Tu {0x301c, 0x60b0}, 255e6213840SShawn Tu {0x301e, 0x1473}, 256e6213840SShawn Tu {0x3020, 0x0013}, 257e6213840SShawn Tu {0x3022, 0x140f}, 258e6213840SShawn Tu {0x3024, 0x0040}, 259e6213840SShawn Tu {0x3026, 0x000f}, 260e6213840SShawn Tu 261e6213840SShawn Tu {0x0b00, 0x0000}, 262e6213840SShawn Tu {0x0b02, 0x0045}, 263e6213840SShawn Tu {0x0b04, 0xb405}, 264e6213840SShawn Tu {0x0b06, 0xc403}, 265e6213840SShawn Tu {0x0b08, 0x0081}, 266e6213840SShawn Tu {0x0b0a, 0x8252}, 267e6213840SShawn Tu {0x0b0c, 0xf814}, 268e6213840SShawn Tu {0x0b0e, 0xc618}, 269e6213840SShawn Tu {0x0b10, 0xa828}, 270e6213840SShawn Tu {0x0b12, 0x004c}, 271e6213840SShawn Tu {0x0b14, 0x4068}, 272e6213840SShawn Tu {0x0b16, 0x0000}, 273e6213840SShawn Tu {0x0f30, 0x5b15}, 274e6213840SShawn Tu {0x0f32, 0x7067}, 275e6213840SShawn Tu {0x0954, 0x0009}, 276e6213840SShawn Tu {0x0956, 0x0000}, 277e6213840SShawn Tu {0x0958, 0xbb80}, 278e6213840SShawn Tu {0x095a, 0x5140}, 279e6213840SShawn Tu {0x0c00, 0x1110}, 280e6213840SShawn Tu {0x0c02, 0x0011}, 281e6213840SShawn Tu {0x0c04, 0x0000}, 282e6213840SShawn Tu {0x0c06, 0x0200}, 283e6213840SShawn Tu {0x0c10, 0x0040}, 284e6213840SShawn Tu {0x0c12, 0x0040}, 285e6213840SShawn Tu {0x0c14, 0x0040}, 286e6213840SShawn Tu {0x0c16, 0x0040}, 287e6213840SShawn Tu {0x0a10, 0x4000}, 288e6213840SShawn Tu {0x3068, 0xf800}, 289e6213840SShawn Tu {0x306a, 0xf876}, 290e6213840SShawn Tu {0x006c, 0x0000}, 291e6213840SShawn Tu {0x005e, 0x0200}, 292e6213840SShawn Tu {0x000e, 0x0100}, 293e6213840SShawn Tu {0x0e0a, 0x0001}, 294e6213840SShawn Tu {0x004a, 0x0100}, 295e6213840SShawn Tu {0x004c, 0x0000}, 296e6213840SShawn Tu {0x004e, 0x0100}, 297e6213840SShawn Tu {0x000c, 0x0022}, 298e6213840SShawn Tu {0x0008, 0x0b00}, 299e6213840SShawn Tu {0x005a, 0x0202}, 300e6213840SShawn Tu {0x0012, 0x000e}, 301e6213840SShawn Tu {0x0018, 0x0a33}, 302e6213840SShawn Tu {0x0022, 0x0008}, 303e6213840SShawn Tu {0x0028, 0x0017}, 304e6213840SShawn Tu {0x0024, 0x0028}, 305e6213840SShawn Tu {0x002a, 0x002d}, 306e6213840SShawn Tu {0x0026, 0x0030}, 307e6213840SShawn Tu {0x002c, 0x07c9}, 308e6213840SShawn Tu {0x002e, 0x1111}, 309e6213840SShawn Tu {0x0030, 0x1111}, 310e6213840SShawn Tu {0x0032, 0x1111}, 311e6213840SShawn Tu {0x0006, 0x07bc}, 312e6213840SShawn Tu {0x0a22, 0x0000}, 313e6213840SShawn Tu {0x0a12, 0x0a20}, 314e6213840SShawn Tu {0x0a14, 0x0798}, 315e6213840SShawn Tu {0x003e, 0x0000}, 316e6213840SShawn Tu {0x0074, 0x080e}, 317e6213840SShawn Tu {0x0070, 0x0407}, 318e6213840SShawn Tu {0x0002, 0x0000}, 319e6213840SShawn Tu {0x0a02, 0x0100}, 320e6213840SShawn Tu {0x0a24, 0x0100}, 321e6213840SShawn Tu {0x0046, 0x0000}, 322e6213840SShawn Tu {0x0076, 0x0000}, 323e6213840SShawn Tu {0x0060, 0x0000}, 324e6213840SShawn Tu {0x0062, 0x0530}, 325e6213840SShawn Tu {0x0064, 0x0500}, 326e6213840SShawn Tu {0x0066, 0x0530}, 327e6213840SShawn Tu {0x0068, 0x0500}, 328e6213840SShawn Tu {0x0122, 0x0300}, 329e6213840SShawn Tu {0x015a, 0xff08}, 330e6213840SShawn Tu {0x0804, 0x0300}, 331e6213840SShawn Tu {0x0806, 0x0100}, 332e6213840SShawn Tu {0x005c, 0x0102}, 333e6213840SShawn Tu {0x0a1a, 0x0800}, 334e6213840SShawn Tu }; 335e6213840SShawn Tu 336e6213840SShawn Tu static const struct hi556_reg mode_2592x1944_regs[] = { 337e6213840SShawn Tu {0x0a00, 0x0000}, 338e6213840SShawn Tu {0x0b0a, 0x8252}, 339e6213840SShawn Tu {0x0f30, 0x5b15}, 340e6213840SShawn Tu {0x0f32, 0x7067}, 341e6213840SShawn Tu {0x004a, 0x0100}, 342e6213840SShawn Tu {0x004c, 0x0000}, 343e6213840SShawn Tu {0x004e, 0x0100}, 344e6213840SShawn Tu {0x000c, 0x0022}, 345e6213840SShawn Tu {0x0008, 0x0b00}, 346e6213840SShawn Tu {0x005a, 0x0202}, 347e6213840SShawn Tu {0x0012, 0x000e}, 348e6213840SShawn Tu {0x0018, 0x0a33}, 349e6213840SShawn Tu {0x0022, 0x0008}, 350e6213840SShawn Tu {0x0028, 0x0017}, 351e6213840SShawn Tu {0x0024, 0x0028}, 352e6213840SShawn Tu {0x002a, 0x002d}, 353e6213840SShawn Tu {0x0026, 0x0030}, 354e6213840SShawn Tu {0x002c, 0x07c9}, 355e6213840SShawn Tu {0x002e, 0x1111}, 356e6213840SShawn Tu {0x0030, 0x1111}, 357e6213840SShawn Tu {0x0032, 0x1111}, 358e6213840SShawn Tu {0x0006, 0x0814}, 359e6213840SShawn Tu {0x0a22, 0x0000}, 360e6213840SShawn Tu {0x0a12, 0x0a20}, 361e6213840SShawn Tu {0x0a14, 0x0798}, 362e6213840SShawn Tu {0x003e, 0x0000}, 363e6213840SShawn Tu {0x0074, 0x0812}, 364e6213840SShawn Tu {0x0070, 0x0409}, 365e6213840SShawn Tu {0x0804, 0x0300}, 366e6213840SShawn Tu {0x0806, 0x0100}, 367e6213840SShawn Tu {0x0a04, 0x014a}, 368e6213840SShawn Tu {0x090c, 0x0fdc}, 369e6213840SShawn Tu {0x090e, 0x002d}, 370e6213840SShawn Tu 371e6213840SShawn Tu {0x0902, 0x4319}, 372e6213840SShawn Tu {0x0914, 0xc10a}, 373e6213840SShawn Tu {0x0916, 0x071f}, 374e6213840SShawn Tu {0x0918, 0x0408}, 375e6213840SShawn Tu {0x091a, 0x0c0d}, 376e6213840SShawn Tu {0x091c, 0x0f09}, 377e6213840SShawn Tu {0x091e, 0x0a00}, 378e6213840SShawn Tu {0x0958, 0xbb80}, 379e6213840SShawn Tu }; 380e6213840SShawn Tu 381e6213840SShawn Tu static const struct hi556_reg mode_1296x972_regs[] = { 382e6213840SShawn Tu {0x0a00, 0x0000}, 383e6213840SShawn Tu {0x0b0a, 0x8259}, 384e6213840SShawn Tu {0x0f30, 0x5b15}, 385e6213840SShawn Tu {0x0f32, 0x7167}, 386e6213840SShawn Tu {0x004a, 0x0100}, 387e6213840SShawn Tu {0x004c, 0x0000}, 388e6213840SShawn Tu {0x004e, 0x0100}, 389e6213840SShawn Tu {0x000c, 0x0122}, 390e6213840SShawn Tu {0x0008, 0x0b00}, 391e6213840SShawn Tu {0x005a, 0x0404}, 392e6213840SShawn Tu {0x0012, 0x000c}, 393e6213840SShawn Tu {0x0018, 0x0a33}, 394e6213840SShawn Tu {0x0022, 0x0008}, 395e6213840SShawn Tu {0x0028, 0x0017}, 396e6213840SShawn Tu {0x0024, 0x0022}, 397e6213840SShawn Tu {0x002a, 0x002b}, 398e6213840SShawn Tu {0x0026, 0x0030}, 399e6213840SShawn Tu {0x002c, 0x07c9}, 400e6213840SShawn Tu {0x002e, 0x3311}, 401e6213840SShawn Tu {0x0030, 0x3311}, 402e6213840SShawn Tu {0x0032, 0x3311}, 403e6213840SShawn Tu {0x0006, 0x0814}, 404e6213840SShawn Tu {0x0a22, 0x0000}, 405e6213840SShawn Tu {0x0a12, 0x0510}, 406e6213840SShawn Tu {0x0a14, 0x03cc}, 407e6213840SShawn Tu {0x003e, 0x0000}, 408e6213840SShawn Tu {0x0074, 0x0812}, 409e6213840SShawn Tu {0x0070, 0x0409}, 410e6213840SShawn Tu {0x0804, 0x0308}, 411e6213840SShawn Tu {0x0806, 0x0100}, 412e6213840SShawn Tu {0x0a04, 0x016a}, 413e6213840SShawn Tu {0x090e, 0x0010}, 414e6213840SShawn Tu {0x090c, 0x09c0}, 415e6213840SShawn Tu 416e6213840SShawn Tu {0x0902, 0x4319}, 417e6213840SShawn Tu {0x0914, 0xc106}, 418e6213840SShawn Tu {0x0916, 0x040e}, 419e6213840SShawn Tu {0x0918, 0x0304}, 420e6213840SShawn Tu {0x091a, 0x0708}, 421e6213840SShawn Tu {0x091c, 0x0e06}, 422e6213840SShawn Tu {0x091e, 0x0300}, 423e6213840SShawn Tu {0x0958, 0xbb80}, 424e6213840SShawn Tu }; 425e6213840SShawn Tu 426e6213840SShawn Tu static const char * const hi556_test_pattern_menu[] = { 427e6213840SShawn Tu "Disabled", 428e6213840SShawn Tu "Solid Colour", 429e6213840SShawn Tu "100% Colour Bars", 430e6213840SShawn Tu "Fade To Grey Colour Bars", 431e6213840SShawn Tu "PN9", 432e6213840SShawn Tu "Gradient Horizontal", 433e6213840SShawn Tu "Gradient Vertical", 434e6213840SShawn Tu "Check Board", 435e6213840SShawn Tu "Slant Pattern", 436e6213840SShawn Tu }; 437e6213840SShawn Tu 438e6213840SShawn Tu static const s64 link_freq_menu_items[] = { 439e6213840SShawn Tu HI556_LINK_FREQ_437MHZ, 440e6213840SShawn Tu }; 441e6213840SShawn Tu 442e6213840SShawn Tu static const struct hi556_link_freq_config link_freq_configs[] = { 443e6213840SShawn Tu [HI556_LINK_FREQ_437MHZ_INDEX] = { 444e6213840SShawn Tu .reg_list = { 445e6213840SShawn Tu .num_of_regs = ARRAY_SIZE(mipi_data_rate_874mbps), 446e6213840SShawn Tu .regs = mipi_data_rate_874mbps, 447e6213840SShawn Tu } 448e6213840SShawn Tu } 449e6213840SShawn Tu }; 450e6213840SShawn Tu 451e6213840SShawn Tu static const struct hi556_mode supported_modes[] = { 452e6213840SShawn Tu { 453e6213840SShawn Tu .width = 2592, 454e6213840SShawn Tu .height = 1944, 455e6213840SShawn Tu .fll_def = HI556_FLL_30FPS, 456e6213840SShawn Tu .fll_min = HI556_FLL_30FPS_MIN, 457e6213840SShawn Tu .llp = 0x0b00, 458e6213840SShawn Tu .reg_list = { 459e6213840SShawn Tu .num_of_regs = ARRAY_SIZE(mode_2592x1944_regs), 460e6213840SShawn Tu .regs = mode_2592x1944_regs, 461e6213840SShawn Tu }, 462e6213840SShawn Tu .link_freq_index = HI556_LINK_FREQ_437MHZ_INDEX, 463e6213840SShawn Tu }, 464e6213840SShawn Tu { 465e6213840SShawn Tu .width = 1296, 466e6213840SShawn Tu .height = 972, 467e6213840SShawn Tu .fll_def = HI556_FLL_30FPS, 468e6213840SShawn Tu .fll_min = HI556_FLL_30FPS_MIN, 469e6213840SShawn Tu .llp = 0x0b00, 470e6213840SShawn Tu .reg_list = { 471e6213840SShawn Tu .num_of_regs = ARRAY_SIZE(mode_1296x972_regs), 472e6213840SShawn Tu .regs = mode_1296x972_regs, 473e6213840SShawn Tu }, 474e6213840SShawn Tu .link_freq_index = HI556_LINK_FREQ_437MHZ_INDEX, 475e6213840SShawn Tu } 476e6213840SShawn Tu }; 477e6213840SShawn Tu 478e6213840SShawn Tu struct hi556 { 479e6213840SShawn Tu struct v4l2_subdev sd; 480e6213840SShawn Tu struct media_pad pad; 481e6213840SShawn Tu struct v4l2_ctrl_handler ctrl_handler; 482e6213840SShawn Tu 483e6213840SShawn Tu /* V4L2 Controls */ 484e6213840SShawn Tu struct v4l2_ctrl *link_freq; 485e6213840SShawn Tu struct v4l2_ctrl *pixel_rate; 486e6213840SShawn Tu struct v4l2_ctrl *vblank; 487e6213840SShawn Tu struct v4l2_ctrl *hblank; 488e6213840SShawn Tu struct v4l2_ctrl *exposure; 489e6213840SShawn Tu 490e6213840SShawn Tu /* Current mode */ 491e6213840SShawn Tu const struct hi556_mode *cur_mode; 492e6213840SShawn Tu 493e6213840SShawn Tu /* To serialize asynchronus callbacks */ 494e6213840SShawn Tu struct mutex mutex; 495e6213840SShawn Tu 496e6213840SShawn Tu /* Streaming on/off */ 497e6213840SShawn Tu bool streaming; 498e6213840SShawn Tu }; 499e6213840SShawn Tu 500e6213840SShawn Tu static u64 to_pixel_rate(u32 f_index) 501e6213840SShawn Tu { 502e6213840SShawn Tu u64 pixel_rate = link_freq_menu_items[f_index] * 2 * HI556_DATA_LANES; 503e6213840SShawn Tu 504e6213840SShawn Tu do_div(pixel_rate, HI556_RGB_DEPTH); 505e6213840SShawn Tu 506e6213840SShawn Tu return pixel_rate; 507e6213840SShawn Tu } 508e6213840SShawn Tu 509e6213840SShawn Tu static int hi556_read_reg(struct hi556 *hi556, u16 reg, u16 len, u32 *val) 510e6213840SShawn Tu { 511e6213840SShawn Tu struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd); 512e6213840SShawn Tu struct i2c_msg msgs[2]; 513e6213840SShawn Tu u8 addr_buf[2]; 514e6213840SShawn Tu u8 data_buf[4] = {0}; 515e6213840SShawn Tu int ret; 516e6213840SShawn Tu 517e6213840SShawn Tu if (len > 4) 518e6213840SShawn Tu return -EINVAL; 519e6213840SShawn Tu 520e6213840SShawn Tu put_unaligned_be16(reg, addr_buf); 521e6213840SShawn Tu msgs[0].addr = client->addr; 522e6213840SShawn Tu msgs[0].flags = 0; 523e6213840SShawn Tu msgs[0].len = sizeof(addr_buf); 524e6213840SShawn Tu msgs[0].buf = addr_buf; 525e6213840SShawn Tu msgs[1].addr = client->addr; 526e6213840SShawn Tu msgs[1].flags = I2C_M_RD; 527e6213840SShawn Tu msgs[1].len = len; 528e6213840SShawn Tu msgs[1].buf = &data_buf[4 - len]; 529e6213840SShawn Tu 530e6213840SShawn Tu ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 531e6213840SShawn Tu if (ret != ARRAY_SIZE(msgs)) 532e6213840SShawn Tu return -EIO; 533e6213840SShawn Tu 534e6213840SShawn Tu *val = get_unaligned_be32(data_buf); 535e6213840SShawn Tu 536e6213840SShawn Tu return 0; 537e6213840SShawn Tu } 538e6213840SShawn Tu 539e6213840SShawn Tu static int hi556_write_reg(struct hi556 *hi556, u16 reg, u16 len, u32 val) 540e6213840SShawn Tu { 541e6213840SShawn Tu struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd); 542e6213840SShawn Tu u8 buf[6]; 543e6213840SShawn Tu 544e6213840SShawn Tu if (len > 4) 545e6213840SShawn Tu return -EINVAL; 546e6213840SShawn Tu 547e6213840SShawn Tu put_unaligned_be16(reg, buf); 548e6213840SShawn Tu put_unaligned_be32(val << 8 * (4 - len), buf + 2); 549e6213840SShawn Tu if (i2c_master_send(client, buf, len + 2) != len + 2) 550e6213840SShawn Tu return -EIO; 551e6213840SShawn Tu 552e6213840SShawn Tu return 0; 553e6213840SShawn Tu } 554e6213840SShawn Tu 555e6213840SShawn Tu static int hi556_write_reg_list(struct hi556 *hi556, 556e6213840SShawn Tu const struct hi556_reg_list *r_list) 557e6213840SShawn Tu { 558e6213840SShawn Tu struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd); 559e6213840SShawn Tu unsigned int i; 560e6213840SShawn Tu int ret; 561e6213840SShawn Tu 562e6213840SShawn Tu for (i = 0; i < r_list->num_of_regs; i++) { 563e6213840SShawn Tu ret = hi556_write_reg(hi556, r_list->regs[i].address, 564e6213840SShawn Tu HI556_REG_VALUE_16BIT, 565e6213840SShawn Tu r_list->regs[i].val); 566e6213840SShawn Tu if (ret) { 567e6213840SShawn Tu dev_err_ratelimited(&client->dev, 568e6213840SShawn Tu "failed to write reg 0x%4.4x. error = %d", 569e6213840SShawn Tu r_list->regs[i].address, ret); 570e6213840SShawn Tu return ret; 571e6213840SShawn Tu } 572e6213840SShawn Tu } 573e6213840SShawn Tu 574e6213840SShawn Tu return 0; 575e6213840SShawn Tu } 576e6213840SShawn Tu 577e6213840SShawn Tu static int hi556_update_digital_gain(struct hi556 *hi556, u32 d_gain) 578e6213840SShawn Tu { 579e6213840SShawn Tu int ret; 580e6213840SShawn Tu 581e6213840SShawn Tu ret = hi556_write_reg(hi556, HI556_REG_MWB_GR_GAIN, 582e6213840SShawn Tu HI556_REG_VALUE_16BIT, d_gain); 583e6213840SShawn Tu if (ret) 584e6213840SShawn Tu return ret; 585e6213840SShawn Tu 586e6213840SShawn Tu ret = hi556_write_reg(hi556, HI556_REG_MWB_GB_GAIN, 587e6213840SShawn Tu HI556_REG_VALUE_16BIT, d_gain); 588e6213840SShawn Tu if (ret) 589e6213840SShawn Tu return ret; 590e6213840SShawn Tu 591e6213840SShawn Tu ret = hi556_write_reg(hi556, HI556_REG_MWB_R_GAIN, 592e6213840SShawn Tu HI556_REG_VALUE_16BIT, d_gain); 593e6213840SShawn Tu if (ret) 594e6213840SShawn Tu return ret; 595e6213840SShawn Tu 596e6213840SShawn Tu return hi556_write_reg(hi556, HI556_REG_MWB_B_GAIN, 597e6213840SShawn Tu HI556_REG_VALUE_16BIT, d_gain); 598e6213840SShawn Tu } 599e6213840SShawn Tu 600e6213840SShawn Tu static int hi556_test_pattern(struct hi556 *hi556, u32 pattern) 601e6213840SShawn Tu { 602e6213840SShawn Tu int ret; 603e6213840SShawn Tu u32 val; 604e6213840SShawn Tu 605e6213840SShawn Tu if (pattern) { 606e6213840SShawn Tu ret = hi556_read_reg(hi556, HI556_REG_ISP, 607e6213840SShawn Tu HI556_REG_VALUE_08BIT, &val); 608e6213840SShawn Tu if (ret) 609e6213840SShawn Tu return ret; 610e6213840SShawn Tu 611e6213840SShawn Tu ret = hi556_write_reg(hi556, HI556_REG_ISP, 612e6213840SShawn Tu HI556_REG_VALUE_08BIT, 613e6213840SShawn Tu val | HI556_REG_ISP_TPG_EN); 614e6213840SShawn Tu if (ret) 615e6213840SShawn Tu return ret; 616e6213840SShawn Tu } 617e6213840SShawn Tu 618e6213840SShawn Tu return hi556_write_reg(hi556, HI556_REG_TEST_PATTERN, 619e6213840SShawn Tu HI556_REG_VALUE_08BIT, pattern); 620e6213840SShawn Tu } 621e6213840SShawn Tu 622e6213840SShawn Tu static int hi556_set_ctrl(struct v4l2_ctrl *ctrl) 623e6213840SShawn Tu { 624e6213840SShawn Tu struct hi556 *hi556 = container_of(ctrl->handler, 625e6213840SShawn Tu struct hi556, ctrl_handler); 626e6213840SShawn Tu struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd); 627e6213840SShawn Tu s64 exposure_max; 628e6213840SShawn Tu int ret = 0; 629e6213840SShawn Tu 630e6213840SShawn Tu /* Propagate change of current control to all related controls */ 631e6213840SShawn Tu if (ctrl->id == V4L2_CID_VBLANK) { 632e6213840SShawn Tu /* Update max exposure while meeting expected vblanking */ 633e6213840SShawn Tu exposure_max = hi556->cur_mode->height + ctrl->val - 634e6213840SShawn Tu HI556_EXPOSURE_MAX_MARGIN; 635e6213840SShawn Tu __v4l2_ctrl_modify_range(hi556->exposure, 636e6213840SShawn Tu hi556->exposure->minimum, 637e6213840SShawn Tu exposure_max, hi556->exposure->step, 638e6213840SShawn Tu exposure_max); 639e6213840SShawn Tu } 640e6213840SShawn Tu 641e6213840SShawn Tu /* V4L2 controls values will be applied only when power is already up */ 642e6213840SShawn Tu if (!pm_runtime_get_if_in_use(&client->dev)) 643e6213840SShawn Tu return 0; 644e6213840SShawn Tu 645e6213840SShawn Tu switch (ctrl->id) { 646e6213840SShawn Tu case V4L2_CID_ANALOGUE_GAIN: 647e6213840SShawn Tu ret = hi556_write_reg(hi556, HI556_REG_ANALOG_GAIN, 648e6213840SShawn Tu HI556_REG_VALUE_16BIT, ctrl->val); 649e6213840SShawn Tu break; 650e6213840SShawn Tu 651e6213840SShawn Tu case V4L2_CID_DIGITAL_GAIN: 652e6213840SShawn Tu ret = hi556_update_digital_gain(hi556, ctrl->val); 653e6213840SShawn Tu break; 654e6213840SShawn Tu 655e6213840SShawn Tu case V4L2_CID_EXPOSURE: 656e6213840SShawn Tu ret = hi556_write_reg(hi556, HI556_REG_EXPOSURE, 657e6213840SShawn Tu HI556_REG_VALUE_16BIT, ctrl->val); 658e6213840SShawn Tu break; 659e6213840SShawn Tu 660e6213840SShawn Tu case V4L2_CID_VBLANK: 661e6213840SShawn Tu /* Update FLL that meets expected vertical blanking */ 662e6213840SShawn Tu ret = hi556_write_reg(hi556, HI556_REG_FLL, 663e6213840SShawn Tu HI556_REG_VALUE_16BIT, 664e6213840SShawn Tu hi556->cur_mode->height + ctrl->val); 665e6213840SShawn Tu break; 666e6213840SShawn Tu 667e6213840SShawn Tu case V4L2_CID_TEST_PATTERN: 668e6213840SShawn Tu ret = hi556_test_pattern(hi556, ctrl->val); 669e6213840SShawn Tu break; 670e6213840SShawn Tu 671e6213840SShawn Tu default: 672e6213840SShawn Tu ret = -EINVAL; 673e6213840SShawn Tu break; 674e6213840SShawn Tu } 675e6213840SShawn Tu 676e6213840SShawn Tu pm_runtime_put(&client->dev); 677e6213840SShawn Tu 678e6213840SShawn Tu return ret; 679e6213840SShawn Tu } 680e6213840SShawn Tu 681e6213840SShawn Tu static const struct v4l2_ctrl_ops hi556_ctrl_ops = { 682e6213840SShawn Tu .s_ctrl = hi556_set_ctrl, 683e6213840SShawn Tu }; 684e6213840SShawn Tu 685e6213840SShawn Tu static int hi556_init_controls(struct hi556 *hi556) 686e6213840SShawn Tu { 687e6213840SShawn Tu struct v4l2_ctrl_handler *ctrl_hdlr; 688e6213840SShawn Tu s64 exposure_max, h_blank; 689e6213840SShawn Tu int ret; 690e6213840SShawn Tu 691e6213840SShawn Tu ctrl_hdlr = &hi556->ctrl_handler; 692e6213840SShawn Tu ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8); 693e6213840SShawn Tu if (ret) 694e6213840SShawn Tu return ret; 695e6213840SShawn Tu 696e6213840SShawn Tu ctrl_hdlr->lock = &hi556->mutex; 697e6213840SShawn Tu hi556->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &hi556_ctrl_ops, 698e6213840SShawn Tu V4L2_CID_LINK_FREQ, 699e6213840SShawn Tu ARRAY_SIZE(link_freq_menu_items) - 1, 700e6213840SShawn Tu 0, link_freq_menu_items); 701e6213840SShawn Tu if (hi556->link_freq) 702e6213840SShawn Tu hi556->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; 703e6213840SShawn Tu 704e6213840SShawn Tu hi556->pixel_rate = v4l2_ctrl_new_std 705e6213840SShawn Tu (ctrl_hdlr, &hi556_ctrl_ops, 706e6213840SShawn Tu V4L2_CID_PIXEL_RATE, 0, 707e6213840SShawn Tu to_pixel_rate(HI556_LINK_FREQ_437MHZ_INDEX), 708e6213840SShawn Tu 1, 709e6213840SShawn Tu to_pixel_rate(HI556_LINK_FREQ_437MHZ_INDEX)); 710e6213840SShawn Tu hi556->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &hi556_ctrl_ops, 711e6213840SShawn Tu V4L2_CID_VBLANK, 712e6213840SShawn Tu hi556->cur_mode->fll_min - 713e6213840SShawn Tu hi556->cur_mode->height, 714e6213840SShawn Tu HI556_FLL_MAX - 715e6213840SShawn Tu hi556->cur_mode->height, 1, 716e6213840SShawn Tu hi556->cur_mode->fll_def - 717e6213840SShawn Tu hi556->cur_mode->height); 718e6213840SShawn Tu 719e6213840SShawn Tu h_blank = hi556->cur_mode->llp - hi556->cur_mode->width; 720e6213840SShawn Tu 721e6213840SShawn Tu hi556->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &hi556_ctrl_ops, 722e6213840SShawn Tu V4L2_CID_HBLANK, h_blank, h_blank, 1, 723e6213840SShawn Tu h_blank); 724e6213840SShawn Tu if (hi556->hblank) 725e6213840SShawn Tu hi556->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; 726e6213840SShawn Tu 727e6213840SShawn Tu v4l2_ctrl_new_std(ctrl_hdlr, &hi556_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, 728e6213840SShawn Tu HI556_ANAL_GAIN_MIN, HI556_ANAL_GAIN_MAX, 729e6213840SShawn Tu HI556_ANAL_GAIN_STEP, HI556_ANAL_GAIN_MIN); 730e6213840SShawn Tu v4l2_ctrl_new_std(ctrl_hdlr, &hi556_ctrl_ops, V4L2_CID_DIGITAL_GAIN, 731e6213840SShawn Tu HI556_DGTL_GAIN_MIN, HI556_DGTL_GAIN_MAX, 732e6213840SShawn Tu HI556_DGTL_GAIN_STEP, HI556_DGTL_GAIN_DEFAULT); 733e6213840SShawn Tu exposure_max = hi556->cur_mode->fll_def - HI556_EXPOSURE_MAX_MARGIN; 734e6213840SShawn Tu hi556->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &hi556_ctrl_ops, 735e6213840SShawn Tu V4L2_CID_EXPOSURE, 736e6213840SShawn Tu HI556_EXPOSURE_MIN, exposure_max, 737e6213840SShawn Tu HI556_EXPOSURE_STEP, 738e6213840SShawn Tu exposure_max); 739e6213840SShawn Tu v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &hi556_ctrl_ops, 740e6213840SShawn Tu V4L2_CID_TEST_PATTERN, 741e6213840SShawn Tu ARRAY_SIZE(hi556_test_pattern_menu) - 1, 742e6213840SShawn Tu 0, 0, hi556_test_pattern_menu); 743e6213840SShawn Tu if (ctrl_hdlr->error) 744e6213840SShawn Tu return ctrl_hdlr->error; 745e6213840SShawn Tu 746e6213840SShawn Tu hi556->sd.ctrl_handler = ctrl_hdlr; 747e6213840SShawn Tu 748e6213840SShawn Tu return 0; 749e6213840SShawn Tu } 750e6213840SShawn Tu 751e6213840SShawn Tu static void hi556_assign_pad_format(const struct hi556_mode *mode, 752e6213840SShawn Tu struct v4l2_mbus_framefmt *fmt) 753e6213840SShawn Tu { 754e6213840SShawn Tu fmt->width = mode->width; 755e6213840SShawn Tu fmt->height = mode->height; 756e6213840SShawn Tu fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; 757e6213840SShawn Tu fmt->field = V4L2_FIELD_NONE; 758e6213840SShawn Tu } 759e6213840SShawn Tu 760e6213840SShawn Tu static int hi556_start_streaming(struct hi556 *hi556) 761e6213840SShawn Tu { 762e6213840SShawn Tu struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd); 763e6213840SShawn Tu const struct hi556_reg_list *reg_list; 764e6213840SShawn Tu int link_freq_index, ret; 765e6213840SShawn Tu 766e6213840SShawn Tu link_freq_index = hi556->cur_mode->link_freq_index; 767e6213840SShawn Tu reg_list = &link_freq_configs[link_freq_index].reg_list; 768e6213840SShawn Tu ret = hi556_write_reg_list(hi556, reg_list); 769e6213840SShawn Tu if (ret) { 770e6213840SShawn Tu dev_err(&client->dev, "failed to set plls"); 771e6213840SShawn Tu return ret; 772e6213840SShawn Tu } 773e6213840SShawn Tu 774e6213840SShawn Tu reg_list = &hi556->cur_mode->reg_list; 775e6213840SShawn Tu ret = hi556_write_reg_list(hi556, reg_list); 776e6213840SShawn Tu if (ret) { 777e6213840SShawn Tu dev_err(&client->dev, "failed to set mode"); 778e6213840SShawn Tu return ret; 779e6213840SShawn Tu } 780e6213840SShawn Tu 781e6213840SShawn Tu ret = __v4l2_ctrl_handler_setup(hi556->sd.ctrl_handler); 782e6213840SShawn Tu if (ret) 783e6213840SShawn Tu return ret; 784e6213840SShawn Tu 785e6213840SShawn Tu ret = hi556_write_reg(hi556, HI556_REG_MODE_SELECT, 786e6213840SShawn Tu HI556_REG_VALUE_16BIT, HI556_MODE_STREAMING); 787e6213840SShawn Tu 788e6213840SShawn Tu if (ret) { 789e6213840SShawn Tu dev_err(&client->dev, "failed to set stream"); 790e6213840SShawn Tu return ret; 791e6213840SShawn Tu } 792e6213840SShawn Tu 793e6213840SShawn Tu return 0; 794e6213840SShawn Tu } 795e6213840SShawn Tu 796e6213840SShawn Tu static void hi556_stop_streaming(struct hi556 *hi556) 797e6213840SShawn Tu { 798e6213840SShawn Tu struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd); 799e6213840SShawn Tu 800e6213840SShawn Tu if (hi556_write_reg(hi556, HI556_REG_MODE_SELECT, 801e6213840SShawn Tu HI556_REG_VALUE_16BIT, HI556_MODE_STANDBY)) 802e6213840SShawn Tu dev_err(&client->dev, "failed to set stream"); 803e6213840SShawn Tu } 804e6213840SShawn Tu 805e6213840SShawn Tu static int hi556_set_stream(struct v4l2_subdev *sd, int enable) 806e6213840SShawn Tu { 807e6213840SShawn Tu struct hi556 *hi556 = to_hi556(sd); 808e6213840SShawn Tu struct i2c_client *client = v4l2_get_subdevdata(sd); 809e6213840SShawn Tu int ret = 0; 810e6213840SShawn Tu 811e6213840SShawn Tu if (hi556->streaming == enable) 812e6213840SShawn Tu return 0; 813e6213840SShawn Tu 814e6213840SShawn Tu mutex_lock(&hi556->mutex); 815e6213840SShawn Tu if (enable) { 816e6213840SShawn Tu ret = pm_runtime_get_sync(&client->dev); 817e6213840SShawn Tu if (ret < 0) { 818e6213840SShawn Tu pm_runtime_put_noidle(&client->dev); 819e6213840SShawn Tu mutex_unlock(&hi556->mutex); 820e6213840SShawn Tu return ret; 821e6213840SShawn Tu } 822e6213840SShawn Tu 823e6213840SShawn Tu ret = hi556_start_streaming(hi556); 824e6213840SShawn Tu if (ret) { 825e6213840SShawn Tu enable = 0; 826e6213840SShawn Tu hi556_stop_streaming(hi556); 827e6213840SShawn Tu pm_runtime_put(&client->dev); 828e6213840SShawn Tu } 829e6213840SShawn Tu } else { 830e6213840SShawn Tu hi556_stop_streaming(hi556); 831e6213840SShawn Tu pm_runtime_put(&client->dev); 832e6213840SShawn Tu } 833e6213840SShawn Tu 834e6213840SShawn Tu hi556->streaming = enable; 835e6213840SShawn Tu mutex_unlock(&hi556->mutex); 836e6213840SShawn Tu 837e6213840SShawn Tu return ret; 838e6213840SShawn Tu } 839e6213840SShawn Tu 840e6213840SShawn Tu static int __maybe_unused hi556_suspend(struct device *dev) 841e6213840SShawn Tu { 84234b3c34dSKrzysztof Kozlowski struct v4l2_subdev *sd = dev_get_drvdata(dev); 843e6213840SShawn Tu struct hi556 *hi556 = to_hi556(sd); 844e6213840SShawn Tu 845e6213840SShawn Tu mutex_lock(&hi556->mutex); 846e6213840SShawn Tu if (hi556->streaming) 847e6213840SShawn Tu hi556_stop_streaming(hi556); 848e6213840SShawn Tu 849e6213840SShawn Tu mutex_unlock(&hi556->mutex); 850e6213840SShawn Tu 851e6213840SShawn Tu return 0; 852e6213840SShawn Tu } 853e6213840SShawn Tu 854e6213840SShawn Tu static int __maybe_unused hi556_resume(struct device *dev) 855e6213840SShawn Tu { 85634b3c34dSKrzysztof Kozlowski struct v4l2_subdev *sd = dev_get_drvdata(dev); 857e6213840SShawn Tu struct hi556 *hi556 = to_hi556(sd); 858e6213840SShawn Tu int ret; 859e6213840SShawn Tu 860e6213840SShawn Tu mutex_lock(&hi556->mutex); 861e6213840SShawn Tu if (hi556->streaming) { 862e6213840SShawn Tu ret = hi556_start_streaming(hi556); 863e6213840SShawn Tu if (ret) 864e6213840SShawn Tu goto error; 865e6213840SShawn Tu } 866e6213840SShawn Tu 867e6213840SShawn Tu mutex_unlock(&hi556->mutex); 868e6213840SShawn Tu 869e6213840SShawn Tu return 0; 870e6213840SShawn Tu 871e6213840SShawn Tu error: 872e6213840SShawn Tu hi556_stop_streaming(hi556); 873e6213840SShawn Tu hi556->streaming = 0; 874e6213840SShawn Tu mutex_unlock(&hi556->mutex); 875e6213840SShawn Tu return ret; 876e6213840SShawn Tu } 877e6213840SShawn Tu 878e6213840SShawn Tu static int hi556_set_format(struct v4l2_subdev *sd, 879e6213840SShawn Tu struct v4l2_subdev_pad_config *cfg, 880e6213840SShawn Tu struct v4l2_subdev_format *fmt) 881e6213840SShawn Tu { 882e6213840SShawn Tu struct hi556 *hi556 = to_hi556(sd); 883e6213840SShawn Tu const struct hi556_mode *mode; 884e6213840SShawn Tu s32 vblank_def, h_blank; 885e6213840SShawn Tu 886e6213840SShawn Tu mode = v4l2_find_nearest_size(supported_modes, 887e6213840SShawn Tu ARRAY_SIZE(supported_modes), width, 888e6213840SShawn Tu height, fmt->format.width, 889e6213840SShawn Tu fmt->format.height); 890e6213840SShawn Tu 891e6213840SShawn Tu mutex_lock(&hi556->mutex); 892e6213840SShawn Tu hi556_assign_pad_format(mode, &fmt->format); 893e6213840SShawn Tu if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { 894e6213840SShawn Tu *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format; 895e6213840SShawn Tu } else { 896e6213840SShawn Tu hi556->cur_mode = mode; 897e6213840SShawn Tu __v4l2_ctrl_s_ctrl(hi556->link_freq, mode->link_freq_index); 898e6213840SShawn Tu __v4l2_ctrl_s_ctrl_int64(hi556->pixel_rate, 899e6213840SShawn Tu to_pixel_rate(mode->link_freq_index)); 900e6213840SShawn Tu 901e6213840SShawn Tu /* Update limits and set FPS to default */ 902e6213840SShawn Tu vblank_def = mode->fll_def - mode->height; 903e6213840SShawn Tu __v4l2_ctrl_modify_range(hi556->vblank, 904e6213840SShawn Tu mode->fll_min - mode->height, 905e6213840SShawn Tu HI556_FLL_MAX - mode->height, 1, 906e6213840SShawn Tu vblank_def); 907e6213840SShawn Tu __v4l2_ctrl_s_ctrl(hi556->vblank, vblank_def); 908e6213840SShawn Tu 909e6213840SShawn Tu h_blank = hi556->cur_mode->llp - hi556->cur_mode->width; 910e6213840SShawn Tu 911e6213840SShawn Tu __v4l2_ctrl_modify_range(hi556->hblank, h_blank, h_blank, 1, 912e6213840SShawn Tu h_blank); 913e6213840SShawn Tu } 914e6213840SShawn Tu 915e6213840SShawn Tu mutex_unlock(&hi556->mutex); 916e6213840SShawn Tu 917e6213840SShawn Tu return 0; 918e6213840SShawn Tu } 919e6213840SShawn Tu 920e6213840SShawn Tu static int hi556_get_format(struct v4l2_subdev *sd, 921e6213840SShawn Tu struct v4l2_subdev_pad_config *cfg, 922e6213840SShawn Tu struct v4l2_subdev_format *fmt) 923e6213840SShawn Tu { 924e6213840SShawn Tu struct hi556 *hi556 = to_hi556(sd); 925e6213840SShawn Tu 926e6213840SShawn Tu mutex_lock(&hi556->mutex); 927e6213840SShawn Tu if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) 928e6213840SShawn Tu fmt->format = *v4l2_subdev_get_try_format(&hi556->sd, cfg, 929e6213840SShawn Tu fmt->pad); 930e6213840SShawn Tu else 931e6213840SShawn Tu hi556_assign_pad_format(hi556->cur_mode, &fmt->format); 932e6213840SShawn Tu 933e6213840SShawn Tu mutex_unlock(&hi556->mutex); 934e6213840SShawn Tu 935e6213840SShawn Tu return 0; 936e6213840SShawn Tu } 937e6213840SShawn Tu 938e6213840SShawn Tu static int hi556_enum_mbus_code(struct v4l2_subdev *sd, 939e6213840SShawn Tu struct v4l2_subdev_pad_config *cfg, 940e6213840SShawn Tu struct v4l2_subdev_mbus_code_enum *code) 941e6213840SShawn Tu { 942e6213840SShawn Tu if (code->index > 0) 943e6213840SShawn Tu return -EINVAL; 944e6213840SShawn Tu 945e6213840SShawn Tu code->code = MEDIA_BUS_FMT_SGRBG10_1X10; 946e6213840SShawn Tu 947e6213840SShawn Tu return 0; 948e6213840SShawn Tu } 949e6213840SShawn Tu 950e6213840SShawn Tu static int hi556_enum_frame_size(struct v4l2_subdev *sd, 951e6213840SShawn Tu struct v4l2_subdev_pad_config *cfg, 952e6213840SShawn Tu struct v4l2_subdev_frame_size_enum *fse) 953e6213840SShawn Tu { 954e6213840SShawn Tu if (fse->index >= ARRAY_SIZE(supported_modes)) 955e6213840SShawn Tu return -EINVAL; 956e6213840SShawn Tu 957e6213840SShawn Tu if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10) 958e6213840SShawn Tu return -EINVAL; 959e6213840SShawn Tu 960e6213840SShawn Tu fse->min_width = supported_modes[fse->index].width; 961e6213840SShawn Tu fse->max_width = fse->min_width; 962e6213840SShawn Tu fse->min_height = supported_modes[fse->index].height; 963e6213840SShawn Tu fse->max_height = fse->min_height; 964e6213840SShawn Tu 965e6213840SShawn Tu return 0; 966e6213840SShawn Tu } 967e6213840SShawn Tu 968e6213840SShawn Tu static int hi556_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) 969e6213840SShawn Tu { 970e6213840SShawn Tu struct hi556 *hi556 = to_hi556(sd); 971e6213840SShawn Tu 972e6213840SShawn Tu mutex_lock(&hi556->mutex); 973e6213840SShawn Tu hi556_assign_pad_format(&supported_modes[0], 974e6213840SShawn Tu v4l2_subdev_get_try_format(sd, fh->pad, 0)); 975e6213840SShawn Tu mutex_unlock(&hi556->mutex); 976e6213840SShawn Tu 977e6213840SShawn Tu return 0; 978e6213840SShawn Tu } 979e6213840SShawn Tu 980e6213840SShawn Tu static const struct v4l2_subdev_video_ops hi556_video_ops = { 981e6213840SShawn Tu .s_stream = hi556_set_stream, 982e6213840SShawn Tu }; 983e6213840SShawn Tu 984e6213840SShawn Tu static const struct v4l2_subdev_pad_ops hi556_pad_ops = { 985e6213840SShawn Tu .set_fmt = hi556_set_format, 986e6213840SShawn Tu .get_fmt = hi556_get_format, 987e6213840SShawn Tu .enum_mbus_code = hi556_enum_mbus_code, 988e6213840SShawn Tu .enum_frame_size = hi556_enum_frame_size, 989e6213840SShawn Tu }; 990e6213840SShawn Tu 991e6213840SShawn Tu static const struct v4l2_subdev_ops hi556_subdev_ops = { 992e6213840SShawn Tu .video = &hi556_video_ops, 993e6213840SShawn Tu .pad = &hi556_pad_ops, 994e6213840SShawn Tu }; 995e6213840SShawn Tu 996e6213840SShawn Tu static const struct media_entity_operations hi556_subdev_entity_ops = { 997e6213840SShawn Tu .link_validate = v4l2_subdev_link_validate, 998e6213840SShawn Tu }; 999e6213840SShawn Tu 1000e6213840SShawn Tu static const struct v4l2_subdev_internal_ops hi556_internal_ops = { 1001e6213840SShawn Tu .open = hi556_open, 1002e6213840SShawn Tu }; 1003e6213840SShawn Tu 1004e6213840SShawn Tu static int hi556_identify_module(struct hi556 *hi556) 1005e6213840SShawn Tu { 1006e6213840SShawn Tu struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd); 1007e6213840SShawn Tu int ret; 1008e6213840SShawn Tu u32 val; 1009e6213840SShawn Tu 1010e6213840SShawn Tu ret = hi556_read_reg(hi556, HI556_REG_CHIP_ID, 1011e6213840SShawn Tu HI556_REG_VALUE_16BIT, &val); 1012e6213840SShawn Tu if (ret) 1013e6213840SShawn Tu return ret; 1014e6213840SShawn Tu 1015e6213840SShawn Tu if (val != HI556_CHIP_ID) { 1016e6213840SShawn Tu dev_err(&client->dev, "chip id mismatch: %x!=%x", 1017e6213840SShawn Tu HI556_CHIP_ID, val); 1018e6213840SShawn Tu return -ENXIO; 1019e6213840SShawn Tu } 1020e6213840SShawn Tu 1021e6213840SShawn Tu return 0; 1022e6213840SShawn Tu } 1023e6213840SShawn Tu 1024e6213840SShawn Tu static int hi556_check_hwcfg(struct device *dev) 1025e6213840SShawn Tu { 1026e6213840SShawn Tu struct fwnode_handle *ep; 1027e6213840SShawn Tu struct fwnode_handle *fwnode = dev_fwnode(dev); 1028e6213840SShawn Tu struct v4l2_fwnode_endpoint bus_cfg = { 1029e6213840SShawn Tu .bus_type = V4L2_MBUS_CSI2_DPHY 1030e6213840SShawn Tu }; 1031e6213840SShawn Tu u32 mclk; 1032e6213840SShawn Tu int ret = 0; 1033e6213840SShawn Tu unsigned int i, j; 1034e6213840SShawn Tu 1035e6213840SShawn Tu if (!fwnode) 1036e6213840SShawn Tu return -ENXIO; 1037e6213840SShawn Tu 1038e6213840SShawn Tu ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk); 1039e6213840SShawn Tu if (ret) { 1040e6213840SShawn Tu dev_err(dev, "can't get clock frequency"); 1041e6213840SShawn Tu return ret; 1042e6213840SShawn Tu } 1043e6213840SShawn Tu 1044e6213840SShawn Tu if (mclk != HI556_MCLK) { 1045e6213840SShawn Tu dev_err(dev, "external clock %d is not supported", mclk); 1046e6213840SShawn Tu return -EINVAL; 1047e6213840SShawn Tu } 1048e6213840SShawn Tu 1049e6213840SShawn Tu ep = fwnode_graph_get_next_endpoint(fwnode, NULL); 1050e6213840SShawn Tu if (!ep) 1051e6213840SShawn Tu return -ENXIO; 1052e6213840SShawn Tu 1053e6213840SShawn Tu ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); 1054e6213840SShawn Tu fwnode_handle_put(ep); 1055e6213840SShawn Tu if (ret) 1056e6213840SShawn Tu return ret; 1057e6213840SShawn Tu 1058e6213840SShawn Tu if (bus_cfg.bus.mipi_csi2.num_data_lanes != 2) { 1059e6213840SShawn Tu dev_err(dev, "number of CSI2 data lanes %d is not supported", 1060e6213840SShawn Tu bus_cfg.bus.mipi_csi2.num_data_lanes); 1061e6213840SShawn Tu ret = -EINVAL; 1062e6213840SShawn Tu goto check_hwcfg_error; 1063e6213840SShawn Tu } 1064e6213840SShawn Tu 1065e6213840SShawn Tu if (!bus_cfg.nr_of_link_frequencies) { 1066e6213840SShawn Tu dev_err(dev, "no link frequencies defined"); 1067e6213840SShawn Tu ret = -EINVAL; 1068e6213840SShawn Tu goto check_hwcfg_error; 1069e6213840SShawn Tu } 1070e6213840SShawn Tu 1071e6213840SShawn Tu for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); i++) { 1072e6213840SShawn Tu for (j = 0; j < bus_cfg.nr_of_link_frequencies; j++) { 1073e6213840SShawn Tu if (link_freq_menu_items[i] == 1074e6213840SShawn Tu bus_cfg.link_frequencies[j]) 1075e6213840SShawn Tu break; 1076e6213840SShawn Tu } 1077e6213840SShawn Tu 1078e6213840SShawn Tu if (j == bus_cfg.nr_of_link_frequencies) { 1079e6213840SShawn Tu dev_err(dev, "no link frequency %lld supported", 1080e6213840SShawn Tu link_freq_menu_items[i]); 1081e6213840SShawn Tu ret = -EINVAL; 1082e6213840SShawn Tu goto check_hwcfg_error; 1083e6213840SShawn Tu } 1084e6213840SShawn Tu } 1085e6213840SShawn Tu 1086e6213840SShawn Tu check_hwcfg_error: 1087e6213840SShawn Tu v4l2_fwnode_endpoint_free(&bus_cfg); 1088e6213840SShawn Tu 1089e6213840SShawn Tu return ret; 1090e6213840SShawn Tu } 1091e6213840SShawn Tu 1092e6213840SShawn Tu static int hi556_remove(struct i2c_client *client) 1093e6213840SShawn Tu { 1094e6213840SShawn Tu struct v4l2_subdev *sd = i2c_get_clientdata(client); 1095e6213840SShawn Tu struct hi556 *hi556 = to_hi556(sd); 1096e6213840SShawn Tu 1097e6213840SShawn Tu v4l2_async_unregister_subdev(sd); 1098e6213840SShawn Tu media_entity_cleanup(&sd->entity); 1099e6213840SShawn Tu v4l2_ctrl_handler_free(sd->ctrl_handler); 1100e6213840SShawn Tu pm_runtime_disable(&client->dev); 1101e6213840SShawn Tu mutex_destroy(&hi556->mutex); 1102e6213840SShawn Tu 1103e6213840SShawn Tu return 0; 1104e6213840SShawn Tu } 1105e6213840SShawn Tu 1106e6213840SShawn Tu static int hi556_probe(struct i2c_client *client) 1107e6213840SShawn Tu { 1108e6213840SShawn Tu struct hi556 *hi556; 1109e6213840SShawn Tu int ret; 1110e6213840SShawn Tu 1111e6213840SShawn Tu ret = hi556_check_hwcfg(&client->dev); 1112e6213840SShawn Tu if (ret) { 1113e6213840SShawn Tu dev_err(&client->dev, "failed to check HW configuration: %d", 1114e6213840SShawn Tu ret); 1115e6213840SShawn Tu return ret; 1116e6213840SShawn Tu } 1117e6213840SShawn Tu 1118e6213840SShawn Tu hi556 = devm_kzalloc(&client->dev, sizeof(*hi556), GFP_KERNEL); 1119e6213840SShawn Tu if (!hi556) 1120e6213840SShawn Tu return -ENOMEM; 1121e6213840SShawn Tu 1122e6213840SShawn Tu v4l2_i2c_subdev_init(&hi556->sd, client, &hi556_subdev_ops); 1123e6213840SShawn Tu ret = hi556_identify_module(hi556); 1124e6213840SShawn Tu if (ret) { 1125e6213840SShawn Tu dev_err(&client->dev, "failed to find sensor: %d", ret); 1126e6213840SShawn Tu return ret; 1127e6213840SShawn Tu } 1128e6213840SShawn Tu 1129e6213840SShawn Tu mutex_init(&hi556->mutex); 1130e6213840SShawn Tu hi556->cur_mode = &supported_modes[0]; 1131e6213840SShawn Tu ret = hi556_init_controls(hi556); 1132e6213840SShawn Tu if (ret) { 1133e6213840SShawn Tu dev_err(&client->dev, "failed to init controls: %d", ret); 1134e6213840SShawn Tu goto probe_error_v4l2_ctrl_handler_free; 1135e6213840SShawn Tu } 1136e6213840SShawn Tu 1137e6213840SShawn Tu hi556->sd.internal_ops = &hi556_internal_ops; 1138e6213840SShawn Tu hi556->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 1139e6213840SShawn Tu hi556->sd.entity.ops = &hi556_subdev_entity_ops; 1140e6213840SShawn Tu hi556->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; 1141e6213840SShawn Tu hi556->pad.flags = MEDIA_PAD_FL_SOURCE; 1142e6213840SShawn Tu ret = media_entity_pads_init(&hi556->sd.entity, 1, &hi556->pad); 1143e6213840SShawn Tu if (ret) { 1144e6213840SShawn Tu dev_err(&client->dev, "failed to init entity pads: %d", ret); 1145e6213840SShawn Tu goto probe_error_v4l2_ctrl_handler_free; 1146e6213840SShawn Tu } 1147e6213840SShawn Tu 1148*15786f7bSSakari Ailus ret = v4l2_async_register_subdev_sensor(&hi556->sd); 1149e6213840SShawn Tu if (ret < 0) { 1150e6213840SShawn Tu dev_err(&client->dev, "failed to register V4L2 subdev: %d", 1151e6213840SShawn Tu ret); 1152e6213840SShawn Tu goto probe_error_media_entity_cleanup; 1153e6213840SShawn Tu } 1154e6213840SShawn Tu 1155e6213840SShawn Tu pm_runtime_set_active(&client->dev); 1156e6213840SShawn Tu pm_runtime_enable(&client->dev); 1157e6213840SShawn Tu pm_runtime_idle(&client->dev); 1158e6213840SShawn Tu 1159e6213840SShawn Tu return 0; 1160e6213840SShawn Tu 1161e6213840SShawn Tu probe_error_media_entity_cleanup: 1162e6213840SShawn Tu media_entity_cleanup(&hi556->sd.entity); 1163e6213840SShawn Tu 1164e6213840SShawn Tu probe_error_v4l2_ctrl_handler_free: 1165e6213840SShawn Tu v4l2_ctrl_handler_free(hi556->sd.ctrl_handler); 1166e6213840SShawn Tu mutex_destroy(&hi556->mutex); 1167e6213840SShawn Tu 1168e6213840SShawn Tu return ret; 1169e6213840SShawn Tu } 1170e6213840SShawn Tu 1171e6213840SShawn Tu static const struct dev_pm_ops hi556_pm_ops = { 1172e6213840SShawn Tu SET_SYSTEM_SLEEP_PM_OPS(hi556_suspend, hi556_resume) 1173e6213840SShawn Tu }; 1174e6213840SShawn Tu 1175e6213840SShawn Tu #ifdef CONFIG_ACPI 1176e6213840SShawn Tu static const struct acpi_device_id hi556_acpi_ids[] = { 1177e6213840SShawn Tu {"INT3537"}, 1178e6213840SShawn Tu {} 1179e6213840SShawn Tu }; 1180e6213840SShawn Tu 1181e6213840SShawn Tu MODULE_DEVICE_TABLE(acpi, hi556_acpi_ids); 1182e6213840SShawn Tu #endif 1183e6213840SShawn Tu 1184e6213840SShawn Tu static struct i2c_driver hi556_i2c_driver = { 1185e6213840SShawn Tu .driver = { 1186e6213840SShawn Tu .name = "hi556", 1187e6213840SShawn Tu .pm = &hi556_pm_ops, 1188e6213840SShawn Tu .acpi_match_table = ACPI_PTR(hi556_acpi_ids), 1189e6213840SShawn Tu }, 1190e6213840SShawn Tu .probe_new = hi556_probe, 1191e6213840SShawn Tu .remove = hi556_remove, 1192e6213840SShawn Tu }; 1193e6213840SShawn Tu 1194e6213840SShawn Tu module_i2c_driver(hi556_i2c_driver); 1195e6213840SShawn Tu 1196e6213840SShawn Tu MODULE_AUTHOR("Shawn Tu <shawnx.tu@intel.com>"); 1197e6213840SShawn Tu MODULE_DESCRIPTION("Hynix HI556 sensor driver"); 1198e6213840SShawn Tu MODULE_LICENSE("GPL v2"); 1199