• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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