1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (c) 2022 Intel Corporation. 3 4 #include <linux/acpi.h> 5 #include <linux/clk.h> 6 #include <linux/delay.h> 7 #include <linux/gpio/consumer.h> 8 #include <linux/i2c.h> 9 #include <linux/module.h> 10 #include <linux/pm_runtime.h> 11 #include <linux/regulator/consumer.h> 12 #include <media/v4l2-cci.h> 13 #include <media/v4l2-ctrls.h> 14 #include <media/v4l2-device.h> 15 #include <media/v4l2-fwnode.h> 16 17 #define OG01A1B_LINK_FREQ_500MHZ 500000000ULL 18 #define OG01A1B_SCLK 120000000LL 19 #define OG01A1B_MCLK 19200000 20 #define OG01A1B_DATA_LANES 2 21 22 #define OG01A1B_REG_CHIP_ID CCI_REG24(0x300a) 23 #define OG01A1B_CHIP_ID 0x470141 24 25 #define OG01A1B_REG_MODE_SELECT CCI_REG8(0x0100) 26 #define OG01A1B_MODE_STANDBY 0x00 27 #define OG01A1B_MODE_STREAMING 0x01 28 29 /* vertical-timings from sensor */ 30 #define OG01A1B_REG_VTS CCI_REG16(0x380e) 31 #define OG01A1B_VTS_120FPS 0x0498 32 #define OG01A1B_VTS_120FPS_MIN 0x0498 33 #define OG01A1B_VTS_MAX 0x7fff 34 35 /* horizontal-timings from sensor */ 36 #define OG01A1B_REG_HTS CCI_REG16(0x380c) 37 38 /* Exposure controls from sensor */ 39 #define OG01A1B_REG_EXPOSURE CCI_REG16(0x3501) 40 #define OG01A1B_EXPOSURE_MIN 1 41 #define OG01A1B_EXPOSURE_MAX_MARGIN 14 42 #define OG01A1B_EXPOSURE_STEP 1 43 44 /* Analog gain controls from sensor */ 45 #define OG01A1B_REG_ANALOG_GAIN CCI_REG16(0x3508) 46 #define OG01A1B_ANAL_GAIN_MIN 16 47 #define OG01A1B_ANAL_GAIN_MAX 248 /* Max = 15.5x */ 48 #define OG01A1B_ANAL_GAIN_STEP 1 49 50 /* Digital gain controls from sensor */ 51 #define OG01A1B_REG_DIG_GAIN CCI_REG24(0x350a) 52 #define OG01A1B_DGTL_GAIN_MIN 1024 53 #define OG01A1B_DGTL_GAIN_MAX 16384 /* Max = 16x */ 54 #define OG01A1B_DGTL_GAIN_STEP 1 55 #define OG01A1B_DGTL_GAIN_DEFAULT 1024 56 57 /* Test Pattern Control */ 58 #define OG01A1B_REG_TEST_PATTERN CCI_REG8(0x5100) 59 #define OG01A1B_TEST_PATTERN_ENABLE BIT(7) 60 #define OG01A1B_TEST_PATTERN_BAR_SHIFT 2 61 62 #define to_og01a1b(_sd) container_of(_sd, struct og01a1b, sd) 63 64 enum { 65 OG01A1B_LINK_FREQ_1000MBPS, 66 }; 67 68 struct og01a1b_reg_list { 69 const struct cci_reg_sequence *regs; 70 u32 num_of_regs; 71 }; 72 73 struct og01a1b_link_freq_config { 74 const struct og01a1b_reg_list reg_list; 75 }; 76 77 struct og01a1b_mode { 78 /* Frame width in pixels */ 79 u32 width; 80 81 /* Frame height in pixels */ 82 u32 height; 83 84 /* Horizontal timining size */ 85 u32 hts; 86 87 /* Default vertical timining size */ 88 u32 vts_def; 89 90 /* Min vertical timining size */ 91 u32 vts_min; 92 93 /* Link frequency needed for this resolution */ 94 u32 link_freq_index; 95 96 /* Sensor register settings for this resolution */ 97 const struct og01a1b_reg_list reg_list; 98 }; 99 100 static const u32 og01a1b_mbus_formats[] = { 101 MEDIA_BUS_FMT_Y10_1X10, 102 MEDIA_BUS_FMT_Y8_1X8, 103 }; 104 105 static const struct cci_reg_sequence mipi_data_rate_1000mbps[] = { 106 { CCI_REG8(0x0103), 0x01 }, 107 { CCI_REG8(0x0303), 0x02 }, 108 { CCI_REG8(0x0304), 0x00 }, 109 { CCI_REG8(0x0305), 0xd2 }, 110 { CCI_REG8(0x0323), 0x02 }, 111 { CCI_REG8(0x0324), 0x01 }, 112 { CCI_REG8(0x0325), 0x77 }, 113 }; 114 115 static const struct cci_reg_sequence mode_1280x1024_regs[] = { 116 { CCI_REG8(0x0300), 0x0a }, 117 { CCI_REG8(0x0301), 0x29 }, 118 { CCI_REG8(0x0302), 0x31 }, 119 { CCI_REG8(0x0303), 0x02 }, 120 { CCI_REG8(0x0304), 0x00 }, 121 { CCI_REG8(0x0305), 0xd2 }, 122 { CCI_REG8(0x0306), 0x00 }, 123 { CCI_REG8(0x0307), 0x01 }, 124 { CCI_REG8(0x0308), 0x02 }, 125 { CCI_REG8(0x0309), 0x00 }, 126 { CCI_REG8(0x0310), 0x00 }, 127 { CCI_REG8(0x0311), 0x00 }, 128 { CCI_REG8(0x0312), 0x07 }, 129 { CCI_REG8(0x0313), 0x00 }, 130 { CCI_REG8(0x0314), 0x00 }, 131 { CCI_REG8(0x0315), 0x00 }, 132 { CCI_REG8(0x0320), 0x02 }, 133 { CCI_REG8(0x0321), 0x01 }, 134 { CCI_REG8(0x0322), 0x01 }, 135 { CCI_REG8(0x0323), 0x02 }, 136 { CCI_REG8(0x0324), 0x01 }, 137 { CCI_REG8(0x0325), 0x77 }, 138 { CCI_REG8(0x0326), 0xce }, 139 { CCI_REG8(0x0327), 0x04 }, 140 { CCI_REG8(0x0329), 0x02 }, 141 { CCI_REG8(0x032a), 0x04 }, 142 { CCI_REG8(0x032b), 0x04 }, 143 { CCI_REG8(0x032c), 0x02 }, 144 { CCI_REG8(0x032d), 0x01 }, 145 { CCI_REG8(0x032e), 0x00 }, 146 { CCI_REG8(0x300d), 0x02 }, 147 { CCI_REG8(0x300e), 0x04 }, 148 { CCI_REG8(0x3021), 0x08 }, 149 { CCI_REG8(0x301e), 0x03 }, 150 { CCI_REG8(0x3103), 0x00 }, 151 { CCI_REG8(0x3106), 0x08 }, 152 { CCI_REG8(0x3107), 0x40 }, 153 { CCI_REG8(0x3216), 0x01 }, 154 { CCI_REG8(0x3217), 0x00 }, 155 { CCI_REG8(0x3218), 0xc0 }, 156 { CCI_REG8(0x3219), 0x55 }, 157 { CCI_REG8(0x3500), 0x00 }, 158 { CCI_REG8(0x3501), 0x04 }, 159 { CCI_REG8(0x3502), 0x8a }, 160 { CCI_REG8(0x3506), 0x01 }, 161 { CCI_REG8(0x3507), 0x72 }, 162 { CCI_REG8(0x3508), 0x01 }, 163 { CCI_REG8(0x3509), 0x00 }, 164 { CCI_REG8(0x350a), 0x01 }, 165 { CCI_REG8(0x350b), 0x00 }, 166 { CCI_REG8(0x350c), 0x00 }, 167 { CCI_REG8(0x3541), 0x00 }, 168 { CCI_REG8(0x3542), 0x40 }, 169 { CCI_REG8(0x3605), 0xe0 }, 170 { CCI_REG8(0x3606), 0x41 }, 171 { CCI_REG8(0x3614), 0x20 }, 172 { CCI_REG8(0x3620), 0x0b }, 173 { CCI_REG8(0x3630), 0x07 }, 174 { CCI_REG8(0x3636), 0xa0 }, 175 { CCI_REG8(0x3637), 0xf9 }, 176 { CCI_REG8(0x3638), 0x09 }, 177 { CCI_REG8(0x3639), 0x38 }, 178 { CCI_REG8(0x363f), 0x09 }, 179 { CCI_REG8(0x3640), 0x17 }, 180 { CCI_REG8(0x3665), 0x80 }, 181 { CCI_REG8(0x3670), 0x68 }, 182 { CCI_REG8(0x3674), 0x00 }, 183 { CCI_REG8(0x3677), 0x3f }, 184 { CCI_REG8(0x3679), 0x00 }, 185 { CCI_REG8(0x369f), 0x19 }, 186 { CCI_REG8(0x36a0), 0x03 }, 187 { CCI_REG8(0x36a2), 0x19 }, 188 { CCI_REG8(0x36a3), 0x03 }, 189 { CCI_REG8(0x370d), 0x66 }, 190 { CCI_REG8(0x370f), 0x00 }, 191 { CCI_REG8(0x3710), 0x03 }, 192 { CCI_REG8(0x3715), 0x03 }, 193 { CCI_REG8(0x3716), 0x03 }, 194 { CCI_REG8(0x3717), 0x06 }, 195 { CCI_REG8(0x3733), 0x00 }, 196 { CCI_REG8(0x3778), 0x00 }, 197 { CCI_REG8(0x37a8), 0x0f }, 198 { CCI_REG8(0x37a9), 0x01 }, 199 { CCI_REG8(0x37aa), 0x07 }, 200 { CCI_REG8(0x37bd), 0x1c }, 201 { CCI_REG8(0x37c1), 0x2f }, 202 { CCI_REG8(0x37c3), 0x09 }, 203 { CCI_REG8(0x37c8), 0x1d }, 204 { CCI_REG8(0x37ca), 0x30 }, 205 { CCI_REG8(0x37df), 0x00 }, 206 { CCI_REG8(0x3800), 0x00 }, 207 { CCI_REG8(0x3801), 0x00 }, 208 { CCI_REG8(0x3802), 0x00 }, 209 { CCI_REG8(0x3803), 0x00 }, 210 { CCI_REG8(0x3804), 0x05 }, 211 { CCI_REG8(0x3805), 0x0f }, 212 { CCI_REG8(0x3806), 0x04 }, 213 { CCI_REG8(0x3807), 0x0f }, 214 { CCI_REG8(0x3808), 0x05 }, 215 { CCI_REG8(0x3809), 0x00 }, 216 { CCI_REG8(0x380a), 0x04 }, 217 { CCI_REG8(0x380b), 0x00 }, 218 { CCI_REG8(0x380c), 0x03 }, 219 { CCI_REG8(0x380d), 0x50 }, 220 { CCI_REG8(0x380e), 0x04 }, 221 { CCI_REG8(0x380f), 0x98 }, 222 { CCI_REG8(0x3810), 0x00 }, 223 { CCI_REG8(0x3811), 0x08 }, 224 { CCI_REG8(0x3812), 0x00 }, 225 { CCI_REG8(0x3813), 0x08 }, 226 { CCI_REG8(0x3814), 0x11 }, 227 { CCI_REG8(0x3815), 0x11 }, 228 { CCI_REG8(0x3820), 0x40 }, 229 { CCI_REG8(0x3821), 0x04 }, 230 { CCI_REG8(0x3826), 0x00 }, 231 { CCI_REG8(0x3827), 0x00 }, 232 { CCI_REG8(0x382a), 0x08 }, 233 { CCI_REG8(0x382b), 0x52 }, 234 { CCI_REG8(0x382d), 0xba }, 235 { CCI_REG8(0x383d), 0x14 }, 236 { CCI_REG8(0x384a), 0xa2 }, 237 { CCI_REG8(0x3866), 0x0e }, 238 { CCI_REG8(0x3867), 0x07 }, 239 { CCI_REG8(0x3884), 0x00 }, 240 { CCI_REG8(0x3885), 0x08 }, 241 { CCI_REG8(0x3893), 0x68 }, 242 { CCI_REG8(0x3894), 0x2a }, 243 { CCI_REG8(0x3898), 0x00 }, 244 { CCI_REG8(0x3899), 0x31 }, 245 { CCI_REG8(0x389a), 0x04 }, 246 { CCI_REG8(0x389b), 0x00 }, 247 { CCI_REG8(0x389c), 0x0b }, 248 { CCI_REG8(0x389d), 0xad }, 249 { CCI_REG8(0x389f), 0x08 }, 250 { CCI_REG8(0x38a0), 0x00 }, 251 { CCI_REG8(0x38a1), 0x00 }, 252 { CCI_REG8(0x38a8), 0x70 }, 253 { CCI_REG8(0x38ac), 0xea }, 254 { CCI_REG8(0x38b2), 0x00 }, 255 { CCI_REG8(0x38b3), 0x08 }, 256 { CCI_REG8(0x38bc), 0x20 }, 257 { CCI_REG8(0x38c4), 0x0c }, 258 { CCI_REG8(0x38c5), 0x3a }, 259 { CCI_REG8(0x38c7), 0x3a }, 260 { CCI_REG8(0x38e1), 0xc0 }, 261 { CCI_REG8(0x38ec), 0x3c }, 262 { CCI_REG8(0x38f0), 0x09 }, 263 { CCI_REG8(0x38f1), 0x6f }, 264 { CCI_REG8(0x38fe), 0x3c }, 265 { CCI_REG8(0x391e), 0x00 }, 266 { CCI_REG8(0x391f), 0x00 }, 267 { CCI_REG8(0x3920), 0xa5 }, 268 { CCI_REG8(0x3921), 0x00 }, 269 { CCI_REG8(0x3922), 0x00 }, 270 { CCI_REG8(0x3923), 0x00 }, 271 { CCI_REG8(0x3924), 0x05 }, 272 { CCI_REG8(0x3925), 0x00 }, 273 { CCI_REG8(0x3926), 0x00 }, 274 { CCI_REG8(0x3927), 0x00 }, 275 { CCI_REG8(0x3928), 0x1a }, 276 { CCI_REG8(0x3929), 0x01 }, 277 { CCI_REG8(0x392a), 0xb4 }, 278 { CCI_REG8(0x392b), 0x00 }, 279 { CCI_REG8(0x392c), 0x10 }, 280 { CCI_REG8(0x392f), 0x40 }, 281 { CCI_REG8(0x4000), 0xcf }, 282 { CCI_REG8(0x4003), 0x40 }, 283 { CCI_REG8(0x4008), 0x00 }, 284 { CCI_REG8(0x4009), 0x07 }, 285 { CCI_REG8(0x400a), 0x02 }, 286 { CCI_REG8(0x400b), 0x54 }, 287 { CCI_REG8(0x400c), 0x00 }, 288 { CCI_REG8(0x400d), 0x07 }, 289 { CCI_REG8(0x4010), 0xc0 }, 290 { CCI_REG8(0x4012), 0x02 }, 291 { CCI_REG8(0x4014), 0x04 }, 292 { CCI_REG8(0x4015), 0x04 }, 293 { CCI_REG8(0x4017), 0x02 }, 294 { CCI_REG8(0x4042), 0x01 }, 295 { CCI_REG8(0x4306), 0x04 }, 296 { CCI_REG8(0x4307), 0x12 }, 297 { CCI_REG8(0x4509), 0x00 }, 298 { CCI_REG8(0x450b), 0x83 }, 299 { CCI_REG8(0x4604), 0x68 }, 300 { CCI_REG8(0x4608), 0x0a }, 301 { CCI_REG8(0x4700), 0x06 }, 302 { CCI_REG8(0x4800), 0x64 }, 303 { CCI_REG8(0x481b), 0x3c }, 304 { CCI_REG8(0x4825), 0x32 }, 305 { CCI_REG8(0x4833), 0x18 }, 306 { CCI_REG8(0x4837), 0x0f }, 307 { CCI_REG8(0x4850), 0x40 }, 308 { CCI_REG8(0x4860), 0x00 }, 309 { CCI_REG8(0x4861), 0xec }, 310 { CCI_REG8(0x4864), 0x00 }, 311 { CCI_REG8(0x4883), 0x00 }, 312 { CCI_REG8(0x4888), 0x90 }, 313 { CCI_REG8(0x4889), 0x05 }, 314 { CCI_REG8(0x488b), 0x04 }, 315 { CCI_REG8(0x4f00), 0x04 }, 316 { CCI_REG8(0x4f10), 0x04 }, 317 { CCI_REG8(0x4f21), 0x01 }, 318 { CCI_REG8(0x4f22), 0x40 }, 319 { CCI_REG8(0x4f23), 0x44 }, 320 { CCI_REG8(0x4f24), 0x51 }, 321 { CCI_REG8(0x4f25), 0x41 }, 322 { CCI_REG8(0x5000), 0x1f }, 323 { CCI_REG8(0x500a), 0x00 }, 324 { CCI_REG8(0x5100), 0x00 }, 325 { CCI_REG8(0x5111), 0x20 }, 326 { CCI_REG8(0x3020), 0x20 }, 327 { CCI_REG8(0x3613), 0x03 }, 328 { CCI_REG8(0x38c9), 0x02 }, 329 { CCI_REG8(0x5304), 0x01 }, 330 { CCI_REG8(0x3620), 0x08 }, 331 { CCI_REG8(0x3639), 0x58 }, 332 { CCI_REG8(0x363a), 0x10 }, 333 { CCI_REG8(0x3674), 0x04 }, 334 { CCI_REG8(0x3780), 0xff }, 335 { CCI_REG8(0x3781), 0xff }, 336 { CCI_REG8(0x3782), 0x00 }, 337 { CCI_REG8(0x3783), 0x01 }, 338 { CCI_REG8(0x3798), 0xa3 }, 339 { CCI_REG8(0x37aa), 0x10 }, 340 { CCI_REG8(0x38a8), 0xf0 }, 341 { CCI_REG8(0x38c4), 0x09 }, 342 { CCI_REG8(0x38c5), 0xb0 }, 343 { CCI_REG8(0x38df), 0x80 }, 344 { CCI_REG8(0x38ff), 0x05 }, 345 { CCI_REG8(0x4010), 0xf1 }, 346 { CCI_REG8(0x4011), 0x70 }, 347 { CCI_REG8(0x3667), 0x80 }, 348 { CCI_REG8(0x4d00), 0x4a }, 349 { CCI_REG8(0x4d01), 0x18 }, 350 { CCI_REG8(0x4d02), 0xbb }, 351 { CCI_REG8(0x4d03), 0xde }, 352 { CCI_REG8(0x4d04), 0x93 }, 353 { CCI_REG8(0x4d05), 0xff }, 354 { CCI_REG8(0x4d09), 0x0a }, 355 { CCI_REG8(0x37aa), 0x16 }, 356 { CCI_REG8(0x3606), 0x42 }, 357 { CCI_REG8(0x3605), 0x00 }, 358 { CCI_REG8(0x36a2), 0x17 }, 359 { CCI_REG8(0x300d), 0x0a }, 360 { CCI_REG8(0x4d00), 0x4d }, 361 { CCI_REG8(0x4d01), 0x95 }, 362 { CCI_REG8(0x3d8c), 0x70 }, 363 { CCI_REG8(0x3d8d), 0xe9 }, 364 { CCI_REG8(0x5300), 0x00 }, 365 { CCI_REG8(0x5301), 0x10 }, 366 { CCI_REG8(0x5302), 0x00 }, 367 { CCI_REG8(0x5303), 0xe3 }, 368 { CCI_REG8(0x3d88), 0x00 }, 369 { CCI_REG8(0x3d89), 0x10 }, 370 { CCI_REG8(0x3d8a), 0x00 }, 371 { CCI_REG8(0x3d8b), 0xe3 }, 372 { CCI_REG8(0x4f22), 0x00 }, 373 }; 374 375 static const char * const og01a1b_test_pattern_menu[] = { 376 "Disabled", 377 "Standard Color Bar", 378 "Top-Bottom Darker Color Bar", 379 "Right-Left Darker Color Bar", 380 "Bottom-Top Darker Color Bar" 381 }; 382 383 static const s64 link_freq_menu_items[] = { 384 OG01A1B_LINK_FREQ_500MHZ, 385 }; 386 387 static const struct og01a1b_link_freq_config link_freq_configs[] = { 388 [OG01A1B_LINK_FREQ_1000MBPS] = { 389 .reg_list = { 390 .num_of_regs = ARRAY_SIZE(mipi_data_rate_1000mbps), 391 .regs = mipi_data_rate_1000mbps, 392 } 393 } 394 }; 395 396 static const struct og01a1b_mode supported_modes[] = { 397 { 398 .width = 1280, 399 .height = 1024, 400 .hts = 848, 401 .vts_def = OG01A1B_VTS_120FPS, 402 .vts_min = OG01A1B_VTS_120FPS_MIN, 403 .reg_list = { 404 .num_of_regs = ARRAY_SIZE(mode_1280x1024_regs), 405 .regs = mode_1280x1024_regs, 406 }, 407 .link_freq_index = OG01A1B_LINK_FREQ_1000MBPS, 408 }, 409 }; 410 411 struct og01a1b { 412 struct device *dev; 413 struct regmap *regmap; 414 struct clk *xvclk; 415 struct gpio_desc *reset_gpio; 416 struct regulator *avdd; 417 struct regulator *dovdd; 418 struct regulator *dvdd; 419 420 struct v4l2_subdev sd; 421 struct media_pad pad; 422 struct v4l2_ctrl_handler ctrl_handler; 423 424 /* V4L2 Controls */ 425 struct v4l2_ctrl *link_freq; 426 struct v4l2_ctrl *pixel_rate; 427 struct v4l2_ctrl *vblank; 428 struct v4l2_ctrl *hblank; 429 struct v4l2_ctrl *exposure; 430 431 /* Current mode */ 432 const struct og01a1b_mode *cur_mode; 433 434 /* Selected media bus format output */ 435 u32 code; 436 }; 437 438 static u64 to_pixel_rate(u32 f_index, u32 bpp) 439 { 440 u64 pixel_rate = link_freq_menu_items[f_index] * 2 * OG01A1B_DATA_LANES; 441 442 do_div(pixel_rate, bpp); 443 444 return pixel_rate; 445 } 446 447 static u64 to_pixels_per_line(u32 hts, u32 f_index, u32 bpp) 448 { 449 u64 ppl = hts * to_pixel_rate(f_index, bpp); 450 451 do_div(ppl, OG01A1B_SCLK); 452 453 return ppl; 454 } 455 456 static int og01a1b_test_pattern(struct og01a1b *og01a1b, u32 pattern) 457 { 458 if (pattern) 459 pattern = (pattern - 1) << OG01A1B_TEST_PATTERN_BAR_SHIFT | 460 OG01A1B_TEST_PATTERN_ENABLE; 461 462 return cci_write(og01a1b->regmap, OG01A1B_REG_TEST_PATTERN, 463 pattern, NULL); 464 } 465 466 static int og01a1b_set_ctrl(struct v4l2_ctrl *ctrl) 467 { 468 struct og01a1b *og01a1b = container_of(ctrl->handler, 469 struct og01a1b, ctrl_handler); 470 s64 exposure_max; 471 int ret = 0; 472 473 /* Propagate change of current control to all related controls */ 474 if (ctrl->id == V4L2_CID_VBLANK) { 475 /* Update max exposure while meeting expected vblanking */ 476 exposure_max = og01a1b->cur_mode->height + ctrl->val - 477 OG01A1B_EXPOSURE_MAX_MARGIN; 478 __v4l2_ctrl_modify_range(og01a1b->exposure, 479 og01a1b->exposure->minimum, 480 exposure_max, og01a1b->exposure->step, 481 exposure_max); 482 } 483 484 /* V4L2 controls values will be applied only when power is already up */ 485 if (!pm_runtime_get_if_in_use(og01a1b->dev)) 486 return 0; 487 488 switch (ctrl->id) { 489 case V4L2_CID_ANALOGUE_GAIN: 490 ret = cci_write(og01a1b->regmap, OG01A1B_REG_ANALOG_GAIN, 491 ctrl->val << 4, NULL); 492 break; 493 494 case V4L2_CID_DIGITAL_GAIN: 495 ret = cci_write(og01a1b->regmap, OG01A1B_REG_DIG_GAIN, 496 ctrl->val << 6, NULL); 497 break; 498 499 case V4L2_CID_EXPOSURE: 500 ret = cci_write(og01a1b->regmap, OG01A1B_REG_EXPOSURE, 501 ctrl->val, NULL); 502 break; 503 504 case V4L2_CID_VBLANK: 505 ret = cci_write(og01a1b->regmap, OG01A1B_REG_VTS, 506 og01a1b->cur_mode->height + ctrl->val, NULL); 507 break; 508 509 case V4L2_CID_TEST_PATTERN: 510 ret = og01a1b_test_pattern(og01a1b, ctrl->val); 511 break; 512 513 default: 514 ret = -EINVAL; 515 break; 516 } 517 518 pm_runtime_put(og01a1b->dev); 519 520 return ret; 521 } 522 523 static const struct v4l2_ctrl_ops og01a1b_ctrl_ops = { 524 .s_ctrl = og01a1b_set_ctrl, 525 }; 526 527 static int og01a1b_init_controls(struct og01a1b *og01a1b) 528 { 529 struct v4l2_ctrl_handler *ctrl_hdlr; 530 s64 exposure_max, h_blank; 531 u32 bpp; 532 int ret; 533 534 ctrl_hdlr = &og01a1b->ctrl_handler; 535 ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8); 536 if (ret) 537 return ret; 538 539 og01a1b->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, 540 &og01a1b_ctrl_ops, 541 V4L2_CID_LINK_FREQ, 542 ARRAY_SIZE 543 (link_freq_menu_items) - 1, 544 0, link_freq_menu_items); 545 if (og01a1b->link_freq) 546 og01a1b->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; 547 548 bpp = (og01a1b->code == MEDIA_BUS_FMT_Y10_1X10 ? 10 : 8); 549 og01a1b->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &og01a1b_ctrl_ops, 550 V4L2_CID_PIXEL_RATE, 0, 551 to_pixel_rate(OG01A1B_LINK_FREQ_1000MBPS, bpp), 552 1, 553 to_pixel_rate(OG01A1B_LINK_FREQ_1000MBPS, bpp)); 554 og01a1b->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &og01a1b_ctrl_ops, 555 V4L2_CID_VBLANK, 556 og01a1b->cur_mode->vts_min - 557 og01a1b->cur_mode->height, 558 OG01A1B_VTS_MAX - 559 og01a1b->cur_mode->height, 1, 560 og01a1b->cur_mode->vts_def - 561 og01a1b->cur_mode->height); 562 h_blank = to_pixels_per_line(og01a1b->cur_mode->hts, 563 og01a1b->cur_mode->link_freq_index, bpp) - 564 og01a1b->cur_mode->width; 565 og01a1b->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &og01a1b_ctrl_ops, 566 V4L2_CID_HBLANK, h_blank, h_blank, 567 1, h_blank); 568 if (og01a1b->hblank) 569 og01a1b->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; 570 571 v4l2_ctrl_new_std(ctrl_hdlr, &og01a1b_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, 572 OG01A1B_ANAL_GAIN_MIN, OG01A1B_ANAL_GAIN_MAX, 573 OG01A1B_ANAL_GAIN_STEP, OG01A1B_ANAL_GAIN_MIN); 574 v4l2_ctrl_new_std(ctrl_hdlr, &og01a1b_ctrl_ops, V4L2_CID_DIGITAL_GAIN, 575 OG01A1B_DGTL_GAIN_MIN, OG01A1B_DGTL_GAIN_MAX, 576 OG01A1B_DGTL_GAIN_STEP, OG01A1B_DGTL_GAIN_DEFAULT); 577 exposure_max = (og01a1b->cur_mode->vts_def - 578 OG01A1B_EXPOSURE_MAX_MARGIN); 579 og01a1b->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &og01a1b_ctrl_ops, 580 V4L2_CID_EXPOSURE, 581 OG01A1B_EXPOSURE_MIN, 582 exposure_max, 583 OG01A1B_EXPOSURE_STEP, 584 exposure_max); 585 v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &og01a1b_ctrl_ops, 586 V4L2_CID_TEST_PATTERN, 587 ARRAY_SIZE(og01a1b_test_pattern_menu) - 1, 588 0, 0, og01a1b_test_pattern_menu); 589 590 if (ctrl_hdlr->error) 591 return ctrl_hdlr->error; 592 593 og01a1b->sd.ctrl_handler = ctrl_hdlr; 594 595 return 0; 596 } 597 598 static void og01a1b_update_pad_format(const struct og01a1b_mode *mode, 599 struct v4l2_mbus_framefmt *fmt) 600 { 601 fmt->width = mode->width; 602 fmt->height = mode->height; 603 fmt->field = V4L2_FIELD_NONE; 604 } 605 606 static int og01a1b_enable_streams(struct v4l2_subdev *sd, 607 struct v4l2_subdev_state *state, u32 pad, 608 u64 streams_mask) 609 { 610 struct og01a1b *og01a1b = to_og01a1b(sd); 611 unsigned int link_freq_index = og01a1b->cur_mode->link_freq_index; 612 const struct og01a1b_reg_list *reg_list; 613 int ret; 614 615 ret = pm_runtime_resume_and_get(og01a1b->dev); 616 if (ret) 617 return ret; 618 619 reg_list = &link_freq_configs[link_freq_index].reg_list; 620 ret = cci_multi_reg_write(og01a1b->regmap, reg_list->regs, 621 reg_list->num_of_regs, NULL); 622 if (ret) { 623 dev_err(og01a1b->dev, "failed to set plls: %d\n", ret); 624 goto error; 625 } 626 627 reg_list = &og01a1b->cur_mode->reg_list; 628 ret = cci_multi_reg_write(og01a1b->regmap, reg_list->regs, 629 reg_list->num_of_regs, NULL); 630 if (ret) { 631 dev_err(og01a1b->dev, "failed to set mode: %d\n", ret); 632 goto error; 633 } 634 635 ret = cci_write(og01a1b->regmap, CCI_REG8(0x3662), 636 (og01a1b->code == MEDIA_BUS_FMT_Y10_1X10 ? 0x4 : 0x6), 637 NULL); 638 if (ret) { 639 dev_err(og01a1b->dev, "failed to set output format: %d\n", ret); 640 goto error; 641 } 642 643 ret = __v4l2_ctrl_handler_setup(og01a1b->sd.ctrl_handler); 644 if (ret) 645 goto error; 646 647 ret = cci_write(og01a1b->regmap, OG01A1B_REG_MODE_SELECT, 648 OG01A1B_MODE_STREAMING, NULL); 649 if (ret) { 650 dev_err(og01a1b->dev, "failed to start streaming: %d\n", ret); 651 goto error; 652 } 653 654 return 0; 655 656 error: 657 pm_runtime_put_autosuspend(og01a1b->dev); 658 659 return ret; 660 } 661 662 static int og01a1b_disable_streams(struct v4l2_subdev *sd, 663 struct v4l2_subdev_state *state, u32 pad, 664 u64 streams_mask) 665 { 666 struct og01a1b *og01a1b = to_og01a1b(sd); 667 int ret; 668 669 ret = cci_write(og01a1b->regmap, OG01A1B_REG_MODE_SELECT, 670 OG01A1B_MODE_STANDBY, NULL); 671 if (ret) 672 dev_err(og01a1b->dev, "failed to stop streaming: %d\n", ret); 673 674 pm_runtime_put_autosuspend(og01a1b->dev); 675 676 return ret; 677 } 678 679 static int og01a1b_set_format(struct v4l2_subdev *sd, 680 struct v4l2_subdev_state *sd_state, 681 struct v4l2_subdev_format *fmt) 682 { 683 struct og01a1b *og01a1b = to_og01a1b(sd); 684 const struct og01a1b_mode *mode; 685 s32 vblank_def, h_blank, bpp; 686 687 mode = v4l2_find_nearest_size(supported_modes, 688 ARRAY_SIZE(supported_modes), width, 689 height, fmt->format.width, 690 fmt->format.height); 691 692 og01a1b_update_pad_format(mode, &fmt->format); 693 694 if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) 695 goto set_format; 696 697 bpp = (fmt->format.code == MEDIA_BUS_FMT_Y10_1X10 ? 10 : 8); 698 __v4l2_ctrl_s_ctrl(og01a1b->link_freq, mode->link_freq_index); 699 __v4l2_ctrl_s_ctrl_int64(og01a1b->pixel_rate, 700 to_pixel_rate(mode->link_freq_index, bpp)); 701 702 /* Update limits and set FPS to default */ 703 vblank_def = mode->vts_def - mode->height; 704 __v4l2_ctrl_modify_range(og01a1b->vblank, 705 mode->vts_min - mode->height, 706 OG01A1B_VTS_MAX - mode->height, 1, vblank_def); 707 __v4l2_ctrl_s_ctrl(og01a1b->vblank, vblank_def); 708 h_blank = to_pixels_per_line(mode->hts, mode->link_freq_index, 709 bpp) - mode->width; 710 __v4l2_ctrl_modify_range(og01a1b->hblank, h_blank, h_blank, 1, h_blank); 711 712 og01a1b->cur_mode = mode; 713 og01a1b->code = fmt->format.code; 714 715 set_format: 716 *v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format; 717 718 return 0; 719 } 720 721 static int og01a1b_enum_mbus_code(struct v4l2_subdev *sd, 722 struct v4l2_subdev_state *sd_state, 723 struct v4l2_subdev_mbus_code_enum *code) 724 { 725 if (code->index > ARRAY_SIZE(og01a1b_mbus_formats) - 1) 726 return -EINVAL; 727 728 code->code = og01a1b_mbus_formats[code->index]; 729 730 return 0; 731 } 732 733 static int og01a1b_enum_frame_size(struct v4l2_subdev *sd, 734 struct v4l2_subdev_state *sd_state, 735 struct v4l2_subdev_frame_size_enum *fse) 736 { 737 if (fse->index >= ARRAY_SIZE(supported_modes)) 738 return -EINVAL; 739 740 if (fse->code != MEDIA_BUS_FMT_Y10_1X10 && 741 fse->code != MEDIA_BUS_FMT_Y8_1X8) 742 return -EINVAL; 743 744 fse->min_width = supported_modes[fse->index].width; 745 fse->max_width = fse->min_width; 746 fse->min_height = supported_modes[fse->index].height; 747 fse->max_height = fse->min_height; 748 749 return 0; 750 } 751 752 static int og01a1b_init_state(struct v4l2_subdev *sd, 753 struct v4l2_subdev_state *state) 754 { 755 struct og01a1b *og01a1b = to_og01a1b(sd); 756 struct v4l2_subdev_format fmt = { 757 .which = V4L2_SUBDEV_FORMAT_TRY, 758 .pad = 0, 759 .format = { 760 .width = og01a1b->cur_mode->width, 761 .height = og01a1b->cur_mode->height, 762 .code = og01a1b->code, 763 }, 764 }; 765 766 og01a1b_set_format(sd, state, &fmt); 767 768 return 0; 769 } 770 771 static const struct v4l2_subdev_video_ops og01a1b_video_ops = { 772 .s_stream = v4l2_subdev_s_stream_helper, 773 }; 774 775 static const struct v4l2_subdev_pad_ops og01a1b_pad_ops = { 776 .set_fmt = og01a1b_set_format, 777 .get_fmt = v4l2_subdev_get_fmt, 778 .enum_mbus_code = og01a1b_enum_mbus_code, 779 .enum_frame_size = og01a1b_enum_frame_size, 780 .enable_streams = og01a1b_enable_streams, 781 .disable_streams = og01a1b_disable_streams, 782 }; 783 784 static const struct v4l2_subdev_ops og01a1b_subdev_ops = { 785 .video = &og01a1b_video_ops, 786 .pad = &og01a1b_pad_ops, 787 }; 788 789 static const struct media_entity_operations og01a1b_subdev_entity_ops = { 790 .link_validate = v4l2_subdev_link_validate, 791 }; 792 793 static const struct v4l2_subdev_internal_ops og01a1b_internal_ops = { 794 .init_state = og01a1b_init_state, 795 }; 796 797 static int og01a1b_identify_module(struct og01a1b *og01a1b) 798 { 799 int ret; 800 u64 val; 801 802 ret = cci_read(og01a1b->regmap, OG01A1B_REG_CHIP_ID, &val, NULL); 803 if (ret) 804 return ret; 805 806 if (val != OG01A1B_CHIP_ID) { 807 dev_err(og01a1b->dev, "chip id mismatch: %x!=%llx", 808 OG01A1B_CHIP_ID, val); 809 return -ENXIO; 810 } 811 812 return 0; 813 } 814 815 static int og01a1b_check_hwcfg(struct og01a1b *og01a1b) 816 { 817 struct device *dev = og01a1b->dev; 818 struct fwnode_handle *ep; 819 struct fwnode_handle *fwnode = dev_fwnode(dev); 820 struct v4l2_fwnode_endpoint bus_cfg = { 821 .bus_type = V4L2_MBUS_CSI2_DPHY 822 }; 823 int ret; 824 unsigned int i, j; 825 826 if (!fwnode) 827 return -ENXIO; 828 829 ep = fwnode_graph_get_next_endpoint(fwnode, NULL); 830 if (!ep) 831 return -ENXIO; 832 833 ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); 834 fwnode_handle_put(ep); 835 if (ret) 836 return ret; 837 838 if (bus_cfg.bus.mipi_csi2.num_data_lanes != OG01A1B_DATA_LANES) { 839 dev_err(dev, "number of CSI2 data lanes %d is not supported", 840 bus_cfg.bus.mipi_csi2.num_data_lanes); 841 ret = -EINVAL; 842 goto check_hwcfg_error; 843 } 844 845 if (!bus_cfg.nr_of_link_frequencies) { 846 dev_err(dev, "no link frequencies defined"); 847 ret = -EINVAL; 848 goto check_hwcfg_error; 849 } 850 851 for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); i++) { 852 for (j = 0; j < bus_cfg.nr_of_link_frequencies; j++) { 853 if (link_freq_menu_items[i] == 854 bus_cfg.link_frequencies[j]) 855 break; 856 } 857 858 if (j == bus_cfg.nr_of_link_frequencies) { 859 dev_err(dev, "no link frequency %lld supported", 860 link_freq_menu_items[i]); 861 ret = -EINVAL; 862 goto check_hwcfg_error; 863 } 864 } 865 866 check_hwcfg_error: 867 v4l2_fwnode_endpoint_free(&bus_cfg); 868 869 return ret; 870 } 871 872 /* Power/clock management functions */ 873 static int og01a1b_power_on(struct device *dev) 874 { 875 unsigned long delay = DIV_ROUND_UP(8192UL * USEC_PER_SEC, OG01A1B_MCLK); 876 struct v4l2_subdev *sd = dev_get_drvdata(dev); 877 struct og01a1b *og01a1b = to_og01a1b(sd); 878 int ret; 879 880 if (og01a1b->avdd) { 881 ret = regulator_enable(og01a1b->avdd); 882 if (ret) 883 return ret; 884 } 885 886 if (og01a1b->dovdd) { 887 ret = regulator_enable(og01a1b->dovdd); 888 if (ret) 889 goto avdd_disable; 890 } 891 892 if (og01a1b->dvdd) { 893 ret = regulator_enable(og01a1b->dvdd); 894 if (ret) 895 goto dovdd_disable; 896 } 897 898 ret = clk_prepare_enable(og01a1b->xvclk); 899 if (ret) 900 goto dvdd_disable; 901 902 gpiod_set_value_cansleep(og01a1b->reset_gpio, 0); 903 904 if (og01a1b->reset_gpio) 905 usleep_range(5 * USEC_PER_MSEC, 6 * USEC_PER_MSEC); 906 else if (og01a1b->xvclk) 907 usleep_range(delay, 2 * delay); 908 909 return 0; 910 911 dvdd_disable: 912 if (og01a1b->dvdd) 913 regulator_disable(og01a1b->dvdd); 914 dovdd_disable: 915 if (og01a1b->dovdd) 916 regulator_disable(og01a1b->dovdd); 917 avdd_disable: 918 if (og01a1b->avdd) 919 regulator_disable(og01a1b->avdd); 920 921 return ret; 922 } 923 924 static int og01a1b_power_off(struct device *dev) 925 { 926 unsigned long delay = DIV_ROUND_UP(512 * USEC_PER_SEC, OG01A1B_MCLK); 927 struct v4l2_subdev *sd = dev_get_drvdata(dev); 928 struct og01a1b *og01a1b = to_og01a1b(sd); 929 930 if (og01a1b->xvclk) 931 usleep_range(delay, 2 * delay); 932 933 clk_disable_unprepare(og01a1b->xvclk); 934 935 gpiod_set_value_cansleep(og01a1b->reset_gpio, 1); 936 937 if (og01a1b->dvdd) 938 regulator_disable(og01a1b->dvdd); 939 940 if (og01a1b->dovdd) 941 regulator_disable(og01a1b->dovdd); 942 943 if (og01a1b->avdd) 944 regulator_disable(og01a1b->avdd); 945 946 return 0; 947 } 948 949 static void og01a1b_remove(struct i2c_client *client) 950 { 951 struct v4l2_subdev *sd = i2c_get_clientdata(client); 952 struct og01a1b *og01a1b = to_og01a1b(sd); 953 954 v4l2_async_unregister_subdev(sd); 955 v4l2_subdev_cleanup(&og01a1b->sd); 956 media_entity_cleanup(&sd->entity); 957 v4l2_ctrl_handler_free(sd->ctrl_handler); 958 pm_runtime_disable(og01a1b->dev); 959 } 960 961 static int og01a1b_probe(struct i2c_client *client) 962 { 963 struct og01a1b *og01a1b; 964 unsigned long freq; 965 int ret; 966 967 og01a1b = devm_kzalloc(&client->dev, sizeof(*og01a1b), GFP_KERNEL); 968 if (!og01a1b) 969 return -ENOMEM; 970 971 og01a1b->dev = &client->dev; 972 973 v4l2_i2c_subdev_init(&og01a1b->sd, client, &og01a1b_subdev_ops); 974 975 og01a1b->regmap = devm_cci_regmap_init_i2c(client, 16); 976 if (IS_ERR(og01a1b->regmap)) 977 return dev_err_probe(og01a1b->dev, PTR_ERR(og01a1b->regmap), 978 "failed to init CCI\n"); 979 980 og01a1b->xvclk = devm_v4l2_sensor_clk_get(og01a1b->dev, NULL); 981 if (IS_ERR(og01a1b->xvclk)) 982 return dev_err_probe(og01a1b->dev, PTR_ERR(og01a1b->xvclk), 983 "failed to get xvclk clock\n"); 984 985 freq = clk_get_rate(og01a1b->xvclk); 986 if (freq != OG01A1B_MCLK) 987 return dev_err_probe(og01a1b->dev, -EINVAL, 988 "external clock %lu is not supported", 989 freq); 990 991 ret = og01a1b_check_hwcfg(og01a1b); 992 if (ret) { 993 dev_err(og01a1b->dev, "failed to check HW configuration: %d", 994 ret); 995 return ret; 996 } 997 998 og01a1b->reset_gpio = devm_gpiod_get_optional(og01a1b->dev, "reset", 999 GPIOD_OUT_LOW); 1000 if (IS_ERR(og01a1b->reset_gpio)) { 1001 dev_err(og01a1b->dev, "cannot get reset GPIO\n"); 1002 return PTR_ERR(og01a1b->reset_gpio); 1003 } 1004 1005 og01a1b->avdd = devm_regulator_get_optional(og01a1b->dev, "avdd"); 1006 if (IS_ERR(og01a1b->avdd)) { 1007 ret = PTR_ERR(og01a1b->avdd); 1008 if (ret != -ENODEV) { 1009 dev_err_probe(og01a1b->dev, ret, 1010 "Failed to get 'avdd' regulator\n"); 1011 return ret; 1012 } 1013 1014 og01a1b->avdd = NULL; 1015 } 1016 1017 og01a1b->dovdd = devm_regulator_get_optional(og01a1b->dev, "dovdd"); 1018 if (IS_ERR(og01a1b->dovdd)) { 1019 ret = PTR_ERR(og01a1b->dovdd); 1020 if (ret != -ENODEV) { 1021 dev_err_probe(og01a1b->dev, ret, 1022 "Failed to get 'dovdd' regulator\n"); 1023 return ret; 1024 } 1025 1026 og01a1b->dovdd = NULL; 1027 } 1028 1029 og01a1b->dvdd = devm_regulator_get_optional(og01a1b->dev, "dvdd"); 1030 if (IS_ERR(og01a1b->dvdd)) { 1031 ret = PTR_ERR(og01a1b->dvdd); 1032 if (ret != -ENODEV) { 1033 dev_err_probe(og01a1b->dev, ret, 1034 "Failed to get 'dvdd' regulator\n"); 1035 return ret; 1036 } 1037 1038 og01a1b->dvdd = NULL; 1039 } 1040 1041 /* The sensor must be powered on to read the CHIP_ID register */ 1042 ret = og01a1b_power_on(og01a1b->dev); 1043 if (ret) 1044 return ret; 1045 1046 ret = og01a1b_identify_module(og01a1b); 1047 if (ret) { 1048 dev_err(og01a1b->dev, "failed to find sensor: %d", ret); 1049 goto power_off; 1050 } 1051 1052 og01a1b->cur_mode = &supported_modes[0]; 1053 og01a1b->code = og01a1b_mbus_formats[0]; 1054 ret = og01a1b_init_controls(og01a1b); 1055 if (ret) { 1056 dev_err(og01a1b->dev, "failed to init controls: %d", ret); 1057 goto probe_error_v4l2_ctrl_handler_free; 1058 } 1059 1060 og01a1b->sd.state_lock = og01a1b->ctrl_handler.lock; 1061 og01a1b->sd.internal_ops = &og01a1b_internal_ops; 1062 og01a1b->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 1063 og01a1b->sd.entity.ops = &og01a1b_subdev_entity_ops; 1064 og01a1b->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; 1065 og01a1b->pad.flags = MEDIA_PAD_FL_SOURCE; 1066 ret = media_entity_pads_init(&og01a1b->sd.entity, 1, &og01a1b->pad); 1067 if (ret) { 1068 dev_err(og01a1b->dev, "failed to init entity pads: %d", ret); 1069 goto probe_error_v4l2_ctrl_handler_free; 1070 } 1071 1072 ret = v4l2_subdev_init_finalize(&og01a1b->sd); 1073 if (ret < 0) { 1074 dev_err_probe(og01a1b->dev, ret, 1075 "failed to finalize subdevice init\n"); 1076 goto probe_error_media_entity_cleanup; 1077 } 1078 1079 ret = v4l2_async_register_subdev_sensor(&og01a1b->sd); 1080 if (ret < 0) { 1081 dev_err(og01a1b->dev, "failed to register V4L2 subdev: %d", 1082 ret); 1083 goto probe_error_v4l2_subdev_cleanup; 1084 } 1085 1086 /* Enable runtime PM and turn off the device */ 1087 pm_runtime_set_active(og01a1b->dev); 1088 pm_runtime_enable(og01a1b->dev); 1089 pm_runtime_idle(og01a1b->dev); 1090 1091 return 0; 1092 1093 probe_error_v4l2_subdev_cleanup: 1094 v4l2_subdev_cleanup(&og01a1b->sd); 1095 1096 probe_error_media_entity_cleanup: 1097 media_entity_cleanup(&og01a1b->sd.entity); 1098 1099 probe_error_v4l2_ctrl_handler_free: 1100 v4l2_ctrl_handler_free(og01a1b->sd.ctrl_handler); 1101 1102 power_off: 1103 og01a1b_power_off(og01a1b->dev); 1104 1105 return ret; 1106 } 1107 1108 static const struct dev_pm_ops og01a1b_pm_ops = { 1109 SET_RUNTIME_PM_OPS(og01a1b_power_off, og01a1b_power_on, NULL) 1110 }; 1111 1112 #ifdef CONFIG_ACPI 1113 static const struct acpi_device_id og01a1b_acpi_ids[] = { 1114 {"OVTI01AC"}, 1115 {} 1116 }; 1117 1118 MODULE_DEVICE_TABLE(acpi, og01a1b_acpi_ids); 1119 #endif 1120 1121 static const struct of_device_id og01a1b_of_match[] = { 1122 { .compatible = "ovti,og01a1b" }, 1123 { /* sentinel */ } 1124 }; 1125 MODULE_DEVICE_TABLE(of, og01a1b_of_match); 1126 1127 static struct i2c_driver og01a1b_i2c_driver = { 1128 .driver = { 1129 .name = "og01a1b", 1130 .pm = &og01a1b_pm_ops, 1131 .acpi_match_table = ACPI_PTR(og01a1b_acpi_ids), 1132 .of_match_table = og01a1b_of_match, 1133 }, 1134 .probe = og01a1b_probe, 1135 .remove = og01a1b_remove, 1136 }; 1137 1138 module_i2c_driver(og01a1b_i2c_driver); 1139 1140 MODULE_AUTHOR("Shawn Tu"); 1141 MODULE_DESCRIPTION("OmniVision OG01A1B sensor driver"); 1142 MODULE_LICENSE("GPL v2"); 1143