1 /*
2  * Copyright 2017-2018, 2020 NXP
3  * All rights reserved.
4  *
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_video_common.h"
10 #include "fsl_camera.h"
11 #include "fsl_camera_device.h"
12 #include "fsl_ov5640.h"
13 
14 /*******************************************************************************
15  * Definitions
16  ******************************************************************************/
17 #define OV5640_DelayMs VIDEO_DelayMs
18 
19 #define OV5640_SCCB_ADDR            0x3CU
20 #define OV5640_RESOLUTION_PARAM_NUM 0x16U
21 
22 #define OV5640_WriteReg(handle, reg, val)                             \
23     SCCB_WriteReg(OV5640_SCCB_ADDR, kSCCB_RegAddr16Bit, (reg), (val), \
24                   ((ov5640_resource_t *)((handle)->resource))->i2cSendFunc)
25 
26 #define OV5640_WriteMultiRegs(handle, reg, val, len)                             \
27     SCCB_WriteMultiRegs(OV5640_SCCB_ADDR, kSCCB_RegAddr16Bit, (reg), (val), len, \
28                         ((ov5640_resource_t *)((handle)->resource))->i2cSendFunc)
29 
30 #define OV5640_ReadReg(handle, reg, val)                             \
31     SCCB_ReadReg(OV5640_SCCB_ADDR, kSCCB_RegAddr16Bit, (reg), (val), \
32                  ((ov5640_resource_t *)((handle)->resource))->i2cReceiveFunc)
33 
34 #define OV5640_ModifyReg(handle, reg, clrMask, val)                               \
35     SCCB_ModifyReg(OV5640_SCCB_ADDR, kSCCB_RegAddr16Bit, (reg), (clrMask), (val), \
36                    ((ov5640_resource_t *)((handle)->resource))->i2cReceiveFunc,   \
37                    ((ov5640_resource_t *)((handle)->resource))->i2cSendFunc)
38 
39 #define OV5640_POLARITY_CTRL00_VSYNC_MASK           (1U << 0U)
40 #define OV5640_POLARITY_CTRL00_HREF_MASK            (1U << 1U)
41 #define OV5640_POLARITY_CTRL00_GATE_PCLK_HREF_MASK  (1U << 2U)
42 #define OV5640_POLARITY_CTRL00_GATE_PCLK_VSYNC_MASK (1U << 3U)
43 #define OV5640_POLARITY_CTRL00_PCLK_MASK            (1U << 5U)
44 
45 #define OV5640_SDE_CTRL0_REG  0x5580
46 #define OV5640_SDE_CTRL1_REG  0x5581
47 #define OV5640_SDE_CTRL2_REG  0x5582
48 #define OV5640_SDE_CTRL3_REG  0x5583
49 #define OV5640_SDE_CTRL4_REG  0x5584
50 #define OV5640_SDE_CTRL5_REG  0x5585
51 #define OV5640_SDE_CTRL6_REG  0x5586
52 #define OV5640_SDE_CTRL7_REG  0x5587
53 #define OV5640_SDE_CTRL8_REG  0x5588
54 #define OV5640_SDE_CTRL9_REG  0x5589
55 #define OV5640_SDE_CTRL10_REG 0x558a
56 #define OV5640_SDE_CTRL11_REG 0x558b
57 #define OV5640_SDE_CTRL12_REG 0x558c
58 
59 #define OV5640_AWB_R_H_REG  0x3400
60 #define OV5640_AWB_R_L_REG  0x3401
61 #define OV5640_AWB_G_H_REG  0x3402
62 #define OV5640_AWB_G_L_REG  0x3403
63 #define OV5640_AWB_B_H_REG  0x3404
64 #define OV5640_AWB_B_L_REG  0x3405
65 #define OV5640_AWB_CTRL_REG 0x3406
66 
67 #define OV5640_CHECK_RET(x)            \
68     do                                 \
69     {                                  \
70         status = (x);                  \
71         if (kStatus_Success != status) \
72         {                              \
73             return status;             \
74         }                              \
75     } while (false)
76 
77 typedef struct _ov5640_reg_val
78 {
79     uint16_t regAddr; /*!< Register address. */
80     uint8_t regVal;   /*!<Register value. */
81 } ov5640_reg_val_t;
82 
83 typedef struct _ov5640_resolution_param
84 {
85     uint32_t resolution; /*!< Resolution, see @ref video_resolution_t and @ref FSL_VIDEO_RESOLUTION. */
86     uint8_t param[OV5640_RESOLUTION_PARAM_NUM]; /*!< Parameter 0x3800 to 0x3813. */
87 } ov5640_resolution_param_t;
88 
89 typedef struct
90 {
91     uint32_t resolution;
92     uint8_t framePerSec;
93     uint8_t pllCtrl1;
94     uint8_t pllCtrl2;
95     uint8_t vfifoCtrl0C;
96     uint8_t pclkDiv;
97     uint8_t pclkPeriod;
98 } ov5640_clock_config_t;
99 
100 typedef struct
101 {
102     uint8_t lightMode;
103     uint8_t awbCtrl;
104     uint8_t awbR_H;
105     uint8_t awbR_L;
106     uint8_t awbG_H;
107     uint8_t awbG_L;
108     uint8_t awbB_H;
109     uint8_t awbB_L;
110 } ov5640_light_mode_config_t;
111 
112 typedef struct
113 {
114     uint8_t effect;
115     uint8_t sdeCtrl0;
116     uint8_t sdeCtrl3;
117     uint8_t sdeCtrl4;
118 } ov5640_special_effect_config_t;
119 
120 typedef status_t (*ov5640_cmd_func_t)(camera_device_handle_t *handle, int32_t arg);
121 
122 typedef struct
123 {
124     camera_device_cmd_t cmd;
125     ov5640_cmd_func_t func;
126 } ov5640_cmd_func_map_t;
127 
128 /*******************************************************************************
129  * Prototypes
130  ******************************************************************************/
131 status_t OV5640_Init(camera_device_handle_t *handle, const camera_config_t *config);
132 
133 status_t OV5640_Deinit(camera_device_handle_t *handle);
134 
135 status_t OV5640_Control(camera_device_handle_t *handle, camera_device_cmd_t cmd, int32_t arg);
136 
137 status_t OV5640_Start(camera_device_handle_t *handle);
138 
139 status_t OV5640_Stop(camera_device_handle_t *handle);
140 
141 status_t OV5640_InitExt(camera_device_handle_t *handle, const camera_config_t *config, const void *specialConfig);
142 
143 status_t OV5640_SetSpecialEffect(camera_device_handle_t *handle, int32_t effect);
144 
145 status_t OV5640_SetLightMode(camera_device_handle_t *handle, int32_t lightMode);
146 
147 status_t OV5640_SetSaturation(camera_device_handle_t *handle, int32_t saturation);
148 
149 status_t OV5640_SetContrast(camera_device_handle_t *handle, int32_t contrast);
150 
151 status_t OV5640_SetBrightness(camera_device_handle_t *handle, int32_t brightness);
152 
153 /*******************************************************************************
154  * Variables
155  ******************************************************************************/
156 static const ov5640_reg_val_t ov5640InitParam[] = {
157     {0x3008, 0x42},
158 
159     /* System setting. */
160     {0x3103, 0x03},
161     {0x3000, 0x00},
162     {0x3004, 0xff},
163     {0x3002, 0x1c},
164     {0x3006, 0xc3},
165     {0x302e, 0x08},
166     {0x3037, 0x13},
167     {0x3108, 0x01},
168     {0x3618, 0x00},
169     {0x3612, 0x29},
170     {0x3708, 0x64},
171     {0x3709, 0x52},
172     {0x370c, 0x03},
173     {0x3820, 0x41},
174     {0x3821, 0x07},
175     {0x3630, 0x36},
176     {0x3631, 0x0e},
177     {0x3632, 0xe2},
178     {0x3633, 0x12},
179     {0x3621, 0xe0},
180     {0x3704, 0xa0},
181     {0x3703, 0x5a},
182     {0x3715, 0x78},
183     {0x3717, 0x01},
184     {0x370b, 0x60},
185     {0x3705, 0x1a},
186     {0x3905, 0x02},
187     {0x3906, 0x10},
188     {0x3901, 0x0a},
189     {0x3731, 0x12},
190     {0x3600, 0x08},
191     {0x3601, 0x33},
192     {0x302d, 0x60},
193     {0x3620, 0x52},
194     {0x371b, 0x20},
195     {0x471c, 0x50},
196     {0x3a13, 0x43},
197     {0x3a18, 0x00},
198     {0x3a19, 0x7c},
199     {0x3635, 0x13},
200     {0x3636, 0x03},
201     {0x3634, 0x40},
202     {0x3622, 0x01},
203     {0x3c01, 0x00},
204     {0x3a00, 0x58},
205     {0x4001, 0x02},
206     {0x4004, 0x02},
207     {0x4005, 0x1a},
208     {0x5001, 0xa3},
209 
210     /* AEC */
211     {0x3a0f, 0x30},
212     {0x3a10, 0x28},
213     {0x3a1b, 0x30},
214     {0x3a1e, 0x26},
215     {0x3a11, 0x60},
216     {0x3a1f, 0x14},
217 
218     /* AWB */
219     {0x5180, 0xff},
220     {0x5181, 0xf2},
221     {0x5182, 0x00},
222     {0x5183, 0x14},
223     {0x5184, 0x25},
224     {0x5185, 0x24},
225     {0x5186, 0x09},
226     {0x5187, 0x09},
227     {0x5188, 0x09},
228     {0x5189, 0x88},
229     {0x518a, 0x54},
230     {0x518b, 0xee},
231     {0x518c, 0xb2},
232     {0x518d, 0x50},
233     {0x518e, 0x34},
234     {0x518f, 0x6b},
235     {0x5190, 0x46},
236     {0x5191, 0xf8},
237     {0x5192, 0x04},
238     {0x5193, 0x70},
239     {0x5194, 0xf0},
240     {0x5195, 0xf0},
241     {0x5196, 0x03},
242     {0x5197, 0x01},
243     {0x5198, 0x04},
244     {0x5199, 0x6c},
245     {0x519a, 0x04},
246     {0x519b, 0x00},
247     {0x519c, 0x09},
248     {0x519d, 0x2b},
249     {0x519e, 0x38},
250 
251     /* Color Matrix */
252     {0x5381, 0x1e},
253     {0x5382, 0x5b},
254     {0x5383, 0x08},
255     {0x5384, 0x0a},
256     {0x5385, 0x7e},
257     {0x5386, 0x88},
258     {0x5387, 0x7c},
259     {0x5388, 0x6c},
260     {0x5389, 0x10},
261     {0x538a, 0x01},
262     {0x538b, 0x98},
263 
264     /* sharp */
265     {0x5300, 0x08},
266     {0x5301, 0x30},
267     {0x5302, 0x10},
268     {0x5303, 0x00},
269     {0x5304, 0x08},
270     {0x5305, 0x30},
271     {0x5306, 0x08},
272     {0x5307, 0x16},
273     {0x5309, 0x08},
274     {0x530a, 0x30},
275     {0x530b, 0x04},
276     {0x530c, 0x06},
277 
278     /* Gamma */
279     {0x5480, 0x01},
280     {0x5481, 0x08},
281     {0x5482, 0x14},
282     {0x5483, 0x28},
283     {0x5484, 0x51},
284     {0x5485, 0x65},
285     {0x5486, 0x71},
286     {0x5487, 0x7d},
287     {0x5488, 0x87},
288     {0x5489, 0x91},
289     {0x548a, 0x9a},
290     {0x548b, 0xaa},
291     {0x548c, 0xb8},
292     {0x548d, 0xcd},
293     {0x548e, 0xdd},
294     {0x548f, 0xea},
295     {0x5490, 0x1d},
296 
297     /* UV adjust. */
298     {0x5580, 0x02},
299     {0x5583, 0x40},
300     {0x5584, 0x10},
301     {0x5589, 0x10},
302     {0x558a, 0x00},
303     {0x558b, 0xf8},
304 
305     /* Lens correction. */
306     {0x5800, 0x23},
307     {0x5801, 0x14},
308     {0x5802, 0x0f},
309     {0x5803, 0x0f},
310     {0x5804, 0x12},
311     {0x5805, 0x26},
312     {0x5806, 0x0c},
313     {0x5807, 0x08},
314     {0x5808, 0x05},
315     {0x5809, 0x05},
316     {0x580a, 0x08},
317     {0x580b, 0x0d},
318     {0x580c, 0x08},
319     {0x580d, 0x03},
320     {0x580e, 0x00},
321     {0x580f, 0x00},
322     {0x5810, 0x03},
323     {0x5811, 0x09},
324     {0x5812, 0x07},
325     {0x5813, 0x03},
326     {0x5814, 0x00},
327     {0x5815, 0x01},
328     {0x5816, 0x03},
329     {0x5817, 0x08},
330     {0x5818, 0x0d},
331     {0x5819, 0x08},
332     {0x581a, 0x05},
333     {0x581b, 0x06},
334     {0x581c, 0x08},
335     {0x581d, 0x0e},
336     {0x581e, 0x29},
337     {0x581f, 0x17},
338     {0x5820, 0x11},
339     {0x5821, 0x11},
340     {0x5822, 0x15},
341     {0x5823, 0x28},
342     {0x5824, 0x46},
343     {0x5825, 0x26},
344     {0x5826, 0x08},
345     {0x5827, 0x26},
346     {0x5828, 0x64},
347     {0x5829, 0x26},
348     {0x582a, 0x24},
349     {0x582b, 0x22},
350     {0x582c, 0x24},
351     {0x582d, 0x24},
352     {0x582e, 0x06},
353     {0x582f, 0x22},
354     {0x5830, 0x40},
355     {0x5831, 0x42},
356     {0x5832, 0x24},
357     {0x5833, 0x26},
358     {0x5834, 0x24},
359     {0x5835, 0x22},
360     {0x5836, 0x22},
361     {0x5837, 0x26},
362     {0x5838, 0x44},
363     {0x5839, 0x24},
364     {0x583a, 0x26},
365     {0x583b, 0x28},
366     {0x583c, 0x42},
367     {0x583d, 0xce},
368 };
369 
370 static const ov5640_resolution_param_t resolutionParam[] = {
371     {
372         .resolution = (uint32_t)kVIDEO_ResolutionVGA,
373         .param      = {0x00, 0x00, 0x00, 0x04, 0x0a, 0x3f, 0x07, 0x9b, 0x02, 0x80, 0x01,
374                   0xe0, 0x07, 0x68, 0x03, 0xd8, 0x00, 0x10, 0x00, 0x06, 0x31, 0x31},
375     },
376     {
377         .resolution = (uint32_t)kVIDEO_ResolutionQVGA,
378         .param      = {0x00, 0x00, 0x00, 0x04, 0x0a, 0x3f, 0x07, 0x9b, 0x01, 0x40, 0x00,
379                   0xf0, 0x07, 0x68, 0x03, 0xd8, 0x00, 0x10, 0x00, 0x06, 0x31, 0x31},
380     },
381     {
382         .resolution = FSL_VIDEO_RESOLUTION(480, 272),
383         .param      = {0x00, 0x00, 0x00, 0xfa, 0x0a, 0x3f, 0x06, 0xa9, 0x01, 0xE0, 0x01,
384                   0x10, 0x07, 0x64, 0x02, 0xe4, 0x00, 0x10, 0x00, 0x04, 0x31, 0x31},
385     },
386     {
387         .resolution = (uint32_t)kVIDEO_Resolution720P,
388         .param      = {0x00, 0x00, 0x00, 0xfa, 0x0a, 0x3f, 0x06, 0xa9, 0x05, 0x00, 0x02,
389                   0xd0, 0x07, 0x64, 0x02, 0xe4, 0x00, 0x10, 0x00, 0x04, 0x31, 0x31},
390     },
391     {
392         .resolution = (uint32_t)kVIDEO_Resolution1080P,
393         .param      = {0x01, 0x50, 0x01, 0xb2, 0x08, 0xef, 0x05, 0xf1, 0x07, 0x80, 0x04,
394                   0x38, 0x09, 0xc4, 0x04, 0x60, 0x00, 0x10, 0x00, 0x04, 0x11, 0x11},
395     },
396 };
397 
398 /* DVP */
399 static const ov5640_clock_config_t s_ov5640DvpClockConfigs[] = {
400     {
401         .resolution  = (uint32_t)kVIDEO_ResolutionVGA,
402         .framePerSec = 15,
403         .pllCtrl1    = 0x21,
404         .pllCtrl2    = 0x46,
405         .vfifoCtrl0C = 0x22,
406         .pclkDiv     = 0x02,
407         .pclkPeriod  = 0x22,
408     },
409     {
410         .resolution  = (uint32_t)kVIDEO_ResolutionVGA,
411         .framePerSec = 30,
412         .pllCtrl1    = 0x11,
413         .pllCtrl2    = 0x46,
414         .vfifoCtrl0C = 0x22,
415         .pclkDiv     = 0x02,
416         .pclkPeriod  = 0x22,
417     },
418     {
419         .resolution  = (uint32_t)kVIDEO_ResolutionQVGA,
420         .framePerSec = 15,
421         .pllCtrl1    = 0x21,
422         .pllCtrl2    = 0x46,
423         .vfifoCtrl0C = 0x22,
424         .pclkDiv     = 0x02,
425         .pclkPeriod  = 0x22,
426     },
427     {
428         .resolution  = (uint32_t)kVIDEO_ResolutionQVGA,
429         .framePerSec = 30,
430         .pllCtrl1    = 0x11,
431         .pllCtrl2    = 0x46,
432         .vfifoCtrl0C = 0x22,
433         .pclkDiv     = 0x02,
434         .pclkPeriod  = 0x22,
435     },
436     {
437         .resolution  = FSL_VIDEO_RESOLUTION(480, 272),
438         .framePerSec = 15,
439         .pllCtrl1    = 0x41,
440         .pllCtrl2    = 0x69,
441         .vfifoCtrl0C = 0x20,
442         .pclkDiv     = 0x04,
443         .pclkPeriod  = 0x16,
444     },
445     {
446         .resolution  = FSL_VIDEO_RESOLUTION(480, 272),
447         .framePerSec = 30,
448         .pllCtrl1    = 0x21,
449         .pllCtrl2    = 0x69,
450         .vfifoCtrl0C = 0x20,
451         .pclkDiv     = 0x04,
452         .pclkPeriod  = 0x16,
453     },
454     {
455         .resolution  = (uint32_t)kVIDEO_Resolution720P,
456         .framePerSec = 15,
457         .pllCtrl1    = 0x41,
458         .pllCtrl2    = 0x69,
459         .vfifoCtrl0C = 0x20,
460         .pclkDiv     = 0x04,
461         .pclkPeriod  = 0x16,
462     },
463     {
464         .resolution  = (uint32_t)kVIDEO_Resolution720P,
465         .framePerSec = 30,
466         .pllCtrl1    = 0x21,
467         .pllCtrl2    = 0x69,
468         .vfifoCtrl0C = 0x20,
469         .pclkDiv     = 0x04,
470         .pclkPeriod  = 0x16,
471     },
472     {
473         .resolution  = (uint32_t)kVIDEO_Resolution1080P,
474         .framePerSec = 15,
475         .pllCtrl1    = 0x21,
476         .pllCtrl2    = 0x69,
477         .vfifoCtrl0C = 0x20,
478         .pclkDiv     = 0x04,
479         .pclkPeriod  = 0x16,
480     },
481 };
482 
483 /* MIPI */
484 static const ov5640_clock_config_t s_ov5640MipiClockConfigs[] = {
485     {
486         .resolution  = (uint32_t)kVIDEO_ResolutionVGA,
487         .framePerSec = 15,
488         .pllCtrl1    = 0x22,
489         .pllCtrl2    = 0x38,
490         .vfifoCtrl0C = 0x22,
491         .pclkDiv     = 0x02,
492         .pclkPeriod  = 0x0a,
493     },
494     {
495         .resolution  = (uint32_t)kVIDEO_ResolutionVGA,
496         .framePerSec = 30,
497         .pllCtrl1    = 0x14,
498         .pllCtrl2    = 0x38,
499         .vfifoCtrl0C = 0x22,
500         .pclkDiv     = 0x02,
501         .pclkPeriod  = 0x0a,
502     },
503     {
504         .resolution  = (uint32_t)kVIDEO_ResolutionQVGA,
505         .framePerSec = 15,
506         .pllCtrl1    = 0x22,
507         .pllCtrl2    = 0x38,
508         .vfifoCtrl0C = 0x22,
509         .pclkDiv     = 0x02,
510         .pclkPeriod  = 0x0a,
511     },
512     {
513         .resolution  = (uint32_t)kVIDEO_ResolutionQVGA,
514         .framePerSec = 30,
515         .pllCtrl1    = 0x14,
516         .pllCtrl2    = 0x38,
517         .vfifoCtrl0C = 0x22,
518         .pclkDiv     = 0x02,
519         .pclkPeriod  = 0x0a,
520     },
521     {
522         .resolution  = (uint32_t)kVIDEO_Resolution720P,
523         .framePerSec = 15,
524         .pllCtrl1    = 0x41,
525         .pllCtrl2    = 0x54,
526         .vfifoCtrl0C = 0x20,
527         .pclkDiv     = 0x04,
528         .pclkPeriod  = 0x0a,
529     },
530     {
531         .resolution  = (uint32_t)kVIDEO_Resolution720P,
532         .framePerSec = 30,
533         .pllCtrl1    = 0x21,
534         .pllCtrl2    = 0x54,
535         .vfifoCtrl0C = 0x20,
536         .pclkDiv     = 0x04,
537         .pclkPeriod  = 0x0a,
538     },
539     {
540         .resolution  = (uint32_t)kVIDEO_Resolution1080P,
541         .framePerSec = 15,
542         .pllCtrl1    = 0x21,
543         .pllCtrl2    = 0x54,
544         .vfifoCtrl0C = 0x20,
545         .pclkDiv     = 0x04,
546         .pclkPeriod  = 0x0a,
547     },
548     {
549         .resolution  = (uint32_t)kVIDEO_Resolution1080P,
550         .framePerSec = 30,
551         .pllCtrl1    = 0x11,
552         .pllCtrl2    = 0x54,
553         .vfifoCtrl0C = 0x20,
554         .pclkDiv     = 0x04,
555         .pclkPeriod  = 0x0a,
556     },
557 };
558 
559 static const ov5640_light_mode_config_t s_ov5640LightModeConfigs[] = {
560     /* Auto. */
561     {
562         .lightMode = CAMERA_LIGHT_MODE_AUTO,
563         .awbCtrl   = 0x00,
564         .awbR_H    = 0x04,
565         .awbR_L    = 0x00,
566         .awbG_H    = 0x04,
567         .awbG_L    = 0x00,
568         .awbB_H    = 0x04,
569         .awbB_L    = 0x00,
570     },
571     /* Sunny. */
572     {
573         .lightMode = CAMERA_LIGHT_MODE_SUNNY,
574         .awbCtrl   = 0x01,
575         .awbR_H    = 0x06,
576         .awbR_L    = 0x1c,
577         .awbG_H    = 0x04,
578         .awbG_L    = 0x00,
579         .awbB_H    = 0x04,
580         .awbB_L    = 0xf3,
581     },
582     /* Office. */
583     {
584         .lightMode = CAMERA_LIGHT_MODE_OFFICE,
585         .awbCtrl   = 0x01,
586         .awbR_H    = 0x05,
587         .awbR_L    = 0x48,
588         .awbG_H    = 0x04,
589         .awbG_L    = 0x00,
590         .awbB_H    = 0x07,
591         .awbB_L    = 0xcf,
592     },
593     /* Cloudy. */
594     {
595         .lightMode = CAMERA_LIGHT_MODE_CLOUDY,
596         .awbCtrl   = 0x01,
597         .awbR_H    = 0x06,
598         .awbR_L    = 0x48,
599         .awbG_H    = 0x04,
600         .awbG_L    = 0x00,
601         .awbB_H    = 0x04,
602         .awbB_L    = 0xd3,
603     },
604     /* Home. */
605     {
606         .lightMode = CAMERA_LIGHT_MODE_HOME,
607         .awbCtrl   = 0x01,
608         .awbR_H    = 0x04,
609         .awbR_L    = 0x10,
610         .awbG_H    = 0x04,
611         .awbG_L    = 0x00,
612         .awbB_H    = 0x08,
613         .awbB_L    = 0x40,
614     },
615 };
616 
617 static const ov5640_special_effect_config_t s_ov5640SpecialEffectConfigs[] = {
618     /* Normal. */
619     {
620         .effect   = CAMERA_SPECIAL_EFFECT_NORMAL,
621         .sdeCtrl0 = 0x06,
622         .sdeCtrl3 = 0x40,
623         .sdeCtrl4 = 0x10,
624     },
625     /* Bluish. */
626     {
627         .effect   = CAMERA_SPECIAL_EFFECT_BLUISH,
628         .sdeCtrl0 = 0x1e,
629         .sdeCtrl3 = 0xa0,
630         .sdeCtrl4 = 0x40,
631     },
632     /* Redish. */
633     {
634         .effect   = CAMERA_SPECIAL_EFFECT_REDISH,
635         .sdeCtrl0 = 0x1e,
636         .sdeCtrl3 = 0x80,
637         .sdeCtrl4 = 0xc0,
638     },
639     /* B & W */
640     {
641         .effect   = CAMERA_SPECIAL_EFFECT_BW,
642         .sdeCtrl0 = 0x1e,
643         .sdeCtrl3 = 0x80,
644         .sdeCtrl4 = 0x80,
645     },
646     /* Sepia. */
647     {
648         .effect   = CAMERA_SPECIAL_EFFECT_SEPIA,
649         .sdeCtrl0 = 0x1e,
650         .sdeCtrl3 = 0x40,
651         .sdeCtrl4 = 0xa0,
652     },
653     /* Negtive. */
654     {
655         .effect   = CAMERA_SPECIAL_EFFECT_NEGTIVE,
656         .sdeCtrl0 = 0x40,
657         .sdeCtrl3 = 0x40,
658         .sdeCtrl4 = 0x10,
659     },
660     /* Greenish. */
661     {
662         .effect   = CAMERA_SPECIAL_EFFECT_GREENISH,
663         .sdeCtrl0 = 0x1e,
664         .sdeCtrl3 = 0x60,
665         .sdeCtrl4 = 0x60,
666     },
667 };
668 
669 static const ov5640_cmd_func_map_t s_ov5640CmdFuncMap[] = {
670     {
671         kCAMERA_DeviceLightMode,
672         OV5640_SetLightMode,
673     },
674     {
675         kCAMERA_DeviceSaturation,
676         OV5640_SetSaturation,
677     },
678     {
679         kCAMERA_DeviceBrightness,
680         OV5640_SetBrightness,
681     },
682     {
683         kCAMERA_DeviceContrast,
684         OV5640_SetContrast,
685     },
686     {
687         kCAMERA_DeviceSpecialEffect,
688         OV5640_SetSpecialEffect,
689     },
690 };
691 
692 const camera_device_operations_t ov5640_ops = {
693     .init     = OV5640_Init,
694     .deinit   = OV5640_Deinit,
695     .start    = OV5640_Start,
696     .stop     = OV5640_Stop,
697     .control  = OV5640_Control,
698     .init_ext = OV5640_InitExt,
699 };
700 
701 /*******************************************************************************
702  * Code
703  ******************************************************************************/
704 
OV5640_LoadRegVal(camera_device_handle_t * handle,const ov5640_reg_val_t regVal[],uint32_t num)705 static status_t OV5640_LoadRegVal(camera_device_handle_t *handle, const ov5640_reg_val_t regVal[], uint32_t num)
706 {
707     uint32_t i;
708     status_t status;
709 
710     for (i = 0; i < num; i++)
711     {
712         status = OV5640_WriteReg(handle, regVal[i].regAddr, regVal[i].regVal);
713 
714         if (kStatus_Success != status)
715         {
716             return status;
717         }
718     }
719 
720     return kStatus_Success;
721 }
722 
OV5640_SoftwareReset(camera_device_handle_t * handle)723 static status_t OV5640_SoftwareReset(camera_device_handle_t *handle)
724 {
725     ov5640_reg_val_t param[] = {{0x3103, 0x11}, {0x3008, 0x82}};
726 
727     return OV5640_LoadRegVal(handle, param, ARRAY_SIZE(param));
728 }
729 
OV5640_GetResolutionParam(uint32_t resolution)730 static const uint8_t *OV5640_GetResolutionParam(uint32_t resolution)
731 {
732     /*
733      * This function returns the parameter for specific resolution, if
734      * the resolution is not supported, returns NULL.
735      */
736     uint32_t i;
737 
738     for (i = 0; i < ARRAY_SIZE(resolutionParam); i++)
739     {
740         if (resolution == resolutionParam[i].resolution)
741         {
742             return resolutionParam[i].param;
743         }
744     }
745 
746     return NULL;
747 }
748 
OV5640_GetClockConfig(const camera_config_t * config)749 static const ov5640_clock_config_t *OV5640_GetClockConfig(const camera_config_t *config)
750 {
751     uint32_t i;
752 
753     if (kCAMERA_InterfaceMIPI == config->interface)
754     {
755         for (i = 0; i < ARRAY_SIZE(s_ov5640MipiClockConfigs); i++)
756         {
757             if ((config->framePerSec == s_ov5640MipiClockConfigs[i].framePerSec) &&
758                 (config->resolution == s_ov5640MipiClockConfigs[i].resolution))
759             {
760                 return &s_ov5640MipiClockConfigs[i];
761             }
762         }
763     }
764     else
765     {
766         for (i = 0; i < ARRAY_SIZE(s_ov5640DvpClockConfigs); i++)
767         {
768             if ((config->framePerSec == s_ov5640DvpClockConfigs[i].framePerSec) &&
769                 (config->resolution == s_ov5640DvpClockConfigs[i].resolution))
770             {
771                 return &s_ov5640DvpClockConfigs[i];
772             }
773         }
774     }
775 
776     return NULL;
777 }
778 
OV5640_SetPixelFormat(camera_device_handle_t * handle,video_pixel_format_t pixelFormat)779 static status_t OV5640_SetPixelFormat(camera_device_handle_t *handle, video_pixel_format_t pixelFormat)
780 {
781     status_t status;
782     uint8_t param[2];
783 
784     switch (pixelFormat)
785     {
786         case kVIDEO_PixelFormatYUYV:
787             param[0] = 0x3F;
788             param[1] = 0x00;
789             break;
790 
791         case kVIDEO_PixelFormatRGB565:
792         default:
793             param[0] = 0x6f;
794             param[1] = 0x01;
795             break;
796     }
797 
798     OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x4300, param[0]));
799     OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x501f, param[1]));
800 
801     return kStatus_Success;
802 }
803 
OV5640_Init(camera_device_handle_t * handle,const camera_config_t * config)804 status_t OV5640_Init(camera_device_handle_t *handle, const camera_config_t *config)
805 {
806     status_t status;
807     ov5640_resource_t *resource = (ov5640_resource_t *)(handle->resource);
808     uint8_t reg;
809     const ov5640_clock_config_t *clockConfig;
810 
811     /* Verify the configuration. */
812     const uint8_t *resParam = OV5640_GetResolutionParam(config->resolution);
813 
814     if (NULL == resParam)
815     {
816         return kStatus_InvalidArgument;
817     }
818 
819     if ((kVIDEO_PixelFormatYUYV != config->pixelFormat) && (kVIDEO_PixelFormatRGB565 != config->pixelFormat))
820     {
821         return kStatus_InvalidArgument;
822     }
823 
824     if ((kCAMERA_InterfaceNonGatedClock != config->interface) && (kCAMERA_InterfaceGatedClock != config->interface) &&
825         (kCAMERA_InterfaceCCIR656 != config->interface) && (kCAMERA_InterfaceMIPI != config->interface))
826     {
827         return kStatus_InvalidArgument;
828     }
829 
830     /* Only support 2 data lanes. */
831     if ((kCAMERA_InterfaceMIPI == config->interface) && (2U != config->csiLanes))
832     {
833         return kStatus_InvalidArgument;
834     }
835 
836     clockConfig = OV5640_GetClockConfig(config);
837 
838     if (NULL == clockConfig)
839     {
840         return kStatus_InvalidArgument;
841     }
842 
843     resource->pullPowerDownPin(true);
844     resource->pullResetPin(false);
845 
846     /* Delay 5ms. */
847     OV5640_DelayMs(5);
848 
849     resource->pullPowerDownPin(false);
850 
851     /* Delay 1ms. */
852     OV5640_DelayMs(1);
853 
854     resource->pullResetPin(true);
855 
856     /* Delay 20ms. */
857     OV5640_DelayMs(20);
858 
859     OV5640_CHECK_RET(OV5640_SoftwareReset(handle));
860 
861     /* Delay 5ms. */
862     OV5640_DelayMs(5);
863 
864     /* Initialize. */
865     status = OV5640_LoadRegVal(handle, ov5640InitParam, ARRAY_SIZE(ov5640InitParam));
866     if (kStatus_Success != status)
867     {
868         return status;
869     }
870 
871     /* Resolution. */
872     OV5640_CHECK_RET(OV5640_WriteMultiRegs(handle, 0x3800, resParam, OV5640_RESOLUTION_PARAM_NUM));
873 
874     if ((uint32_t)kVIDEO_Resolution1080P == config->resolution)
875     {
876         OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x3709, 0x12));
877         OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x3821, 0x06));
878     }
879 
880     OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x302c, 0xc2));
881 
882     /* Pixel format. */
883     OV5640_CHECK_RET(OV5640_SetPixelFormat(handle, config->pixelFormat));
884 
885     /* Clock. */
886     OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x3035, clockConfig->pllCtrl1));
887     OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x3036, clockConfig->pllCtrl2));
888     OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x460c, clockConfig->vfifoCtrl0C));
889     OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x3824, clockConfig->pclkDiv));
890     OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x4837, clockConfig->pclkPeriod));
891 
892     /* Interface. */
893     if (kCAMERA_InterfaceMIPI == config->interface)
894     {
895         OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x3034, 0x18));
896 
897         /* Set Frex, Vsync, Href, PCLK, data, GPIO to input. */
898         OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x3017, 0x00));
899         OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x3018, 0x00));
900 
901         /*
902          * Set to MIPI mode, set data lane. Currently only support 2 data lanes,
903          * if need to use 1 data lane, write 0x25 to register 0x300e.
904          */
905         OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x300e, 0x45));
906 
907         /* Virtual channel. */
908         OV5640_CHECK_RET(OV5640_ModifyReg(handle, 0x4814, (3U << 6), (uint8_t)(config->mipiChannel) << 6));
909 
910         OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x4800, 0x04));
911     }
912     else
913     {
914         OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x3034, 0x1a));
915 
916         /* Set Frex, Vsync, Href, PCLK, data, GPIO to output. */
917         OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x3017, 0xFF));
918         OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x3018, 0xFF));
919 
920         /* DVP mode */
921         OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x300e, 0x58));
922 
923         if (kCAMERA_InterfaceCCIR656 == config->interface)
924         {
925             OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x4719, 0x01));
926             OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x4730, 0x01));
927         }
928     }
929 
930     /* Signal polarity */
931     reg = 0;
932     if ((uint32_t)kCAMERA_HrefActiveHigh != (config->controlFlags & (uint32_t)kCAMERA_HrefActiveHigh))
933     {
934         reg |= OV5640_POLARITY_CTRL00_HREF_MASK;
935     }
936     if ((uint32_t)kCAMERA_VsyncActiveHigh != (config->controlFlags & (uint32_t)kCAMERA_VsyncActiveHigh))
937     {
938         reg |= OV5640_POLARITY_CTRL00_VSYNC_MASK;
939     }
940     if ((uint32_t)kCAMERA_DataLatchOnRisingEdge == (config->controlFlags & (uint32_t)kCAMERA_DataLatchOnRisingEdge))
941     {
942         reg |= OV5640_POLARITY_CTRL00_PCLK_MASK;
943     }
944 
945     if (kCAMERA_InterfaceNonGatedClock == config->interface)
946     {
947         reg |= OV5640_POLARITY_CTRL00_GATE_PCLK_HREF_MASK | OV5640_POLARITY_CTRL00_GATE_PCLK_VSYNC_MASK;
948     }
949 
950     OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x4740, reg));
951 
952     /* Lenc on, raw gamma on, BPC on, WPC on, CIP on. */
953     OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x5000, 0xa7));
954 
955     OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x3008, 0x02));
956 
957     return kStatus_Success;
958 }
959 
OV5640_Deinit(camera_device_handle_t * handle)960 status_t OV5640_Deinit(camera_device_handle_t *handle)
961 {
962     ((ov5640_resource_t *)(handle->resource))->pullPowerDownPin(true);
963 
964     return kStatus_Success;
965 }
966 
OV5640_Control(camera_device_handle_t * handle,camera_device_cmd_t cmd,int32_t arg)967 status_t OV5640_Control(camera_device_handle_t *handle, camera_device_cmd_t cmd, int32_t arg)
968 {
969     for (uint8_t i = 0; i < ARRAY_SIZE(s_ov5640CmdFuncMap); i++)
970     {
971         if (s_ov5640CmdFuncMap[i].cmd == cmd)
972         {
973             return s_ov5640CmdFuncMap[i].func(handle, arg);
974         }
975     }
976 
977     return kStatus_InvalidArgument;
978 }
979 
OV5640_Start(camera_device_handle_t * handle)980 status_t OV5640_Start(camera_device_handle_t *handle)
981 {
982     return OV5640_WriteReg(handle, 0x3008, 0x02);
983 }
984 
OV5640_Stop(camera_device_handle_t * handle)985 status_t OV5640_Stop(camera_device_handle_t *handle)
986 {
987     return OV5640_WriteReg(handle, 0x3008, 0x42);
988 }
989 
OV5640_InitExt(camera_device_handle_t * handle,const camera_config_t * config,const void * specialConfig)990 status_t OV5640_InitExt(camera_device_handle_t *handle, const camera_config_t *config, const void *specialConfig)
991 {
992     return OV5640_Init(handle, config);
993 }
994 
OV5640_SetBrightness(camera_device_handle_t * handle,int32_t brightness)995 status_t OV5640_SetBrightness(camera_device_handle_t *handle, int32_t brightness)
996 {
997     status_t status;
998 
999     if ((brightness < -4) || (brightness > 4))
1000     {
1001         return kStatus_InvalidArgument;
1002     }
1003 
1004     OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x3212, 0x03));
1005     if (brightness >= 0)
1006     {
1007         status = OV5640_WriteReg(handle, OV5640_SDE_CTRL8_REG, 0x01);
1008     }
1009     else
1010     {
1011         brightness = -brightness;
1012         status     = OV5640_WriteReg(handle, OV5640_SDE_CTRL8_REG, 0x09);
1013     }
1014 
1015     if (kStatus_Success != status)
1016     {
1017         return status;
1018     }
1019 
1020     OV5640_CHECK_RET(OV5640_WriteReg(handle, OV5640_SDE_CTRL7_REG, ((uint8_t)brightness) << 4U));
1021 
1022     OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x3212, 0x13));
1023     return OV5640_WriteReg(handle, 0x3212, 0xa3);
1024 }
1025 
OV5640_SetContrast(camera_device_handle_t * handle,int32_t contrast)1026 status_t OV5640_SetContrast(camera_device_handle_t *handle, int32_t contrast)
1027 {
1028     status_t status;
1029     uint8_t regVal;
1030 
1031     if ((-4 > contrast) || (4 < contrast))
1032     {
1033         return kStatus_InvalidArgument;
1034     }
1035 
1036     contrast = 0x20 + contrast * 0x04;
1037     regVal   = (uint8_t)contrast;
1038 
1039     OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x3212, 0x03));
1040 
1041     OV5640_CHECK_RET(OV5640_WriteReg(handle, OV5640_SDE_CTRL0_REG, 0x04));
1042     OV5640_CHECK_RET(OV5640_WriteReg(handle, OV5640_SDE_CTRL5_REG, regVal));
1043     OV5640_CHECK_RET(OV5640_WriteReg(handle, OV5640_SDE_CTRL6_REG, regVal));
1044 
1045     OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x3212, 0x13));
1046     return OV5640_WriteReg(handle, 0x3212, 0xa3);
1047 }
1048 
OV5640_SetSaturation(camera_device_handle_t * handle,int32_t saturation)1049 status_t OV5640_SetSaturation(camera_device_handle_t *handle, int32_t saturation)
1050 {
1051     status_t status;
1052     uint8_t regVal;
1053 
1054     if ((-4 > saturation) || (4 < saturation))
1055     {
1056         return kStatus_InvalidArgument;
1057     }
1058 
1059     saturation = 0x40 + saturation * 0x10;
1060     regVal     = (uint8_t)saturation;
1061 
1062     OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x3212, 0x03));
1063 
1064     OV5640_CHECK_RET(OV5640_WriteReg(handle, OV5640_SDE_CTRL0_REG, 0x02));
1065     OV5640_CHECK_RET(OV5640_WriteReg(handle, OV5640_SDE_CTRL3_REG, regVal));
1066     OV5640_CHECK_RET(OV5640_WriteReg(handle, OV5640_SDE_CTRL4_REG, regVal));
1067     OV5640_CHECK_RET(OV5640_WriteReg(handle, OV5640_SDE_CTRL8_REG, 0x41));
1068 
1069     OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x3212, 0x13));
1070     return OV5640_WriteReg(handle, 0x3212, 0xa3);
1071 }
1072 
OV5640_SetLightMode(camera_device_handle_t * handle,int32_t lightMode)1073 status_t OV5640_SetLightMode(camera_device_handle_t *handle, int32_t lightMode)
1074 {
1075     status_t status;
1076     uint8_t i;
1077 
1078     for (i = 0; i < ARRAY_SIZE(s_ov5640LightModeConfigs); i++)
1079     {
1080         if (lightMode == (int32_t)s_ov5640LightModeConfigs[i].lightMode)
1081         {
1082             OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x3212, 0x03));
1083 
1084             OV5640_CHECK_RET(OV5640_WriteReg(handle, OV5640_AWB_CTRL_REG, s_ov5640LightModeConfigs[i].awbCtrl));
1085             OV5640_CHECK_RET(OV5640_WriteReg(handle, OV5640_AWB_R_H_REG, s_ov5640LightModeConfigs[i].awbR_H));
1086             OV5640_CHECK_RET(OV5640_WriteReg(handle, OV5640_AWB_R_L_REG, s_ov5640LightModeConfigs[i].awbR_L));
1087             OV5640_CHECK_RET(OV5640_WriteReg(handle, OV5640_AWB_G_H_REG, s_ov5640LightModeConfigs[i].awbG_H));
1088             OV5640_CHECK_RET(OV5640_WriteReg(handle, OV5640_AWB_G_L_REG, s_ov5640LightModeConfigs[i].awbG_L));
1089             OV5640_CHECK_RET(OV5640_WriteReg(handle, OV5640_AWB_B_H_REG, s_ov5640LightModeConfigs[i].awbB_H));
1090             OV5640_CHECK_RET(OV5640_WriteReg(handle, OV5640_AWB_B_L_REG, s_ov5640LightModeConfigs[i].awbB_L));
1091 
1092             OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x3212, 0x13));
1093             return OV5640_WriteReg(handle, 0x3212, 0xa3);
1094         }
1095     }
1096 
1097     /* No configuration found. */
1098     return kStatus_InvalidArgument;
1099 }
1100 
OV5640_SetSpecialEffect(camera_device_handle_t * handle,int32_t effect)1101 status_t OV5640_SetSpecialEffect(camera_device_handle_t *handle, int32_t effect)
1102 {
1103     status_t status;
1104     uint8_t i;
1105 
1106     for (i = 0; i < ARRAY_SIZE(s_ov5640SpecialEffectConfigs); i++)
1107     {
1108         if (effect == (int32_t)s_ov5640SpecialEffectConfigs[i].effect)
1109         {
1110             OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x3212, 0x03));
1111 
1112             OV5640_CHECK_RET(OV5640_WriteReg(handle, OV5640_SDE_CTRL0_REG, s_ov5640SpecialEffectConfigs[i].sdeCtrl0));
1113             OV5640_CHECK_RET(OV5640_WriteReg(handle, OV5640_SDE_CTRL3_REG, s_ov5640SpecialEffectConfigs[i].sdeCtrl3));
1114             OV5640_CHECK_RET(OV5640_WriteReg(handle, OV5640_SDE_CTRL4_REG, s_ov5640SpecialEffectConfigs[i].sdeCtrl4));
1115 
1116             OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x5003, 0x08));
1117             OV5640_CHECK_RET(OV5640_WriteReg(handle, 0x3212, 0x13));
1118             return OV5640_WriteReg(handle, 0x3212, 0xa3);
1119         }
1120     }
1121 
1122     /* No configuration found. */
1123     return kStatus_InvalidArgument;
1124 }
1125