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