1 | // SPDX-License-Identifier: GPL-2.0 |
---|---|
2 | // Copyright (c) 2022 Intel Corporation. |
3 | |
4 | #include <linux/unaligned.h> |
5 | #include <linux/acpi.h> |
6 | #include <linux/clk.h> |
7 | #include <linux/i2c.h> |
8 | #include <linux/gpio/consumer.h> |
9 | #include <linux/module.h> |
10 | #include <linux/delay.h> |
11 | #include <linux/pm_runtime.h> |
12 | #include <linux/regulator/consumer.h> |
13 | #include <media/v4l2-common.h> |
14 | #include <media/v4l2-ctrls.h> |
15 | #include <media/v4l2-device.h> |
16 | #include <media/v4l2-fwnode.h> |
17 | |
18 | #define OV08X40_REG_VALUE_08BIT 1 |
19 | #define OV08X40_REG_VALUE_16BIT 2 |
20 | #define OV08X40_REG_VALUE_24BIT 3 |
21 | |
22 | #define OV08X40_REG_MODE_SELECT 0x0100 |
23 | #define OV08X40_MODE_STANDBY 0x00 |
24 | #define OV08X40_MODE_STREAMING 0x01 |
25 | |
26 | #define OV08X40_REG_AO_STANDBY 0x1000 |
27 | #define OV08X40_AO_STREAMING 0x04 |
28 | |
29 | #define OV08X40_REG_MS_SELECT 0x1001 |
30 | #define OV08X40_MS_STANDBY 0x00 |
31 | #define OV08X40_MS_STREAMING 0x04 |
32 | |
33 | #define OV08X40_REG_SOFTWARE_RST 0x0103 |
34 | #define OV08X40_SOFTWARE_RST 0x01 |
35 | |
36 | /* Chip ID */ |
37 | #define OV08X40_REG_CHIP_ID 0x300a |
38 | #define OV08X40_CHIP_ID 0x560858 |
39 | |
40 | /* V_TIMING internal */ |
41 | #define OV08X40_REG_VTS 0x380e |
42 | #define OV08X40_VTS_30FPS 0x09c4 /* the VTS need to be half in normal mode */ |
43 | #define OV08X40_VTS_BIN_30FPS 0x115c |
44 | #define OV08X40_VTS_MAX 0x7fff |
45 | |
46 | /* H TIMING internal */ |
47 | #define OV08X40_REG_HTS 0x380c |
48 | #define OV08X40_HTS_30FPS 0x0280 |
49 | |
50 | /* Exposure control */ |
51 | #define OV08X40_REG_EXPOSURE 0x3500 |
52 | #define OV08X40_EXPOSURE_MAX_MARGIN 8 |
53 | #define OV08X40_EXPOSURE_BIN_MAX_MARGIN 2 |
54 | #define OV08X40_EXPOSURE_MIN 4 |
55 | #define OV08X40_EXPOSURE_STEP 1 |
56 | #define OV08X40_EXPOSURE_DEFAULT 0x40 |
57 | |
58 | /* Short Exposure control */ |
59 | #define OV08X40_REG_SHORT_EXPOSURE 0x3540 |
60 | |
61 | /* Analog gain control */ |
62 | #define OV08X40_REG_ANALOG_GAIN 0x3508 |
63 | #define OV08X40_ANA_GAIN_MIN 0x80 |
64 | #define OV08X40_ANA_GAIN_MAX 0x07c0 |
65 | #define OV08X40_ANA_GAIN_STEP 1 |
66 | #define OV08X40_ANA_GAIN_DEFAULT 0x80 |
67 | |
68 | /* Digital gain control */ |
69 | #define OV08X40_REG_DGTL_GAIN_H 0x350a |
70 | #define OV08X40_REG_DGTL_GAIN_M 0x350b |
71 | #define OV08X40_REG_DGTL_GAIN_L 0x350c |
72 | |
73 | #define OV08X40_DGTL_GAIN_MIN 1024 /* Min = 1 X */ |
74 | #define OV08X40_DGTL_GAIN_MAX (4096 - 1) /* Max = 4 X */ |
75 | #define OV08X40_DGTL_GAIN_DEFAULT 2560 /* Default gain = 2.5 X */ |
76 | #define OV08X40_DGTL_GAIN_STEP 1 /* Each step = 1/1024 */ |
77 | |
78 | #define OV08X40_DGTL_GAIN_L_SHIFT 6 |
79 | #define OV08X40_DGTL_GAIN_L_MASK 0x3 |
80 | #define OV08X40_DGTL_GAIN_M_SHIFT 2 |
81 | #define OV08X40_DGTL_GAIN_M_MASK 0xff |
82 | #define OV08X40_DGTL_GAIN_H_SHIFT 10 |
83 | #define OV08X40_DGTL_GAIN_H_MASK 0x1F |
84 | |
85 | /* Test Pattern Control */ |
86 | #define OV08X40_REG_TEST_PATTERN 0x50C1 |
87 | #define OV08X40_REG_ISP 0x5000 |
88 | #define OV08X40_REG_SHORT_TEST_PATTERN 0x53C1 |
89 | #define OV08X40_TEST_PATTERN_ENABLE BIT(0) |
90 | #define OV08X40_TEST_PATTERN_MASK 0xcf |
91 | #define OV08X40_TEST_PATTERN_BAR_SHIFT 4 |
92 | |
93 | /* Flip Control */ |
94 | #define OV08X40_REG_VFLIP 0x3820 |
95 | #define OV08X40_REG_MIRROR 0x3821 |
96 | |
97 | /* Horizontal Window Offset */ |
98 | #define OV08X40_REG_H_WIN_OFFSET 0x3811 |
99 | |
100 | /* Vertical Window Offset */ |
101 | #define OV08X40_REG_V_WIN_OFFSET 0x3813 |
102 | |
103 | /* Burst Register */ |
104 | #define OV08X40_REG_XTALK_FIRST_A 0x5a80 |
105 | #define OV08X40_REG_XTALK_LAST_A 0x5b9f |
106 | #define OV08X40_REG_XTALK_FIRST_B 0x5bc0 |
107 | #define OV08X40_REG_XTALK_LAST_B 0x5f1f |
108 | |
109 | enum { |
110 | OV08X40_LINK_FREQ_400MHZ_INDEX, |
111 | OV08X40_LINK_FREQ_749MHZ_INDEX, |
112 | }; |
113 | |
114 | struct ov08x40_reg { |
115 | u16 address; |
116 | u8 val; |
117 | }; |
118 | |
119 | struct ov08x40_reg_list { |
120 | u32 num_of_regs; |
121 | const struct ov08x40_reg *regs; |
122 | }; |
123 | |
124 | /* Link frequency config */ |
125 | struct ov08x40_link_freq_config { |
126 | /* registers for this link frequency */ |
127 | struct ov08x40_reg_list reg_list; |
128 | }; |
129 | |
130 | /* Mode : resolution and related config&values */ |
131 | struct ov08x40_mode { |
132 | /* Frame width */ |
133 | u32 width; |
134 | /* Frame height */ |
135 | u32 height; |
136 | |
137 | u32 lanes; |
138 | /* V-timing */ |
139 | u32 vts_def; |
140 | u32 vts_min; |
141 | |
142 | /* Line Length Pixels */ |
143 | u32 llp; |
144 | |
145 | /* Index of Link frequency config to be used */ |
146 | u32 link_freq_index; |
147 | /* Default register values */ |
148 | struct ov08x40_reg_list reg_list; |
149 | |
150 | /* Exposure calculation */ |
151 | u16 exposure_margin; |
152 | u16 exposure_shift; |
153 | }; |
154 | |
155 | static const struct ov08x40_reg ov08x40_global_regs[] = { |
156 | {0x1216, 0x60}, |
157 | {0x1217, 0x5b}, |
158 | {0x1218, 0x00}, |
159 | {0x1220, 0x24}, |
160 | {0x198a, 0x00}, |
161 | {0x198b, 0x01}, |
162 | {0x198e, 0x00}, |
163 | {0x198f, 0x01}, |
164 | {0x3009, 0x04}, |
165 | {0x3015, 0x00}, |
166 | {0x3016, 0xb0}, |
167 | {0x3017, 0xf0}, |
168 | {0x3018, 0xf0}, |
169 | {0x3019, 0xd2}, |
170 | {0x301a, 0xb0}, |
171 | {0x301c, 0x81}, |
172 | {0x301d, 0x02}, |
173 | {0x301e, 0x80}, |
174 | {0x3022, 0xf0}, |
175 | {0x3025, 0x89}, |
176 | {0x3030, 0x03}, |
177 | {0x3044, 0xc2}, |
178 | {0x3050, 0x35}, |
179 | {0x3051, 0x60}, |
180 | {0x3052, 0x25}, |
181 | {0x3053, 0x00}, |
182 | {0x3054, 0x00}, |
183 | {0x3055, 0x02}, |
184 | {0x3056, 0x80}, |
185 | {0x3057, 0x80}, |
186 | {0x3058, 0x80}, |
187 | {0x3059, 0x00}, |
188 | {0x3107, 0x86}, |
189 | {0x3401, 0x80}, |
190 | {0x3402, 0x8c}, |
191 | {0x3404, 0x01}, |
192 | {0x3407, 0x01}, |
193 | {0x341b, 0x30}, |
194 | {0x3420, 0x00}, |
195 | {0x3421, 0x00}, |
196 | {0x3422, 0x00}, |
197 | {0x3423, 0x00}, |
198 | {0x3424, 0x00}, |
199 | {0x3425, 0x00}, |
200 | {0x3426, 0x10}, |
201 | {0x3427, 0x00}, |
202 | {0x3428, 0x0f}, |
203 | {0x3429, 0x00}, |
204 | {0x342a, 0x00}, |
205 | {0x342b, 0x00}, |
206 | {0x342c, 0x00}, |
207 | {0x342d, 0x00}, |
208 | {0x342e, 0x00}, |
209 | {0x342f, 0x11}, |
210 | {0x3430, 0x11}, |
211 | {0x3431, 0x10}, |
212 | {0x3432, 0x00}, |
213 | {0x3433, 0x00}, |
214 | {0x3434, 0x00}, |
215 | {0x3435, 0x00}, |
216 | {0x3436, 0x00}, |
217 | {0x3437, 0x00}, |
218 | {0x3442, 0x02}, |
219 | {0x3443, 0x02}, |
220 | {0x3444, 0x07}, |
221 | {0x3450, 0x00}, |
222 | {0x3451, 0x00}, |
223 | {0x3452, 0x18}, |
224 | {0x3453, 0x18}, |
225 | {0x3454, 0x00}, |
226 | {0x3455, 0x80}, |
227 | {0x3456, 0x08}, |
228 | {0x3500, 0x00}, |
229 | {0x3502, 0x10}, |
230 | {0x3504, 0x4c}, |
231 | {0x3506, 0x30}, |
232 | {0x3507, 0x00}, |
233 | {0x350a, 0x01}, |
234 | {0x350b, 0x00}, |
235 | {0x350c, 0x00}, |
236 | {0x3540, 0x00}, |
237 | {0x3544, 0x4c}, |
238 | {0x3546, 0x30}, |
239 | {0x3547, 0x00}, |
240 | {0x3549, 0x00}, |
241 | {0x354a, 0x01}, |
242 | {0x354b, 0x00}, |
243 | {0x354c, 0x00}, |
244 | {0x3601, 0x40}, |
245 | {0x3602, 0x90}, |
246 | {0x3608, 0x0a}, |
247 | {0x3609, 0x08}, |
248 | {0x360f, 0x99}, |
249 | {0x3680, 0xa4}, |
250 | {0x3682, 0x80}, |
251 | {0x3688, 0x02}, |
252 | {0x368a, 0x2e}, |
253 | {0x368e, 0x71}, |
254 | {0x3696, 0xd1}, |
255 | {0x3699, 0x00}, |
256 | {0x369a, 0x00}, |
257 | {0x36a4, 0x00}, |
258 | {0x36a6, 0x00}, |
259 | {0x3711, 0x00}, |
260 | {0x3713, 0x00}, |
261 | {0x3716, 0x00}, |
262 | {0x3718, 0x07}, |
263 | {0x371a, 0x1c}, |
264 | {0x371b, 0x00}, |
265 | {0x3720, 0x08}, |
266 | {0x3725, 0x32}, |
267 | {0x3727, 0x05}, |
268 | {0x3760, 0x02}, |
269 | {0x3762, 0x02}, |
270 | {0x3763, 0x02}, |
271 | {0x3764, 0x02}, |
272 | {0x3765, 0x2c}, |
273 | {0x3766, 0x04}, |
274 | {0x3767, 0x2c}, |
275 | {0x3768, 0x02}, |
276 | {0x3769, 0x00}, |
277 | {0x376b, 0x20}, |
278 | {0x37b2, 0x01}, |
279 | {0x3800, 0x00}, |
280 | {0x3801, 0x00}, |
281 | {0x3802, 0x00}, |
282 | {0x3804, 0x0f}, |
283 | {0x3805, 0x1f}, |
284 | {0x3806, 0x09}, |
285 | {0x380c, 0x02}, |
286 | {0x3810, 0x00}, |
287 | {0x3812, 0x00}, |
288 | {0x3814, 0x11}, |
289 | {0x3815, 0x11}, |
290 | {0x3822, 0x00}, |
291 | {0x3828, 0x0f}, |
292 | {0x382a, 0x80}, |
293 | {0x382e, 0x41}, |
294 | {0x3837, 0x08}, |
295 | {0x383a, 0x81}, |
296 | {0x383b, 0x81}, |
297 | {0x383c, 0x11}, |
298 | {0x383d, 0x11}, |
299 | {0x383e, 0x00}, |
300 | {0x383f, 0x38}, |
301 | {0x3840, 0x00}, |
302 | {0x3847, 0x00}, |
303 | {0x384a, 0x00}, |
304 | {0x384c, 0x02}, |
305 | {0x3856, 0x50}, |
306 | {0x3857, 0x30}, |
307 | {0x3858, 0x80}, |
308 | {0x3859, 0x40}, |
309 | {0x3860, 0x00}, |
310 | {0x3888, 0x00}, |
311 | {0x3889, 0x00}, |
312 | {0x388a, 0x00}, |
313 | {0x388b, 0x00}, |
314 | {0x388c, 0x00}, |
315 | {0x388d, 0x00}, |
316 | {0x388e, 0x00}, |
317 | {0x388f, 0x00}, |
318 | {0x3895, 0x00}, |
319 | {0x3911, 0x90}, |
320 | {0x3913, 0x90}, |
321 | {0x3921, 0x0f}, |
322 | {0x3928, 0x15}, |
323 | {0x3929, 0x2a}, |
324 | {0x392c, 0x02}, |
325 | {0x392e, 0x04}, |
326 | {0x392f, 0x03}, |
327 | {0x3931, 0x07}, |
328 | {0x3932, 0x10}, |
329 | {0x3938, 0x09}, |
330 | {0x3a1f, 0x8a}, |
331 | {0x3a22, 0x91}, |
332 | {0x3a23, 0x15}, |
333 | {0x3a25, 0x96}, |
334 | {0x3a28, 0xb4}, |
335 | {0x3a29, 0x26}, |
336 | {0x3a2b, 0xba}, |
337 | {0x3a2e, 0xbf}, |
338 | {0x3a2f, 0x18}, |
339 | {0x3a31, 0xc1}, |
340 | {0x3a74, 0x84}, |
341 | {0x3a99, 0x84}, |
342 | {0x3ab9, 0xa6}, |
343 | {0x3aba, 0xba}, |
344 | {0x3b0a, 0x01}, |
345 | {0x3b0b, 0x00}, |
346 | {0x3b0e, 0x01}, |
347 | {0x3b0f, 0x00}, |
348 | {0x3b12, 0x84}, |
349 | {0x3b14, 0xbb}, |
350 | {0x3b15, 0xbf}, |
351 | {0x3b1b, 0xc9}, |
352 | {0x3b21, 0xc9}, |
353 | {0x3b3f, 0x9d}, |
354 | {0x3b45, 0x9d}, |
355 | {0x3c84, 0x00}, |
356 | {0x3d84, 0x04}, |
357 | {0x3d85, 0x8b}, |
358 | {0x3daa, 0x80}, |
359 | {0x3dab, 0x14}, |
360 | {0x3dac, 0x80}, |
361 | {0x3dad, 0xc8}, |
362 | {0x3dae, 0x81}, |
363 | {0x3daf, 0x7b}, |
364 | {0x3f00, 0x10}, |
365 | {0x3f01, 0x11}, |
366 | {0x3f06, 0x0d}, |
367 | {0x3f07, 0x0b}, |
368 | {0x3f08, 0x0d}, |
369 | {0x3f09, 0x0b}, |
370 | {0x3f0a, 0x01}, |
371 | {0x3f0b, 0x11}, |
372 | {0x3f0c, 0x33}, |
373 | {0x4001, 0x07}, |
374 | {0x4007, 0x20}, |
375 | {0x4008, 0x00}, |
376 | {0x4009, 0x05}, |
377 | {0x400a, 0x00}, |
378 | {0x400c, 0x00}, |
379 | {0x400e, 0x14}, |
380 | {0x4010, 0xf4}, |
381 | {0x4011, 0x03}, |
382 | {0x4012, 0x55}, |
383 | {0x4015, 0x00}, |
384 | {0x4017, 0x00}, |
385 | {0x4018, 0x0f}, |
386 | {0x4019, 0x00}, |
387 | {0x401a, 0x40}, |
388 | {0x401b, 0x08}, |
389 | {0x401c, 0x00}, |
390 | {0x401d, 0x10}, |
391 | {0x401e, 0x02}, |
392 | {0x401f, 0x00}, |
393 | {0x4020, 0x04}, |
394 | {0x4021, 0x00}, |
395 | {0x4022, 0x04}, |
396 | {0x4023, 0x00}, |
397 | {0x4024, 0x04}, |
398 | {0x4025, 0x00}, |
399 | {0x4026, 0x04}, |
400 | {0x4027, 0x00}, |
401 | {0x4030, 0x00}, |
402 | {0x4031, 0x00}, |
403 | {0x4032, 0x00}, |
404 | {0x4033, 0x00}, |
405 | {0x4034, 0x00}, |
406 | {0x4035, 0x00}, |
407 | {0x4036, 0x00}, |
408 | {0x4037, 0x00}, |
409 | {0x4040, 0x00}, |
410 | {0x4041, 0x80}, |
411 | {0x4042, 0x00}, |
412 | {0x4043, 0x80}, |
413 | {0x4044, 0x00}, |
414 | {0x4045, 0x80}, |
415 | {0x4046, 0x00}, |
416 | {0x4047, 0x80}, |
417 | {0x4050, 0x06}, |
418 | {0x4051, 0xff}, |
419 | {0x4052, 0xff}, |
420 | {0x4053, 0xff}, |
421 | {0x4054, 0xff}, |
422 | {0x4055, 0xff}, |
423 | {0x4056, 0xff}, |
424 | {0x4057, 0x7f}, |
425 | {0x4058, 0x00}, |
426 | {0x4059, 0x00}, |
427 | {0x405a, 0x00}, |
428 | {0x405b, 0x00}, |
429 | {0x405c, 0x07}, |
430 | {0x405d, 0xff}, |
431 | {0x405e, 0x07}, |
432 | {0x405f, 0xff}, |
433 | {0x4060, 0x00}, |
434 | {0x4061, 0x00}, |
435 | {0x4062, 0x00}, |
436 | {0x4063, 0x00}, |
437 | {0x4064, 0x00}, |
438 | {0x4065, 0x00}, |
439 | {0x4066, 0x00}, |
440 | {0x4067, 0x00}, |
441 | {0x4068, 0x00}, |
442 | {0x4069, 0x00}, |
443 | {0x406a, 0x00}, |
444 | {0x406b, 0x00}, |
445 | {0x406c, 0x00}, |
446 | {0x406d, 0x00}, |
447 | {0x406e, 0x00}, |
448 | {0x406f, 0x00}, |
449 | {0x4070, 0x00}, |
450 | {0x4071, 0x00}, |
451 | {0x4072, 0x00}, |
452 | {0x4073, 0x00}, |
453 | {0x4074, 0x00}, |
454 | {0x4075, 0x00}, |
455 | {0x4076, 0x00}, |
456 | {0x4077, 0x00}, |
457 | {0x4078, 0x00}, |
458 | {0x4079, 0x00}, |
459 | {0x407a, 0x00}, |
460 | {0x407b, 0x00}, |
461 | {0x407c, 0x00}, |
462 | {0x407d, 0x00}, |
463 | {0x407e, 0x00}, |
464 | {0x407f, 0x00}, |
465 | {0x4080, 0x78}, |
466 | {0x4081, 0x78}, |
467 | {0x4082, 0x78}, |
468 | {0x4083, 0x78}, |
469 | {0x40e0, 0x00}, |
470 | {0x40e1, 0x00}, |
471 | {0x40e2, 0x00}, |
472 | {0x40e3, 0x00}, |
473 | {0x40e4, 0x00}, |
474 | {0x40e5, 0x00}, |
475 | {0x40e6, 0x00}, |
476 | {0x40e7, 0x00}, |
477 | {0x40e8, 0x00}, |
478 | {0x40e9, 0x80}, |
479 | {0x40ea, 0x00}, |
480 | {0x40eb, 0x80}, |
481 | {0x40ec, 0x00}, |
482 | {0x40ed, 0x80}, |
483 | {0x40ee, 0x00}, |
484 | {0x40ef, 0x80}, |
485 | {0x40f0, 0x02}, |
486 | {0x40f1, 0x04}, |
487 | {0x4300, 0x00}, |
488 | {0x4301, 0x00}, |
489 | {0x4302, 0x00}, |
490 | {0x4303, 0x00}, |
491 | {0x4304, 0x00}, |
492 | {0x4305, 0x00}, |
493 | {0x4306, 0x00}, |
494 | {0x4307, 0x00}, |
495 | {0x4308, 0x00}, |
496 | {0x4309, 0x00}, |
497 | {0x430a, 0x00}, |
498 | {0x430b, 0xff}, |
499 | {0x430c, 0xff}, |
500 | {0x430d, 0x00}, |
501 | {0x430e, 0x00}, |
502 | {0x4315, 0x00}, |
503 | {0x4316, 0x00}, |
504 | {0x4317, 0x00}, |
505 | {0x4318, 0x00}, |
506 | {0x4319, 0x00}, |
507 | {0x431a, 0x00}, |
508 | {0x431b, 0x00}, |
509 | {0x431c, 0x00}, |
510 | {0x4500, 0x07}, |
511 | {0x4502, 0x00}, |
512 | {0x4503, 0x0f}, |
513 | {0x4504, 0x80}, |
514 | {0x4506, 0x01}, |
515 | {0x4509, 0x05}, |
516 | {0x450c, 0x00}, |
517 | {0x450d, 0x20}, |
518 | {0x450e, 0x00}, |
519 | {0x450f, 0x00}, |
520 | {0x4510, 0x00}, |
521 | {0x4523, 0x00}, |
522 | {0x4526, 0x00}, |
523 | {0x4543, 0x00}, |
524 | {0x4544, 0x00}, |
525 | {0x4545, 0x00}, |
526 | {0x4546, 0x00}, |
527 | {0x4547, 0x10}, |
528 | {0x4602, 0x00}, |
529 | {0x4603, 0x15}, |
530 | {0x460b, 0x07}, |
531 | {0x4680, 0x11}, |
532 | {0x4686, 0x00}, |
533 | {0x4687, 0x00}, |
534 | {0x4700, 0x00}, |
535 | {0x4800, 0x64}, |
536 | {0x4806, 0x40}, |
537 | {0x480b, 0x10}, |
538 | {0x480c, 0x80}, |
539 | {0x480f, 0x32}, |
540 | {0x4813, 0xe4}, |
541 | {0x4884, 0x04}, |
542 | {0x4c00, 0xf8}, |
543 | {0x4c01, 0x44}, |
544 | {0x4c03, 0x00}, |
545 | {0x4d00, 0x00}, |
546 | {0x4d01, 0x16}, |
547 | {0x4d04, 0x10}, |
548 | {0x4d05, 0x00}, |
549 | {0x4d06, 0x0c}, |
550 | {0x4d07, 0x00}, |
551 | {0x5008, 0xb0}, |
552 | {0x50c1, 0x00}, |
553 | {0x53c1, 0x00}, |
554 | {0x5f40, 0x00}, |
555 | {0x5f41, 0x40}, |
556 | }; |
557 | |
558 | static const struct ov08x40_reg_list ov08x40_global_setting = { |
559 | .num_of_regs = ARRAY_SIZE(ov08x40_global_regs), |
560 | .regs = ov08x40_global_regs, |
561 | }; |
562 | |
563 | static const struct ov08x40_reg mipi_data_rate_800mbps[] = { |
564 | {0x0103, 0x01}, |
565 | {0x1000, 0x00}, |
566 | {0x1601, 0xd0}, |
567 | {0x1001, 0x04}, |
568 | {0x5004, 0x53}, |
569 | {0x5110, 0x00}, |
570 | {0x5111, 0x14}, |
571 | {0x5112, 0x01}, |
572 | {0x5113, 0x7b}, |
573 | {0x5114, 0x00}, |
574 | {0x5152, 0xa3}, |
575 | {0x5a52, 0x1f}, |
576 | {0x5a1a, 0x0e}, |
577 | {0x5a1b, 0x10}, |
578 | {0x5a1f, 0x0e}, |
579 | {0x5a27, 0x0e}, |
580 | {0x6002, 0x2e}, |
581 | {0x0300, 0x3a}, /* PLL CTRL */ |
582 | {0x0301, 0xc8}, |
583 | {0x0302, 0x31}, |
584 | {0x0303, 0x03}, |
585 | {0x0304, 0x01}, |
586 | {0x0305, 0xa1}, |
587 | {0x0306, 0x04}, |
588 | {0x0307, 0x01}, |
589 | {0x0308, 0x03}, |
590 | {0x0309, 0x03}, |
591 | {0x0310, 0x0a}, |
592 | {0x0311, 0x02}, |
593 | {0x0312, 0x01}, |
594 | {0x0313, 0x08}, |
595 | {0x0314, 0x66}, |
596 | {0x0315, 0x00}, |
597 | {0x0316, 0x34}, |
598 | {0x0320, 0x02}, |
599 | {0x0321, 0x03}, |
600 | {0x0323, 0x05}, |
601 | {0x0324, 0x01}, |
602 | {0x0325, 0xb8}, |
603 | {0x0326, 0x4a}, |
604 | {0x0327, 0x04}, |
605 | {0x0329, 0x00}, |
606 | {0x032a, 0x05}, |
607 | {0x032b, 0x00}, |
608 | {0x032c, 0x00}, |
609 | {0x032d, 0x00}, |
610 | {0x032e, 0x02}, |
611 | {0x032f, 0xa0}, |
612 | {0x0350, 0x00}, |
613 | {0x0360, 0x01}, |
614 | {0x3012, 0x41}, /* MIPI SC Lanes */ |
615 | }; |
616 | |
617 | static const struct ov08x40_reg mipi_data_rate_1500mbps[] = { |
618 | {0x0103, 0x01}, |
619 | {0x1000, 0x00}, |
620 | {0x1601, 0xd0}, |
621 | {0x1001, 0x04}, |
622 | {0x5004, 0x53}, |
623 | {0x5110, 0x00}, |
624 | {0x5111, 0x14}, |
625 | {0x5112, 0x01}, |
626 | {0x5113, 0x7b}, |
627 | {0x5114, 0x00}, |
628 | {0x5152, 0xa3}, |
629 | {0x5a52, 0x1f}, |
630 | {0x5a1a, 0x0e}, |
631 | {0x5a1b, 0x10}, |
632 | {0x5a1f, 0x0e}, |
633 | {0x5a27, 0x0e}, |
634 | {0x6002, 0x2e}, |
635 | {0x0300, 0x3a}, /* PLL */ |
636 | {0x0301, 0x88}, |
637 | {0x0302, 0x31}, |
638 | {0x0303, 0x05}, |
639 | {0x0304, 0x01}, |
640 | {0x0305, 0x38}, |
641 | {0x0306, 0x04}, |
642 | {0x0307, 0x00}, |
643 | {0x0308, 0x03}, |
644 | {0x0309, 0x02}, |
645 | {0x0310, 0x0a}, |
646 | {0x0311, 0x02}, |
647 | {0x0312, 0x01}, |
648 | {0x0313, 0x08}, |
649 | {0x0314, 0x00}, |
650 | {0x0315, 0x00}, |
651 | {0x0316, 0x2c}, |
652 | {0x0320, 0x02}, |
653 | {0x0321, 0x03}, |
654 | {0x0323, 0x05}, |
655 | {0x0324, 0x01}, |
656 | {0x0325, 0xb8}, |
657 | {0x0326, 0x4a}, |
658 | {0x0327, 0x04}, |
659 | {0x0329, 0x00}, |
660 | {0x032a, 0x05}, |
661 | {0x032b, 0x00}, |
662 | {0x032c, 0x00}, |
663 | {0x032d, 0x00}, |
664 | {0x032e, 0x02}, |
665 | {0x032f, 0xa0}, |
666 | {0x0350, 0x00}, |
667 | {0x0360, 0x01}, |
668 | {0x3012, 0x21}, /* MIPI SC Lanes */ |
669 | }; |
670 | |
671 | static const struct ov08x40_reg mode_3856x2176_regs_800mbps[] = { |
672 | {0x5000, 0x5d}, |
673 | {0x5001, 0x20}, |
674 | {0x3012, 0x41}, |
675 | {0x3400, 0x1c}, |
676 | {0x3419, 0x13}, |
677 | {0x341a, 0x89}, |
678 | {0x3426, 0x00}, |
679 | {0x3501, 0x02}, |
680 | {0x3502, 0x00}, |
681 | {0x3508, 0x01}, |
682 | {0x3509, 0x00}, |
683 | {0x3541, 0x01}, |
684 | {0x3542, 0x00}, |
685 | {0x3548, 0x01}, |
686 | {0x3712, 0x51}, |
687 | {0x3714, 0x24}, |
688 | {0x3761, 0x17}, |
689 | {0x376e, 0x03}, |
690 | {0x37b0, 0x00}, |
691 | {0x37b1, 0xab}, |
692 | {0x37b3, 0x82}, |
693 | {0x37b4, 0x00}, |
694 | {0x37b5, 0xe4}, |
695 | {0x37b6, 0x01}, |
696 | {0x37b7, 0xee}, |
697 | {0x3820, 0x00}, |
698 | {0x3821, 0x04}, |
699 | {0x3823, 0x04}, |
700 | {0x384d, 0x80}, |
701 | {0x3894, 0x00}, |
702 | {0x400b, 0x08}, |
703 | {0x400d, 0x08}, |
704 | {0x4016, 0x2d}, |
705 | {0x4501, 0x00}, |
706 | {0x4542, 0x00}, |
707 | {0x4837, 0x14}, |
708 | {0x4850, 0x42}, |
709 | {0x3a20, 0x00}, |
710 | {0x3939, 0x9d}, |
711 | {0x3902, 0x0e}, |
712 | {0x3903, 0x0e}, |
713 | {0x3904, 0x0e}, |
714 | {0x3905, 0x0e}, |
715 | {0x3906, 0x07}, |
716 | {0x3907, 0x0d}, |
717 | {0x3908, 0x11}, |
718 | {0x3909, 0x12}, |
719 | {0x390c, 0x33}, |
720 | {0x390d, 0x66}, |
721 | {0x390e, 0xaa}, |
722 | {0x3915, 0x90}, |
723 | {0x3917, 0x90}, |
724 | {0x3440, 0xa4}, |
725 | {0x3a26, 0x1d}, |
726 | {0x3a2c, 0x4a}, |
727 | {0x3a32, 0x55}, |
728 | {0x392d, 0x02}, |
729 | {0x3930, 0x08}, |
730 | {0x3933, 0x0c}, |
731 | {0x392a, 0x54}, |
732 | {0x392b, 0xa8}, |
733 | {0x380d, 0x80}, |
734 | {0x380e, 0x13}, |
735 | {0x380f, 0x88}, |
736 | {0x3803, 0x70}, |
737 | {0x3807, 0x0f}, |
738 | {0x3808, 0x0f}, |
739 | {0x3809, 0x10}, |
740 | {0x380a, 0x08}, |
741 | {0x380b, 0x80}, |
742 | {0x3811, 0x08}, |
743 | {0x3813, 0x10}, |
744 | {0x3501, 0x10}, |
745 | {0x3508, 0x0f}, |
746 | {0x3509, 0x80}, |
747 | {0x3813, 0x0f}, |
748 | }; |
749 | |
750 | /* OV08X 1C 3856x2176_DPHY1500M-2L */ |
751 | static const struct ov08x40_reg mode_3856x2176_regs_1500mbps[] = { |
752 | {0x5000, 0x5d}, |
753 | {0x5001, 0x20}, |
754 | {0x3012, 0x21}, |
755 | {0x3400, 0x1c}, |
756 | {0x3419, 0x12}, |
757 | {0x341a, 0x99}, |
758 | {0x3426, 0x00}, |
759 | {0x3501, 0x02}, |
760 | {0x3502, 0x00}, |
761 | {0x3508, 0x01}, |
762 | {0x3509, 0x00}, |
763 | {0x3541, 0x01}, |
764 | {0x3542, 0x00}, |
765 | {0x3548, 0x01}, |
766 | {0x3712, 0x51}, |
767 | {0x3714, 0x24}, |
768 | {0x3761, 0x17}, |
769 | {0x376e, 0x03}, |
770 | {0x37b0, 0x00}, |
771 | {0x37b1, 0xab}, |
772 | {0x37b3, 0x82}, |
773 | {0x37b4, 0x00}, |
774 | {0x37b5, 0xe4}, |
775 | {0x37b6, 0x01}, |
776 | {0x37b7, 0xee}, |
777 | {0x3803, 0x70}, |
778 | {0x3807, 0x0f}, |
779 | {0x3808, 0x0f}, |
780 | {0x3809, 0x10}, |
781 | {0x380a, 0x08}, |
782 | {0x380b, 0x80}, |
783 | {0x380d, 0xa0}, |
784 | {0x380e, 0x12}, |
785 | {0x380f, 0x98}, |
786 | {0x3811, 0x08}, |
787 | {0x3813, 0x10}, |
788 | {0x3820, 0x00}, |
789 | {0x3821, 0x04}, |
790 | {0x3823, 0x04}, |
791 | {0x384d, 0xa0}, |
792 | {0x3894, 0x00}, |
793 | {0x400b, 0x08}, |
794 | {0x400d, 0x08}, |
795 | {0x4016, 0x2d}, |
796 | {0x4501, 0x00}, |
797 | {0x4542, 0x00}, |
798 | {0x4837, 0x0a}, |
799 | {0x4850, 0x47}, |
800 | {0x3a20, 0x00}, |
801 | {0x3939, 0x9d}, |
802 | {0x3902, 0x0e}, |
803 | {0x3903, 0x0e}, |
804 | {0x3904, 0x0e}, |
805 | {0x3905, 0x0e}, |
806 | {0x3906, 0x07}, |
807 | {0x3907, 0x0d}, |
808 | {0x3908, 0x11}, |
809 | {0x3909, 0x12}, |
810 | {0x390c, 0x33}, |
811 | {0x390d, 0x66}, |
812 | {0x390e, 0xaa}, |
813 | {0x3915, 0x90}, |
814 | {0x3917, 0x90}, |
815 | {0x3440, 0xa4}, |
816 | {0x3a26, 0x1d}, |
817 | {0x3a2c, 0x4a}, |
818 | {0x3a32, 0x55}, |
819 | {0x392d, 0x02}, |
820 | {0x3930, 0x08}, |
821 | {0x3933, 0x0c}, |
822 | {0x392a, 0x54}, |
823 | {0x392b, 0xa8}, |
824 | {0x3501, 0x10}, |
825 | {0x3508, 0x0f}, |
826 | {0x3509, 0x80}, |
827 | {0x3813, 0x0f}, |
828 | }; |
829 | |
830 | /* OV08X 4C1stg 1928x1088_DPHY1500M-2L 30fps */ |
831 | static const struct ov08x40_reg mode_1928x1088_regs_1500mbps[] = { |
832 | {0x5000, 0x55}, |
833 | {0x5001, 0x00}, |
834 | {0x3012, 0x21}, |
835 | {0x3400, 0x30}, |
836 | {0x3419, 0x08}, |
837 | {0x341a, 0x4f}, |
838 | {0x3426, 0x00}, |
839 | {0x3501, 0x02}, |
840 | {0x3502, 0x00}, |
841 | {0x3508, 0x01}, |
842 | {0x3509, 0x00}, |
843 | {0x3541, 0x01}, |
844 | {0x3542, 0x00}, |
845 | {0x3548, 0x01}, |
846 | {0x3712, 0x50}, |
847 | {0x3714, 0x21}, |
848 | {0x3761, 0x28}, |
849 | {0x376e, 0x07}, |
850 | {0x37b0, 0x01}, |
851 | {0x37b1, 0x0f}, |
852 | {0x37b3, 0xd6}, |
853 | {0x37b4, 0x01}, |
854 | {0x37b5, 0x48}, |
855 | {0x37b6, 0x02}, |
856 | {0x37b7, 0x40}, |
857 | {0x3803, 0x78}, |
858 | {0x3807, 0x07}, |
859 | {0x3808, 0x07}, |
860 | {0x3809, 0x88}, |
861 | {0x380a, 0x04}, |
862 | {0x380b, 0x40}, |
863 | {0x380d, 0xf0}, |
864 | {0x380e, 0x08}, |
865 | {0x380f, 0x4e}, |
866 | {0x3811, 0x04}, |
867 | {0x3813, 0x03}, |
868 | {0x3820, 0x02}, |
869 | {0x3821, 0x14}, |
870 | {0x3823, 0x84}, |
871 | {0x384d, 0xf0}, |
872 | {0x3894, 0x03}, |
873 | {0x400b, 0x04}, |
874 | {0x400d, 0x04}, |
875 | {0x4016, 0x27}, |
876 | {0x4501, 0x10}, |
877 | {0x4542, 0x01}, |
878 | {0x4837, 0x0a}, |
879 | {0x4850, 0x47}, |
880 | {0x4911, 0x00}, |
881 | {0x4919, 0x00}, |
882 | {0x491a, 0x40}, |
883 | {0x4920, 0x04}, |
884 | {0x4921, 0x00}, |
885 | {0x4922, 0x04}, |
886 | {0x4923, 0x00}, |
887 | {0x4924, 0x04}, |
888 | {0x4925, 0x00}, |
889 | {0x4926, 0x04}, |
890 | {0x4927, 0x00}, |
891 | {0x4930, 0x00}, |
892 | {0x4931, 0x00}, |
893 | {0x4932, 0x00}, |
894 | {0x4933, 0x00}, |
895 | {0x4934, 0x00}, |
896 | {0x4935, 0x00}, |
897 | {0x4936, 0x00}, |
898 | {0x4937, 0x00}, |
899 | {0x4940, 0x00}, |
900 | {0x4941, 0x80}, |
901 | {0x4942, 0x00}, |
902 | {0x4943, 0x80}, |
903 | {0x4944, 0x00}, |
904 | {0x4945, 0x80}, |
905 | {0x4946, 0x00}, |
906 | {0x4947, 0x80}, |
907 | {0x4960, 0x00}, |
908 | {0x4961, 0x00}, |
909 | {0x4962, 0x00}, |
910 | {0x4963, 0x00}, |
911 | {0x4964, 0x00}, |
912 | {0x4965, 0x00}, |
913 | {0x4966, 0x00}, |
914 | {0x4967, 0x00}, |
915 | {0x4968, 0x00}, |
916 | {0x4969, 0x00}, |
917 | {0x496a, 0x00}, |
918 | {0x496b, 0x00}, |
919 | {0x496c, 0x00}, |
920 | {0x496d, 0x00}, |
921 | {0x496e, 0x00}, |
922 | {0x496f, 0x00}, |
923 | {0x4970, 0x00}, |
924 | {0x4971, 0x00}, |
925 | {0x4972, 0x00}, |
926 | {0x4973, 0x00}, |
927 | {0x4974, 0x00}, |
928 | {0x4975, 0x00}, |
929 | {0x4976, 0x00}, |
930 | {0x4977, 0x00}, |
931 | {0x4978, 0x00}, |
932 | {0x4979, 0x00}, |
933 | {0x497a, 0x00}, |
934 | {0x497b, 0x00}, |
935 | {0x497c, 0x00}, |
936 | {0x497d, 0x00}, |
937 | {0x497e, 0x00}, |
938 | {0x497f, 0x00}, |
939 | {0x49e0, 0x00}, |
940 | {0x49e1, 0x00}, |
941 | {0x49e2, 0x00}, |
942 | {0x49e3, 0x00}, |
943 | {0x49e4, 0x00}, |
944 | {0x49e5, 0x00}, |
945 | {0x49e6, 0x00}, |
946 | {0x49e7, 0x00}, |
947 | {0x49e8, 0x00}, |
948 | {0x49e9, 0x80}, |
949 | {0x49ea, 0x00}, |
950 | {0x49eb, 0x80}, |
951 | {0x49ec, 0x00}, |
952 | {0x49ed, 0x80}, |
953 | {0x49ee, 0x00}, |
954 | {0x49ef, 0x80}, |
955 | {0x49f0, 0x02}, |
956 | {0x49f1, 0x04}, |
957 | {0x3a20, 0x05}, |
958 | {0x3939, 0x6b}, |
959 | {0x3902, 0x10}, |
960 | {0x3903, 0x10}, |
961 | {0x3904, 0x10}, |
962 | {0x3905, 0x10}, |
963 | {0x3906, 0x01}, |
964 | {0x3907, 0x0b}, |
965 | {0x3908, 0x10}, |
966 | {0x3909, 0x13}, |
967 | {0x390b, 0x11}, |
968 | {0x390c, 0x21}, |
969 | {0x390d, 0x32}, |
970 | {0x390e, 0x76}, |
971 | {0x3a1a, 0x1c}, |
972 | {0x3a26, 0x17}, |
973 | {0x3a2c, 0x50}, |
974 | {0x3a32, 0x4f}, |
975 | {0x3ace, 0x01}, |
976 | {0x3ad2, 0x01}, |
977 | {0x3ad6, 0x01}, |
978 | {0x3ada, 0x01}, |
979 | {0x3ade, 0x01}, |
980 | {0x3ae2, 0x01}, |
981 | {0x3aee, 0x01}, |
982 | {0x3af2, 0x01}, |
983 | {0x3af6, 0x01}, |
984 | {0x3afa, 0x01}, |
985 | {0x3afe, 0x01}, |
986 | {0x3b02, 0x01}, |
987 | {0x3b06, 0x01}, |
988 | {0x392d, 0x01}, |
989 | {0x3930, 0x09}, |
990 | {0x3933, 0x0d}, |
991 | {0x392a, 0x52}, |
992 | {0x392b, 0xa3}, |
993 | {0x340b, 0x1b}, |
994 | {0x3501, 0x01}, |
995 | {0x3508, 0x0f}, |
996 | {0x3509, 0x00}, |
997 | {0x3541, 0x00}, |
998 | {0x3542, 0x80}, |
999 | {0x3548, 0x0f}, |
1000 | {0x3813, 0x03}, |
1001 | }; |
1002 | |
1003 | static const struct ov08x40_reg mode_3856x2416_regs[] = { |
1004 | {0x5000, 0x5d}, |
1005 | {0x5001, 0x20}, |
1006 | {0x3012, 0x41}, |
1007 | {0x3400, 0x1c}, |
1008 | {0x3419, 0x13}, |
1009 | {0x341a, 0x89}, |
1010 | {0x3426, 0x00}, |
1011 | {0x3501, 0x02}, |
1012 | {0x3502, 0x00}, |
1013 | {0x3508, 0x01}, |
1014 | {0x3509, 0x00}, |
1015 | {0x3541, 0x01}, |
1016 | {0x3542, 0x00}, |
1017 | {0x3548, 0x01}, |
1018 | {0x3712, 0x51}, |
1019 | {0x3714, 0x24}, |
1020 | {0x3761, 0x17}, |
1021 | {0x376e, 0x03}, |
1022 | {0x37b0, 0x00}, |
1023 | {0x37b1, 0xab}, |
1024 | {0x37b3, 0x82}, |
1025 | {0x37b4, 0x00}, |
1026 | {0x37b5, 0xe4}, |
1027 | {0x37b6, 0x01}, |
1028 | {0x37b7, 0xee}, |
1029 | {0x3803, 0x00}, |
1030 | {0x3807, 0x7f}, |
1031 | {0x3808, 0x0f}, |
1032 | {0x3809, 0x10}, |
1033 | {0x380a, 0x09}, |
1034 | {0x380b, 0x70}, |
1035 | {0x380d, 0x80}, |
1036 | {0x380e, 0x13}, |
1037 | {0x380f, 0x88}, |
1038 | {0x3811, 0x08}, |
1039 | {0x3813, 0x07}, |
1040 | {0x3820, 0x00}, |
1041 | {0x3821, 0x04}, |
1042 | {0x3823, 0x04}, |
1043 | {0x384d, 0x80}, |
1044 | {0x3894, 0x00}, |
1045 | {0x400b, 0x08}, |
1046 | {0x400d, 0x08}, |
1047 | {0x4016, 0x2d}, |
1048 | {0x4501, 0x00}, |
1049 | {0x4542, 0x00}, |
1050 | {0x4837, 0x14}, |
1051 | {0x4850, 0x42}, |
1052 | {0x3a20, 0x00}, |
1053 | {0x3939, 0x9d}, |
1054 | {0x3902, 0x0e}, |
1055 | {0x3903, 0x0e}, |
1056 | {0x3904, 0x0e}, |
1057 | {0x3905, 0x0e}, |
1058 | {0x3906, 0x07}, |
1059 | {0x3907, 0x0d}, |
1060 | {0x3908, 0x11}, |
1061 | {0x3909, 0x12}, |
1062 | {0x390c, 0x33}, |
1063 | {0x390d, 0x66}, |
1064 | {0x390e, 0xaa}, |
1065 | {0x3915, 0x90}, |
1066 | {0x3917, 0x90}, |
1067 | {0x3440, 0xa4}, |
1068 | {0x3a26, 0x1d}, |
1069 | {0x3a2c, 0x4a}, |
1070 | {0x3a32, 0x55}, |
1071 | {0x392d, 0x02}, |
1072 | {0x3930, 0x08}, |
1073 | {0x3933, 0x0c}, |
1074 | {0x392a, 0x54}, |
1075 | {0x392b, 0xa8}, |
1076 | {0x3501, 0x10}, |
1077 | {0x3508, 0x0f}, |
1078 | {0x3509, 0x80}, |
1079 | }; |
1080 | |
1081 | static const struct ov08x40_reg mode_1928x1208_regs[] = { |
1082 | {0x5000, 0x55}, |
1083 | {0x5001, 0x00}, |
1084 | {0x3012, 0x41}, |
1085 | {0x3400, 0x1c}, |
1086 | {0x3419, 0x08}, |
1087 | {0x341a, 0xaf}, |
1088 | {0x3426, 0x00}, |
1089 | {0x3501, 0x02}, |
1090 | {0x3502, 0x00}, |
1091 | {0x3508, 0x01}, |
1092 | {0x3509, 0x00}, |
1093 | {0x3541, 0x01}, |
1094 | {0x3542, 0x00}, |
1095 | {0x3548, 0x01}, |
1096 | {0x3712, 0x50}, |
1097 | {0x3714, 0x21}, |
1098 | {0x3761, 0x28}, |
1099 | {0x376e, 0x07}, |
1100 | {0x37b0, 0x01}, |
1101 | {0x37b1, 0x0f}, |
1102 | {0x37b3, 0xd6}, |
1103 | {0x37b4, 0x01}, |
1104 | {0x37b5, 0x48}, |
1105 | {0x37b6, 0x02}, |
1106 | {0x37b7, 0x40}, |
1107 | {0x3803, 0x00}, |
1108 | {0x3807, 0x7f}, |
1109 | {0x3808, 0x07}, |
1110 | {0x3809, 0x88}, |
1111 | {0x380a, 0x04}, |
1112 | {0x380b, 0xb8}, |
1113 | {0x380d, 0xd0}, |
1114 | {0x380e, 0x11}, |
1115 | {0x380f, 0x5c}, |
1116 | {0x3811, 0x04}, |
1117 | {0x3813, 0x03}, |
1118 | {0x3820, 0x02}, |
1119 | {0x3821, 0x14}, |
1120 | {0x3823, 0x04}, |
1121 | {0x384d, 0xd0}, |
1122 | {0x3894, 0x00}, |
1123 | {0x400b, 0x04}, |
1124 | {0x400d, 0x04}, |
1125 | {0x4016, 0x27}, |
1126 | {0x4501, 0x10}, |
1127 | {0x4542, 0x00}, |
1128 | {0x4837, 0x14}, |
1129 | {0x4850, 0x42}, |
1130 | {0x3a20, 0x05}, |
1131 | {0x3939, 0x6b}, |
1132 | {0x3902, 0x10}, |
1133 | {0x3903, 0x10}, |
1134 | {0x3904, 0x10}, |
1135 | {0x3905, 0x10}, |
1136 | {0x3906, 0x01}, |
1137 | {0x3907, 0x0b}, |
1138 | {0x3908, 0x10}, |
1139 | {0x3909, 0x13}, |
1140 | {0x390b, 0x11}, |
1141 | {0x390c, 0x21}, |
1142 | {0x390d, 0x32}, |
1143 | {0x390e, 0x76}, |
1144 | {0x3a1a, 0x1c}, |
1145 | {0x3a26, 0x17}, |
1146 | {0x3a2c, 0x50}, |
1147 | {0x3a32, 0x4f}, |
1148 | {0x3ace, 0x01}, |
1149 | {0x3ad2, 0x01}, |
1150 | {0x3ad6, 0x01}, |
1151 | {0x3ada, 0x01}, |
1152 | {0x3ade, 0x01}, |
1153 | {0x3ae2, 0x01}, |
1154 | {0x3aee, 0x01}, |
1155 | {0x3af2, 0x01}, |
1156 | {0x3af6, 0x01}, |
1157 | {0x3afa, 0x01}, |
1158 | {0x3afe, 0x01}, |
1159 | {0x3b02, 0x01}, |
1160 | {0x3b06, 0x01}, |
1161 | {0x392d, 0x01}, |
1162 | {0x3930, 0x09}, |
1163 | {0x3933, 0x0d}, |
1164 | {0x392a, 0x52}, |
1165 | {0x392b, 0xa3}, |
1166 | {0x340b, 0x1b}, |
1167 | {0x3501, 0x08}, |
1168 | {0x3508, 0x04}, |
1169 | {0x3509, 0x00}, |
1170 | }; |
1171 | |
1172 | static const char * const ov08x40_test_pattern_menu[] = { |
1173 | "Disabled", |
1174 | "Vertical Color Bar Type 1", |
1175 | "Vertical Color Bar Type 2", |
1176 | "Vertical Color Bar Type 3", |
1177 | "Vertical Color Bar Type 4" |
1178 | }; |
1179 | |
1180 | /* Configurations for supported link frequencies */ |
1181 | #define OV08X40_LINK_FREQ_400MHZ 400000000ULL |
1182 | #define OV08X40_LINK_FREQ_749MHZ 749000000ULL |
1183 | #define OV08X40_SCLK_96MHZ 96000000ULL |
1184 | #define OV08X40_XVCLK 19200000 |
1185 | #define OV08X40_DATA_LANES 4 |
1186 | |
1187 | /* |
1188 | * pixel_rate = link_freq * data-rate * nr_of_lanes / bits_per_sample |
1189 | * data rate => double data rate; number of lanes => 4; bits per pixel => 10 |
1190 | */ |
1191 | static u64 link_freq_to_pixel_rate(u64 f) |
1192 | { |
1193 | f *= 2 * OV08X40_DATA_LANES; |
1194 | do_div(f, 10); |
1195 | |
1196 | return f; |
1197 | } |
1198 | |
1199 | /* Menu items for LINK_FREQ V4L2 control */ |
1200 | static const s64 link_freq_menu_items[] = { |
1201 | OV08X40_LINK_FREQ_400MHZ, |
1202 | OV08X40_LINK_FREQ_749MHZ, |
1203 | }; |
1204 | |
1205 | /* Link frequency configs */ |
1206 | static const struct ov08x40_link_freq_config link_freq_configs[] = { |
1207 | [OV08X40_LINK_FREQ_400MHZ_INDEX] = { |
1208 | .reg_list = { |
1209 | .num_of_regs = ARRAY_SIZE(mipi_data_rate_800mbps), |
1210 | .regs = mipi_data_rate_800mbps, |
1211 | } |
1212 | }, |
1213 | [OV08X40_LINK_FREQ_749MHZ_INDEX] = { |
1214 | .reg_list = { |
1215 | .num_of_regs = ARRAY_SIZE(mipi_data_rate_1500mbps), |
1216 | .regs = mipi_data_rate_1500mbps, |
1217 | } |
1218 | }, |
1219 | }; |
1220 | |
1221 | /* Mode configs */ |
1222 | static const struct ov08x40_mode supported_modes[] = { |
1223 | { |
1224 | .width = 3856, |
1225 | .height = 2416, |
1226 | .vts_def = OV08X40_VTS_30FPS, |
1227 | .vts_min = OV08X40_VTS_30FPS, |
1228 | .llp = 0x10aa, /* in normal mode, tline time = 2 * HTS / SCLK */ |
1229 | .lanes = 4, |
1230 | .reg_list = { |
1231 | .num_of_regs = ARRAY_SIZE(mode_3856x2416_regs), |
1232 | .regs = mode_3856x2416_regs, |
1233 | }, |
1234 | .link_freq_index = OV08X40_LINK_FREQ_400MHZ_INDEX, |
1235 | .exposure_shift = 1, |
1236 | .exposure_margin = OV08X40_EXPOSURE_MAX_MARGIN, |
1237 | }, |
1238 | { |
1239 | .width = 3856, |
1240 | .height = 2176, |
1241 | .vts_def = OV08X40_VTS_30FPS, |
1242 | .vts_min = OV08X40_VTS_30FPS, |
1243 | .llp = 0x10aa, /* in normal mode, tline time = 2 * HTS / SCLK */ |
1244 | .lanes = 4, |
1245 | .reg_list = { |
1246 | .num_of_regs = ARRAY_SIZE(mode_3856x2176_regs_800mbps), |
1247 | .regs = mode_3856x2176_regs_800mbps, |
1248 | }, |
1249 | .link_freq_index = OV08X40_LINK_FREQ_400MHZ_INDEX, |
1250 | .exposure_shift = 1, |
1251 | .exposure_margin = OV08X40_EXPOSURE_MAX_MARGIN, |
1252 | }, |
1253 | |
1254 | { |
1255 | .width = 1928, |
1256 | .height = 1208, |
1257 | .vts_def = OV08X40_VTS_BIN_30FPS, |
1258 | .vts_min = OV08X40_VTS_BIN_30FPS, |
1259 | .llp = 0x960, |
1260 | .lanes = 4, |
1261 | .reg_list = { |
1262 | .num_of_regs = ARRAY_SIZE(mode_1928x1208_regs), |
1263 | .regs = mode_1928x1208_regs, |
1264 | }, |
1265 | .link_freq_index = OV08X40_LINK_FREQ_400MHZ_INDEX, |
1266 | .exposure_shift = 0, |
1267 | .exposure_margin = OV08X40_EXPOSURE_BIN_MAX_MARGIN, |
1268 | }, |
1269 | { |
1270 | .width = 3856, |
1271 | .height = 2176, |
1272 | .vts_def = OV08X40_VTS_30FPS, |
1273 | .vts_min = OV08X40_VTS_30FPS, |
1274 | .llp = 0x10aa, /* in normal mode, tline time = 2 * HTS / SCLK */ |
1275 | .lanes = 2, |
1276 | .reg_list = { |
1277 | .num_of_regs = ARRAY_SIZE(mode_3856x2176_regs_1500mbps), |
1278 | .regs = mode_3856x2176_regs_1500mbps, |
1279 | }, |
1280 | .link_freq_index = OV08X40_LINK_FREQ_749MHZ_INDEX, |
1281 | .exposure_shift = 1, |
1282 | .exposure_margin = OV08X40_EXPOSURE_MAX_MARGIN, |
1283 | }, |
1284 | { |
1285 | .width = 1928, |
1286 | .height = 1088, |
1287 | .vts_def = OV08X40_VTS_BIN_30FPS, |
1288 | .vts_min = OV08X40_VTS_BIN_30FPS, |
1289 | .llp = 0x960, |
1290 | .lanes = 2, |
1291 | .reg_list = { |
1292 | .num_of_regs = ARRAY_SIZE(mode_1928x1088_regs_1500mbps), |
1293 | .regs = mode_1928x1088_regs_1500mbps, |
1294 | }, |
1295 | .link_freq_index = OV08X40_LINK_FREQ_749MHZ_INDEX, |
1296 | .exposure_shift = 0, |
1297 | .exposure_margin = OV08X40_EXPOSURE_MAX_MARGIN, |
1298 | }, |
1299 | }; |
1300 | |
1301 | static const char * const ov08x40_supply_names[] = { |
1302 | "dovdd", /* Digital I/O power */ |
1303 | "avdd", /* Analog power */ |
1304 | "dvdd", /* Digital core power */ |
1305 | }; |
1306 | |
1307 | struct ov08x40 { |
1308 | struct v4l2_subdev sd; |
1309 | struct media_pad pad; |
1310 | |
1311 | struct v4l2_ctrl_handler ctrl_handler; |
1312 | /* V4L2 Controls */ |
1313 | struct v4l2_ctrl *link_freq; |
1314 | struct v4l2_ctrl *pixel_rate; |
1315 | struct v4l2_ctrl *vblank; |
1316 | struct v4l2_ctrl *hblank; |
1317 | struct v4l2_ctrl *exposure; |
1318 | |
1319 | struct clk *xvclk; |
1320 | struct gpio_desc *reset_gpio; |
1321 | struct regulator_bulk_data supplies[ARRAY_SIZE(ov08x40_supply_names)]; |
1322 | |
1323 | /* Current mode */ |
1324 | const struct ov08x40_mode *cur_mode; |
1325 | |
1326 | /* Mutex for serialized access */ |
1327 | struct mutex mutex; |
1328 | |
1329 | /* data lanes */ |
1330 | u8 mipi_lanes; |
1331 | |
1332 | /* True if the device has been identified */ |
1333 | bool identified; |
1334 | |
1335 | unsigned long link_freq_bitmap; |
1336 | }; |
1337 | |
1338 | #define to_ov08x40(_sd) container_of(_sd, struct ov08x40, sd) |
1339 | |
1340 | static int ov08x40_power_on(struct device *dev) |
1341 | { |
1342 | struct v4l2_subdev *sd = dev_get_drvdata(dev); |
1343 | struct ov08x40 *ov08x = to_ov08x40(sd); |
1344 | int ret; |
1345 | |
1346 | ret = clk_prepare_enable(clk: ov08x->xvclk); |
1347 | if (ret < 0) { |
1348 | dev_err(dev, "failed to enable xvclk\n"); |
1349 | return ret; |
1350 | } |
1351 | |
1352 | if (ov08x->reset_gpio) { |
1353 | gpiod_set_value_cansleep(desc: ov08x->reset_gpio, value: 1); |
1354 | usleep_range(min: 1000, max: 2000); |
1355 | } |
1356 | |
1357 | ret = regulator_bulk_enable(ARRAY_SIZE(ov08x40_supply_names), |
1358 | consumers: ov08x->supplies); |
1359 | if (ret < 0) { |
1360 | dev_err(dev, "failed to enable regulators\n"); |
1361 | goto disable_clk; |
1362 | } |
1363 | |
1364 | gpiod_set_value_cansleep(desc: ov08x->reset_gpio, value: 0); |
1365 | usleep_range(min: 5000, max: 5500); |
1366 | |
1367 | return 0; |
1368 | |
1369 | disable_clk: |
1370 | gpiod_set_value_cansleep(desc: ov08x->reset_gpio, value: 1); |
1371 | clk_disable_unprepare(clk: ov08x->xvclk); |
1372 | |
1373 | return ret; |
1374 | } |
1375 | |
1376 | static int ov08x40_power_off(struct device *dev) |
1377 | { |
1378 | struct v4l2_subdev *sd = dev_get_drvdata(dev); |
1379 | struct ov08x40 *ov08x = to_ov08x40(sd); |
1380 | |
1381 | gpiod_set_value_cansleep(desc: ov08x->reset_gpio, value: 1); |
1382 | regulator_bulk_disable(ARRAY_SIZE(ov08x40_supply_names), |
1383 | consumers: ov08x->supplies); |
1384 | clk_disable_unprepare(clk: ov08x->xvclk); |
1385 | |
1386 | return 0; |
1387 | } |
1388 | |
1389 | /* Read registers up to 4 at a time */ |
1390 | static int ov08x40_read_reg(struct ov08x40 *ov08x, |
1391 | u16 reg, u32 len, u32 *val) |
1392 | { |
1393 | struct i2c_client *client = v4l2_get_subdevdata(sd: &ov08x->sd); |
1394 | struct i2c_msg msgs[2]; |
1395 | u8 *data_be_p; |
1396 | int ret; |
1397 | __be32 data_be = 0; |
1398 | __be16 reg_addr_be = cpu_to_be16(reg); |
1399 | |
1400 | if (len > 4) |
1401 | return -EINVAL; |
1402 | |
1403 | data_be_p = (u8 *)&data_be; |
1404 | /* Write register address */ |
1405 | msgs[0].addr = client->addr; |
1406 | msgs[0].flags = 0; |
1407 | msgs[0].len = 2; |
1408 | msgs[0].buf = (u8 *)®_addr_be; |
1409 | |
1410 | /* Read data from register */ |
1411 | msgs[1].addr = client->addr; |
1412 | msgs[1].flags = I2C_M_RD; |
1413 | msgs[1].len = len; |
1414 | msgs[1].buf = &data_be_p[4 - len]; |
1415 | |
1416 | ret = i2c_transfer(adap: client->adapter, msgs, ARRAY_SIZE(msgs)); |
1417 | if (ret != ARRAY_SIZE(msgs)) |
1418 | return ret < 0 ? ret : -EIO; |
1419 | |
1420 | *val = be32_to_cpu(data_be); |
1421 | |
1422 | return 0; |
1423 | } |
1424 | |
1425 | static int __ov08x40_burst_fill_regs(struct i2c_client *client, u16 first_reg, |
1426 | u16 last_reg, size_t num_regs, u8 val) |
1427 | { |
1428 | struct i2c_msg msgs; |
1429 | size_t i; |
1430 | int ret; |
1431 | |
1432 | msgs.addr = client->addr; |
1433 | msgs.flags = 0; |
1434 | msgs.len = 2 + num_regs; |
1435 | msgs.buf = kmalloc(msgs.len, GFP_KERNEL); |
1436 | |
1437 | if (!msgs.buf) |
1438 | return -ENOMEM; |
1439 | |
1440 | put_unaligned_be16(val: first_reg, p: msgs.buf); |
1441 | |
1442 | for (i = 0; i < num_regs; ++i) |
1443 | msgs.buf[2 + i] = val; |
1444 | |
1445 | ret = i2c_transfer(adap: client->adapter, msgs: &msgs, num: 1); |
1446 | |
1447 | kfree(objp: msgs.buf); |
1448 | |
1449 | if (ret != 1) { |
1450 | dev_err(&client->dev, "Failed regs transferred: %d\n", ret); |
1451 | return -EIO; |
1452 | } |
1453 | |
1454 | return 0; |
1455 | } |
1456 | |
1457 | static int ov08x40_burst_fill_regs(struct ov08x40 *ov08x, u16 first_reg, |
1458 | u16 last_reg, u8 val) |
1459 | { |
1460 | struct i2c_client *client = v4l2_get_subdevdata(sd: &ov08x->sd); |
1461 | size_t num_regs, num_write_regs; |
1462 | int ret; |
1463 | |
1464 | num_regs = last_reg - first_reg + 1; |
1465 | num_write_regs = num_regs; |
1466 | |
1467 | if (client->adapter->quirks && client->adapter->quirks->max_write_len) |
1468 | num_write_regs = client->adapter->quirks->max_write_len - 2; |
1469 | |
1470 | while (first_reg < last_reg) { |
1471 | ret = __ov08x40_burst_fill_regs(client, first_reg, last_reg, |
1472 | num_regs: num_write_regs, val); |
1473 | if (ret) |
1474 | return ret; |
1475 | |
1476 | first_reg += num_write_regs; |
1477 | } |
1478 | |
1479 | return 0; |
1480 | } |
1481 | |
1482 | /* Write registers up to 4 at a time */ |
1483 | static int ov08x40_write_reg(struct ov08x40 *ov08x, |
1484 | u16 reg, u32 len, u32 __val) |
1485 | { |
1486 | struct i2c_client *client = v4l2_get_subdevdata(sd: &ov08x->sd); |
1487 | int buf_i, val_i, ret; |
1488 | u8 buf[6], *val_p; |
1489 | __be32 val; |
1490 | |
1491 | if (len > 4) |
1492 | return -EINVAL; |
1493 | |
1494 | buf[0] = reg >> 8; |
1495 | buf[1] = reg & 0xff; |
1496 | |
1497 | val = cpu_to_be32(__val); |
1498 | val_p = (u8 *)&val; |
1499 | buf_i = 2; |
1500 | val_i = 4 - len; |
1501 | |
1502 | while (val_i < 4) |
1503 | buf[buf_i++] = val_p[val_i++]; |
1504 | |
1505 | ret = i2c_master_send(client, buf, count: len + 2); |
1506 | if (ret != len + 2) |
1507 | return ret < 0 ? ret : -EIO; |
1508 | |
1509 | return 0; |
1510 | } |
1511 | |
1512 | /* Write a list of registers */ |
1513 | static int ov08x40_write_regs(struct ov08x40 *ov08x, |
1514 | const struct ov08x40_reg *regs, u32 len) |
1515 | { |
1516 | struct i2c_client *client = v4l2_get_subdevdata(sd: &ov08x->sd); |
1517 | int ret; |
1518 | u32 i; |
1519 | |
1520 | for (i = 0; i < len; i++) { |
1521 | ret = ov08x40_write_reg(ov08x, reg: regs[i].address, len: 1, |
1522 | val: regs[i].val); |
1523 | |
1524 | if (ret) { |
1525 | dev_err_ratelimited(&client->dev, |
1526 | "Failed to write reg 0x%4.4x. error = %d\n", |
1527 | regs[i].address, ret); |
1528 | |
1529 | return ret; |
1530 | } |
1531 | } |
1532 | |
1533 | return 0; |
1534 | } |
1535 | |
1536 | static int ov08x40_write_reg_list(struct ov08x40 *ov08x, |
1537 | const struct ov08x40_reg_list *r_list) |
1538 | { |
1539 | return ov08x40_write_regs(ov08x, regs: r_list->regs, len: r_list->num_of_regs); |
1540 | } |
1541 | |
1542 | static int ov08x40_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) |
1543 | { |
1544 | const struct ov08x40_mode *default_mode = &supported_modes[0]; |
1545 | struct ov08x40 *ov08x = to_ov08x40(sd); |
1546 | struct v4l2_mbus_framefmt *try_fmt = |
1547 | v4l2_subdev_state_get_format(fh->state, 0); |
1548 | |
1549 | mutex_lock(&ov08x->mutex); |
1550 | |
1551 | /* Initialize try_fmt */ |
1552 | try_fmt->width = default_mode->width; |
1553 | try_fmt->height = default_mode->height; |
1554 | try_fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; |
1555 | try_fmt->field = V4L2_FIELD_NONE; |
1556 | |
1557 | /* No crop or compose */ |
1558 | mutex_unlock(lock: &ov08x->mutex); |
1559 | |
1560 | return 0; |
1561 | } |
1562 | |
1563 | static int ov08x40_update_digital_gain(struct ov08x40 *ov08x, u32 d_gain) |
1564 | { |
1565 | int ret; |
1566 | u32 val; |
1567 | |
1568 | /* |
1569 | * 0x350C[1:0], 0x350B[7:0], 0x350A[4:0] |
1570 | */ |
1571 | |
1572 | val = (d_gain & OV08X40_DGTL_GAIN_L_MASK) << OV08X40_DGTL_GAIN_L_SHIFT; |
1573 | ret = ov08x40_write_reg(ov08x, OV08X40_REG_DGTL_GAIN_L, |
1574 | OV08X40_REG_VALUE_08BIT, val: val); |
1575 | if (ret) |
1576 | return ret; |
1577 | |
1578 | val = (d_gain >> OV08X40_DGTL_GAIN_M_SHIFT) & OV08X40_DGTL_GAIN_M_MASK; |
1579 | ret = ov08x40_write_reg(ov08x, OV08X40_REG_DGTL_GAIN_M, |
1580 | OV08X40_REG_VALUE_08BIT, val: val); |
1581 | if (ret) |
1582 | return ret; |
1583 | |
1584 | val = (d_gain >> OV08X40_DGTL_GAIN_H_SHIFT) & OV08X40_DGTL_GAIN_H_MASK; |
1585 | |
1586 | return ov08x40_write_reg(ov08x, OV08X40_REG_DGTL_GAIN_H, |
1587 | OV08X40_REG_VALUE_08BIT, val: val); |
1588 | } |
1589 | |
1590 | static int ov08x40_enable_test_pattern(struct ov08x40 *ov08x, u32 pattern) |
1591 | { |
1592 | int ret; |
1593 | u32 val; |
1594 | |
1595 | ret = ov08x40_read_reg(ov08x, OV08X40_REG_TEST_PATTERN, |
1596 | OV08X40_REG_VALUE_08BIT, val: &val); |
1597 | if (ret) |
1598 | return ret; |
1599 | |
1600 | if (pattern) { |
1601 | ret = ov08x40_read_reg(ov08x, OV08X40_REG_ISP, |
1602 | OV08X40_REG_VALUE_08BIT, val: &val); |
1603 | if (ret) |
1604 | return ret; |
1605 | |
1606 | ret = ov08x40_write_reg(ov08x, OV08X40_REG_ISP, |
1607 | OV08X40_REG_VALUE_08BIT, |
1608 | val: val | BIT(1)); |
1609 | if (ret) |
1610 | return ret; |
1611 | |
1612 | ret = ov08x40_read_reg(ov08x, OV08X40_REG_SHORT_TEST_PATTERN, |
1613 | OV08X40_REG_VALUE_08BIT, val: &val); |
1614 | if (ret) |
1615 | return ret; |
1616 | |
1617 | ret = ov08x40_write_reg(ov08x, OV08X40_REG_SHORT_TEST_PATTERN, |
1618 | OV08X40_REG_VALUE_08BIT, |
1619 | val: val | BIT(0)); |
1620 | if (ret) |
1621 | return ret; |
1622 | |
1623 | ret = ov08x40_read_reg(ov08x, OV08X40_REG_TEST_PATTERN, |
1624 | OV08X40_REG_VALUE_08BIT, val: &val); |
1625 | if (ret) |
1626 | return ret; |
1627 | |
1628 | val &= OV08X40_TEST_PATTERN_MASK; |
1629 | val |= ((pattern - 1) << OV08X40_TEST_PATTERN_BAR_SHIFT) | |
1630 | OV08X40_TEST_PATTERN_ENABLE; |
1631 | } else { |
1632 | val &= ~OV08X40_TEST_PATTERN_ENABLE; |
1633 | } |
1634 | |
1635 | return ov08x40_write_reg(ov08x, OV08X40_REG_TEST_PATTERN, |
1636 | OV08X40_REG_VALUE_08BIT, val: val); |
1637 | } |
1638 | |
1639 | static int ov08x40_set_ctrl_hflip(struct ov08x40 *ov08x, u32 ctrl_val) |
1640 | { |
1641 | int ret; |
1642 | u32 val; |
1643 | |
1644 | ret = ov08x40_read_reg(ov08x, OV08X40_REG_MIRROR, |
1645 | OV08X40_REG_VALUE_08BIT, val: &val); |
1646 | if (ret) |
1647 | return ret; |
1648 | |
1649 | return ov08x40_write_reg(ov08x, OV08X40_REG_MIRROR, |
1650 | OV08X40_REG_VALUE_08BIT, |
1651 | val: ctrl_val ? val | BIT(2) : val & ~BIT(2)); |
1652 | } |
1653 | |
1654 | static int ov08x40_set_ctrl_vflip(struct ov08x40 *ov08x, u32 ctrl_val) |
1655 | { |
1656 | int ret; |
1657 | u32 val; |
1658 | |
1659 | ret = ov08x40_read_reg(ov08x, OV08X40_REG_VFLIP, |
1660 | OV08X40_REG_VALUE_08BIT, val: &val); |
1661 | if (ret) |
1662 | return ret; |
1663 | |
1664 | return ov08x40_write_reg(ov08x, OV08X40_REG_VFLIP, |
1665 | OV08X40_REG_VALUE_08BIT, |
1666 | val: ctrl_val ? val | BIT(2) : val & ~BIT(2)); |
1667 | } |
1668 | |
1669 | static int ov08x40_set_ctrl(struct v4l2_ctrl *ctrl) |
1670 | { |
1671 | struct ov08x40 *ov08x = container_of(ctrl->handler, |
1672 | struct ov08x40, ctrl_handler); |
1673 | struct i2c_client *client = v4l2_get_subdevdata(sd: &ov08x->sd); |
1674 | s64 max; |
1675 | int exp; |
1676 | int fll; |
1677 | int ret = 0; |
1678 | |
1679 | /* Propagate change of current control to all related controls */ |
1680 | switch (ctrl->id) { |
1681 | case V4L2_CID_VBLANK: |
1682 | /* Update max exposure while meeting expected vblanking */ |
1683 | /* |
1684 | * because in normal mode, 1 HTS = 0.5 tline |
1685 | * fps = sclk / hts / vts |
1686 | * so the vts value needs to be double |
1687 | */ |
1688 | max = ((ov08x->cur_mode->height + ctrl->val) << |
1689 | ov08x->cur_mode->exposure_shift) - |
1690 | ov08x->cur_mode->exposure_margin; |
1691 | |
1692 | __v4l2_ctrl_modify_range(ctrl: ov08x->exposure, |
1693 | min: ov08x->exposure->minimum, |
1694 | max, step: ov08x->exposure->step, def: max); |
1695 | break; |
1696 | } |
1697 | |
1698 | /* |
1699 | * Applying V4L2 control value only happens |
1700 | * when power is up for streaming |
1701 | */ |
1702 | if (!pm_runtime_get_if_in_use(dev: &client->dev)) |
1703 | return 0; |
1704 | |
1705 | switch (ctrl->id) { |
1706 | case V4L2_CID_ANALOGUE_GAIN: |
1707 | ret = ov08x40_write_reg(ov08x, OV08X40_REG_ANALOG_GAIN, |
1708 | OV08X40_REG_VALUE_16BIT, |
1709 | val: ctrl->val << 1); |
1710 | break; |
1711 | case V4L2_CID_DIGITAL_GAIN: |
1712 | ret = ov08x40_update_digital_gain(ov08x, d_gain: ctrl->val); |
1713 | break; |
1714 | case V4L2_CID_EXPOSURE: |
1715 | exp = (ctrl->val << ov08x->cur_mode->exposure_shift) - |
1716 | ov08x->cur_mode->exposure_margin; |
1717 | |
1718 | ret = ov08x40_write_reg(ov08x, OV08X40_REG_EXPOSURE, |
1719 | OV08X40_REG_VALUE_24BIT, |
1720 | val: exp); |
1721 | break; |
1722 | case V4L2_CID_VBLANK: |
1723 | fll = ((ov08x->cur_mode->height + ctrl->val) << |
1724 | ov08x->cur_mode->exposure_shift); |
1725 | |
1726 | ret = ov08x40_write_reg(ov08x, OV08X40_REG_VTS, |
1727 | OV08X40_REG_VALUE_16BIT, |
1728 | val: fll); |
1729 | break; |
1730 | case V4L2_CID_TEST_PATTERN: |
1731 | ret = ov08x40_enable_test_pattern(ov08x, pattern: ctrl->val); |
1732 | break; |
1733 | case V4L2_CID_HFLIP: |
1734 | ov08x40_set_ctrl_hflip(ov08x, ctrl_val: ctrl->val); |
1735 | break; |
1736 | case V4L2_CID_VFLIP: |
1737 | ov08x40_set_ctrl_vflip(ov08x, ctrl_val: ctrl->val); |
1738 | break; |
1739 | default: |
1740 | dev_info(&client->dev, |
1741 | "ctrl(id:0x%x,val:0x%x) is not handled\n", |
1742 | ctrl->id, ctrl->val); |
1743 | break; |
1744 | } |
1745 | |
1746 | pm_runtime_put(dev: &client->dev); |
1747 | |
1748 | return ret; |
1749 | } |
1750 | |
1751 | static bool filter_by_mipi_lanes(const void *array, size_t index, |
1752 | const void *context) |
1753 | { |
1754 | const struct ov08x40_mode *mode = array; |
1755 | const struct ov08x40 *ov08x = context; |
1756 | |
1757 | return mode->lanes == ov08x->mipi_lanes; |
1758 | } |
1759 | |
1760 | static const struct v4l2_ctrl_ops ov08x40_ctrl_ops = { |
1761 | .s_ctrl = ov08x40_set_ctrl, |
1762 | }; |
1763 | |
1764 | static int ov08x40_enum_mbus_code(struct v4l2_subdev *sd, |
1765 | struct v4l2_subdev_state *sd_state, |
1766 | struct v4l2_subdev_mbus_code_enum *code) |
1767 | { |
1768 | /* Only one bayer order(GRBG) is supported */ |
1769 | if (code->index > 0) |
1770 | return -EINVAL; |
1771 | |
1772 | code->code = MEDIA_BUS_FMT_SGRBG10_1X10; |
1773 | |
1774 | return 0; |
1775 | } |
1776 | |
1777 | static int ov08x40_enum_frame_size(struct v4l2_subdev *sd, |
1778 | struct v4l2_subdev_state *sd_state, |
1779 | struct v4l2_subdev_frame_size_enum *fse) |
1780 | { |
1781 | struct ov08x40 *ov08x = to_ov08x40(sd); |
1782 | size_t i, count = 0; |
1783 | |
1784 | if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10) |
1785 | return -EINVAL; |
1786 | |
1787 | for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { |
1788 | if (!filter_by_mipi_lanes(array: &supported_modes[i], index: i, context: ov08x)) |
1789 | continue; |
1790 | |
1791 | if (count == fse->index) { |
1792 | fse->min_width = supported_modes[i].width; |
1793 | fse->max_width = fse->min_width; |
1794 | fse->min_height = supported_modes[i].height; |
1795 | fse->max_height = fse->min_height; |
1796 | return 0; |
1797 | } |
1798 | |
1799 | count++; |
1800 | } |
1801 | |
1802 | return -EINVAL; |
1803 | } |
1804 | |
1805 | static void ov08x40_update_pad_format(const struct ov08x40_mode *mode, |
1806 | struct v4l2_subdev_format *fmt) |
1807 | { |
1808 | fmt->format.width = mode->width; |
1809 | fmt->format.height = mode->height; |
1810 | fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10; |
1811 | fmt->format.field = V4L2_FIELD_NONE; |
1812 | } |
1813 | |
1814 | static int ov08x40_do_get_pad_format(struct ov08x40 *ov08x, |
1815 | struct v4l2_subdev_state *sd_state, |
1816 | struct v4l2_subdev_format *fmt) |
1817 | { |
1818 | struct v4l2_mbus_framefmt *framefmt; |
1819 | |
1820 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { |
1821 | framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); |
1822 | fmt->format = *framefmt; |
1823 | } else { |
1824 | ov08x40_update_pad_format(mode: ov08x->cur_mode, fmt); |
1825 | } |
1826 | |
1827 | return 0; |
1828 | } |
1829 | |
1830 | static int ov08x40_get_pad_format(struct v4l2_subdev *sd, |
1831 | struct v4l2_subdev_state *sd_state, |
1832 | struct v4l2_subdev_format *fmt) |
1833 | { |
1834 | struct ov08x40 *ov08x = to_ov08x40(sd); |
1835 | int ret; |
1836 | |
1837 | mutex_lock(&ov08x->mutex); |
1838 | ret = ov08x40_do_get_pad_format(ov08x, sd_state, fmt); |
1839 | mutex_unlock(lock: &ov08x->mutex); |
1840 | |
1841 | return ret; |
1842 | } |
1843 | |
1844 | static int |
1845 | ov08x40_set_pad_format(struct v4l2_subdev *sd, |
1846 | struct v4l2_subdev_state *sd_state, |
1847 | struct v4l2_subdev_format *fmt) |
1848 | { |
1849 | struct ov08x40 *ov08x = to_ov08x40(sd); |
1850 | const struct ov08x40_mode *mode; |
1851 | struct v4l2_mbus_framefmt *framefmt; |
1852 | s32 vblank_def; |
1853 | s32 vblank_min; |
1854 | s64 h_blank; |
1855 | s64 pixel_rate; |
1856 | s64 link_freq; |
1857 | u64 steps; |
1858 | |
1859 | mutex_lock(&ov08x->mutex); |
1860 | |
1861 | /* Only one raw bayer(GRBG) order is supported */ |
1862 | if (fmt->format.code != MEDIA_BUS_FMT_SGRBG10_1X10) |
1863 | fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10; |
1864 | |
1865 | mode = v4l2_find_nearest_size_conditional(supported_modes, |
1866 | ARRAY_SIZE(supported_modes), |
1867 | width, height, |
1868 | fmt->format.width, |
1869 | fmt->format.height, |
1870 | filter_by_mipi_lanes, |
1871 | ov08x); |
1872 | ov08x40_update_pad_format(mode, fmt); |
1873 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { |
1874 | framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); |
1875 | *framefmt = fmt->format; |
1876 | } else { |
1877 | ov08x->cur_mode = mode; |
1878 | __v4l2_ctrl_s_ctrl(ctrl: ov08x->link_freq, val: mode->link_freq_index); |
1879 | link_freq = link_freq_menu_items[mode->link_freq_index]; |
1880 | pixel_rate = link_freq_to_pixel_rate(f: link_freq); |
1881 | __v4l2_ctrl_s_ctrl_int64(ctrl: ov08x->pixel_rate, val: pixel_rate); |
1882 | |
1883 | /* Update limits and set FPS to default */ |
1884 | vblank_def = ov08x->cur_mode->vts_def - |
1885 | ov08x->cur_mode->height; |
1886 | vblank_min = ov08x->cur_mode->vts_min - |
1887 | ov08x->cur_mode->height; |
1888 | |
1889 | /* |
1890 | * The frame length line should be aligned to a multiple of 4, |
1891 | * as provided by the sensor vendor, in normal mode. |
1892 | */ |
1893 | steps = mode->exposure_shift == 1 ? 4 : 1; |
1894 | |
1895 | __v4l2_ctrl_modify_range(ctrl: ov08x->vblank, min: vblank_min, |
1896 | OV08X40_VTS_MAX |
1897 | - ov08x->cur_mode->height, |
1898 | step: steps, |
1899 | def: vblank_def); |
1900 | __v4l2_ctrl_s_ctrl(ctrl: ov08x->vblank, val: vblank_def); |
1901 | |
1902 | h_blank = ov08x->cur_mode->llp - ov08x->cur_mode->width; |
1903 | |
1904 | __v4l2_ctrl_modify_range(ctrl: ov08x->hblank, min: h_blank, |
1905 | max: h_blank, step: 1, def: h_blank); |
1906 | } |
1907 | |
1908 | mutex_unlock(lock: &ov08x->mutex); |
1909 | |
1910 | return 0; |
1911 | } |
1912 | |
1913 | static int ov08x40_start_streaming(struct ov08x40 *ov08x) |
1914 | { |
1915 | struct i2c_client *client = v4l2_get_subdevdata(sd: &ov08x->sd); |
1916 | const struct ov08x40_reg_list *reg_list; |
1917 | int ret, link_freq_index; |
1918 | |
1919 | /* Get out of from software reset */ |
1920 | ret = ov08x40_write_reg(ov08x, OV08X40_REG_SOFTWARE_RST, |
1921 | OV08X40_REG_VALUE_08BIT, OV08X40_SOFTWARE_RST); |
1922 | if (ret) { |
1923 | dev_err(&client->dev, "%s failed to set powerup registers\n", |
1924 | __func__); |
1925 | return ret; |
1926 | } |
1927 | |
1928 | link_freq_index = ov08x->cur_mode->link_freq_index; |
1929 | reg_list = &link_freq_configs[link_freq_index].reg_list; |
1930 | |
1931 | ret = ov08x40_write_reg_list(ov08x, r_list: reg_list); |
1932 | if (ret) { |
1933 | dev_err(&client->dev, "%s failed to set plls\n", __func__); |
1934 | return ret; |
1935 | } |
1936 | |
1937 | reg_list = &ov08x40_global_setting; |
1938 | ret = ov08x40_write_reg_list(ov08x, r_list: reg_list); |
1939 | if (ret) { |
1940 | dev_err(&client->dev, "%s failed to set global setting\n", |
1941 | __func__); |
1942 | return ret; |
1943 | } |
1944 | |
1945 | /* Apply default values of current mode */ |
1946 | reg_list = &ov08x->cur_mode->reg_list; |
1947 | ret = ov08x40_write_reg_list(ov08x, r_list: reg_list); |
1948 | if (ret) { |
1949 | dev_err(&client->dev, "%s failed to set mode\n", __func__); |
1950 | return ret; |
1951 | } |
1952 | |
1953 | /* Use i2c burst to write register on full size registers */ |
1954 | if (ov08x->cur_mode->exposure_shift == 1) { |
1955 | ret = ov08x40_burst_fill_regs(ov08x, OV08X40_REG_XTALK_FIRST_A, |
1956 | OV08X40_REG_XTALK_LAST_A, val: 0x75); |
1957 | if (ret == 0) |
1958 | ret = ov08x40_burst_fill_regs(ov08x, |
1959 | OV08X40_REG_XTALK_FIRST_B, |
1960 | OV08X40_REG_XTALK_LAST_B, |
1961 | val: 0x75); |
1962 | } |
1963 | |
1964 | if (ret) { |
1965 | dev_err(&client->dev, "%s failed to set regs\n", __func__); |
1966 | return ret; |
1967 | } |
1968 | |
1969 | /* Apply customized values from user */ |
1970 | ret = __v4l2_ctrl_handler_setup(hdl: ov08x->sd.ctrl_handler); |
1971 | if (ret) |
1972 | return ret; |
1973 | |
1974 | return ov08x40_write_reg(ov08x, OV08X40_REG_MODE_SELECT, |
1975 | OV08X40_REG_VALUE_08BIT, |
1976 | OV08X40_MODE_STREAMING); |
1977 | } |
1978 | |
1979 | /* Stop streaming */ |
1980 | static int ov08x40_stop_streaming(struct ov08x40 *ov08x) |
1981 | { |
1982 | return ov08x40_write_reg(ov08x, OV08X40_REG_MODE_SELECT, |
1983 | OV08X40_REG_VALUE_08BIT, OV08X40_MODE_STANDBY); |
1984 | } |
1985 | |
1986 | /* Verify chip ID */ |
1987 | static int ov08x40_identify_module(struct ov08x40 *ov08x) |
1988 | { |
1989 | struct i2c_client *client = v4l2_get_subdevdata(sd: &ov08x->sd); |
1990 | int ret; |
1991 | u32 val; |
1992 | |
1993 | if (ov08x->identified) |
1994 | return 0; |
1995 | |
1996 | ret = ov08x40_read_reg(ov08x, OV08X40_REG_CHIP_ID, |
1997 | OV08X40_REG_VALUE_24BIT, val: &val); |
1998 | if (ret) { |
1999 | dev_err(&client->dev, "error reading chip-id register: %d\n", ret); |
2000 | return ret; |
2001 | } |
2002 | |
2003 | if (val != OV08X40_CHIP_ID) { |
2004 | dev_err(&client->dev, "chip id mismatch: %x!=%x\n", |
2005 | OV08X40_CHIP_ID, val); |
2006 | return -ENXIO; |
2007 | } |
2008 | |
2009 | dev_dbg(&client->dev, "chip id 0x%x\n", val); |
2010 | ov08x->identified = true; |
2011 | |
2012 | return 0; |
2013 | } |
2014 | |
2015 | static int ov08x40_set_stream(struct v4l2_subdev *sd, int enable) |
2016 | { |
2017 | struct ov08x40 *ov08x = to_ov08x40(sd); |
2018 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
2019 | int ret = 0; |
2020 | |
2021 | mutex_lock(&ov08x->mutex); |
2022 | |
2023 | if (enable) { |
2024 | ret = pm_runtime_resume_and_get(dev: &client->dev); |
2025 | if (ret < 0) |
2026 | goto err_unlock; |
2027 | |
2028 | ret = ov08x40_identify_module(ov08x); |
2029 | if (ret) |
2030 | goto err_rpm_put; |
2031 | |
2032 | /* |
2033 | * Apply default & customized values |
2034 | * and then start streaming. |
2035 | */ |
2036 | ret = ov08x40_start_streaming(ov08x); |
2037 | if (ret) |
2038 | goto err_rpm_put; |
2039 | } else { |
2040 | ov08x40_stop_streaming(ov08x); |
2041 | pm_runtime_put(dev: &client->dev); |
2042 | } |
2043 | |
2044 | mutex_unlock(lock: &ov08x->mutex); |
2045 | |
2046 | return ret; |
2047 | |
2048 | err_rpm_put: |
2049 | pm_runtime_put(dev: &client->dev); |
2050 | err_unlock: |
2051 | mutex_unlock(lock: &ov08x->mutex); |
2052 | |
2053 | return ret; |
2054 | } |
2055 | |
2056 | static const struct v4l2_subdev_video_ops ov08x40_video_ops = { |
2057 | .s_stream = ov08x40_set_stream, |
2058 | }; |
2059 | |
2060 | static const struct v4l2_subdev_pad_ops ov08x40_pad_ops = { |
2061 | .enum_mbus_code = ov08x40_enum_mbus_code, |
2062 | .get_fmt = ov08x40_get_pad_format, |
2063 | .set_fmt = ov08x40_set_pad_format, |
2064 | .enum_frame_size = ov08x40_enum_frame_size, |
2065 | }; |
2066 | |
2067 | static const struct v4l2_subdev_ops ov08x40_subdev_ops = { |
2068 | .video = &ov08x40_video_ops, |
2069 | .pad = &ov08x40_pad_ops, |
2070 | }; |
2071 | |
2072 | static const struct media_entity_operations ov08x40_subdev_entity_ops = { |
2073 | .link_validate = v4l2_subdev_link_validate, |
2074 | }; |
2075 | |
2076 | static const struct v4l2_subdev_internal_ops ov08x40_internal_ops = { |
2077 | .open = ov08x40_open, |
2078 | }; |
2079 | |
2080 | static int ov08x40_init_controls(struct ov08x40 *ov08x) |
2081 | { |
2082 | struct i2c_client *client = v4l2_get_subdevdata(sd: &ov08x->sd); |
2083 | struct v4l2_fwnode_device_properties props; |
2084 | struct v4l2_ctrl_handler *ctrl_hdlr; |
2085 | s64 exposure_max; |
2086 | s64 vblank_def; |
2087 | s64 vblank_min; |
2088 | s64 hblank; |
2089 | s64 pixel_rate_min; |
2090 | s64 pixel_rate_max; |
2091 | const struct ov08x40_mode *mode; |
2092 | int ret; |
2093 | |
2094 | ctrl_hdlr = &ov08x->ctrl_handler; |
2095 | ret = v4l2_ctrl_handler_init(ctrl_hdlr, 10); |
2096 | if (ret) |
2097 | return ret; |
2098 | |
2099 | mutex_init(&ov08x->mutex); |
2100 | ctrl_hdlr->lock = &ov08x->mutex; |
2101 | ov08x->link_freq = v4l2_ctrl_new_int_menu(hdl: ctrl_hdlr, |
2102 | ops: &ov08x40_ctrl_ops, |
2103 | V4L2_CID_LINK_FREQ, |
2104 | max: __fls(word: ov08x->link_freq_bitmap), |
2105 | __ffs(ov08x->link_freq_bitmap), |
2106 | qmenu_int: link_freq_menu_items); |
2107 | if (ov08x->link_freq) |
2108 | ov08x->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; |
2109 | |
2110 | pixel_rate_max = link_freq_to_pixel_rate(f: link_freq_menu_items[0]); |
2111 | pixel_rate_min = 0; |
2112 | /* By default, PIXEL_RATE is read only */ |
2113 | ov08x->pixel_rate = v4l2_ctrl_new_std(hdl: ctrl_hdlr, ops: &ov08x40_ctrl_ops, |
2114 | V4L2_CID_PIXEL_RATE, |
2115 | min: pixel_rate_min, max: pixel_rate_max, |
2116 | step: 1, def: pixel_rate_max); |
2117 | |
2118 | mode = ov08x->cur_mode; |
2119 | vblank_def = mode->vts_def - mode->height; |
2120 | vblank_min = mode->vts_min - mode->height; |
2121 | ov08x->vblank = v4l2_ctrl_new_std(hdl: ctrl_hdlr, ops: &ov08x40_ctrl_ops, |
2122 | V4L2_CID_VBLANK, |
2123 | min: vblank_min, |
2124 | OV08X40_VTS_MAX - mode->height, step: 1, |
2125 | def: vblank_def); |
2126 | |
2127 | hblank = ov08x->cur_mode->llp - ov08x->cur_mode->width; |
2128 | |
2129 | ov08x->hblank = v4l2_ctrl_new_std(hdl: ctrl_hdlr, ops: &ov08x40_ctrl_ops, |
2130 | V4L2_CID_HBLANK, |
2131 | min: hblank, max: hblank, step: 1, def: hblank); |
2132 | if (ov08x->hblank) |
2133 | ov08x->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; |
2134 | |
2135 | exposure_max = mode->vts_def - OV08X40_EXPOSURE_MAX_MARGIN; |
2136 | ov08x->exposure = v4l2_ctrl_new_std(hdl: ctrl_hdlr, ops: &ov08x40_ctrl_ops, |
2137 | V4L2_CID_EXPOSURE, |
2138 | OV08X40_EXPOSURE_MIN, |
2139 | max: exposure_max, OV08X40_EXPOSURE_STEP, |
2140 | def: exposure_max); |
2141 | |
2142 | v4l2_ctrl_new_std(hdl: ctrl_hdlr, ops: &ov08x40_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, |
2143 | OV08X40_ANA_GAIN_MIN, OV08X40_ANA_GAIN_MAX, |
2144 | OV08X40_ANA_GAIN_STEP, OV08X40_ANA_GAIN_DEFAULT); |
2145 | |
2146 | /* Digital gain */ |
2147 | v4l2_ctrl_new_std(hdl: ctrl_hdlr, ops: &ov08x40_ctrl_ops, V4L2_CID_DIGITAL_GAIN, |
2148 | OV08X40_DGTL_GAIN_MIN, OV08X40_DGTL_GAIN_MAX, |
2149 | OV08X40_DGTL_GAIN_STEP, OV08X40_DGTL_GAIN_DEFAULT); |
2150 | |
2151 | v4l2_ctrl_new_std_menu_items(hdl: ctrl_hdlr, ops: &ov08x40_ctrl_ops, |
2152 | V4L2_CID_TEST_PATTERN, |
2153 | ARRAY_SIZE(ov08x40_test_pattern_menu) - 1, |
2154 | mask: 0, def: 0, qmenu: ov08x40_test_pattern_menu); |
2155 | |
2156 | v4l2_ctrl_new_std(hdl: ctrl_hdlr, ops: &ov08x40_ctrl_ops, |
2157 | V4L2_CID_HFLIP, min: 0, max: 1, step: 1, def: 0); |
2158 | v4l2_ctrl_new_std(hdl: ctrl_hdlr, ops: &ov08x40_ctrl_ops, |
2159 | V4L2_CID_VFLIP, min: 0, max: 1, step: 1, def: 0); |
2160 | |
2161 | if (ctrl_hdlr->error) { |
2162 | ret = ctrl_hdlr->error; |
2163 | dev_err(&client->dev, "%s control init failed (%d)\n", |
2164 | __func__, ret); |
2165 | goto error; |
2166 | } |
2167 | |
2168 | ret = v4l2_fwnode_device_parse(dev: &client->dev, props: &props); |
2169 | if (ret) |
2170 | goto error; |
2171 | |
2172 | ret = v4l2_ctrl_new_fwnode_properties(hdl: ctrl_hdlr, ctrl_ops: &ov08x40_ctrl_ops, |
2173 | p: &props); |
2174 | if (ret) |
2175 | goto error; |
2176 | |
2177 | ov08x->sd.ctrl_handler = ctrl_hdlr; |
2178 | |
2179 | return 0; |
2180 | |
2181 | error: |
2182 | v4l2_ctrl_handler_free(hdl: ctrl_hdlr); |
2183 | mutex_destroy(lock: &ov08x->mutex); |
2184 | |
2185 | return ret; |
2186 | } |
2187 | |
2188 | static void ov08x40_free_controls(struct ov08x40 *ov08x) |
2189 | { |
2190 | v4l2_ctrl_handler_free(hdl: ov08x->sd.ctrl_handler); |
2191 | mutex_destroy(lock: &ov08x->mutex); |
2192 | } |
2193 | |
2194 | static int ov08x40_check_hwcfg(struct ov08x40 *ov08x, struct device *dev) |
2195 | { |
2196 | struct v4l2_fwnode_endpoint bus_cfg = { |
2197 | .bus_type = V4L2_MBUS_CSI2_DPHY |
2198 | }; |
2199 | struct fwnode_handle *ep; |
2200 | struct fwnode_handle *fwnode = dev_fwnode(dev); |
2201 | unsigned int i; |
2202 | int ret; |
2203 | u32 xvclk_rate; |
2204 | |
2205 | /* |
2206 | * Sometimes the fwnode graph is initialized by the bridge driver. |
2207 | * Bridge drivers doing this also add sensor properties, wait for this. |
2208 | */ |
2209 | ep = fwnode_graph_get_next_endpoint(fwnode, NULL); |
2210 | if (!ep) |
2211 | return dev_err_probe(dev, err: -EPROBE_DEFER, |
2212 | fmt: "waiting for fwnode graph endpoint\n"); |
2213 | |
2214 | ret = v4l2_fwnode_endpoint_alloc_parse(fwnode: ep, vep: &bus_cfg); |
2215 | fwnode_handle_put(fwnode: ep); |
2216 | if (ret) |
2217 | return dev_err_probe(dev, err: ret, fmt: "parsing endpoint failed\n"); |
2218 | |
2219 | ov08x->reset_gpio = devm_gpiod_get_optional(dev, con_id: "reset", |
2220 | flags: GPIOD_OUT_HIGH); |
2221 | if (IS_ERR(ptr: ov08x->reset_gpio)) { |
2222 | ret = dev_err_probe(dev, err: PTR_ERR(ptr: ov08x->reset_gpio), |
2223 | fmt: "getting reset GPIO\n"); |
2224 | goto out_err; |
2225 | } |
2226 | |
2227 | for (i = 0; i < ARRAY_SIZE(ov08x40_supply_names); i++) |
2228 | ov08x->supplies[i].supply = ov08x40_supply_names[i]; |
2229 | |
2230 | ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ov08x40_supply_names), |
2231 | consumers: ov08x->supplies); |
2232 | if (ret) |
2233 | goto out_err; |
2234 | |
2235 | ov08x->xvclk = devm_clk_get_optional(dev, NULL); |
2236 | if (IS_ERR(ptr: ov08x->xvclk)) { |
2237 | ret = dev_err_probe(dev, err: PTR_ERR(ptr: ov08x->xvclk), |
2238 | fmt: "getting xvclk\n"); |
2239 | goto out_err; |
2240 | } |
2241 | if (ov08x->xvclk) { |
2242 | xvclk_rate = clk_get_rate(clk: ov08x->xvclk); |
2243 | } else { |
2244 | ret = fwnode_property_read_u32(dev_fwnode(dev), propname: "clock-frequency", |
2245 | val: &xvclk_rate); |
2246 | if (ret) { |
2247 | dev_err(dev, "can't get clock frequency\n"); |
2248 | goto out_err; |
2249 | } |
2250 | } |
2251 | |
2252 | if (xvclk_rate != OV08X40_XVCLK) { |
2253 | dev_err(dev, "external clock %d is not supported\n", |
2254 | xvclk_rate); |
2255 | ret = -EINVAL; |
2256 | goto out_err; |
2257 | } |
2258 | |
2259 | switch (bus_cfg.bus.mipi_csi2.num_data_lanes) { |
2260 | case 2: |
2261 | case 4: |
2262 | ov08x->mipi_lanes = bus_cfg.bus.mipi_csi2.num_data_lanes; |
2263 | break; |
2264 | default: |
2265 | dev_err(dev, "number of CSI2 data lanes %d is not supported\n", |
2266 | bus_cfg.bus.mipi_csi2.num_data_lanes); |
2267 | ret = -EINVAL; |
2268 | goto out_err; |
2269 | } |
2270 | |
2271 | if (!bus_cfg.nr_of_link_frequencies) { |
2272 | dev_err(dev, "no link frequencies defined\n"); |
2273 | ret = -EINVAL; |
2274 | goto out_err; |
2275 | } |
2276 | ret = v4l2_link_freq_to_bitmap(dev, fw_link_freqs: bus_cfg.link_frequencies, |
2277 | num_of_fw_link_freqs: bus_cfg.nr_of_link_frequencies, |
2278 | driver_link_freqs: link_freq_menu_items, |
2279 | ARRAY_SIZE(link_freq_menu_items), |
2280 | bitmap: &ov08x->link_freq_bitmap); |
2281 | |
2282 | out_err: |
2283 | v4l2_fwnode_endpoint_free(vep: &bus_cfg); |
2284 | |
2285 | return ret; |
2286 | } |
2287 | |
2288 | static int ov08x40_probe(struct i2c_client *client) |
2289 | { struct ov08x40 *ov08x; |
2290 | int ret; |
2291 | bool full_power; |
2292 | |
2293 | ov08x = devm_kzalloc(dev: &client->dev, size: sizeof(*ov08x), GFP_KERNEL); |
2294 | if (!ov08x) |
2295 | return -ENOMEM; |
2296 | |
2297 | /* Check HW config */ |
2298 | ret = ov08x40_check_hwcfg(ov08x, dev: &client->dev); |
2299 | if (ret) |
2300 | return ret; |
2301 | |
2302 | /* Initialize subdev */ |
2303 | v4l2_i2c_subdev_init(sd: &ov08x->sd, client, ops: &ov08x40_subdev_ops); |
2304 | |
2305 | full_power = acpi_dev_state_d0(dev: &client->dev); |
2306 | if (full_power) { |
2307 | ret = ov08x40_power_on(dev: &client->dev); |
2308 | if (ret) { |
2309 | dev_err(&client->dev, "failed to power on\n"); |
2310 | return ret; |
2311 | } |
2312 | |
2313 | /* Check module identity */ |
2314 | ret = ov08x40_identify_module(ov08x); |
2315 | if (ret) |
2316 | goto probe_power_off; |
2317 | } |
2318 | |
2319 | /* Set default mode to max resolution */ |
2320 | ov08x->cur_mode = &supported_modes[0]; |
2321 | |
2322 | ret = ov08x40_init_controls(ov08x); |
2323 | if (ret) |
2324 | goto probe_power_off; |
2325 | |
2326 | /* Initialize subdev */ |
2327 | ov08x->sd.internal_ops = &ov08x40_internal_ops; |
2328 | ov08x->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; |
2329 | ov08x->sd.entity.ops = &ov08x40_subdev_entity_ops; |
2330 | ov08x->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; |
2331 | |
2332 | /* Initialize source pad */ |
2333 | ov08x->pad.flags = MEDIA_PAD_FL_SOURCE; |
2334 | ret = media_entity_pads_init(entity: &ov08x->sd.entity, num_pads: 1, pads: &ov08x->pad); |
2335 | if (ret) { |
2336 | dev_err(&client->dev, "%s failed:%d\n", __func__, ret); |
2337 | goto error_handler_free; |
2338 | } |
2339 | |
2340 | ret = v4l2_async_register_subdev_sensor(sd: &ov08x->sd); |
2341 | if (ret < 0) |
2342 | goto error_media_entity; |
2343 | |
2344 | if (full_power) |
2345 | pm_runtime_set_active(dev: &client->dev); |
2346 | pm_runtime_enable(dev: &client->dev); |
2347 | pm_runtime_idle(dev: &client->dev); |
2348 | |
2349 | return 0; |
2350 | |
2351 | error_media_entity: |
2352 | media_entity_cleanup(entity: &ov08x->sd.entity); |
2353 | |
2354 | error_handler_free: |
2355 | ov08x40_free_controls(ov08x); |
2356 | |
2357 | probe_power_off: |
2358 | ov08x40_power_off(dev: &client->dev); |
2359 | |
2360 | return ret; |
2361 | } |
2362 | |
2363 | static void ov08x40_remove(struct i2c_client *client) |
2364 | { |
2365 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
2366 | struct ov08x40 *ov08x = to_ov08x40(sd); |
2367 | |
2368 | v4l2_async_unregister_subdev(sd); |
2369 | media_entity_cleanup(entity: &sd->entity); |
2370 | ov08x40_free_controls(ov08x); |
2371 | |
2372 | pm_runtime_disable(dev: &client->dev); |
2373 | if (!pm_runtime_status_suspended(dev: &client->dev)) |
2374 | ov08x40_power_off(dev: &client->dev); |
2375 | pm_runtime_set_suspended(dev: &client->dev); |
2376 | } |
2377 | |
2378 | static DEFINE_RUNTIME_DEV_PM_OPS(ov08x40_pm_ops, ov08x40_power_off, |
2379 | ov08x40_power_on, NULL); |
2380 | |
2381 | #ifdef CONFIG_ACPI |
2382 | static const struct acpi_device_id ov08x40_acpi_ids[] = { |
2383 | {"OVTI08F4"}, |
2384 | { /* sentinel */ } |
2385 | }; |
2386 | |
2387 | MODULE_DEVICE_TABLE(acpi, ov08x40_acpi_ids); |
2388 | #endif |
2389 | |
2390 | static const struct of_device_id ov08x40_of_match[] = { |
2391 | { .compatible = "ovti,ov08x40"}, |
2392 | { /* sentinel */ } |
2393 | }; |
2394 | MODULE_DEVICE_TABLE(of, ov08x40_of_match); |
2395 | |
2396 | static struct i2c_driver ov08x40_i2c_driver = { |
2397 | .driver = { |
2398 | .name = "ov08x40", |
2399 | .acpi_match_table = ACPI_PTR(ov08x40_acpi_ids), |
2400 | .of_match_table = ov08x40_of_match, |
2401 | .pm = pm_sleep_ptr(&ov08x40_pm_ops), |
2402 | }, |
2403 | .probe = ov08x40_probe, |
2404 | .remove = ov08x40_remove, |
2405 | .flags = I2C_DRV_ACPI_WAIVE_D0_PROBE, |
2406 | }; |
2407 | |
2408 | module_i2c_driver(ov08x40_i2c_driver); |
2409 | |
2410 | MODULE_AUTHOR("Jason Chen <jason.z.chen@intel.com>"); |
2411 | MODULE_AUTHOR("Qingwu Zhang <qingwu.zhang@intel.com>"); |
2412 | MODULE_AUTHOR("Shawn Tu"); |
2413 | MODULE_DESCRIPTION("OmniVision OV08X40 sensor driver"); |
2414 | MODULE_LICENSE("GPL"); |
2415 |
Definitions
- ov08x40_reg
- ov08x40_reg_list
- ov08x40_link_freq_config
- ov08x40_mode
- ov08x40_global_regs
- ov08x40_global_setting
- mipi_data_rate_800mbps
- mipi_data_rate_1500mbps
- mode_3856x2176_regs_800mbps
- mode_3856x2176_regs_1500mbps
- mode_1928x1088_regs_1500mbps
- mode_3856x2416_regs
- mode_1928x1208_regs
- ov08x40_test_pattern_menu
- link_freq_to_pixel_rate
- link_freq_menu_items
- link_freq_configs
- supported_modes
- ov08x40_supply_names
- ov08x40
- ov08x40_power_on
- ov08x40_power_off
- ov08x40_read_reg
- __ov08x40_burst_fill_regs
- ov08x40_burst_fill_regs
- ov08x40_write_reg
- ov08x40_write_regs
- ov08x40_write_reg_list
- ov08x40_open
- ov08x40_update_digital_gain
- ov08x40_enable_test_pattern
- ov08x40_set_ctrl_hflip
- ov08x40_set_ctrl_vflip
- ov08x40_set_ctrl
- filter_by_mipi_lanes
- ov08x40_ctrl_ops
- ov08x40_enum_mbus_code
- ov08x40_enum_frame_size
- ov08x40_update_pad_format
- ov08x40_do_get_pad_format
- ov08x40_get_pad_format
- ov08x40_set_pad_format
- ov08x40_start_streaming
- ov08x40_stop_streaming
- ov08x40_identify_module
- ov08x40_set_stream
- ov08x40_video_ops
- ov08x40_pad_ops
- ov08x40_subdev_ops
- ov08x40_subdev_entity_ops
- ov08x40_internal_ops
- ov08x40_init_controls
- ov08x40_free_controls
- ov08x40_check_hwcfg
- ov08x40_probe
- ov08x40_remove
- ov08x40_pm_ops
- ov08x40_acpi_ids
- ov08x40_of_match
Improve your Profiling and Debugging skills
Find out more