1 /*
2  * Copyright (c) 2024 Felipe Neves
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT galaxycore_gc2145
8 #include <zephyr/kernel.h>
9 #include <zephyr/device.h>
10 
11 #include <zephyr/drivers/video.h>
12 #include <zephyr/drivers/video-controls.h>
13 #include <zephyr/drivers/i2c.h>
14 #include <zephyr/drivers/gpio.h>
15 
16 #include <zephyr/logging/log.h>
17 LOG_MODULE_REGISTER(video_gc2145, CONFIG_VIDEO_LOG_LEVEL);
18 
19 #define GC2145_REG_AMODE1               0x17
20 #define GC2145_AMODE1_WINDOW_MASK       0xFC
21 #define GC2145_REG_AMODE1_DEF           0x14
22 #define GC2145_REG_OUTPUT_FMT           0x84
23 #define GC2145_REG_OUTPUT_FMT_RGB565    0x06
24 #define GC2145_REG_SYNC_MODE            0x86
25 #define GC2145_REG_SYNC_MODE_DEF        0x23
26 #define GC2145_REG_SYNC_MODE_COL_SWITCH 0x10
27 #define GC2145_REG_SYNC_MODE_ROW_SWITCH 0x20
28 #define GC2145_REG_RESET                0xFE
29 #define GC2145_REG_SW_RESET             0x80
30 #define GC2145_PID_VAL                  0x21
31 #define GC2145_REV_VAL                  0x55
32 #define GC2145_SET_P0_REGS              0x00
33 #define GC2145_REG_CROP_ENABLE          0x90
34 #define GC2145_CROP_SET_ENABLE          0x01
35 #define GC2145_REG_BLANK_WINDOW_BASE    0x09
36 #define GC2145_REG_WINDOW_BASE          0x91
37 #define GC2145_REG_SUBSAMPLE            0x99
38 #define GC2145_REG_SUBSAMPLE_MODE       0x9A
39 #define GC2145_SUBSAMPLE_MODE_SMOOTH    0x0E
40 
41 #define UXGA_HSIZE 1600
42 #define UXGA_VSIZE 1200
43 
44 struct gc2145_reg {
45 	uint8_t addr;
46 	uint8_t value;
47 };
48 
49 static const struct gc2145_reg default_regs[] = {
50 	{0xfe, 0xf0},
51 	{0xfe, 0xf0},
52 	{0xfe, 0xf0},
53 	{0xfc, 0x06},
54 	{0xf6, 0x00},
55 	{0xf7, 0x1d},
56 	{0xf8, 0x85},
57 	{0xfa, 0x00},
58 	{0xf9, 0xfe},
59 	{0xf2, 0x00},
60 
61 	/* ISP settings */
62 	{0xfe, 0x00},
63 	{0x03, 0x04},
64 	{0x04, 0xe2},
65 
66 	{0x09, 0x00},
67 	{0x0a, 0x00},
68 
69 	{0x0b, 0x00},
70 	{0x0c, 0x00},
71 
72 	{0x0d, 0x04}, /* Window height */
73 	{0x0e, 0xc0},
74 
75 	{0x0f, 0x06}, /* Window width */
76 	{0x10, 0x52},
77 
78 	{0x99, 0x11}, /* Subsample */
79 	{0x9a, 0x0E}, /* Subsample mode */
80 
81 	{0x12, 0x2e},
82 	{GC2145_REG_OUTPUT_FMT, 0x14}, /* Analog Mode 1 (vflip/mirror[1:0]) */
83 	{0x18, 0x22},                  /* Analog Mode 2 */
84 	{0x19, 0x0e},
85 	{0x1a, 0x01},
86 	{0x1b, 0x4b},
87 	{0x1c, 0x07},
88 	{0x1d, 0x10},
89 	{0x1e, 0x88},
90 	{0x1f, 0x78},
91 	{0x20, 0x03},
92 	{0x21, 0x40},
93 	{0x22, 0xa0},
94 	{0x24, 0x16},
95 	{0x25, 0x01},
96 	{0x26, 0x10},
97 	{0x2d, 0x60},
98 	{0x30, 0x01},
99 	{0x31, 0x90},
100 	{0x33, 0x06},
101 	{0x34, 0x01},
102 	{0x80, 0x7f},
103 	{0x81, 0x26},
104 	{0x82, 0xfa},
105 	{0x83, 0x00},
106 	{GC2145_REG_OUTPUT_FMT, 0x06},
107 	{GC2145_REG_SYNC_MODE, 0x23},
108 	{0x88, 0x03},
109 	{0x89, 0x03},
110 	{0x85, 0x08},
111 	{0x8a, 0x00},
112 	{0x8b, 0x00},
113 	{0xb0, 0x55},
114 	{0xc3, 0x00},
115 	{0xc4, 0x80},
116 	{0xc5, 0x90},
117 	{0xc6, 0x3b},
118 	{0xc7, 0x46},
119 	{0xec, 0x06},
120 	{0xed, 0x04},
121 	{0xee, 0x60},
122 	{0xef, 0x90},
123 	{0xb6, 0x01},
124 
125 	{0x90, 0x01},
126 	{0x91, 0x00},
127 	{0x92, 0x00},
128 	{0x93, 0x00},
129 	{0x94, 0x00},
130 	{0x95, 0x02},
131 	{0x96, 0x58},
132 	{0x97, 0x03},
133 	{0x98, 0x20},
134 	{0x99, 0x22},
135 	{0x9a, 0x0E},
136 
137 	{0x9b, 0x00},
138 	{0x9c, 0x00},
139 	{0x9d, 0x00},
140 	{0x9e, 0x00},
141 	{0x9f, 0x00},
142 	{0xa0, 0x00},
143 	{0xa1, 0x00},
144 	{0xa2, 0x00},
145 
146 	/* BLK Settings */
147 	{0xfe, 0x00},
148 	{0x40, 0x42},
149 	{0x41, 0x00},
150 	{0x43, 0x5b},
151 	{0x5e, 0x00},
152 	{0x5f, 0x00},
153 	{0x60, 0x00},
154 	{0x61, 0x00},
155 	{0x62, 0x00},
156 	{0x63, 0x00},
157 	{0x64, 0x00},
158 	{0x65, 0x00},
159 	{0x66, 0x20},
160 	{0x67, 0x20},
161 	{0x68, 0x20},
162 	{0x69, 0x20},
163 	{0x76, 0x00},
164 	{0x6a, 0x08},
165 	{0x6b, 0x08},
166 	{0x6c, 0x08},
167 	{0x6d, 0x08},
168 	{0x6e, 0x08},
169 	{0x6f, 0x08},
170 	{0x70, 0x08},
171 	{0x71, 0x08},
172 	{0x76, 0x00},
173 	{0x72, 0xf0},
174 	{0x7e, 0x3c},
175 	{0x7f, 0x00},
176 	{0xfe, 0x02},
177 	{0x48, 0x15},
178 	{0x49, 0x00},
179 	{0x4b, 0x0b},
180 	{0xfe, 0x00},
181 
182 	/* AEC Settings */
183 	{0xfe, 0x01},
184 	{0x01, 0x04},
185 	{0x02, 0xc0},
186 	{0x03, 0x04},
187 	{0x04, 0x90},
188 	{0x05, 0x30},
189 	{0x06, 0x90},
190 	{0x07, 0x30},
191 	{0x08, 0x80},
192 	{0x09, 0x00},
193 	{0x0a, 0x82},
194 	{0x0b, 0x11},
195 	{0x0c, 0x10},
196 	{0x11, 0x10},
197 	{0x13, 0x68},
198 	{GC2145_REG_OUTPUT_FMT, 0x00},
199 	{0x1c, 0x11},
200 	{0x1e, 0x61},
201 	{0x1f, 0x35},
202 	{0x20, 0x40},
203 	{0x22, 0x40},
204 	{0x23, 0x20},
205 	{0xfe, 0x02},
206 	{0x0f, 0x04},
207 	{0xfe, 0x01},
208 	{0x12, 0x30},
209 	{0x15, 0xb0},
210 	{0x10, 0x31},
211 	{0x3e, 0x28},
212 	{0x3f, 0xb0},
213 	{0x40, 0x90},
214 	{0x41, 0x0f},
215 	{0xfe, 0x02},
216 	{0x90, 0x6c},
217 	{0x91, 0x03},
218 	{0x92, 0xcb},
219 	{0x94, 0x33},
220 	{0x95, 0x84},
221 	{0x97, 0x65},
222 	{0xa2, 0x11},
223 	{0xfe, 0x00},
224 	{0xfe, 0x02},
225 	{0x80, 0xc1},
226 	{0x81, 0x08},
227 	{0x82, 0x05},
228 	{0x83, 0x08},
229 	{GC2145_REG_OUTPUT_FMT, 0x0a},
230 	{GC2145_REG_SYNC_MODE, 0xf0},
231 	{0x87, 0x50},
232 	{0x88, 0x15},
233 	{0x89, 0xb0},
234 	{0x8a, 0x30},
235 	{0x8b, 0x10},
236 	{0xfe, 0x01},
237 	{0x21, 0x04},
238 	{0xfe, 0x02},
239 	{0xa3, 0x50},
240 	{0xa4, 0x20},
241 	{0xa5, 0x40},
242 	{0xa6, 0x80},
243 	{0xab, 0x40},
244 	{0xae, 0x0c},
245 	{0xb3, 0x46},
246 	{0xb4, 0x64},
247 	{0xb6, 0x38},
248 	{0xb7, 0x01},
249 	{0xb9, 0x2b},
250 	{0x3c, 0x04},
251 	{0x3d, 0x15},
252 	{0x4b, 0x06},
253 	{0x4c, 0x20},
254 	{0xfe, 0x00},
255 
256 	/* Gamma Control */
257 	{0xfe, 0x02},
258 	{0x10, 0x09},
259 	{0x11, 0x0d},
260 	{0x12, 0x13},
261 	{0x13, 0x19},
262 	{0x14, 0x27},
263 	{0x15, 0x37},
264 	{0x16, 0x45},
265 	{GC2145_REG_OUTPUT_FMT, 0x53},
266 	{0x18, 0x69},
267 	{0x19, 0x7d},
268 	{0x1a, 0x8f},
269 	{0x1b, 0x9d},
270 	{0x1c, 0xa9},
271 	{0x1d, 0xbd},
272 	{0x1e, 0xcd},
273 	{0x1f, 0xd9},
274 	{0x20, 0xe3},
275 	{0x21, 0xea},
276 	{0x22, 0xef},
277 	{0x23, 0xf5},
278 	{0x24, 0xf9},
279 	{0x25, 0xff},
280 	{0xfe, 0x00},
281 	{0xc6, 0x20},
282 	{0xc7, 0x2b},
283 	{0xfe, 0x02},
284 	{0x26, 0x0f},
285 	{0x27, 0x14},
286 	{0x28, 0x19},
287 	{0x29, 0x1e},
288 	{0x2a, 0x27},
289 	{0x2b, 0x33},
290 	{0x2c, 0x3b},
291 	{0x2d, 0x45},
292 	{0x2e, 0x59},
293 	{0x2f, 0x69},
294 	{0x30, 0x7c},
295 	{0x31, 0x89},
296 	{0x32, 0x98},
297 	{0x33, 0xae},
298 	{0x34, 0xc0},
299 	{0x35, 0xcf},
300 	{0x36, 0xda},
301 	{0x37, 0xe2},
302 	{0x38, 0xe9},
303 	{0x39, 0xf3},
304 	{0x3a, 0xf9},
305 	{0x3b, 0xff},
306 	{0xfe, 0x02},
307 	{0xd1, 0x32},
308 	{0xd2, 0x32},
309 	{0xd3, 0x40},
310 	{0xd6, 0xf0},
311 	{0xd7, 0x10},
312 	{0xd8, 0xda},
313 	{0xdd, 0x14},
314 	{0xde, 0x86},
315 	{0xed, 0x80},
316 	{0xee, 0x00},
317 	{0xef, 0x3f},
318 	{0xd8, 0xd8},
319 	{0xfe, 0x01},
320 	{0x9f, 0x40},
321 	{0xfe, 0x01},
322 	{0xc2, 0x14},
323 	{0xc3, 0x0d},
324 	{0xc4, 0x0c},
325 	{0xc8, 0x15},
326 	{0xc9, 0x0d},
327 	{0xca, 0x0a},
328 	{0xbc, 0x24},
329 	{0xbd, 0x10},
330 	{0xbe, 0x0b},
331 	{0xb6, 0x25},
332 	{0xb7, 0x16},
333 	{0xb8, 0x15},
334 	{0xc5, 0x00},
335 	{0xc6, 0x00},
336 	{0xc7, 0x00},
337 	{0xcb, 0x00},
338 	{0xcc, 0x00},
339 	{0xcd, 0x00},
340 	{0xbf, 0x07},
341 	{0xc0, 0x00},
342 	{0xc1, 0x00},
343 	{0xb9, 0x00},
344 	{0xba, 0x00},
345 	{0xbb, 0x00},
346 	{0xaa, 0x01},
347 	{0xab, 0x01},
348 	{0xac, 0x00},
349 	{0xad, 0x05},
350 	{0xae, 0x06},
351 	{0xaf, 0x0e},
352 	{0xb0, 0x0b},
353 	{0xb1, 0x07},
354 	{0xb2, 0x06},
355 	{0xb3, 0x17},
356 	{0xb4, 0x0e},
357 	{0xb5, 0x0e},
358 	{0xd0, 0x09},
359 	{0xd1, 0x00},
360 	{0xd2, 0x00},
361 	{0xd6, 0x08},
362 	{0xd7, 0x00},
363 	{0xd8, 0x00},
364 	{0xd9, 0x00},
365 	{0xda, 0x00},
366 	{0xdb, 0x00},
367 	{0xd3, 0x0a},
368 	{0xd4, 0x00},
369 	{0xd5, 0x00},
370 	{0xa4, 0x00},
371 	{0xa5, 0x00},
372 	{0xa6, 0x77},
373 	{0xa7, 0x77},
374 	{0xa8, 0x77},
375 	{0xa9, 0x77},
376 	{0xa1, 0x80},
377 	{0xa2, 0x80},
378 
379 	{0xfe, 0x01},
380 	{0xdf, 0x0d},
381 	{0xdc, 0x25},
382 	{0xdd, 0x30},
383 	{0xe0, 0x77},
384 	{0xe1, 0x80},
385 	{0xe2, 0x77},
386 	{0xe3, 0x90},
387 	{0xe6, 0x90},
388 	{0xe7, 0xa0},
389 	{0xe8, 0x90},
390 	{0xe9, 0xa0},
391 	{0xfe, 0x00},
392 	{0xfe, 0x01},
393 	{0x4f, 0x00},
394 	{0x4f, 0x00},
395 	{0x4b, 0x01},
396 	{0x4f, 0x00},
397 
398 	{0x4c, 0x01},
399 	{0x4d, 0x71},
400 	{0x4e, 0x01},
401 	{0x4c, 0x01},
402 	{0x4d, 0x91},
403 	{0x4e, 0x01},
404 	{0x4c, 0x01},
405 	{0x4d, 0x70},
406 	{0x4e, 0x01},
407 	{0x4c, 0x01},
408 	{0x4d, 0x90},
409 	{0x4e, 0x02},
410 	{0x4c, 0x01},
411 	{0x4d, 0xb0},
412 	{0x4e, 0x02},
413 	{0x4c, 0x01},
414 	{0x4d, 0x8f},
415 	{0x4e, 0x02},
416 	{0x4c, 0x01},
417 	{0x4d, 0x6f},
418 	{0x4e, 0x02},
419 	{0x4c, 0x01},
420 	{0x4d, 0xaf},
421 	{0x4e, 0x02},
422 	{0x4c, 0x01},
423 	{0x4d, 0xd0},
424 	{0x4e, 0x02},
425 	{0x4c, 0x01},
426 	{0x4d, 0xf0},
427 	{0x4e, 0x02},
428 	{0x4c, 0x01},
429 	{0x4d, 0xcf},
430 	{0x4e, 0x02},
431 	{0x4c, 0x01},
432 	{0x4d, 0xef},
433 	{0x4e, 0x02},
434 	{0x4c, 0x01},
435 	{0x4d, 0x6e},
436 	{0x4e, 0x03},
437 	{0x4c, 0x01},
438 	{0x4d, 0x8e},
439 	{0x4e, 0x03},
440 	{0x4c, 0x01},
441 	{0x4d, 0xae},
442 	{0x4e, 0x03},
443 	{0x4c, 0x01},
444 	{0x4d, 0xce},
445 	{0x4e, 0x03},
446 	{0x4c, 0x01},
447 	{0x4d, 0x4d},
448 	{0x4e, 0x03},
449 	{0x4c, 0x01},
450 	{0x4d, 0x6d},
451 	{0x4e, 0x03},
452 	{0x4c, 0x01},
453 	{0x4d, 0x8d},
454 	{0x4e, 0x03},
455 	{0x4c, 0x01},
456 	{0x4d, 0xad},
457 	{0x4e, 0x03},
458 	{0x4c, 0x01},
459 	{0x4d, 0xcd},
460 	{0x4e, 0x03},
461 	{0x4c, 0x01},
462 	{0x4d, 0x4c},
463 	{0x4e, 0x03},
464 	{0x4c, 0x01},
465 	{0x4d, 0x6c},
466 	{0x4e, 0x03},
467 	{0x4c, 0x01},
468 	{0x4d, 0x8c},
469 	{0x4e, 0x03},
470 	{0x4c, 0x01},
471 	{0x4d, 0xac},
472 	{0x4e, 0x03},
473 	{0x4c, 0x01},
474 	{0x4d, 0xcc},
475 	{0x4e, 0x03},
476 	{0x4c, 0x01},
477 	{0x4d, 0xcb},
478 	{0x4e, 0x03},
479 	{0x4c, 0x01},
480 	{0x4d, 0x4b},
481 	{0x4e, 0x03},
482 	{0x4c, 0x01},
483 	{0x4d, 0x6b},
484 	{0x4e, 0x03},
485 	{0x4c, 0x01},
486 	{0x4d, 0x8b},
487 	{0x4e, 0x03},
488 	{0x4c, 0x01},
489 	{0x4d, 0xab},
490 	{0x4e, 0x03},
491 	{0x4c, 0x01},
492 	{0x4d, 0x8a},
493 	{0x4e, 0x04},
494 	{0x4c, 0x01},
495 	{0x4d, 0xaa},
496 	{0x4e, 0x04},
497 	{0x4c, 0x01},
498 	{0x4d, 0xca},
499 	{0x4e, 0x04},
500 	{0x4c, 0x01},
501 	{0x4d, 0xca},
502 	{0x4e, 0x04},
503 	{0x4c, 0x01},
504 	{0x4d, 0xc9},
505 	{0x4e, 0x04},
506 	{0x4c, 0x01},
507 	{0x4d, 0x8a},
508 	{0x4e, 0x04},
509 	{0x4c, 0x01},
510 	{0x4d, 0x89},
511 	{0x4e, 0x04},
512 	{0x4c, 0x01},
513 	{0x4d, 0xa9},
514 	{0x4e, 0x04},
515 	{0x4c, 0x02},
516 	{0x4d, 0x0b},
517 	{0x4e, 0x05},
518 	{0x4c, 0x02},
519 	{0x4d, 0x0a},
520 	{0x4e, 0x05},
521 	{0x4c, 0x01},
522 	{0x4d, 0xeb},
523 	{0x4e, 0x05},
524 	{0x4c, 0x01},
525 	{0x4d, 0xea},
526 	{0x4e, 0x05},
527 	{0x4c, 0x02},
528 	{0x4d, 0x09},
529 	{0x4e, 0x05},
530 	{0x4c, 0x02},
531 	{0x4d, 0x29},
532 	{0x4e, 0x05},
533 	{0x4c, 0x02},
534 	{0x4d, 0x2a},
535 	{0x4e, 0x05},
536 	{0x4c, 0x02},
537 	{0x4d, 0x4a},
538 	{0x4e, 0x05},
539 	{0x4c, 0x02},
540 	{0x4d, 0x8a},
541 	{0x4e, 0x06},
542 	{0x4c, 0x02},
543 	{0x4d, 0x49},
544 	{0x4e, 0x06},
545 	{0x4c, 0x02},
546 	{0x4d, 0x69},
547 	{0x4e, 0x06},
548 	{0x4c, 0x02},
549 	{0x4d, 0x89},
550 	{0x4e, 0x06},
551 	{0x4c, 0x02},
552 	{0x4d, 0xa9},
553 	{0x4e, 0x06},
554 	{0x4c, 0x02},
555 	{0x4d, 0x48},
556 	{0x4e, 0x06},
557 	{0x4c, 0x02},
558 	{0x4d, 0x68},
559 	{0x4e, 0x06},
560 	{0x4c, 0x02},
561 	{0x4d, 0x69},
562 	{0x4e, 0x06},
563 	{0x4c, 0x02},
564 	{0x4d, 0xca},
565 	{0x4e, 0x07},
566 	{0x4c, 0x02},
567 	{0x4d, 0xc9},
568 	{0x4e, 0x07},
569 	{0x4c, 0x02},
570 	{0x4d, 0xe9},
571 	{0x4e, 0x07},
572 	{0x4c, 0x03},
573 	{0x4d, 0x09},
574 	{0x4e, 0x07},
575 	{0x4c, 0x02},
576 	{0x4d, 0xc8},
577 	{0x4e, 0x07},
578 	{0x4c, 0x02},
579 	{0x4d, 0xe8},
580 	{0x4e, 0x07},
581 	{0x4c, 0x02},
582 	{0x4d, 0xa7},
583 	{0x4e, 0x07},
584 	{0x4c, 0x02},
585 	{0x4d, 0xc7},
586 	{0x4e, 0x07},
587 	{0x4c, 0x02},
588 	{0x4d, 0xe7},
589 	{0x4e, 0x07},
590 	{0x4c, 0x03},
591 	{0x4d, 0x07},
592 	{0x4e, 0x07},
593 
594 	{0x4f, 0x01},
595 	{0x50, 0x80},
596 	{0x51, 0xa8},
597 	{0x52, 0x47},
598 	{0x53, 0x38},
599 	{0x54, 0xc7},
600 	{0x56, 0x0e},
601 	{0x58, 0x08},
602 	{0x5b, 0x00},
603 	{0x5c, 0x74},
604 	{0x5d, 0x8b},
605 	{0x61, 0xdb},
606 	{0x62, 0xb8},
607 	{0x63, 0x86},
608 	{0x64, 0xc0},
609 	{0x65, 0x04},
610 	{0x67, 0xa8},
611 	{0x68, 0xb0},
612 	{0x69, 0x00},
613 	{0x6a, 0xa8},
614 	{0x6b, 0xb0},
615 	{0x6c, 0xaf},
616 	{0x6d, 0x8b},
617 	{0x6e, 0x50},
618 	{0x6f, 0x18},
619 	{0x73, 0xf0},
620 	{0x70, 0x0d},
621 	{0x71, 0x60},
622 	{0x72, 0x80},
623 	{0x74, 0x01},
624 	{0x75, 0x01},
625 	{0x7f, 0x0c},
626 	{0x76, 0x70},
627 	{0x77, 0x58},
628 	{0x78, 0xa0},
629 	{0x79, 0x5e},
630 	{0x7a, 0x54},
631 	{0x7b, 0x58},
632 	{0xfe, 0x00},
633 	{0xfe, 0x02},
634 	{0xc0, 0x01},
635 	{0xc1, 0x44},
636 	{0xc2, 0xfd},
637 	{0xc3, 0x04},
638 	{0xc4, 0xF0},
639 	{0xc5, 0x48},
640 	{0xc6, 0xfd},
641 	{0xc7, 0x46},
642 	{0xc8, 0xfd},
643 	{0xc9, 0x02},
644 	{0xca, 0xe0},
645 	{0xcb, 0x45},
646 	{0xcc, 0xec},
647 	{0xcd, 0x48},
648 	{0xce, 0xf0},
649 	{0xcf, 0xf0},
650 	{0xe3, 0x0c},
651 	{0xe4, 0x4b},
652 	{0xe5, 0xe0},
653 	{0xfe, 0x01},
654 	{0x9f, 0x40},
655 	{0xfe, 0x00},
656 
657 	/* Output Control  */
658 	{0xfe, 0x00},
659 	{0xf2, 0x0f},
660 	{0xfe, 0x02},
661 	{0x40, 0xbf},
662 	{0x46, 0xcf},
663 	{0xfe, 0x00},
664 
665 	{0xfe, 0x00},
666 	{0x05, 0x01},
667 	{0x06, 0x1C},
668 	{0x07, 0x00},
669 	{0x08, 0x32},
670 	{0x11, 0x00},
671 	{0x12, 0x1D},
672 	{0x13, 0x00},
673 	{0x14, 0x00},
674 
675 	{0xfe, 0x01},
676 	{0x3c, 0x00},
677 	{0x3d, 0x04},
678 	{0xfe, 0x00},
679 	{0x00, 0x00},
680 };
681 
682 struct gc2145_config {
683 	struct i2c_dt_spec i2c;
684 #if DT_INST_NODE_HAS_PROP(0, reset_gpios)
685 	struct gpio_dt_spec reset_gpio;
686 #endif
687 };
688 
689 struct gc2145_data {
690 	struct video_format fmt;
691 };
692 
693 #define GC2145_VIDEO_FORMAT_CAP(width, height, format)                                             \
694 	{                                                                                          \
695 		.pixelformat = format, .width_min = width, .width_max = width,                     \
696 		.height_min = height, .height_max = height, .width_step = 0, .height_step = 0,     \
697 	}
698 
699 enum resolutions {
700 	QVGA_RESOLUTION = 0,
701 	VGA_RESOLUTION,
702 	UXGA_RESOLUTION,
703 	RESOLUTIONS_MAX,
704 };
705 
706 static const struct video_format_cap fmts[] = {
707 	[QVGA_RESOLUTION] = GC2145_VIDEO_FORMAT_CAP(320, 240, VIDEO_PIX_FMT_RGB565),   /* QVGA */
708 	[VGA_RESOLUTION] = GC2145_VIDEO_FORMAT_CAP(640, 480, VIDEO_PIX_FMT_RGB565),    /* VGA  */
709 	[UXGA_RESOLUTION] = GC2145_VIDEO_FORMAT_CAP(1600, 1200, VIDEO_PIX_FMT_RGB565), /* UXGA */
710 	[RESOLUTIONS_MAX] = {0},
711 };
712 
gc2145_write_reg(const struct i2c_dt_spec * spec,uint8_t reg_addr,uint8_t value)713 static int gc2145_write_reg(const struct i2c_dt_spec *spec, uint8_t reg_addr, uint8_t value)
714 {
715 	int ret;
716 	uint8_t tries = 3;
717 
718 	/*
719 	 * It rarely happens that the camera does not respond with ACK signal.
720 	 * In that case it usually responds on 2nd try but there is a 3rd one
721 	 * just to be sure that the connection error is not caused by driver
722 	 * itself.
723 	 */
724 	do {
725 		ret = i2c_reg_write_byte_dt(spec, reg_addr, value);
726 		if (!ret) {
727 			return 0;
728 		}
729 		/* If writing failed wait 5ms before next attempt */
730 		k_msleep(5);
731 
732 	} while (tries--);
733 
734 	LOG_ERR("failed to write 0x%x to 0x%x,", value, reg_addr);
735 	return ret;
736 }
737 
gc2145_read_reg(const struct i2c_dt_spec * spec,uint8_t reg_addr,uint8_t * value)738 static int gc2145_read_reg(const struct i2c_dt_spec *spec, uint8_t reg_addr, uint8_t *value)
739 {
740 	int ret;
741 	uint8_t tries = 3;
742 
743 	/*
744 	 * It rarely happens that the camera does not respond with ACK signal.
745 	 * In that case it usually responds on 2nd try but there is a 3rd one
746 	 * just to be sure that the connection error is not caused by driver
747 	 * itself.
748 	 */
749 	do {
750 		ret = i2c_reg_read_byte_dt(spec, reg_addr, value);
751 		if (!ret) {
752 			return 0;
753 		}
754 		/* If writing failed wait 5ms before next attempt */
755 		k_msleep(5);
756 
757 	} while (tries--);
758 
759 	LOG_ERR("failed to read 0x%x register", reg_addr);
760 	return ret;
761 }
762 
gc2145_write_all(const struct device * dev,const struct gc2145_reg * regs,uint16_t reg_num)763 static int gc2145_write_all(const struct device *dev, const struct gc2145_reg *regs,
764 			    uint16_t reg_num)
765 {
766 	const struct gc2145_config *cfg = dev->config;
767 
768 	for (uint16_t i = 0; i < reg_num; i++) {
769 		int ret;
770 
771 		ret = gc2145_write_reg(&cfg->i2c, regs[i].addr, regs[i].value);
772 		if (ret < 0) {
773 			return ret;
774 		}
775 	}
776 
777 	return 0;
778 }
779 
gc2145_soft_reset(const struct device * dev)780 static int gc2145_soft_reset(const struct device *dev)
781 {
782 	int ret;
783 	const struct gc2145_config *cfg = dev->config;
784 
785 	/* Initiate system reset */
786 	ret = gc2145_write_reg(&cfg->i2c, GC2145_REG_RESET, GC2145_REG_SW_RESET);
787 
788 	k_msleep(300);
789 
790 	return ret;
791 }
792 
gc2145_set_ctrl_vflip(const struct device * dev,bool enable)793 static int gc2145_set_ctrl_vflip(const struct device *dev, bool enable)
794 {
795 	int ret;
796 	const struct gc2145_config *cfg = dev->config;
797 	uint8_t old_value;
798 
799 	ret = gc2145_read_reg(&cfg->i2c, GC2145_REG_AMODE1, &old_value);
800 	if (ret < 0) {
801 		return ret;
802 	}
803 
804 	/* Set the vertical flip state */
805 	return gc2145_write_reg(&cfg->i2c, GC2145_REG_AMODE1,
806 				(old_value & GC2145_AMODE1_WINDOW_MASK) | (enable << 1));
807 }
808 
gc2145_set_ctrl_hmirror(const struct device * dev,bool enable)809 static int gc2145_set_ctrl_hmirror(const struct device *dev, bool enable)
810 {
811 	int ret;
812 	const struct gc2145_config *cfg = dev->config;
813 	uint8_t old_value;
814 
815 	ret = gc2145_read_reg(&cfg->i2c, GC2145_REG_AMODE1, &old_value);
816 	if (ret < 0) {
817 		return ret;
818 	}
819 
820 	/* Set the horizontal mirror state */
821 	return gc2145_write_reg(&cfg->i2c, GC2145_REG_AMODE1,
822 				(old_value & GC2145_AMODE1_WINDOW_MASK) | enable);
823 }
824 
gc2145_set_window(const struct device * dev,uint16_t reg,uint16_t x,uint16_t y,uint16_t w,uint16_t h)825 static int gc2145_set_window(const struct device *dev, uint16_t reg, uint16_t x, uint16_t y,
826 			     uint16_t w, uint16_t h)
827 {
828 	int ret;
829 	const struct gc2145_config *cfg = dev->config;
830 
831 	ret = gc2145_write_reg(&cfg->i2c, GC2145_REG_RESET, GC2145_SET_P0_REGS);
832 	if (ret < 0) {
833 		return ret;
834 	}
835 
836 	/* Y/row offset */
837 	ret = gc2145_write_reg(&cfg->i2c, reg++, y >> 8);
838 	if (ret < 0) {
839 		return ret;
840 	}
841 
842 	ret = gc2145_write_reg(&cfg->i2c, reg++, y & 0xff);
843 	if (ret < 0) {
844 		return ret;
845 	}
846 
847 	/* X/col offset */
848 	ret = gc2145_write_reg(&cfg->i2c, reg++, x >> 8);
849 	if (ret < 0) {
850 		return ret;
851 	}
852 
853 	ret = gc2145_write_reg(&cfg->i2c, reg++, x & 0xff);
854 	if (ret < 0) {
855 		return ret;
856 	}
857 
858 	/* Window height */
859 	ret = gc2145_write_reg(&cfg->i2c, reg++, h >> 8);
860 	if (ret < 0) {
861 		return ret;
862 	}
863 
864 	ret = gc2145_write_reg(&cfg->i2c, reg++, h & 0xff);
865 	if (ret < 0) {
866 		return ret;
867 	}
868 
869 	/* Window width */
870 	ret = gc2145_write_reg(&cfg->i2c, reg++, w >> 8);
871 	if (ret < 0) {
872 		return ret;
873 	}
874 
875 	ret = gc2145_write_reg(&cfg->i2c, reg++, w & 0xff);
876 	if (ret < 0) {
877 		return ret;
878 	}
879 
880 	return 0;
881 }
882 
gc2145_set_output_format(const struct device * dev,int output_format)883 static int gc2145_set_output_format(const struct device *dev, int output_format)
884 {
885 	int ret;
886 	const struct gc2145_config *cfg = dev->config;
887 
888 	ret = gc2145_write_reg(&cfg->i2c, GC2145_REG_RESET, GC2145_SET_P0_REGS);
889 	if (ret < 0) {
890 		return ret;
891 	}
892 
893 	if (output_format != VIDEO_PIX_FMT_RGB565) {
894 		LOG_ERR("Image format not supported");
895 		return -ENOTSUP;
896 	}
897 
898 	/* Disable JPEG compression and set output to RGB565 */
899 	ret = gc2145_write_reg(&cfg->i2c, GC2145_REG_OUTPUT_FMT, GC2145_REG_OUTPUT_FMT_RGB565);
900 	if (ret < 0) {
901 		return ret;
902 	}
903 
904 	k_sleep(K_MSEC(30));
905 
906 	return 0;
907 }
908 
gc2145_set_resolution(const struct device * dev,enum resolutions res)909 static int gc2145_set_resolution(const struct device *dev, enum resolutions res)
910 {
911 	int ret;
912 	const struct gc2145_config *cfg = dev->config;
913 
914 	uint16_t w;
915 	uint16_t h;
916 	uint16_t win_w;
917 	uint16_t win_h;
918 	uint16_t c_ratio;
919 	uint16_t r_ratio;
920 	uint16_t x;
921 	uint16_t y;
922 	uint16_t win_x;
923 	uint16_t win_y;
924 
925 	if (res >= RESOLUTIONS_MAX) {
926 		return -EIO;
927 	}
928 
929 	w = fmts[res].width_min;
930 	h = fmts[res].height_min;
931 
932 	/* Add the subsampling factor depending on resolution */
933 	switch (res) {
934 	case QVGA_RESOLUTION:
935 		c_ratio = 3;
936 		r_ratio = 3;
937 		break;
938 	case VGA_RESOLUTION:
939 		c_ratio = 2;
940 		r_ratio = 2;
941 		break;
942 	case UXGA_RESOLUTION:
943 		c_ratio = 1;
944 		r_ratio = 1;
945 		break;
946 	default:
947 		LOG_ERR("Unsupported resolution %d", res);
948 		return -EIO;
949 	};
950 
951 	/* Calculates the window boundaries to obtain the desired resolution */
952 	win_w = w * c_ratio;
953 	win_h = h * r_ratio;
954 	x = (((win_w / c_ratio) - w) / 2);
955 	y = (((win_h / r_ratio) - h) / 2);
956 	win_x = ((UXGA_HSIZE - win_w) / 2);
957 	win_y = ((UXGA_VSIZE - win_h) / 2);
958 
959 	/* Set readout window first. */
960 	ret = gc2145_set_window(dev, GC2145_REG_BLANK_WINDOW_BASE, win_x, win_y, win_w + 16,
961 				win_h + 8);
962 	if (ret < 0) {
963 		return ret;
964 	}
965 
966 	/* Set cropping window next. */
967 	ret = gc2145_set_window(dev, GC2145_REG_WINDOW_BASE, x, y, w, h);
968 	if (ret < 0) {
969 		return ret;
970 	}
971 
972 	/* Enable crop */
973 	ret = gc2145_write_reg(&cfg->i2c, GC2145_REG_CROP_ENABLE, GC2145_CROP_SET_ENABLE);
974 	if (ret < 0) {
975 		return ret;
976 	}
977 
978 	/* Set Sub-sampling ratio and mode */
979 	ret = gc2145_write_reg(&cfg->i2c, GC2145_REG_SUBSAMPLE, ((r_ratio << 4) | c_ratio));
980 	if (ret < 0) {
981 		return ret;
982 	}
983 
984 	ret = gc2145_write_reg(&cfg->i2c, GC2145_REG_SUBSAMPLE_MODE, GC2145_SUBSAMPLE_MODE_SMOOTH);
985 	if (ret < 0) {
986 		return ret;
987 	}
988 	/*
989 	 * Galaxy Core datasheet does not document the reason behind of this
990 	 * and other short delay requirements, but the reason exposed by them
991 	 * is to give enough time for the sensor DSP to handle the I2C transaction
992 	 * give some time time to apply the changes before the next instruction.
993 	 */
994 	k_sleep(K_MSEC(30));
995 
996 	return 0;
997 }
998 
gc2145_check_connection(const struct device * dev)999 static uint8_t gc2145_check_connection(const struct device *dev)
1000 {
1001 	int ret;
1002 	const struct gc2145_config *cfg = dev->config;
1003 	uint8_t reg_pid_val;
1004 	uint8_t reg_ver_val;
1005 
1006 	ret = gc2145_read_reg(&cfg->i2c, 0xf0, &reg_pid_val);
1007 	if (ret < 0) {
1008 		return ret;
1009 	}
1010 
1011 	ret = gc2145_read_reg(&cfg->i2c, 0xf1, &reg_ver_val);
1012 	if (ret < 0) {
1013 		return ret;
1014 	}
1015 
1016 	if ((reg_ver_val != GC2145_REV_VAL) || (reg_pid_val != GC2145_PID_VAL)) {
1017 		LOG_WRN("Unexpected GC2145 pid: 0x%x or rev: 0x%x", reg_pid_val, reg_ver_val);
1018 	}
1019 
1020 	return 0;
1021 }
1022 
gc2145_set_fmt(const struct device * dev,enum video_endpoint_id ep,struct video_format * fmt)1023 static int gc2145_set_fmt(const struct device *dev, enum video_endpoint_id ep,
1024 			  struct video_format *fmt)
1025 {
1026 	struct gc2145_data *drv_data = dev->data;
1027 	enum resolutions res = RESOLUTIONS_MAX;
1028 	int ret;
1029 
1030 	/* We only support RGB565 formats */
1031 	if (fmt->pixelformat != VIDEO_PIX_FMT_RGB565) {
1032 		LOG_ERR("gc2145 camera supports only RGB565");
1033 		return -ENOTSUP;
1034 	}
1035 
1036 	if (memcmp(&drv_data->fmt, fmt, sizeof(drv_data->fmt)) == 0) {
1037 		/* nothing to do */
1038 		return 0;
1039 	}
1040 
1041 	/* Check if camera is capable of handling given format */
1042 	for (int i = 0; i < RESOLUTIONS_MAX; i++) {
1043 		if (fmts[i].width_min == fmt->width && fmts[i].height_min == fmt->height &&
1044 		    fmts[i].pixelformat == fmt->pixelformat) {
1045 			res = (enum resolutions)i;
1046 			break;
1047 		}
1048 	}
1049 	if (res == RESOLUTIONS_MAX) {
1050 		LOG_ERR("Image format not supported");
1051 		return -ENOTSUP;
1052 	}
1053 
1054 	drv_data->fmt = *fmt;
1055 
1056 	/* Set output format */
1057 	ret = gc2145_set_output_format(dev, fmt->pixelformat);
1058 	if (ret < 0) {
1059 		LOG_ERR("Failed to set the output format");
1060 		return ret;
1061 	}
1062 
1063 	/* Set window size */
1064 	ret = gc2145_set_resolution(dev, res);
1065 	if (ret < 0) {
1066 		LOG_ERR("Failed to set the resolution");
1067 		return ret;
1068 	}
1069 
1070 	return 0;
1071 }
1072 
gc2145_get_fmt(const struct device * dev,enum video_endpoint_id ep,struct video_format * fmt)1073 static int gc2145_get_fmt(const struct device *dev, enum video_endpoint_id ep,
1074 			  struct video_format *fmt)
1075 {
1076 	struct gc2145_data *drv_data = dev->data;
1077 
1078 	*fmt = drv_data->fmt;
1079 
1080 	return 0;
1081 }
1082 
gc2145_stream_start(const struct device * dev)1083 static int gc2145_stream_start(const struct device *dev)
1084 {
1085 	const struct gc2145_config *cfg = dev->config;
1086 
1087 	return gc2145_write_reg(&cfg->i2c, 0xf2, 0x0f);
1088 }
1089 
gc2145_stream_stop(const struct device * dev)1090 static int gc2145_stream_stop(const struct device *dev)
1091 {
1092 	const struct gc2145_config *cfg = dev->config;
1093 
1094 	return gc2145_write_reg(&cfg->i2c, 0xf2, 0x00);
1095 }
1096 
gc2145_get_caps(const struct device * dev,enum video_endpoint_id ep,struct video_caps * caps)1097 static int gc2145_get_caps(const struct device *dev, enum video_endpoint_id ep,
1098 			   struct video_caps *caps)
1099 {
1100 	caps->format_caps = fmts;
1101 	return 0;
1102 }
1103 
gc2145_set_ctrl(const struct device * dev,unsigned int cid,void * value)1104 static int gc2145_set_ctrl(const struct device *dev, unsigned int cid, void *value)
1105 {
1106 	switch (cid) {
1107 	case VIDEO_CID_HFLIP:
1108 		return gc2145_set_ctrl_hmirror(dev, (int)value);
1109 	case VIDEO_CID_VFLIP:
1110 		return gc2145_set_ctrl_vflip(dev, (int)value);
1111 	default:
1112 		return -ENOTSUP;
1113 	}
1114 }
1115 
1116 static DEVICE_API(video, gc2145_driver_api) = {
1117 	.set_format = gc2145_set_fmt,
1118 	.get_format = gc2145_get_fmt,
1119 	.get_caps = gc2145_get_caps,
1120 	.stream_start = gc2145_stream_start,
1121 	.stream_stop = gc2145_stream_stop,
1122 	.set_ctrl = gc2145_set_ctrl,
1123 };
1124 
gc2145_init(const struct device * dev)1125 static int gc2145_init(const struct device *dev)
1126 {
1127 	struct video_format fmt;
1128 	int ret;
1129 
1130 #if DT_INST_NODE_HAS_PROP(0, reset_gpios)
1131 	const struct gc2145_config *cfg = dev->config;
1132 
1133 	ret = gpio_pin_configure_dt(&cfg->reset_gpio, GPIO_OUTPUT_ACTIVE);
1134 	if (ret) {
1135 		return ret;
1136 	}
1137 
1138 	k_sleep(K_MSEC(1));
1139 	gpio_pin_set_dt(&cfg->reset_gpio, 0);
1140 	k_sleep(K_MSEC(1));
1141 #endif
1142 
1143 	ret = gc2145_check_connection(dev);
1144 	if (ret) {
1145 		return ret;
1146 	}
1147 
1148 	gc2145_soft_reset(dev);
1149 	gc2145_write_all(dev, default_regs, ARRAY_SIZE(default_regs));
1150 
1151 	/* set default/init format QVGA RGB565 */
1152 	fmt.pixelformat = VIDEO_PIX_FMT_RGB565;
1153 	fmt.width = fmts[QVGA_RESOLUTION].width_min;
1154 	fmt.height = fmts[QVGA_RESOLUTION].height_min;
1155 	fmt.pitch = fmts[QVGA_RESOLUTION].width_min * 2;
1156 
1157 	ret = gc2145_set_fmt(dev, VIDEO_EP_OUT, &fmt);
1158 	if (ret) {
1159 		LOG_ERR("Unable to configure default format");
1160 		return ret;
1161 	}
1162 
1163 	return 0;
1164 }
1165 
1166 /* Unique Instance */
1167 static const struct gc2145_config gc2145_cfg_0 = {
1168 	.i2c = I2C_DT_SPEC_INST_GET(0),
1169 #if DT_INST_NODE_HAS_PROP(0, reset_gpios)
1170 	.reset_gpio = GPIO_DT_SPEC_INST_GET(0, reset_gpios),
1171 #endif
1172 };
1173 static struct gc2145_data gc2145_data_0;
1174 
gc2145_init_0(const struct device * dev)1175 static int gc2145_init_0(const struct device *dev)
1176 {
1177 	const struct gc2145_config *cfg = dev->config;
1178 
1179 	if (!i2c_is_ready_dt(&cfg->i2c)) {
1180 		LOG_ERR("Bus device is not ready");
1181 		return -ENODEV;
1182 	}
1183 
1184 #if DT_INST_NODE_HAS_PROP(0, reset_gpios)
1185 	if (!gpio_is_ready_dt(&cfg->reset_gpio)) {
1186 		LOG_ERR("%s: device %s is not ready", dev->name, cfg->reset_gpio.port->name);
1187 		return -ENODEV;
1188 	}
1189 #endif
1190 
1191 	return gc2145_init(dev);
1192 }
1193 
1194 DEVICE_DT_INST_DEFINE(0, &gc2145_init_0, NULL, &gc2145_data_0, &gc2145_cfg_0, POST_KERNEL,
1195 		      CONFIG_VIDEO_INIT_PRIORITY, &gc2145_driver_api);
1196