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, ®_pid_val);
1007 if (ret < 0) {
1008 return ret;
1009 }
1010
1011 ret = gc2145_read_reg(&cfg->i2c, 0xf1, ®_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