1 /*
2 * Copyright (c) 2021-2023 HPMicro
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include "hpm_ov5640.h"
9
10 static const ov5640_reg_val_t ov5640_init_param[] = {
11 {0x3008, 0x42},
12 /* System setting. */
13 {0x3103, 0x03},
14 {0x3000, 0x00},
15 {0x3004, 0xff},
16 {0x3002, 0x1c},
17 {0x3006, 0xc3},
18 {0x302e, 0x08},
19 {0x3037, 0x13},
20 {0x3108, 0x01},
21 {0x3618, 0x00},
22 {0x3612, 0x29},
23 {0x3708, 0x64},
24 {0x3709, 0x52},
25 {0x370c, 0x03},
26 {0x3820, 0x41},
27 {0x3821, 0x07},
28 {0x3630, 0x36},
29 {0x3631, 0x0e},
30 {0x3632, 0xe2},
31 {0x3633, 0x12},
32 {0x3621, 0xe0},
33 {0x3704, 0xa0},
34 {0x3703, 0x5a},
35 {0x3715, 0x78},
36 {0x3717, 0x01},
37 {0x370b, 0x60},
38 {0x3705, 0x1a},
39 {0x3905, 0x02},
40 {0x3906, 0x10},
41 {0x3901, 0x0a},
42 {0x3731, 0x12},
43 {0x3600, 0x08},
44 {0x3601, 0x33},
45 {0x302d, 0x60},
46 {0x3620, 0x52},
47 {0x371b, 0x20},
48 {0x471c, 0x50},
49 {0x3a13, 0x43},
50 {0x3a18, 0x00},
51 {0x3a19, 0x7c},
52 {0x3635, 0x13},
53 {0x3636, 0x03},
54 {0x3634, 0x40},
55 {0x3622, 0x01},
56 {0x3c01, 0x00},
57 {0x3a00, 0x58},
58 {0x4001, 0x02},
59 {0x4004, 0x02},
60 {0x4005, 0x1a},
61 {0x5001, 0xa3},
62
63 /* AEC */
64 {0x3a0f, 0x30},
65 {0x3a10, 0x28},
66 {0x3a1b, 0x30},
67 {0x3a1e, 0x26},
68 {0x3a11, 0x60},
69 {0x3a1f, 0x14},
70
71 /* AWB */
72 {0x5180, 0xff},
73 {0x5181, 0xf2},
74 {0x5182, 0x00},
75 {0x5183, 0x14},
76 {0x5184, 0x25},
77 {0x5185, 0x24},
78 {0x5186, 0x09},
79 {0x5187, 0x09},
80 {0x5188, 0x09},
81 {0x5189, 0x88},
82 {0x518a, 0x54},
83 {0x518b, 0xee},
84 {0x518c, 0xb2},
85 {0x518d, 0x50},
86 {0x518e, 0x34},
87 {0x518f, 0x6b},
88 {0x5190, 0x46},
89 {0x5191, 0xf8},
90 {0x5192, 0x04},
91 {0x5193, 0x70},
92 {0x5194, 0xf0},
93 {0x5195, 0xf0},
94 {0x5196, 0x03},
95 {0x5197, 0x01},
96 {0x5198, 0x04},
97 {0x5199, 0x6c},
98 {0x519a, 0x04},
99 {0x519b, 0x00},
100 {0x519c, 0x09},
101 {0x519d, 0x2b},
102 {0x519e, 0x38},
103
104 /* Color Matrix */
105 {0x5381, 0x1e},
106 {0x5382, 0x5b},
107 {0x5383, 0x08},
108 {0x5384, 0x0a},
109 {0x5385, 0x7e},
110 {0x5386, 0x88},
111 {0x5387, 0x7c},
112 {0x5388, 0x6c},
113 {0x5389, 0x10},
114 {0x538a, 0x01},
115 {0x538b, 0x98},
116
117 /* sharp */
118 {0x5300, 0x08},
119 {0x5301, 0x30},
120 {0x5302, 0x10},
121 {0x5303, 0x00},
122 {0x5304, 0x08},
123 {0x5305, 0x30},
124 {0x5306, 0x08},
125 {0x5307, 0x16},
126 {0x5309, 0x08},
127 {0x530a, 0x30},
128 {0x530b, 0x04},
129 {0x530c, 0x06},
130
131 /* Gamma */
132 {0x5480, 0x01},
133 {0x5481, 0x08},
134 {0x5482, 0x14},
135 {0x5483, 0x28},
136 {0x5484, 0x51},
137 {0x5485, 0x65},
138 {0x5486, 0x71},
139 {0x5487, 0x7d},
140 {0x5488, 0x87},
141 {0x5489, 0x91},
142 {0x548a, 0x9a},
143 {0x548b, 0xaa},
144 {0x548c, 0xb8},
145 {0x548d, 0xcd},
146 {0x548e, 0xdd},
147 {0x548f, 0xea},
148 {0x5490, 0x1d},
149
150 /* UV adjust. */
151 {0x5580, 0x02},
152 {0x5583, 0x40},
153 {0x5584, 0x10},
154 {0x5589, 0x10},
155 {0x558a, 0x00},
156 {0x558b, 0xf8},
157
158 /* Lens correction. */
159 {0x5800, 0x23},
160 {0x5801, 0x14},
161 {0x5802, 0x0f},
162 {0x5803, 0x0f},
163 {0x5804, 0x12},
164 {0x5805, 0x26},
165 {0x5806, 0x0c},
166 {0x5807, 0x08},
167 {0x5808, 0x05},
168 {0x5809, 0x05},
169 {0x580a, 0x08},
170 {0x580b, 0x0d},
171 {0x580c, 0x08},
172 {0x580d, 0x03},
173 {0x580e, 0x00},
174 {0x580f, 0x00},
175 {0x5810, 0x03},
176 {0x5811, 0x09},
177 {0x5812, 0x07},
178 {0x5813, 0x03},
179 {0x5814, 0x00},
180 {0x5815, 0x01},
181 {0x5816, 0x03},
182 {0x5817, 0x08},
183 {0x5818, 0x0d},
184 {0x5819, 0x08},
185 {0x581a, 0x05},
186 {0x581b, 0x06},
187 {0x581c, 0x08},
188 {0x581d, 0x0e},
189 {0x581e, 0x29},
190 {0x581f, 0x17},
191 {0x5820, 0x11},
192 {0x5821, 0x11},
193 {0x5822, 0x15},
194 {0x5823, 0x28},
195 {0x5824, 0x46},
196 {0x5825, 0x26},
197 {0x5826, 0x08},
198 {0x5827, 0x26},
199 {0x5828, 0x64},
200 {0x5829, 0x26},
201 {0x582a, 0x24},
202 {0x582b, 0x22},
203 {0x582c, 0x24},
204 {0x582d, 0x24},
205 {0x582e, 0x06},
206 {0x582f, 0x22},
207 {0x5830, 0x40},
208 {0x5831, 0x42},
209 {0x5832, 0x24},
210 {0x5833, 0x26},
211 {0x5834, 0x24},
212 {0x5835, 0x22},
213 {0x5836, 0x22},
214 {0x5837, 0x26},
215 {0x5838, 0x44},
216 {0x5839, 0x24},
217 {0x583a, 0x26},
218 {0x583b, 0x28},
219 {0x583c, 0x42},
220 {0x583d, 0xce},
221 {0x481c, 0x00},
222 {0x481d, 0x1},
223
224 /* 50/60Hz detection */
225 {0x3a02, 0x0b}, /* 60Hz max exposure, night mode 5fps */
226 {0x3a03, 0x88}, /* 60Hz max exposure */
227 {0x3a14, 0x0b}, /* 50Hz max exposure, night mode 5fps */
228 {0x3a15, 0x88}, /* 50Hz max exposure */
229 {0x3c01, 0x34}, /* Band auto, bit[7] */
230 {0x3c04, 0x28}, /* threshold low sum */
231 {0x3c05, 0x98}, /* threshold high sum */
232 {0x3c06, 0x00}, /* light meter 1 threshold[15:8] */
233 {0x3c07, 0x08}, /* light meter 1 threshold[7:0] */
234 {0x3c08, 0x00}, /* light meter 2 threshold[15:8] */
235 {0x3c09, 0x1c}, /* light meter 2 threshold[7:0] */
236 {0x3c0a, 0x9c}, /* sample number[15:8] */
237 {0x3c0b, 0x40}, /* sample number[7:0] */
238 {0x3708, 0x64},
239 {0x4001, 0x02}, /* BLC start from line 2 */
240 {0x4005, 0x1a}, /* BLC always update */
241 {0x3000, 0x00}, /* enable blocks */
242 {0x3004, 0xff}, /* enable clocks */
243 {0x302e, 0x00},
244 {0x440e, 0x00},
245 {0x5000, 0xa7}, /* Lenc on, raw gamma on, BPC on, WPC on, CIP on */
246 };
247
248 /* Resolution configuration */
249 static const ov5640_reg_val_t ov5640_resolution_800_480_param[] = {
250 {0x3800, 0x00}, {0x3801, 0x00}, {0x3802, 0x00}, {0x3803, 0x04},
251 {0x3804, 0x0a}, {0x3805, 0x3f}, {0x3806, 0x07}, {0x3807, 0x9b},
252 {0x3808, 0x03}, {0x3809, 0x20}, {0x380A, 0x01}, {0x380B, 0xe0},
253 {0x380C, 0x07}, {0x380D, 0x68}, {0x380E, 0x03}, {0x380F, 0xd8},
254 {0x3810, 0x00}, {0x3811, 0x10}, {0x3812, 0x00}, {0x3813, 0x06}, {0x3814, 0x31}, {0x3815, 0x31},
255 };
256
257 static const ov5640_reg_val_t ov5640_resolution_vga_param[] = {
258 {0x3800, 0x00}, {0x3801, 0x00}, {0x3802, 0x00}, {0x3803, 0x04},
259 {0x3804, 0x0a}, {0x3805, 0x3f}, {0x3806, 0x07}, {0x3807, 0x9b},
260 {0x3808, 0x02}, {0x3809, 0x80}, {0x380A, 0x01}, {0x380B, 0xe0},
261 {0x380C, 0x07}, {0x380D, 0x68}, {0x380E, 0x03}, {0x380F, 0xd8},
262 {0x3810, 0x00}, {0x3811, 0x10}, {0x3812, 0x00}, {0x3813, 0x06}, {0x3814, 0x31}, {0x3815, 0x31},
263 };
264
265 static const ov5640_reg_val_t ov5640_resolution_qvga_param[] = {
266 {0x3800, 0x00}, {0x3801, 0x00}, {0x3802, 0x00}, {0x3803, 0x04},
267 {0x3804, 0x0a}, {0x3805, 0x3f}, {0x3806, 0x07}, {0x3807, 0x9b},
268 {0x3808, 0x01}, {0x3809, 0x40}, {0x380A, 0x00}, {0x380B, 0xf0},
269 {0x380C, 0x07}, {0x380D, 0x68}, {0x380E, 0x03}, {0x380F, 0xd8},
270 {0x3810, 0x00}, {0x3811, 0x10}, {0x3812, 0x00}, {0x3813, 0x06}, {0x3814, 0x31}, {0x3815, 0x31},
271 };
272
273 static const ov5640_reg_val_t ov5640_resolution_480_272_param[] = {
274 {0x3800, 0x00}, {0x3801, 0x00}, {0x3802, 0x00}, {0x3803, 0xfa},
275 {0x3804, 0x0a}, {0x3805, 0x3f}, {0x3806, 0x06}, {0x3807, 0xa9},
276 {0x3808, 0x01}, {0x3809, 0xE0}, {0x380A, 0x01}, {0x380B, 0x10},
277 {0x380C, 0x07}, {0x380D, 0x64}, {0x380E, 0x02}, {0x380F, 0xe4},
278 {0x3810, 0x00}, {0x3811, 0x10}, {0x3812, 0x00}, {0x3813, 0x04}, {0x3814, 0x31}, {0x3815, 0x31},
279 };
280
281 static const ov5640_reg_val_t ov5640_resolution_720p_param[] = {
282 {0x3800, 0x00}, {0x3801, 0x00}, {0x3802, 0x00}, {0x3803, 0xfa},
283 {0x3804, 0x0a}, {0x3805, 0x3f}, {0x3806, 0x06}, {0x3807, 0xa9},
284 {0x3808, 0x05}, {0x3809, 0x00}, {0x380A, 0x02}, {0x380B, 0xd0},
285 {0x380C, 0x07}, {0x380D, 0x64}, {0x380E, 0x02}, {0x380F, 0xe4},
286 {0x3810, 0x00}, {0x3811, 0x10}, {0x3812, 0x00}, {0x3813, 0x04}, {0x3814, 0x31}, {0x3815, 0x31},
287 };
288
289 static const ov5640_reg_val_t ov5640_resolution_1080p_param[] = {
290 {0x3800, 0x01}, {0x3801, 0x50}, {0x3802, 0x01}, {0x3803, 0xb2},
291 {0x3804, 0x08}, {0x3805, 0xef}, {0x3806, 0x05}, {0x3807, 0xf1},
292 {0x3808, 0x07}, {0x3809, 0x80}, {0x380A, 0x04}, {0x380B, 0x38},
293 {0x380C, 0x09}, {0x380D, 0xc4}, {0x380E, 0x04}, {0x380F, 0x60},
294 {0x3810, 0x00}, {0x3811, 0x10}, {0x3812, 0x00}, {0x3813, 0x04}, {0x3814, 0x11}, {0x3815, 0x11},
295 };
296
297 /* DVP clock */
298 static const ov5640_clock_config_t ov5640_dvp_clock_configs[] = {
299 {
300 .resolution = (uint32_t)video_resolution_800_480,
301 .pllctrl1 = 0x11,
302 .pllctrl2 = 0x46,
303 .vfifoctrl0c = 0x22,
304 .pclkdiv = 0x02,
305 .pclkperiod = 0x22,
306 },
307 {
308 .resolution = (uint32_t)video_resolution_vga,
309 .pllctrl1 = 0x11,
310 .pllctrl2 = 0x46,
311 .vfifoctrl0c = 0x22,
312 .pclkdiv = 0x02,
313 .pclkperiod = 0x22,
314 },
315 {
316 .resolution = (uint32_t)video_resolution_qvga,
317 .pllctrl1 = 0x11,
318 .pllctrl2 = 0x46,
319 .vfifoctrl0c = 0x22,
320 .pclkdiv = 0x02,
321 .pclkperiod = 0x22,
322 },
323 {
324 .resolution = (uint32_t)video_resolution_480_272,
325 .pllctrl1 = 0x21,
326 .pllctrl2 = 0x69,
327 .vfifoctrl0c = 0x20,
328 .pclkdiv = 0x04,
329 .pclkperiod = 0x16,
330 },
331 {
332 .resolution = (uint32_t)video_resolution_720p,
333 .pllctrl1 = 0x21,
334 .pllctrl2 = 0x69,
335 .vfifoctrl0c = 0x20,
336 .pclkdiv = 0x04,
337 .pclkperiod = 0x16,
338 },
339 {
340 .resolution = (uint32_t)video_resolution_1080p,
341 .pllctrl1 = 0x21,
342 .pllctrl2 = 0x69,
343 .vfifoctrl0c = 0x20,
344 .pclkdiv = 0x04,
345 .pclkperiod = 0x16,
346 },
347 };
348
349 /* MIPI clock */
350 static const ov5640_clock_config_t ov5640_mipi_clock_configs[] = {
351 {
352 .resolution = (uint32_t)video_resolution_800_480,
353 .pllctrl1 = 0x14,
354 .pllctrl2 = 0x38,
355 .vfifoctrl0c = 0x22,
356 .pclkdiv = 0x02,
357 .pclkperiod = 0x0a,
358 },
359 {
360 .resolution = (uint32_t)video_resolution_vga,
361 .pllctrl1 = 0x14,
362 .pllctrl2 = 0x38,
363 .vfifoctrl0c = 0x22,
364 .pclkdiv = 0x02,
365 .pclkperiod = 0x0a,
366 },
367 {
368 .resolution = (uint32_t)video_resolution_qvga,
369 .pllctrl1 = 0x14,
370 .pllctrl2 = 0x38,
371 .vfifoctrl0c = 0x22,
372 .pclkdiv = 0x02,
373 .pclkperiod = 0x0a,
374 },
375 {
376 .resolution = (uint32_t)video_resolution_480_272,
377 .pllctrl1 = 0x14,
378 .pllctrl2 = 0x38,
379 .vfifoctrl0c = 0x22,
380 .pclkdiv = 0x02,
381 .pclkperiod = 0x0a,
382 },
383 {
384 .resolution = (uint32_t)video_resolution_720p,
385 .pllctrl1 = 0x21,
386 .pllctrl2 = 0x54,
387 .vfifoctrl0c = 0x20,
388 .pclkdiv = 0x04,
389 .pclkperiod = 0x0a,
390 },
391 {
392 .resolution = (uint32_t)video_resolution_1080p,
393 .pllctrl1 = 0x11,
394 .pllctrl2 = 0x54,
395 .vfifoctrl0c = 0x20,
396 .pclkdiv = 0x04,
397 .pclkperiod = 0x0a,
398 },
399 };
400
401 static const ov5640_light_mode_config_t ov5640_light_mode_configs[] = {
402 /* Auto. */
403 {
404 .lightmode = camera_light_mode_auto,
405 .awbctrl = 0x00,
406 .awbr_h = 0x04,
407 .awbr_l = 0x00,
408 .awbg_h = 0x04,
409 .awbg_l = 0x00,
410 .awbb_h = 0x04,
411 .awbb_l = 0x00,
412 },
413 /* Sunny. */
414 {
415 .lightmode = camera_light_mode_sunny,
416 .awbctrl = 0x01,
417 .awbr_h = 0x06,
418 .awbr_l = 0x1c,
419 .awbg_h = 0x04,
420 .awbg_l = 0x00,
421 .awbb_h = 0x04,
422 .awbb_l = 0xf3,
423 },
424 /* Office. */
425 {
426 .lightmode = camera_light_mode_office,
427 .awbctrl = 0x01,
428 .awbr_h = 0x05,
429 .awbr_l = 0x48,
430 .awbg_h = 0x04,
431 .awbg_l = 0x00,
432 .awbb_h = 0x07,
433 .awbb_l = 0xcf,
434 },
435 /* Cloudy. */
436 {
437 .lightmode = camera_light_mode_cloudy,
438 .awbctrl = 0x01,
439 .awbr_h = 0x06,
440 .awbr_l = 0x48,
441 .awbg_h = 0x04,
442 .awbg_l = 0x00,
443 .awbb_h = 0x04,
444 .awbb_l = 0xd3,
445 },
446 /* Home. */
447 {
448 .lightmode = camera_light_mode_home,
449 .awbctrl = 0x01,
450 .awbr_h = 0x04,
451 .awbr_l = 0x10,
452 .awbg_h = 0x04,
453 .awbg_l = 0x00,
454 .awbb_h = 0x08,
455 .awbb_l = 0x40,
456 },
457 };
458
459 static const ov5640_special_effect_config_t ov5640_special_effect_configs[] = {
460 /* Normal. */
461 {
462 .effect = camera_special_effect_normal,
463 .sdectrl0 = 0x06,
464 .sdectrl3 = 0x40,
465 .sdectrl4 = 0x10,
466 },
467 /* Bluish. */
468 {
469 .effect = camera_special_effect_bluish,
470 .sdectrl0 = 0x1e,
471 .sdectrl3 = 0xa0,
472 .sdectrl4 = 0x40,
473 },
474 /* Redish. */
475 {
476 .effect = camera_special_effect_redish,
477 .sdectrl0 = 0x1e,
478 .sdectrl3 = 0x80,
479 .sdectrl4 = 0xc0,
480 },
481 /* B & W */
482 {
483 .effect = camera_special_effect_bw,
484 .sdectrl0 = 0x1e,
485 .sdectrl3 = 0x80,
486 .sdectrl4 = 0x80,
487 },
488 /* Sepia. */
489 {
490 .effect = camera_special_effect_sepia,
491 .sdectrl0 = 0x1e,
492 .sdectrl3 = 0x40,
493 .sdectrl4 = 0xa0,
494 },
495 /* Negtive. */
496 {
497 .effect = camera_special_effect_negtive,
498 .sdectrl0 = 0x40,
499 .sdectrl3 = 0x40,
500 .sdectrl4 = 0x10,
501 },
502 /* Greenish. */
503 {
504 .effect = camera_special_effect_greenish,
505 .sdectrl0 = 0x1e,
506 .sdectrl3 = 0x60,
507 .sdectrl4 = 0x60,
508 },
509 };
510
ov5640_get_clock_config(const camera_config_t * config)511 static const ov5640_clock_config_t *ov5640_get_clock_config(const camera_config_t *config)
512 {
513 uint32_t i;
514
515 if (camera_interface_dvp == config->interface) {
516 for (i = 0; i < ARRAY_SIZE(ov5640_dvp_clock_configs); i++) {
517 if (HPM_CAMERA_RESOLUTION(config->width, config->height) == ov5640_dvp_clock_configs[i].resolution) {
518 return &ov5640_dvp_clock_configs[i];
519 }
520 }
521 } else if (camera_interface_mipi == config->interface) {
522 for (i = 0; i < ARRAY_SIZE(ov5640_mipi_clock_configs); i++) {
523 if (HPM_CAMERA_RESOLUTION(config->width, config->height) == ov5640_mipi_clock_configs[i].resolution) {
524 return &ov5640_mipi_clock_configs[i];
525 }
526 }
527 }
528
529 return NULL;
530 }
531
ov5640_read_register(camera_context_t * context,uint16_t reg,uint8_t * buf)532 hpm_stat_t ov5640_read_register(camera_context_t *context, uint16_t reg, uint8_t *buf)
533 {
534 uint8_t r[2];
535 r[0] = reg >> 8;
536 r[1] = reg & 0xFF;
537
538 hpm_stat_t stat = i2c_master_write(context->ptr, context->i2c_device_addr, r, 2);
539 if (stat != status_success) {
540 return stat;
541 }
542 return i2c_master_read(context->ptr, context->i2c_device_addr, buf, 1);
543 }
544
ov5640_write_register(camera_context_t * context,uint16_t reg,uint8_t val)545 hpm_stat_t ov5640_write_register(camera_context_t *context, uint16_t reg, uint8_t val)
546 {
547 uint8_t r[2];
548 r[0] = reg >> 8;
549 r[1] = reg & 0xFF;
550 return i2c_master_address_write(context->ptr, context->i2c_device_addr, r, sizeof(r), &val, 1);
551 }
552
ov5640_write_multi_registers(camera_context_t * context,const ov5640_reg_val_t regval[],uint32_t len)553 hpm_stat_t ov5640_write_multi_registers(camera_context_t *context, const ov5640_reg_val_t regval[], uint32_t len)
554 {
555 uint32_t i;
556 hpm_stat_t stat = status_success;
557
558 for (i = 0; i < len; i++) {
559 HPM_CHECK_RET(ov5640_write_register(context, regval[i].regaddr, regval[i].regval));
560 }
561
562 return stat;
563 }
564
ov5640_software_reset(camera_context_t * context)565 hpm_stat_t ov5640_software_reset(camera_context_t *context)
566 {
567 hpm_stat_t stat = status_success;
568
569 HPM_CHECK_RET(ov5640_write_register(context, 0x3103, 0x11));
570 HPM_CHECK_RET(ov5640_write_register(context, 0x3008, 0x82));
571
572 return stat;
573 }
574
ov5640_set_pixel_format(camera_context_t * context,display_pixel_format_t pixel_format)575 hpm_stat_t ov5640_set_pixel_format(camera_context_t *context, display_pixel_format_t pixel_format)
576 {
577 hpm_stat_t stat = status_success;
578
579 switch (pixel_format) {
580 case display_pixel_format_y8:
581 case display_pixel_format_yuv422:
582 HPM_CHECK_RET(ov5640_write_register(context, 0x4300, 0x30));
583 HPM_CHECK_RET(ov5640_write_register(context, 0x501f, 0x00));
584 break;
585 case display_pixel_format_ycbcr422:
586 HPM_CHECK_RET(ov5640_write_register(context, 0x4300, 0x32));
587 HPM_CHECK_RET(ov5640_write_register(context, 0x501f, 0x00));
588 break;
589 case display_pixel_format_rgb565:
590 HPM_CHECK_RET(ov5640_write_register(context, 0x4300, 0x6F));
591 HPM_CHECK_RET(ov5640_write_register(context, 0x501f, 0x01));
592 break;
593 default:
594 stat = status_invalid_argument;
595 break;
596 }
597
598 return stat;
599 }
600
ov5640_check_chip_id(camera_context_t * context)601 hpm_stat_t ov5640_check_chip_id(camera_context_t *context)
602 {
603 hpm_stat_t stat = status_success;
604 uint8_t val_h = 0;
605 uint8_t val_l = 0;
606
607 HPM_CHECK_RET(ov5640_read_register(context, OV5640_CHIP_ID_HIGH_BYTE_ADDR, &val_h));
608 HPM_CHECK_RET(ov5640_read_register(context, OV5640_CHIP_ID_LOW_BYTE_ADDR, &val_l));
609
610 if (val_h != OV5640_CHIP_ID_HIGH_BYTE_VALUE) {
611 return status_fail;
612 }
613
614 if (val_l != OV5640_CHIP_ID_LOW_BYTE_VALUE) {
615 return status_fail;
616 }
617
618 return stat;
619 }
620
ov5640_set_image_size(camera_context_t * context,camera_config_t * ov_config)621 hpm_stat_t ov5640_set_image_size(camera_context_t *context, camera_config_t *ov_config)
622 {
623 hpm_stat_t stat = status_success;
624
625 switch (HPM_CAMERA_RESOLUTION(ov_config->width, ov_config->height)) {
626 case video_resolution_800_480:
627 stat = ov5640_write_multi_registers(context, ov5640_resolution_800_480_param, ARRAY_SIZE(ov5640_resolution_800_480_param));
628 break;
629 case video_resolution_vga:
630 stat = ov5640_write_multi_registers(context, ov5640_resolution_vga_param, ARRAY_SIZE(ov5640_resolution_vga_param));
631 break;
632 case video_resolution_qvga:
633 stat = ov5640_write_multi_registers(context, ov5640_resolution_qvga_param, ARRAY_SIZE(ov5640_resolution_qvga_param));
634 break;
635 case video_resolution_480_272:
636 stat = ov5640_write_multi_registers(context, ov5640_resolution_480_272_param, ARRAY_SIZE(ov5640_resolution_480_272_param));
637 break;
638 case video_resolution_720p:
639 stat = ov5640_write_multi_registers(context, ov5640_resolution_720p_param, ARRAY_SIZE(ov5640_resolution_720p_param));
640 break;
641 case video_resolution_1080p:
642 stat = ov5640_write_multi_registers(context, ov5640_resolution_1080p_param, ARRAY_SIZE(ov5640_resolution_1080p_param));
643 break;
644 default:
645 stat = status_invalid_argument;
646 break;
647 }
648
649 return stat;
650 }
651
ov5640_set_clock_config(camera_context_t * context,camera_config_t * ov_config)652 hpm_stat_t ov5640_set_clock_config(camera_context_t *context, camera_config_t *ov_config)
653 {
654 hpm_stat_t stat = status_success;
655 const ov5640_clock_config_t *clock_config = ov5640_get_clock_config(ov_config);
656
657 if (NULL == clock_config) {
658 return status_invalid_argument;
659 }
660
661 HPM_CHECK_RET(ov5640_write_register(context, 0x3035, clock_config->pllctrl1));
662 HPM_CHECK_RET(ov5640_write_register(context, 0x3036, clock_config->pllctrl2));
663 HPM_CHECK_RET(ov5640_write_register(context, 0x460c, clock_config->vfifoctrl0c));
664 HPM_CHECK_RET(ov5640_write_register(context, 0x3824, clock_config->pclkdiv));
665 HPM_CHECK_RET(ov5640_write_register(context, 0x4837, clock_config->pclkperiod));
666
667 return stat;
668 }
669
ov5640_set_interface(camera_context_t * context,camera_config_t * ov_config)670 hpm_stat_t ov5640_set_interface(camera_context_t *context, camera_config_t *ov_config)
671 {
672 hpm_stat_t stat = status_success;
673
674 if (camera_interface_dvp == ov_config->interface) {
675 HPM_CHECK_RET(ov5640_write_register(context, 0x3034, 0x1a));
676
677 /* Set Frex, Vsync, Href, PCLK, data, GPIO to output. */
678 HPM_CHECK_RET(ov5640_write_register(context, 0x3017, 0xFF));
679 HPM_CHECK_RET(ov5640_write_register(context, 0x3018, 0xFF));
680
681 /* DVP mode */
682 HPM_CHECK_RET(ov5640_write_register(context, 0x300e, 0x58));
683 } else if (camera_interface_mipi == ov_config->interface) {
684 HPM_CHECK_RET(ov5640_write_register(context, 0x481D, 0x20));
685 HPM_CHECK_RET(ov5640_write_register(context, 0x481C, 0x0));
686 HPM_CHECK_RET(ov5640_write_register(context, 0x3034, 0x18));
687 HPM_CHECK_RET(ov5640_write_register(context, 0x3017, 0x00));
688 HPM_CHECK_RET(ov5640_write_register(context, 0x3018, 0x00));
689 /* 2lanes mode */
690 HPM_CHECK_RET(ov5640_write_register(context, 0x300e, 0x45));
691 HPM_CHECK_RET(ov5640_write_register(context, 0x302e, 0x08));
692
693 HPM_CHECK_RET(ov5640_write_register(context, 0x4800, 0x04));
694 }
695
696 return stat;
697 }
698
ov5640_start(camera_context_t * context)699 hpm_stat_t ov5640_start(camera_context_t *context)
700 {
701 return ov5640_write_register(context, 0x3008, 0x02);
702 }
703
ov5640_stop(camera_context_t * context)704 hpm_stat_t ov5640_stop(camera_context_t *context)
705 {
706 return ov5640_write_register(context, 0x3008, 0x42);
707 }
708
ov5640_flip(camera_context_t * context)709 hpm_stat_t ov5640_flip(camera_context_t *context)
710 {
711 hpm_stat_t stat = status_success;
712 HPM_CHECK_RET(ov5640_write_register(context, 0x3821, 1));
713 return stat;
714 }
715
716
ov5640_set_brightness(camera_context_t * context,int32_t brightness)717 hpm_stat_t ov5640_set_brightness(camera_context_t *context, int32_t brightness)
718 {
719 hpm_stat_t stat = status_success;
720
721 if ((brightness < -4) || (brightness > 4)) {
722 return status_invalid_argument;
723 }
724
725 HPM_CHECK_RET(ov5640_write_register(context, 0x3212, 0x03));
726 if (brightness >= 0) {
727 HPM_CHECK_RET(ov5640_write_register(context, 0x5588, 0x01));
728 } else {
729 brightness = -brightness;
730 HPM_CHECK_RET(ov5640_write_register(context, 0x5588, 0x09));
731 }
732
733 HPM_CHECK_RET(ov5640_write_register(context, 0x5587, ((uint8_t)brightness) << 4U));
734
735 HPM_CHECK_RET(ov5640_write_register(context, 0x3212, 0x13));
736 HPM_CHECK_RET(ov5640_write_register(context, 0x3212, 0xa3));
737
738 return stat;
739 }
740
ov5640_set_contrast(camera_context_t * context,int32_t contrast)741 hpm_stat_t ov5640_set_contrast(camera_context_t *context, int32_t contrast)
742 {
743 hpm_stat_t stat = status_success;
744 uint8_t regval;
745
746 if ((-4 > contrast) || (4 < contrast)) {
747 return status_invalid_argument;
748 }
749
750 contrast = 0x20 + contrast * 0x04;
751 regval = (uint8_t)contrast;
752
753 HPM_CHECK_RET(ov5640_write_register(context, 0x3212, 0x03));
754
755 HPM_CHECK_RET(ov5640_write_register(context, 0x5580, 0x04));
756 HPM_CHECK_RET(ov5640_write_register(context, 0x5585, regval));
757 HPM_CHECK_RET(ov5640_write_register(context, 0x5586, regval));
758
759 HPM_CHECK_RET(ov5640_write_register(context, 0x3212, 0x13));
760 HPM_CHECK_RET(ov5640_write_register(context, 0x3212, 0xa3));
761
762 return stat;
763 }
764
ov5640_set_saturation(camera_context_t * context,int32_t saturation)765 hpm_stat_t ov5640_set_saturation(camera_context_t *context, int32_t saturation)
766 {
767 hpm_stat_t stat = status_success;
768 uint8_t regval;
769
770 if ((-4 > saturation) || (4 < saturation)) {
771 return status_invalid_argument;
772 }
773
774 saturation = 0x40 + saturation * 0x10;
775 regval = (uint8_t)saturation;
776
777 HPM_CHECK_RET(ov5640_write_register(context, 0x3212, 0x03));
778
779 HPM_CHECK_RET(ov5640_write_register(context, 0x5580, 0x02));
780 HPM_CHECK_RET(ov5640_write_register(context, 0x5583, regval));
781 HPM_CHECK_RET(ov5640_write_register(context, 0x5584, regval));
782 HPM_CHECK_RET(ov5640_write_register(context, 0x5588, 0x41));
783
784 HPM_CHECK_RET(ov5640_write_register(context, 0x3212, 0x13));
785 HPM_CHECK_RET(ov5640_write_register(context, 0x3212, 0xa3));
786
787 return stat;
788 }
789
ov5640_set_light_mode(camera_context_t * context,int32_t lightmode)790 hpm_stat_t ov5640_set_light_mode(camera_context_t *context, int32_t lightmode)
791 {
792 hpm_stat_t stat = status_success;
793 uint8_t i;
794
795 for (i = 0; i < ARRAY_SIZE(ov5640_light_mode_configs); i++) {
796 if (lightmode == (int32_t)ov5640_light_mode_configs[i].lightmode) {
797 HPM_CHECK_RET(ov5640_write_register(context, 0x3212, 0x03));
798
799 HPM_CHECK_RET(ov5640_write_register(context, 0x3406, ov5640_light_mode_configs[i].awbctrl));
800 HPM_CHECK_RET(ov5640_write_register(context, 0x3400, ov5640_light_mode_configs[i].awbr_h));
801 HPM_CHECK_RET(ov5640_write_register(context, 0x3401, ov5640_light_mode_configs[i].awbr_l));
802 HPM_CHECK_RET(ov5640_write_register(context, 0x3402, ov5640_light_mode_configs[i].awbg_h));
803 HPM_CHECK_RET(ov5640_write_register(context, 0x3403, ov5640_light_mode_configs[i].awbg_l));
804 HPM_CHECK_RET(ov5640_write_register(context, 0x3404, ov5640_light_mode_configs[i].awbb_h));
805 HPM_CHECK_RET(ov5640_write_register(context, 0x3405, ov5640_light_mode_configs[i].awbb_l));
806
807 HPM_CHECK_RET(ov5640_write_register(context, 0x3212, 0x13));
808 HPM_CHECK_RET(ov5640_write_register(context, 0x3212, 0xa3));
809
810 return stat;
811 }
812 }
813
814 /* No configuration found. */
815 return status_invalid_argument;
816 }
817
ov5640_set_special_effect(camera_context_t * context,int32_t effect)818 hpm_stat_t ov5640_set_special_effect(camera_context_t *context, int32_t effect)
819 {
820 hpm_stat_t stat = status_success;
821 uint8_t i;
822
823 for (i = 0; i < ARRAY_SIZE(ov5640_special_effect_configs); i++) {
824 if (effect == (int32_t)ov5640_special_effect_configs[i].effect) {
825 HPM_CHECK_RET(ov5640_write_register(context, 0x3212, 0x03));
826
827 HPM_CHECK_RET(ov5640_write_register(context, 0x5580, ov5640_special_effect_configs[i].sdectrl0));
828 HPM_CHECK_RET(ov5640_write_register(context, 0x5583, ov5640_special_effect_configs[i].sdectrl3));
829 HPM_CHECK_RET(ov5640_write_register(context, 0x5584, ov5640_special_effect_configs[i].sdectrl4));
830
831 HPM_CHECK_RET(ov5640_write_register(context, 0x5003, 0x08));
832 HPM_CHECK_RET(ov5640_write_register(context, 0x3212, 0x13));
833 HPM_CHECK_RET(ov5640_write_register(context, 0x3212, 0xa3));
834
835 return stat;
836 }
837 }
838
839 /* No configuration found. */
840 return status_invalid_argument;
841 }
842
ov5640_init(camera_context_t * context,camera_config_t * ov_config)843 hpm_stat_t ov5640_init(camera_context_t *context, camera_config_t *ov_config)
844 {
845 hpm_stat_t stat = status_success;
846
847 /* check the chip id */
848 HPM_CHECK_RET(ov5640_check_chip_id(context));
849
850 /* Initialize: load registers value */
851 HPM_CHECK_RET(ov5640_write_multi_registers(context, ov5640_init_param, ARRAY_SIZE(ov5640_init_param)));
852
853 /* configure image windowing */
854 HPM_CHECK_RET(ov5640_set_image_size(context, ov_config));
855
856 HPM_CHECK_RET(ov5640_flip(context));
857
858 /* configure Pixel format */
859 HPM_CHECK_RET(ov5640_set_pixel_format(context, ov_config->pixel_format));
860
861 /* configure PCLK clock */
862 HPM_CHECK_RET(ov5640_set_clock_config(context, ov_config));
863
864 /* configure interface */
865 HPM_CHECK_RET(ov5640_set_interface(context, ov_config));
866
867 /* configure contrast */
868 HPM_CHECK_RET(ov5640_set_contrast(context, 2));
869
870 /* camera start */
871 HPM_CHECK_RET(ov5640_write_register(context, 0x3008, 0x02));
872
873 return stat;
874 }
875
ov5640_power_up(camera_context_t * context)876 void ov5640_power_up(camera_context_t *context)
877 {
878 assert(context->delay_ms != NULL);
879
880 if (context->write_rst) {
881 context->write_rst(OV5640_RST_ACTIVE);
882 }
883 if (context->write_pwdn) {
884 context->write_pwdn(OV5640_PWDN_ACTIVE);
885 }
886 context->delay_ms(5);
887 if (context->write_pwdn) {
888 context->write_pwdn(OV5640_PWDN_INACTIVE);
889 }
890 context->delay_ms(2);
891 if (context->write_rst) {
892 context->write_rst(OV5640_RST_INACTIVE);
893 }
894 context->delay_ms(20);
895 }
896