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