1 /*
2  * Copyright (c) 2021 Antmicro <www.antmicro.com>
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT ovti_ov2640
8 
9 #include <zephyr/kernel.h>
10 #include <zephyr/device.h>
11 #include <zephyr/logging/log.h>
12 #include <zephyr/drivers/video.h>
13 #include <zephyr/drivers/video-controls.h>
14 #include <zephyr/drivers/i2c.h>
15 #include <zephyr/drivers/gpio.h>
16 
17 LOG_MODULE_REGISTER(video_ov2640, CONFIG_VIDEO_LOG_LEVEL);
18 
19 /* DSP register bank FF=0x00*/
20 #define QS                  0x44
21 #define HSIZE               0x51
22 #define VSIZE               0x52
23 #define XOFFL               0x53
24 #define YOFFL               0x54
25 #define VHYX                0x55
26 #define TEST                0x57
27 #define ZMOW                0x5A
28 #define ZMOH                0x5B
29 #define ZMHH                0x5C
30 #define BPADDR              0x7C
31 #define BPDATA              0x7D
32 #define SIZEL               0x8C
33 #define HSIZE8              0xC0
34 #define VSIZE8              0xC1
35 #define CTRL1               0xC3
36 
37 #define CTRLI               0x50
38 #define CTRLI_LP_DP         0x80
39 
40 #define CTRL0               0xC2
41 #define CTRL0_YUV422        0x08
42 #define CTRL0_YUV_EN        0x04
43 #define CTRL0_RGB_EN        0x02
44 
45 #define CTRL2               0x86
46 #define CTRL2_DCW_EN        0x20
47 #define CTRL2_SDE_EN        0x10
48 #define CTRL2_UV_ADJ_EN     0x08
49 #define CTRL2_UV_AVG_EN     0x04
50 #define CTRL2_CMX_EN        0x01
51 
52 #define CTRL3               0x87
53 #define CTRL3_BPC_EN        0x80
54 #define CTRL3_WPC_EN        0x40
55 #define R_DVP_SP            0xD3
56 #define R_DVP_SP_AUTO_MODE  0x80
57 
58 #define R_BYPASS                0x05
59 #define R_BYPASS_DSP_EN         0x00
60 #define R_BYPASS_DSP_BYPAS      0x01
61 
62 #define IMAGE_MODE              0xDA
63 #define IMAGE_MODE_JPEG_EN      0x10
64 #define IMAGE_MODE_RGB565       0x08
65 
66 #define RESET                   0xE0
67 #define RESET_JPEG              0x10
68 #define RESET_DVP               0x04
69 
70 #define MC_BIST                 0xF9
71 #define MC_BIST_RESET           0x80
72 #define MC_BIST_BOOT_ROM_SEL    0x40
73 
74 #define BANK_SEL                0xFF
75 #define BANK_SEL_DSP            0x00
76 #define BANK_SEL_SENSOR         0x01
77 
78 /* Sensor register bank FF=0x01*/
79 #define COM1                0x03
80 #define REG_PID             0x0A
81 #define REG_PID_VAL         0x26
82 #define REG_VER             0x0B
83 #define REG_VER_VAL         0x42
84 #define AEC                 0x10
85 #define CLKRC               0x11
86 #define COM10               0x15
87 #define HSTART              0x17
88 #define HSTOP               0x18
89 #define VSTART              0x19
90 #define VSTOP               0x1A
91 #define AEW                 0x24
92 #define AEB                 0x25
93 #define ARCOM2              0x34
94 #define FLL                 0x46
95 #define FLH                 0x47
96 #define COM19               0x48
97 #define ZOOMS               0x49
98 #define BD50                0x4F
99 #define BD60                0x50
100 #define REG5D               0x5D
101 #define REG5E               0x5E
102 #define REG5F               0x5F
103 #define REG60               0x60
104 #define HISTO_LOW           0x61
105 #define HISTO_HIGH          0x62
106 
107 #define REG04               0x04
108 #define REG04_DEFAULT       0x28
109 #define REG04_HFLIP_IMG     0x80
110 #define REG04_VFLIP_IMG     0x40
111 #define REG04_VREF_EN       0x10
112 #define REG04_HREF_EN       0x08
113 #define REG04_SET(x)        (REG04_DEFAULT | x)
114 
115 #define COM2                0x09
116 #define COM2_OUT_DRIVE_3x   0x02
117 
118 #define COM3                0x0C
119 #define COM3_DEFAULT        0x38
120 #define COM3_BAND_AUTO      0x02
121 #define COM3_BAND_SET(x)    (COM3_DEFAULT | x)
122 
123 #define COM7                0x12
124 #define COM7_SRST           0x80
125 #define COM7_RES_UXGA       0x00 /* UXGA */
126 #define COM7_ZOOM_EN        0x04 /* Enable Zoom */
127 #define COM7_COLOR_BAR      0x02 /* Enable Color Bar Test */
128 
129 #define COM8                0x13
130 #define COM8_DEFAULT        0xC0
131 #define COM8_BNDF_EN        0x20 /* Enable Banding filter */
132 #define COM8_AGC_EN         0x04 /* AGC Auto/Manual control selection */
133 #define COM8_AEC_EN         0x01 /* Auto/Manual Exposure control */
134 #define COM8_SET(x)         (COM8_DEFAULT | x)
135 
136 #define COM9                0x14 /* AGC gain ceiling */
137 #define COM9_DEFAULT        0x08
138 #define COM9_AGC_GAIN_8x    0x02 /* AGC:    8x */
139 #define COM9_AGC_SET(x)     (COM9_DEFAULT | (x << 5))
140 
141 #define COM10               0x15
142 
143 #define CTRL1_AWB           0x08 /* Enable AWB */
144 
145 #define VV                  0x26
146 #define VV_AGC_TH_SET(h, l) ((h << 4) | (l & 0x0F))
147 
148 #define REG32               0x32
149 #define REG32_UXGA          0x36
150 
151 /* Configuration arrays */
152 #define SVGA_HSIZE     (800)
153 #define SVGA_VSIZE     (600)
154 
155 #define UXGA_HSIZE     (1600)
156 #define UXGA_VSIZE     (1200)
157 
158 struct ov2640_reg {
159 	uint8_t addr;
160 	uint8_t value;
161 };
162 
163 static const struct ov2640_reg default_regs[] = {
164 	{ BANK_SEL, BANK_SEL_DSP },
165 	{ 0x2c,     0xff },
166 	{ 0x2e,     0xdf },
167 	{ BANK_SEL, BANK_SEL_SENSOR },
168 	{ 0x3c,     0x32 },
169 	{ CLKRC,    0x80 }, /* Set PCLK divider */
170 	{ COM2,     COM2_OUT_DRIVE_3x }, /* Output drive x2 */
171 	{ REG04,    REG04_SET(REG04_HREF_EN)},
172 	{ COM8,     COM8_SET(COM8_BNDF_EN | COM8_AGC_EN | COM8_AEC_EN) },
173 	{ COM9,     COM9_AGC_SET(COM9_AGC_GAIN_8x)},
174 	{ COM10,    0x00 }, /* Invert VSYNC */
175 	{ 0x2c,     0x0c },
176 	{ 0x33,     0x78 },
177 	{ 0x3a,     0x33 },
178 	{ 0x3b,     0xfb },
179 	{ 0x3e,     0x00 },
180 	{ 0x43,     0x11 },
181 	{ 0x16,     0x10 },
182 	{ 0x39,     0x02 },
183 	{ 0x35,     0x88 },
184 	{ 0x22,     0x0a },
185 	{ 0x37,     0x40 },
186 	{ 0x23,     0x00 },
187 	{ ARCOM2,   0xa0 },
188 	{ 0x06,     0x02 },
189 	{ 0x06,     0x88 },
190 	{ 0x07,     0xc0 },
191 	{ 0x0d,     0xb7 },
192 	{ 0x0e,     0x01 },
193 	{ 0x4c,     0x00 },
194 	{ 0x4a,     0x81 },
195 	{ 0x21,     0x99 },
196 	{ AEW,      0x40 },
197 	{ AEB,      0x38 },
198 	/* AGC/AEC fast mode operating region */
199 	{ VV,       VV_AGC_TH_SET(0x08, 0x02) },
200 	{ COM19,    0x00 }, /* Zoom control 2 LSBs */
201 	{ ZOOMS,    0x00 }, /* Zoom control 8 MSBs */
202 	{ 0x5c,     0x00 },
203 	{ 0x63,     0x00 },
204 	{ FLL,      0x00 },
205 	{ FLH,      0x00 },
206 
207 	/* Set banding filter */
208 	{ COM3,     COM3_BAND_SET(COM3_BAND_AUTO) },
209 	{ REG5D,    0x55 },
210 	{ REG5E,    0x7d },
211 	{ REG5F,    0x7d },
212 	{ REG60,    0x55 },
213 	{ HISTO_LOW,   0x70 },
214 	{ HISTO_HIGH,  0x80 },
215 	{ 0x7c,     0x05 },
216 	{ 0x20,     0x80 },
217 	{ 0x28,     0x30 },
218 	{ 0x6c,     0x00 },
219 	{ 0x6d,     0x80 },
220 	{ 0x6e,     0x00 },
221 	{ 0x70,     0x02 },
222 	{ 0x71,     0x94 },
223 	{ 0x73,     0xc1 },
224 	{ 0x3d,     0x34 },
225 	/* { COM7,   COM7_RES_UXGA | COM7_ZOOM_EN }, */
226 	{ 0x5a,     0x57 },
227 	{ BD50,     0xbb },
228 	{ BD60,     0x9c },
229 
230 	{ BANK_SEL, BANK_SEL_DSP },
231 	{ 0xe5,     0x7f },
232 	{ MC_BIST,  MC_BIST_RESET | MC_BIST_BOOT_ROM_SEL },
233 	{ 0x41,     0x24 },
234 	{ RESET,    RESET_JPEG | RESET_DVP },
235 	{ 0x76,     0xff },
236 	{ 0x33,     0xa0 },
237 	{ 0x42,     0x20 },
238 	{ 0x43,     0x18 },
239 	{ 0x4c,     0x00 },
240 	{ CTRL3,    CTRL3_BPC_EN | CTRL3_WPC_EN | 0x10 },
241 	{ 0x88,     0x3f },
242 	{ 0xd7,     0x03 },
243 	{ 0xd9,     0x10 },
244 	{ R_DVP_SP, R_DVP_SP_AUTO_MODE | 0x2 },
245 	{ 0xc8,     0x08 },
246 	{ 0xc9,     0x80 },
247 	{ BPADDR,   0x00 },
248 	{ BPDATA,   0x00 },
249 	{ BPADDR,   0x03 },
250 	{ BPDATA,   0x48 },
251 	{ BPDATA,   0x48 },
252 	{ BPADDR,   0x08 },
253 	{ BPDATA,   0x20 },
254 	{ BPDATA,   0x10 },
255 	{ BPDATA,   0x0e },
256 	{ 0x90,     0x00 },
257 	{ 0x91,     0x0e },
258 	{ 0x91,     0x1a },
259 	{ 0x91,     0x31 },
260 	{ 0x91,     0x5a },
261 	{ 0x91,     0x69 },
262 	{ 0x91,     0x75 },
263 	{ 0x91,     0x7e },
264 	{ 0x91,     0x88 },
265 	{ 0x91,     0x8f },
266 	{ 0x91,     0x96 },
267 	{ 0x91,     0xa3 },
268 	{ 0x91,     0xaf },
269 	{ 0x91,     0xc4 },
270 	{ 0x91,     0xd7 },
271 	{ 0x91,     0xe8 },
272 	{ 0x91,     0x20 },
273 	{ 0x92,     0x00 },
274 	{ 0x93,     0x06 },
275 	{ 0x93,     0xe3 },
276 	{ 0x93,     0x03 },
277 	{ 0x93,     0x03 },
278 	{ 0x93,     0x00 },
279 	{ 0x93,     0x02 },
280 	{ 0x93,     0x00 },
281 	{ 0x93,     0x00 },
282 	{ 0x93,     0x00 },
283 	{ 0x93,     0x00 },
284 	{ 0x93,     0x00 },
285 	{ 0x93,     0x00 },
286 	{ 0x93,     0x00 },
287 	{ 0x96,     0x00 },
288 	{ 0x97,     0x08 },
289 	{ 0x97,     0x19 },
290 	{ 0x97,     0x02 },
291 	{ 0x97,     0x0c },
292 	{ 0x97,     0x24 },
293 	{ 0x97,     0x30 },
294 	{ 0x97,     0x28 },
295 	{ 0x97,     0x26 },
296 	{ 0x97,     0x02 },
297 	{ 0x97,     0x98 },
298 	{ 0x97,     0x80 },
299 	{ 0x97,     0x00 },
300 	{ 0x97,     0x00 },
301 	{ 0xa4,     0x00 },
302 	{ 0xa8,     0x00 },
303 	{ 0xc5,     0x11 },
304 	{ 0xc6,     0x51 },
305 	{ 0xbf,     0x80 },
306 	{ 0xc7,     0x10 },
307 	{ 0xb6,     0x66 },
308 	{ 0xb8,     0xA5 },
309 	{ 0xb7,     0x64 },
310 	{ 0xb9,     0x7C },
311 	{ 0xb3,     0xaf },
312 	{ 0xb4,     0x97 },
313 	{ 0xb5,     0xFF },
314 	{ 0xb0,     0xC5 },
315 	{ 0xb1,     0x94 },
316 	{ 0xb2,     0x0f },
317 	{ 0xc4,     0x5c },
318 	{ 0xa6,     0x00 },
319 	{ 0xa7,     0x20 },
320 	{ 0xa7,     0xd8 },
321 	{ 0xa7,     0x1b },
322 	{ 0xa7,     0x31 },
323 	{ 0xa7,     0x00 },
324 	{ 0xa7,     0x18 },
325 	{ 0xa7,     0x20 },
326 	{ 0xa7,     0xd8 },
327 	{ 0xa7,     0x19 },
328 	{ 0xa7,     0x31 },
329 	{ 0xa7,     0x00 },
330 	{ 0xa7,     0x18 },
331 	{ 0xa7,     0x20 },
332 	{ 0xa7,     0xd8 },
333 	{ 0xa7,     0x19 },
334 	{ 0xa7,     0x31 },
335 	{ 0xa7,     0x00 },
336 	{ 0xa7,     0x18 },
337 	{ 0x7f,     0x00 },
338 	{ 0xe5,     0x1f },
339 	{ 0xe1,     0x77 },
340 	{ 0xdd,     0x7f },
341 	{ CTRL0,    CTRL0_YUV422 | CTRL0_YUV_EN | CTRL0_RGB_EN },
342 	{ 0x00,     0x00 }
343 };
344 
345 static const struct ov2640_reg uxga_regs[] = {
346 	{ BANK_SEL, BANK_SEL_SENSOR },
347 	/* DSP input image resolution and window size control */
348 	{ COM7,    COM7_RES_UXGA},
349 	{ COM1,    0x0F }, /* UXGA=0x0F, SVGA=0x0A, CIF=0x06 */
350 	{ REG32,   REG32_UXGA }, /* UXGA=0x36, SVGA/CIF=0x09 */
351 
352 	{ HSTART,  0x11 }, /* UXGA=0x11, SVGA/CIF=0x11 */
353 	{ HSTOP,   0x75 }, /* UXGA=0x75, SVGA/CIF=0x43 */
354 
355 	{ VSTART,  0x01 }, /* UXGA=0x01, SVGA/CIF=0x00 */
356 	{ VSTOP,   0x97 }, /* UXGA=0x97, SVGA/CIF=0x4b */
357 	{ 0x3d,    0x34 }, /* UXGA=0x34, SVGA/CIF=0x38 */
358 
359 	{ 0x35,    0x88 },
360 	{ 0x22,    0x0a },
361 	{ 0x37,    0x40 },
362 	{ 0x34,    0xa0 },
363 	{ 0x06,    0x02 },
364 	{ 0x0d,    0xb7 },
365 	{ 0x0e,    0x01 },
366 	{ 0x42,    0x83 },
367 
368 	/*
369 	 * Set DSP input image size and offset.
370 	 * The sensor output image can be scaled with OUTW/OUTH
371 	 */
372 	{ BANK_SEL, BANK_SEL_DSP },
373 	{ R_BYPASS, R_BYPASS_DSP_BYPAS },
374 
375 	{ RESET,   RESET_DVP },
376 	{ HSIZE8,  (UXGA_HSIZE>>3)}, /* Image Horizontal Size HSIZE[10:3] */
377 	{ VSIZE8,  (UXGA_VSIZE>>3)}, /* Image Vertical Size VSIZE[10:3] */
378 
379 	/* {HSIZE[11], HSIZE[2:0], VSIZE[2:0]} */
380 	{ SIZEL,   ((UXGA_HSIZE>>6)&0x40) | ((UXGA_HSIZE&0x7)<<3) | (UXGA_VSIZE&0x7)},
381 
382 	{ XOFFL,   0x00 }, /* OFFSET_X[7:0] */
383 	{ YOFFL,   0x00 }, /* OFFSET_Y[7:0] */
384 	{ HSIZE,   ((UXGA_HSIZE>>2)&0xFF) }, /* H_SIZE[7:0] real/4 */
385 	{ VSIZE,   ((UXGA_VSIZE>>2)&0xFF) }, /* V_SIZE[7:0] real/4 */
386 
387 	/* V_SIZE[8]/OFFSET_Y[10:8]/H_SIZE[8]/OFFSET_X[10:8] */
388 	{ VHYX,    ((UXGA_VSIZE>>3)&0x80) | ((UXGA_HSIZE>>7)&0x08) },
389 	{ TEST,    (UXGA_HSIZE>>4)&0x80}, /* H_SIZE[9] */
390 
391 	{ CTRL2,   CTRL2_DCW_EN | CTRL2_SDE_EN |
392 		CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN },
393 
394 	/* H_DIVIDER/V_DIVIDER */
395 	{ CTRLI,   CTRLI_LP_DP | 0x00},
396 	/* DVP prescaler */
397 	{ R_DVP_SP, R_DVP_SP_AUTO_MODE | 0x04},
398 
399 	{ R_BYPASS, R_BYPASS_DSP_EN },
400 	{ RESET,    0x00 },
401 	{0, 0},
402 };
403 
404 #define NUM_BRIGHTNESS_LEVELS (5)
405 static const uint8_t brightness_regs[NUM_BRIGHTNESS_LEVELS + 1][5] = {
406 	{ BPADDR, BPDATA, BPADDR, BPDATA, BPDATA },
407 	{ 0x00, 0x04, 0x09, 0x00, 0x00 }, /* -2 */
408 	{ 0x00, 0x04, 0x09, 0x10, 0x00 }, /* -1 */
409 	{ 0x00, 0x04, 0x09, 0x20, 0x00 }, /*  0 */
410 	{ 0x00, 0x04, 0x09, 0x30, 0x00 }, /* +1 */
411 	{ 0x00, 0x04, 0x09, 0x40, 0x00 }, /* +2 */
412 };
413 
414 #define NUM_CONTRAST_LEVELS (5)
415 static const uint8_t contrast_regs[NUM_CONTRAST_LEVELS + 1][7] = {
416 	{ BPADDR, BPDATA, BPADDR, BPDATA, BPDATA, BPDATA, BPDATA },
417 	{ 0x00, 0x04, 0x07, 0x20, 0x18, 0x34, 0x06 }, /* -2 */
418 	{ 0x00, 0x04, 0x07, 0x20, 0x1c, 0x2a, 0x06 }, /* -1 */
419 	{ 0x00, 0x04, 0x07, 0x20, 0x20, 0x20, 0x06 }, /*  0 */
420 	{ 0x00, 0x04, 0x07, 0x20, 0x24, 0x16, 0x06 }, /* +1 */
421 	{ 0x00, 0x04, 0x07, 0x20, 0x28, 0x0c, 0x06 }, /* +2 */
422 };
423 
424 #define NUM_SATURATION_LEVELS (5)
425 static const uint8_t saturation_regs[NUM_SATURATION_LEVELS + 1][5] = {
426 	{ BPADDR, BPDATA, BPADDR, BPDATA, BPDATA },
427 	{ 0x00, 0x02, 0x03, 0x28, 0x28 }, /* -2 */
428 	{ 0x00, 0x02, 0x03, 0x38, 0x38 }, /* -1 */
429 	{ 0x00, 0x02, 0x03, 0x48, 0x48 }, /*  0 */
430 	{ 0x00, 0x02, 0x03, 0x58, 0x58 }, /* +1 */
431 	{ 0x00, 0x02, 0x03, 0x58, 0x58 }, /* +2 */
432 };
433 
434 struct ov2640_config {
435 	struct i2c_dt_spec i2c;
436 #if DT_INST_NODE_HAS_PROP(0, reset_gpios)
437 	struct gpio_dt_spec reset_gpio;
438 #endif
439 	uint8_t clock_rate_control;
440 };
441 
442 struct ov2640_data {
443 	struct video_format fmt;
444 };
445 
446 #define OV2640_VIDEO_FORMAT_CAP(width, height, format) \
447 	{ \
448 		.pixelformat = (format), \
449 		.width_min = (width), \
450 		.width_max = (width), \
451 		.height_min = (height), \
452 		.height_max = (height), \
453 		.width_step = 0, \
454 		.height_step = 0 \
455 	}
456 
457 static const struct video_format_cap fmts[] = {
458 	OV2640_VIDEO_FORMAT_CAP(160, 120, VIDEO_PIX_FMT_RGB565),   /* QQVGA */
459 	OV2640_VIDEO_FORMAT_CAP(176, 144, VIDEO_PIX_FMT_RGB565),   /* QCIF  */
460 	OV2640_VIDEO_FORMAT_CAP(240, 160, VIDEO_PIX_FMT_RGB565),   /* HQVGA */
461 	OV2640_VIDEO_FORMAT_CAP(240, 240, VIDEO_PIX_FMT_RGB565),   /* 240x240 */
462 	OV2640_VIDEO_FORMAT_CAP(320, 240, VIDEO_PIX_FMT_RGB565),   /* QVGA  */
463 	OV2640_VIDEO_FORMAT_CAP(352, 288, VIDEO_PIX_FMT_RGB565),   /* CIF   */
464 	OV2640_VIDEO_FORMAT_CAP(640, 480, VIDEO_PIX_FMT_RGB565),   /* VGA   */
465 	OV2640_VIDEO_FORMAT_CAP(800, 600, VIDEO_PIX_FMT_RGB565),   /* SVGA  */
466 	OV2640_VIDEO_FORMAT_CAP(1024, 768, VIDEO_PIX_FMT_RGB565),  /* XVGA  */
467 	OV2640_VIDEO_FORMAT_CAP(1280, 1024, VIDEO_PIX_FMT_RGB565), /* SXGA  */
468 	OV2640_VIDEO_FORMAT_CAP(1600, 1200, VIDEO_PIX_FMT_RGB565), /* UXGA  */
469 	OV2640_VIDEO_FORMAT_CAP(160, 120, VIDEO_PIX_FMT_JPEG),     /* QQVGA */
470 	OV2640_VIDEO_FORMAT_CAP(176, 144, VIDEO_PIX_FMT_JPEG),     /* QCIF  */
471 	OV2640_VIDEO_FORMAT_CAP(240, 160, VIDEO_PIX_FMT_JPEG),     /* HQVGA */
472 	OV2640_VIDEO_FORMAT_CAP(320, 240, VIDEO_PIX_FMT_JPEG),     /* QVGA  */
473 	OV2640_VIDEO_FORMAT_CAP(352, 288, VIDEO_PIX_FMT_JPEG),     /* CIF   */
474 	OV2640_VIDEO_FORMAT_CAP(640, 480, VIDEO_PIX_FMT_JPEG),     /* VGA   */
475 	OV2640_VIDEO_FORMAT_CAP(800, 600, VIDEO_PIX_FMT_JPEG),     /* SVGA  */
476 	OV2640_VIDEO_FORMAT_CAP(1024, 768, VIDEO_PIX_FMT_JPEG),    /* XVGA  */
477 	OV2640_VIDEO_FORMAT_CAP(1280, 1024, VIDEO_PIX_FMT_JPEG),   /* SXGA  */
478 	OV2640_VIDEO_FORMAT_CAP(1600, 1200, VIDEO_PIX_FMT_JPEG),   /* UXGA  */
479 	{ 0 }
480 };
481 
ov2640_write_reg(const struct i2c_dt_spec * spec,uint8_t reg_addr,uint8_t value)482 static int ov2640_write_reg(const struct i2c_dt_spec *spec, uint8_t reg_addr,
483 				uint8_t value)
484 {
485 	uint8_t tries = 3;
486 
487 	/**
488 	 * It rarely happens that the camera does not respond with ACK signal.
489 	 * In that case it usually responds on 2nd try but there is a 3rd one
490 	 * just to be sure that the connection error is not caused by driver
491 	 * itself.
492 	 */
493 	while (tries--) {
494 		if (!i2c_reg_write_byte_dt(spec, reg_addr, value)) {
495 			return 0;
496 		}
497 		/* If writing failed wait 5ms before next attempt */
498 		k_msleep(5);
499 	}
500 	LOG_ERR("failed to write 0x%x to 0x%x", value, reg_addr);
501 
502 	return -1;
503 }
504 
ov2640_read_reg(const struct i2c_dt_spec * spec,uint8_t reg_addr)505 static int ov2640_read_reg(const struct i2c_dt_spec *spec, uint8_t reg_addr)
506 {
507 	uint8_t tries = 3;
508 	uint8_t value;
509 
510 	/**
511 	 * It rarely happens that the camera does not respond with ACK signal.
512 	 * In that case it usually responds on 2nd try but there is a 3rd one
513 	 * just to be sure that the connection error is not caused by driver
514 	 * itself.
515 	 */
516 	while (tries--) {
517 		if (!i2c_reg_read_byte_dt(spec, reg_addr, &value)) {
518 			return value;
519 		}
520 		/* If reading failed wait 5ms before next attempt */
521 		k_msleep(5);
522 	}
523 	LOG_ERR("failed to read 0x%x register", reg_addr);
524 
525 	return -1;
526 }
527 
ov2640_write_all(const struct device * dev,const struct ov2640_reg * regs,uint16_t reg_num)528 static int ov2640_write_all(const struct device *dev,
529 				const struct ov2640_reg *regs, uint16_t reg_num)
530 {
531 	uint16_t i = 0;
532 	const struct ov2640_config *cfg = dev->config;
533 
534 	for (i = 0; i < reg_num; i++) {
535 		int err;
536 
537 		err = ov2640_write_reg(&cfg->i2c, regs[i].addr, regs[i].value);
538 		if (err) {
539 			return err;
540 		}
541 	}
542 
543 	return 0;
544 }
545 
ov2640_soft_reset(const struct device * dev)546 static int ov2640_soft_reset(const struct device *dev)
547 {
548 	int ret = 0;
549 	const struct ov2640_config *cfg = dev->config;
550 
551 	/* Switch to DSP register bank */
552 	ret |= ov2640_write_reg(&cfg->i2c, BANK_SEL, BANK_SEL_SENSOR);
553 
554 	/* Initiate system reset */
555 	ret |= ov2640_write_reg(&cfg->i2c, COM7, COM7_SRST);
556 
557 	return ret;
558 }
559 
ov2640_set_level(const struct device * dev,int level,int max_level,int cols,const uint8_t regs[][cols])560 static int ov2640_set_level(const struct device *dev, int level,
561 				int max_level, int cols, const uint8_t regs[][cols])
562 {
563 	int ret = 0;
564 	const struct ov2640_config *cfg = dev->config;
565 
566 	level += (max_level / 2 + 1);
567 	if (level < 0 || level > max_level) {
568 		return -ENOTSUP;
569 	}
570 
571 	/* Switch to DSP register bank */
572 	ret |= ov2640_write_reg(&cfg->i2c, BANK_SEL, BANK_SEL_DSP);
573 
574 	for (int i = 0; i < (ARRAY_SIZE(regs[0]) / sizeof(regs[0][0])); i++)	{
575 		ret |= ov2640_write_reg(&cfg->i2c, regs[0][i], regs[level][i]);
576 	}
577 
578 	return ret;
579 }
580 
ov2640_set_brightness(const struct device * dev,int level)581 static int ov2640_set_brightness(const struct device *dev, int level)
582 {
583 	int ret = 0;
584 
585 	ret = ov2640_set_level(dev, level, NUM_BRIGHTNESS_LEVELS,
586 			ARRAY_SIZE(brightness_regs[0]), brightness_regs);
587 
588 	if (ret == -ENOTSUP) {
589 		LOG_ERR("Brightness level %d not supported", level);
590 	}
591 
592 	return ret;
593 }
594 
ov2640_set_saturation(const struct device * dev,int level)595 static int ov2640_set_saturation(const struct device *dev, int level)
596 {
597 	int ret = 0;
598 
599 	ret = ov2640_set_level(dev, level, NUM_SATURATION_LEVELS,
600 			ARRAY_SIZE(saturation_regs[0]), saturation_regs);
601 
602 	if (ret == -ENOTSUP) {
603 		LOG_ERR("Saturation level %d not supported", level);
604 	}
605 
606 	return ret;
607 }
608 
ov2640_set_contrast(const struct device * dev,int level)609 static int ov2640_set_contrast(const struct device *dev, int level)
610 {
611 	int ret = 0;
612 
613 	ret = ov2640_set_level(dev, level, NUM_CONTRAST_LEVELS,
614 			ARRAY_SIZE(contrast_regs[0]), contrast_regs);
615 
616 	if (ret == -ENOTSUP) {
617 		LOG_ERR("Contrast level %d not supported", level);
618 	}
619 
620 	return ret;
621 }
622 
ov2640_set_output_format(const struct device * dev,int output_format)623 static int ov2640_set_output_format(const struct device *dev,
624 				int output_format)
625 {
626 	int ret = 0;
627 	const struct ov2640_config *cfg = dev->config;
628 
629 	/* Switch to DSP register bank */
630 	ret |= ov2640_write_reg(&cfg->i2c, BANK_SEL, BANK_SEL_DSP);
631 
632 	if (output_format == VIDEO_PIX_FMT_JPEG)	{
633 		/* Enable JPEG compression */
634 		ret |= ov2640_write_reg(&cfg->i2c, IMAGE_MODE, IMAGE_MODE_JPEG_EN);
635 	} else if (output_format == VIDEO_PIX_FMT_RGB565)	{
636 		/* Disable JPEG compression and set output to RGB565 */
637 		ret |= ov2640_write_reg(&cfg->i2c, IMAGE_MODE, IMAGE_MODE_RGB565);
638 	} else {
639 		LOG_ERR("Image format not supported");
640 		return -ENOTSUP;
641 	}
642 	k_msleep(30);
643 
644 	return ret;
645 }
646 
ov2640_set_quality(const struct device * dev,int qs)647 static int ov2640_set_quality(const struct device *dev, int qs)
648 {
649 	int ret = 0;
650 	const struct ov2640_config *cfg = dev->config;
651 
652 	/* Switch to DSP register bank */
653 	ret |= ov2640_write_reg(&cfg->i2c, BANK_SEL, BANK_SEL_DSP);
654 
655 	/* Write QS register */
656 	ret |= ov2640_write_reg(&cfg->i2c, QS, qs);
657 
658 	return ret;
659 }
660 
ov2640_set_colorbar(const struct device * dev,uint8_t enable)661 static int ov2640_set_colorbar(const struct device *dev, uint8_t enable)
662 {
663 	int ret = 0;
664 	const struct ov2640_config *cfg = dev->config;
665 
666 	uint8_t reg;
667 
668 	/* Switch to SENSOR register bank */
669 	ret |= ov2640_write_reg(&cfg->i2c, BANK_SEL, BANK_SEL_SENSOR);
670 
671 	/* Update COM7 to enable/disable color bar test pattern */
672 	reg = ov2640_read_reg(&cfg->i2c, COM7);
673 
674 	if (enable) {
675 		reg |= COM7_COLOR_BAR;
676 	} else {
677 		reg &= ~COM7_COLOR_BAR;
678 	}
679 
680 	ret |= ov2640_write_reg(&cfg->i2c, COM7, reg);
681 
682 	return ret;
683 }
684 
ov2640_set_white_bal(const struct device * dev,int enable)685 static int ov2640_set_white_bal(const struct device *dev, int enable)
686 {
687 	int ret = 0;
688 	const struct ov2640_config *cfg = dev->config;
689 
690 	uint8_t reg;
691 
692 	/* Switch to SENSOR register bank */
693 	ret |= ov2640_write_reg(&cfg->i2c, BANK_SEL, BANK_SEL_SENSOR);
694 
695 	/* Update CTRL1 to enable/disable automatic white balance*/
696 	reg = ov2640_read_reg(&cfg->i2c, CTRL1);
697 
698 	if (enable) {
699 		reg |= CTRL1_AWB;
700 	} else {
701 		reg &= ~CTRL1_AWB;
702 	}
703 
704 	ret |= ov2640_write_reg(&cfg->i2c, CTRL1, reg);
705 
706 	return ret;
707 }
708 
ov2640_set_gain_ctrl(const struct device * dev,int enable)709 static int ov2640_set_gain_ctrl(const struct device *dev, int enable)
710 {
711 	int ret = 0;
712 	const struct ov2640_config *cfg = dev->config;
713 
714 	uint8_t reg;
715 
716 	/* Switch to SENSOR register bank */
717 	ret |= ov2640_write_reg(&cfg->i2c, BANK_SEL, BANK_SEL_SENSOR);
718 
719 	/* Update COM8 to enable/disable automatic gain control */
720 	reg = ov2640_read_reg(&cfg->i2c, COM8);
721 
722 	if (enable) {
723 		reg |= COM8_AGC_EN;
724 	} else {
725 		reg &= ~COM8_AGC_EN;
726 	}
727 
728 	ret |= ov2640_write_reg(&cfg->i2c, COM8, reg);
729 
730 	return ret;
731 }
732 
ov2640_set_exposure_ctrl(const struct device * dev,int enable)733 static int ov2640_set_exposure_ctrl(const struct device *dev, int enable)
734 {
735 	int ret = 0;
736 	const struct ov2640_config *cfg = dev->config;
737 
738 	uint8_t reg;
739 
740 	/* Switch to SENSOR register bank */
741 	ret |= ov2640_write_reg(&cfg->i2c, BANK_SEL, BANK_SEL_SENSOR);
742 
743 	/* Update COM8  to enable/disable automatic exposure control */
744 	reg = ov2640_read_reg(&cfg->i2c, COM8);
745 
746 	if (enable) {
747 		reg |= COM8_AEC_EN;
748 	} else {
749 		reg &= ~COM8_AEC_EN;
750 	}
751 
752 	ret |= ov2640_write_reg(&cfg->i2c, COM8, reg);
753 
754 	return ret;
755 }
756 
ov2640_set_horizontal_mirror(const struct device * dev,int enable)757 static int ov2640_set_horizontal_mirror(const struct device *dev,
758 				int enable)
759 {
760 	int ret = 0;
761 	const struct ov2640_config *cfg = dev->config;
762 
763 	uint8_t reg;
764 
765 	/* Switch to SENSOR register bank */
766 	ret |= ov2640_write_reg(&cfg->i2c, BANK_SEL, BANK_SEL_SENSOR);
767 
768 	/* Update REG04 to enable/disable horizontal mirror */
769 	reg = ov2640_read_reg(&cfg->i2c, REG04);
770 
771 	if (enable) {
772 		reg |= REG04_HFLIP_IMG;
773 	} else {
774 		reg &= ~REG04_HFLIP_IMG;
775 	}
776 
777 	ret |= ov2640_write_reg(&cfg->i2c, REG04, reg);
778 
779 	return ret;
780 }
781 
ov2640_set_vertical_flip(const struct device * dev,int enable)782 static int ov2640_set_vertical_flip(const struct device *dev, int enable)
783 {
784 	int ret = 0;
785 	const struct ov2640_config *cfg = dev->config;
786 
787 	uint8_t reg;
788 
789 	/* Switch to SENSOR register bank */
790 	ret |= ov2640_write_reg(&cfg->i2c, BANK_SEL, BANK_SEL_SENSOR);
791 
792 	/* Update REG04 to enable/disable vertical flip */
793 	reg = ov2640_read_reg(&cfg->i2c, REG04);
794 
795 	if (enable) {
796 		reg |= REG04_VFLIP_IMG | REG04_VREF_EN;
797 	} else {
798 		reg &= ~(REG04_VFLIP_IMG | REG04_VREF_EN);
799 	}
800 
801 	ret |= ov2640_write_reg(&cfg->i2c, REG04, reg);
802 
803 	return ret;
804 }
805 
ov2640_set_resolution(const struct device * dev,uint16_t img_width,uint16_t img_height)806 static int ov2640_set_resolution(const struct device *dev,
807 				uint16_t img_width, uint16_t img_height)
808 {
809 	int ret = 0;
810 	const struct ov2640_config *cfg = dev->config;
811 
812 	uint16_t w = img_width;
813 	uint16_t h = img_height;
814 
815 	/* Disable DSP */
816 	ret |= ov2640_write_reg(&cfg->i2c, BANK_SEL, BANK_SEL_DSP);
817 	ret |= ov2640_write_reg(&cfg->i2c, R_BYPASS, R_BYPASS_DSP_BYPAS);
818 
819 	/* Write output width */
820 	ret |= ov2640_write_reg(&cfg->i2c, ZMOW, (w >> 2) & 0xFF); /* OUTW[7:0] (real/4) */
821 	ret |= ov2640_write_reg(&cfg->i2c, ZMOH, (h >> 2) & 0xFF); /* OUTH[7:0] (real/4) */
822 	ret |= ov2640_write_reg(&cfg->i2c, ZMHH, ((h >> 8) & 0x04) |
823 							((w>>10) & 0x03)); /* OUTH[8]/OUTW[9:8] */
824 
825 	/* Set CLKRC */
826 	ret |= ov2640_write_reg(&cfg->i2c, BANK_SEL, BANK_SEL_SENSOR);
827 	ret |= ov2640_write_reg(&cfg->i2c, CLKRC, cfg->clock_rate_control);
828 
829 	/* Write DSP input registers */
830 	ov2640_write_all(dev, uxga_regs, ARRAY_SIZE(uxga_regs));
831 
832 	/* Enable DSP */
833 	ret |= ov2640_write_reg(&cfg->i2c, BANK_SEL, BANK_SEL_DSP);
834 	ret |= ov2640_write_reg(&cfg->i2c, R_BYPASS, R_BYPASS_DSP_EN);
835 
836 	k_msleep(30);
837 
838 	return ret;
839 }
840 
ov2640_check_connection(const struct device * dev)841 uint8_t ov2640_check_connection(const struct device *dev)
842 {
843 	int ret = 0;
844 	const struct ov2640_config *cfg = dev->config;
845 
846 	uint8_t reg_pid_val, reg_ver_val;
847 
848 	ret |= ov2640_write_reg(&cfg->i2c, BANK_SEL, BANK_SEL_SENSOR);
849 	reg_pid_val = ov2640_read_reg(&cfg->i2c, REG_PID);
850 	reg_ver_val = ov2640_read_reg(&cfg->i2c, REG_VER);
851 
852 	if (REG_PID_VAL != reg_pid_val || REG_VER_VAL != reg_ver_val) {
853 		LOG_ERR("OV2640 not detected\n");
854 		return -ENODEV;
855 	}
856 
857 	return ret;
858 }
859 
ov2640_set_fmt(const struct device * dev,enum video_endpoint_id ep,struct video_format * fmt)860 static int ov2640_set_fmt(const struct device *dev,
861 			enum video_endpoint_id ep, struct video_format *fmt)
862 {
863 	struct ov2640_data *drv_data = dev->data;
864 	uint16_t width, height;
865 	int ret = 0;
866 	int i = 0;
867 
868 	/* We only support RGB565 and JPEG pixel formats */
869 	if (fmt->pixelformat != VIDEO_PIX_FMT_RGB565 && fmt->pixelformat != VIDEO_PIX_FMT_JPEG) {
870 		LOG_ERR("ov2640 camera supports only RGB565 and JPG pixelformats!");
871 		return -ENOTSUP;
872 	}
873 
874 	width = fmt->width;
875 	height = fmt->height;
876 
877 	if (!memcmp(&drv_data->fmt, fmt, sizeof(drv_data->fmt))) {
878 		/* nothing to do */
879 		return 0;
880 	}
881 
882 	drv_data->fmt = *fmt;
883 
884 	/* Set output format */
885 	ret |= ov2640_set_output_format(dev, fmt->pixelformat);
886 
887 	/* Check if camera is capable of handling given format */
888 	while (fmts[i].pixelformat) {
889 		if (fmts[i].width_min == width && fmts[i].height_min == height &&
890 			fmts[i].pixelformat == fmt->pixelformat) {
891 			/* Set window size */
892 			ret |= ov2640_set_resolution(dev, fmt->width, fmt->height);
893 			return ret;
894 		}
895 		i++;
896 	}
897 
898 	/* Camera is not capable of handling given format */
899 	LOG_ERR("Image format not supported\n");
900 	return -ENOTSUP;
901 }
902 
ov2640_get_fmt(const struct device * dev,enum video_endpoint_id ep,struct video_format * fmt)903 static int ov2640_get_fmt(const struct device *dev,
904 			enum video_endpoint_id ep, struct video_format *fmt)
905 {
906 	struct ov2640_data *drv_data = dev->data;
907 
908 	*fmt = drv_data->fmt;
909 
910 	return 0;
911 }
912 
ov2640_stream_start(const struct device * dev)913 static int ov2640_stream_start(const struct device *dev)
914 {
915 	return 0;
916 }
917 
ov2640_stream_stop(const struct device * dev)918 static int ov2640_stream_stop(const struct device *dev)
919 {
920 	return 0;
921 }
922 
ov2640_get_caps(const struct device * dev,enum video_endpoint_id ep,struct video_caps * caps)923 static int ov2640_get_caps(const struct device *dev,
924 			   enum video_endpoint_id ep,
925 			   struct video_caps *caps)
926 {
927 	caps->format_caps = fmts;
928 	return 0;
929 }
930 
ov2640_set_ctrl(const struct device * dev,unsigned int cid,void * value)931 static int ov2640_set_ctrl(const struct device *dev,
932 				unsigned int cid, void *value)
933 {
934 	int ret = 0;
935 
936 	switch (cid) {
937 	case VIDEO_CID_HFLIP:
938 		ret |= ov2640_set_horizontal_mirror(dev, (int)value);
939 		break;
940 	case VIDEO_CID_VFLIP:
941 		ret |= ov2640_set_vertical_flip(dev, (int)value);
942 		break;
943 	case VIDEO_CID_EXPOSURE:
944 		ret |= ov2640_set_exposure_ctrl(dev, (int)value);
945 		break;
946 	case VIDEO_CID_GAIN:
947 		ret |= ov2640_set_gain_ctrl(dev, (int)value);
948 		break;
949 	case VIDEO_CID_BRIGHTNESS:
950 		ret |= ov2640_set_brightness(dev, (int)value);
951 		break;
952 	case VIDEO_CID_SATURATION:
953 		ret |= ov2640_set_saturation(dev, (int)value);
954 		break;
955 	case VIDEO_CID_WHITE_BALANCE_TEMPERATURE:
956 		ret |= ov2640_set_white_bal(dev, (int)value);
957 		break;
958 	case VIDEO_CID_CONTRAST:
959 		ret |= ov2640_set_contrast(dev, (int)value);
960 		break;
961 	case VIDEO_CID_TEST_PATTERN:
962 		ret |= ov2640_set_colorbar(dev, (int)value);
963 		break;
964 	case VIDEO_CID_JPEG_COMPRESSION_QUALITY:
965 		ret |= ov2640_set_quality(dev, (int)value);
966 		break;
967 	default:
968 		return -ENOTSUP;
969 	}
970 
971 	return ret;
972 }
973 
974 static DEVICE_API(video, ov2640_driver_api) = {
975 	.set_format = ov2640_set_fmt,
976 	.get_format = ov2640_get_fmt,
977 	.get_caps = ov2640_get_caps,
978 	.stream_start = ov2640_stream_start,
979 	.stream_stop = ov2640_stream_stop,
980 	.set_ctrl = ov2640_set_ctrl,
981 };
982 
ov2640_init(const struct device * dev)983 static int ov2640_init(const struct device *dev)
984 {
985 	struct video_format fmt;
986 	int ret = 0;
987 
988 #if DT_INST_NODE_HAS_PROP(0, reset_gpios)
989 	const struct ov2640_config *cfg = dev->config;
990 
991 	ret = gpio_pin_configure_dt(&cfg->reset_gpio, GPIO_OUTPUT_ACTIVE);
992 	if (ret) {
993 		return ret;
994 	}
995 
996 	gpio_pin_set_dt(&cfg->reset_gpio, 0);
997 	k_sleep(K_MSEC(1));
998 	gpio_pin_set_dt(&cfg->reset_gpio, 1);
999 	k_sleep(K_MSEC(1));
1000 #endif
1001 
1002 	ret = ov2640_check_connection(dev);
1003 
1004 	if (ret) {
1005 		return ret;
1006 	}
1007 
1008 	ov2640_soft_reset(dev);
1009 	k_msleep(300);
1010 
1011 	ov2640_write_all(dev, default_regs, ARRAY_SIZE(default_regs));
1012 
1013 	/* set default/init format SVGA RGB565 */
1014 	fmt.pixelformat = VIDEO_PIX_FMT_RGB565;
1015 	fmt.width = SVGA_HSIZE;
1016 	fmt.height = SVGA_VSIZE;
1017 	fmt.pitch = SVGA_HSIZE * 2;
1018 	ret = ov2640_set_fmt(dev, VIDEO_EP_OUT, &fmt);
1019 	if (ret) {
1020 		LOG_ERR("Unable to configure default format");
1021 		return -EIO;
1022 	}
1023 
1024 	ret |= ov2640_set_exposure_ctrl(dev, 1);
1025 	ret |= ov2640_set_white_bal(dev, 1);
1026 
1027 	return ret;
1028 }
1029 
1030 /* Unique Instance */
1031 static const struct ov2640_config ov2640_cfg_0 = {
1032 	.i2c = I2C_DT_SPEC_INST_GET(0),
1033 #if DT_INST_NODE_HAS_PROP(0, reset_gpios)
1034 	.reset_gpio = GPIO_DT_SPEC_INST_GET(0, reset_gpios),
1035 #endif
1036 	.clock_rate_control = DT_INST_PROP(0, clock_rate_control),
1037 };
1038 static struct ov2640_data ov2640_data_0;
1039 
ov2640_init_0(const struct device * dev)1040 static int ov2640_init_0(const struct device *dev)
1041 {
1042 	const struct ov2640_config *cfg = dev->config;
1043 
1044 	if (!device_is_ready(cfg->i2c.bus)) {
1045 		LOG_ERR("Bus device is not ready");
1046 		return -ENODEV;
1047 	}
1048 
1049 #if DT_INST_NODE_HAS_PROP(0, reset_gpios)
1050 	if (!gpio_is_ready_dt(&cfg->reset_gpio)) {
1051 		LOG_ERR("%s: device %s is not ready", dev->name,
1052 				cfg->reset_gpio.port->name);
1053 		return -ENODEV;
1054 	}
1055 #endif
1056 
1057 	uint32_t i2c_cfg = I2C_MODE_CONTROLLER |
1058 					I2C_SPEED_SET(I2C_SPEED_STANDARD);
1059 
1060 	if (i2c_configure(cfg->i2c.bus, i2c_cfg)) {
1061 		LOG_ERR("Failed to configure ov2640 i2c interface.");
1062 	}
1063 
1064 	return ov2640_init(dev);
1065 }
1066 
1067 DEVICE_DT_INST_DEFINE(0, &ov2640_init_0, NULL,
1068 			&ov2640_data_0, &ov2640_cfg_0,
1069 			POST_KERNEL, CONFIG_VIDEO_INIT_PRIORITY,
1070 			&ov2640_driver_api);
1071