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_ov7725.h"
13 
14 /*******************************************************************************
15  * Definitions
16  ******************************************************************************/
17 #define OV7725_SCCB_ADDR 0x21U
18 #define OV7725_REVISION  0x7721U
19 
20 #define OV7725_WriteReg(handle, reg, val)                            \
21     SCCB_WriteReg(OV7725_SCCB_ADDR, kSCCB_RegAddr8Bit, (reg), (val), \
22                   ((ov7725_resource_t *)((handle)->resource))->i2cSendFunc)
23 
24 #define OV7725_ReadReg(handle, reg, val)                            \
25     SCCB_ReadReg(OV7725_SCCB_ADDR, kSCCB_RegAddr8Bit, (reg), (val), \
26                  ((ov7725_resource_t *)((handle)->resource))->i2cReceiveFunc)
27 
28 #define OV7725_ModifyReg(handle, reg, clrMask, val)                              \
29     SCCB_ModifyReg(OV7725_SCCB_ADDR, kSCCB_RegAddr8Bit, (reg), (clrMask), (val), \
30                    ((ov7725_resource_t *)((handle)->resource))->i2cReceiveFunc,  \
31                    ((ov7725_resource_t *)((handle)->resource))->i2cSendFunc)
32 
33 #define OV7725_CHECK_RET(x)            \
34     do                                 \
35     {                                  \
36         status = (x);                  \
37         if (kStatus_Success != status) \
38         {                              \
39             return status;             \
40         }                              \
41     } while (false)
42 
43 typedef struct _ov7725_clock_config
44 {
45     uint32_t frameRate_Hz;
46     uint32_t inputClk_Hz;
47     uint8_t clkrc;  /*!< Register CLKRC. */
48     uint8_t com4;   /*!< Register COM4. */
49     uint8_t dm_lnl; /*!< Register DM_LNL. */
50 } ov7725_clock_config_t;
51 
52 typedef struct _ov7725_light_mode
53 {
54     uint8_t lightMode;
55     uint8_t com8;
56     uint8_t blue;
57     uint8_t red;
58     uint8_t com5;
59 } ov7725_light_mode_config_t;
60 
61 typedef struct _ov7725_special_effect_config
62 {
63     uint8_t effect;
64     uint8_t sde;
65     uint8_t ufix;
66     uint8_t vfix;
67 } ov7725_special_effect_config_t;
68 
69 typedef struct _ov7725_night_mode
70 {
71     uint8_t nightMode;
72     uint8_t com5;
73 } ov7725_night_mode_t;
74 
75 typedef struct _ov7725_pixel_format_config
76 {
77     video_pixel_format_t fmt;
78     uint8_t com7;
79 } ov7725_pixel_format_config_t;
80 
81 typedef status_t (*ov7725_cmd_func_t)(camera_device_handle_t *handle, int32_t arg);
82 
83 typedef struct _ov7725_cmd_func_map
84 {
85     camera_device_cmd_t cmd;
86     ov7725_cmd_func_t func;
87 } ov7725_cmd_func_map_t;
88 
89 typedef struct _ov7725_reg
90 {
91     uint8_t reg;
92     uint8_t val;
93 } ov7725_reg_t;
94 
95 /*******************************************************************************
96  * Prototypes
97  ******************************************************************************/
98 status_t OV7725_Init(camera_device_handle_t *handle, const camera_config_t *config);
99 
100 status_t OV7725_InitExt(camera_device_handle_t *handle, const camera_config_t *config, const void *specialConfig);
101 
102 status_t OV7725_Deinit(camera_device_handle_t *handle);
103 
104 status_t OV7725_Control(camera_device_handle_t *handle, camera_device_cmd_t cmd, int32_t arg);
105 
106 status_t OV7725_Start(camera_device_handle_t *handle);
107 
108 status_t OV7725_Stop(camera_device_handle_t *handle);
109 
110 status_t OV7725_SetSpecialEffect(camera_device_handle_t *handle, int32_t effect);
111 
112 status_t OV7725_SetLightMode(camera_device_handle_t *handle, int32_t lightMode);
113 
114 status_t OV7725_SetNightMode(camera_device_handle_t *handle, int32_t nightMode);
115 
116 status_t OV7725_SetSaturation(camera_device_handle_t *handle, int32_t saturation);
117 
118 status_t OV7725_SetContrast(camera_device_handle_t *handle, int32_t contrast);
119 
120 status_t OV7725_SetBrightness(camera_device_handle_t *handle, int32_t brightness);
121 
122 /*******************************************************************************
123  * Variables
124  ******************************************************************************/
125 const camera_device_operations_t ov7725_ops = {
126     .init     = OV7725_Init,
127     .deinit   = OV7725_Deinit,
128     .start    = OV7725_Start,
129     .stop     = OV7725_Stop,
130     .control  = OV7725_Control,
131     .init_ext = OV7725_InitExt,
132 };
133 
134 static const ov7725_clock_config_t ov7725ClockConfigs[] = {
135     /* FrameRate, inputClk, clkrc, com4, dm_lnl. */
136     {.frameRate_Hz = 30, .inputClk_Hz = 24000000, .clkrc = 0x01, .com4 = 0x41, .dm_lnl = 0x00},
137     {.frameRate_Hz = 15, .inputClk_Hz = 24000000, .clkrc = 0x03, .com4 = 0x41, .dm_lnl = 0x00},
138     {.frameRate_Hz = 25, .inputClk_Hz = 24000000, .clkrc = 0x01, .com4 = 0x41, .dm_lnl = 0x66},
139     {.frameRate_Hz = 14, .inputClk_Hz = 24000000, .clkrc = 0x03, .com4 = 0x41, .dm_lnl = 0x1a},
140     {.frameRate_Hz = 30, .inputClk_Hz = 26000000, .clkrc = 0x01, .com4 = 0x41, .dm_lnl = 0x2b},
141     {.frameRate_Hz = 15, .inputClk_Hz = 26000000, .clkrc = 0x03, .com4 = 0x41, .dm_lnl = 0x2b},
142     {.frameRate_Hz = 25, .inputClk_Hz = 26000000, .clkrc = 0x01, .com4 = 0x41, .dm_lnl = 0x99},
143     {.frameRate_Hz = 14, .inputClk_Hz = 26000000, .clkrc = 0x03, .com4 = 0x41, .dm_lnl = 0x46},
144     {.frameRate_Hz = 30, .inputClk_Hz = 13000000, .clkrc = 0x00, .com4 = 0x41, .dm_lnl = 0x2b},
145     {.frameRate_Hz = 15, .inputClk_Hz = 13000000, .clkrc = 0x01, .com4 = 0x41, .dm_lnl = 0x2b},
146     {.frameRate_Hz = 25, .inputClk_Hz = 13000000, .clkrc = 0x00, .com4 = 0x41, .dm_lnl = 0x99},
147     {.frameRate_Hz = 14, .inputClk_Hz = 13000000, .clkrc = 0x01, .com4 = 0x41, .dm_lnl = 0x46},
148 };
149 
150 static const ov7725_special_effect_config_t ov7725SpecialEffectConfigs[] = {
151     /* Normal. */
152     {.effect = CAMERA_SPECIAL_EFFECT_NORMAL, .sde = 0x06, .ufix = 0x80, .vfix = 0x80},
153     /* B & W */
154     {.effect = CAMERA_SPECIAL_EFFECT_BW, .sde = 0x26, .ufix = 0x80, .vfix = 0x80},
155     /* Sepia. */
156     {.effect = CAMERA_SPECIAL_EFFECT_SEPIA, .sde = 0x1e, .ufix = 0x40, .vfix = 0xa0},
157     /* Bluish. */
158     {.effect = CAMERA_SPECIAL_EFFECT_BLUISH, .sde = 0x1e, .ufix = 0xa0, .vfix = 0x40},
159     /* Redish. */
160     {.effect = CAMERA_SPECIAL_EFFECT_REDISH, .sde = 0x1e, .ufix = 0x80, .vfix = 0x40},
161     /* Greenish. */
162     {.effect = CAMERA_SPECIAL_EFFECT_GREENISH, .sde = 0x1e, .ufix = 0x60, .vfix = 0x60},
163     /* Negtive. */
164     {.effect = CAMERA_SPECIAL_EFFECT_NEGTIVE, .sde = 0x46, .ufix = 0x00, .vfix = 0x00},
165 };
166 
167 static const ov7725_light_mode_config_t ov7725LightModeConfigs[] = {
168     /* Auto. */
169     {.lightMode = CAMERA_LIGHT_MODE_AUTO, .com8 = 0xff, .blue = 0x80, .red = 0x80, .com5 = 0x65},
170     /* Sunny. */
171     {.lightMode = CAMERA_LIGHT_MODE_SUNNY, .com8 = 0xfd, .blue = 0x5a, .red = 0x5c, .com5 = 0x65},
172     /* Cloudy. */
173     {.lightMode = CAMERA_LIGHT_MODE_CLOUDY, .com8 = 0xfd, .blue = 0x58, .red = 0x60, .com5 = 0x65},
174     /* Office. */
175     {.lightMode = CAMERA_LIGHT_MODE_OFFICE, .com8 = 0xfd, .blue = 0x84, .red = 0x4c, .com5 = 0x65},
176     /* Home. */
177     {.lightMode = CAMERA_LIGHT_MODE_HOME, .com8 = 0xfd, .blue = 0x96, .red = 0x40, .com5 = 0x65},
178     /* Night. */
179     {.lightMode = CAMERA_LIGHT_MODE_NIGHT, .com8 = 0xff, .blue = 0x80, .red = 0x80, .com5 = 0xe5}};
180 
181 static const ov7725_pixel_format_config_t ov7725PixelFormatConfigs[] = {
182     {.fmt = kVIDEO_PixelFormatYUYV, .com7 = (0)},
183     {.fmt = kVIDEO_PixelFormatRGB565, .com7 = (1 << 2) | (2)},
184     {.fmt = kVIDEO_PixelFormatXRGB1555, .com7 = (2 << 2) | (2)},
185     {.fmt = kVIDEO_PixelFormatXRGB4444, .com7 = (3 << 2) | (2)}};
186 
187 static const ov7725_night_mode_t ov7725NightModeConfigs[] = {
188     {.nightMode = CAMERA_NIGHT_MODE_DISABLED, .com5 = 0},
189     {.nightMode = CAMERA_NIGHT_MODE_AUTO_FR_DIVBY2, .com5 = 8 | (1 << 4)},
190     {.nightMode = CAMERA_NIGHT_MODE_AUTO_FR_DIVBY4, .com5 = 8 | (2 << 4)},
191     {.nightMode = CAMERA_NIGHT_MODE_AUTO_FR_DIVBY8, .com5 = 8 | (3 << 4)}};
192 
193 static const ov7725_cmd_func_map_t ov7725CmdFuncMap[] = {
194     {
195         kCAMERA_DeviceLightMode,
196         OV7725_SetLightMode,
197     },
198     {
199         kCAMERA_DeviceSaturation,
200         OV7725_SetSaturation,
201     },
202     {
203         kCAMERA_DeviceBrightness,
204         OV7725_SetBrightness,
205     },
206     {
207         kCAMERA_DeviceContrast,
208         OV7725_SetContrast,
209     },
210     {
211         kCAMERA_DeviceSpecialEffect,
212         OV7725_SetSpecialEffect,
213     },
214     {
215         kCAMERA_DeviceNightMode,
216         OV7725_SetNightMode,
217     },
218 };
219 
220 static const ov7725_reg_t ov7725InitRegs[] = {
221     {0x3d, 0x03},
222     {0x42, 0x7f},
223     {0x4d, 0x09},
224 
225     /* DSP */
226     {0x64, 0xff},
227     {0x65, 0x20},
228     {0x66, 0x00},
229     {0x67, 0x48},
230     {0x0f, 0xc5},
231     {0x13, 0xff},
232 
233     /* AEC/AGC/AWB */
234     {0x63, 0xe0},
235     {0x14, 0x11},
236     {0x22, 0x3f},
237     {0x23, 0x07},
238     {0x24, 0x40},
239     {0x25, 0x30},
240     {0x26, 0xa1},
241     {0x2b, 0x00},
242     {0x6b, 0xaa},
243     {0x0d, 0x41},
244 
245     /* Sharpness. */
246     {0x90, 0x05},
247     {0x91, 0x01},
248     {0x92, 0x03},
249     {0x93, 0x00},
250 
251     /* Matrix. */
252     {0x94, 0x90},
253     {0x95, 0x8a},
254     {0x96, 0x06},
255     {0x97, 0x0b},
256     {0x98, 0x95},
257     {0x99, 0xa0},
258     {0x9a, 0x1e},
259 
260     /* Brightness. */
261     {0x9b, 0x08},
262     /* Contrast. */
263     {0x9c, 0x20},
264     /* UV */
265     {0x9e, 0x81},
266     /* DSE */
267     {0xa6, 0x04},
268 
269     /* Gamma. */
270     {0x7e, 0x0c},
271     {0x7f, 0x16},
272     {0x80, 0x2a},
273     {0x81, 0x4e},
274     {0x82, 0x61},
275     {0x83, 0x6f},
276     {0x84, 0x7b},
277     {0x85, 0x86},
278     {0x86, 0x8e},
279     {0x87, 0x97},
280     {0x88, 0xa4},
281     {0x89, 0xaf},
282     {0x8a, 0xc5},
283     {0x8b, 0xd7},
284     {0x8c, 0xe8},
285 };
286 
287 /*******************************************************************************
288  * Code
289  ******************************************************************************/
290 
OV7725_DelayMs(uint32_t ms)291 static void OV7725_DelayMs(uint32_t ms)
292 {
293     VIDEO_DelayMs(ms);
294 }
295 
OV7725_WriteRegs(camera_device_handle_t * handle,const ov7725_reg_t regs[],uint32_t num)296 static status_t OV7725_WriteRegs(camera_device_handle_t *handle, const ov7725_reg_t regs[], uint32_t num)
297 {
298     status_t status = kStatus_Success;
299 
300     for (uint32_t i = 0; i < num; i++)
301     {
302         status = OV7725_WriteReg(handle, regs[i].reg, regs[i].val);
303 
304         if (kStatus_Success != status)
305         {
306             break;
307         }
308     }
309 
310     return status;
311 }
312 
OV7725_SoftwareReset(camera_device_handle_t * handle)313 static status_t OV7725_SoftwareReset(camera_device_handle_t *handle)
314 {
315     return OV7725_WriteReg(handle, OV7725_COM7_REG, 0x80);
316 }
317 
OV7725_SetClockConfig(camera_device_handle_t * handle,uint32_t frameRate_Hz,uint32_t inputClk_Hz)318 static status_t OV7725_SetClockConfig(camera_device_handle_t *handle, uint32_t frameRate_Hz, uint32_t inputClk_Hz)
319 {
320     status_t status;
321 
322     for (uint32_t i = 0; i < ARRAY_SIZE(ov7725ClockConfigs); i++)
323     {
324         if ((ov7725ClockConfigs[i].frameRate_Hz == frameRate_Hz) && (ov7725ClockConfigs[i].inputClk_Hz == inputClk_Hz))
325         {
326             OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_CLKRC_REG, ov7725ClockConfigs[i].clkrc));
327             OV7725_CHECK_RET(OV7725_ModifyReg(handle, OV7725_COM4_REG, 0xC0, ov7725ClockConfigs[i].com4));
328             OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_EXHCL_REG, 0x00));
329             OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_DM_LNL_REG, ov7725ClockConfigs[i].dm_lnl));
330             OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_DM_LNH_REG, 0x00));
331             OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_ADVFL_REG, 0x00));
332             OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_ADVFH_REG, 0x00));
333             return OV7725_WriteReg(handle, OV7725_COM5_REG, 0x65);
334         }
335     }
336 
337     return kStatus_InvalidArgument;
338 }
339 
OV7725_SetPixelFormat(camera_device_handle_t * handle,video_pixel_format_t fmt)340 static status_t OV7725_SetPixelFormat(camera_device_handle_t *handle, video_pixel_format_t fmt)
341 {
342     for (uint8_t i = 0; i < ARRAY_SIZE(ov7725PixelFormatConfigs); i++)
343     {
344         if (ov7725PixelFormatConfigs[i].fmt == fmt)
345         {
346             return OV7725_ModifyReg(handle, OV7725_COM7_REG, 0x1FU, ov7725PixelFormatConfigs[i].com7);
347         }
348     }
349 
350     return kStatus_InvalidArgument;
351 }
352 
OV7725_Init(camera_device_handle_t * handle,const camera_config_t * config)353 status_t OV7725_Init(camera_device_handle_t *handle, const camera_config_t *config)
354 {
355     status_t status;
356     uint8_t pid = 0U, ver = 0U;
357     uint8_t com10 = 0;
358     uint8_t tmpReg;
359     uint16_t width, height;
360     uint16_t hstart, vstart, hsize;
361     ov7725_resource_t *resource = (ov7725_resource_t *)(handle->resource);
362 
363     if ((kCAMERA_InterfaceNonGatedClock != config->interface) && (kCAMERA_InterfaceGatedClock != config->interface) &&
364         (kCAMERA_InterfaceCCIR656 != config->interface))
365     {
366         return kStatus_InvalidArgument;
367     }
368 
369     width  = FSL_VIDEO_EXTRACT_WIDTH(config->resolution);
370     height = FSL_VIDEO_EXTRACT_HEIGHT(config->resolution);
371 
372     if ((width > 640U) || (height > 480U))
373     {
374         return kStatus_InvalidArgument;
375     }
376 
377     resource->pullPowerDownPin(true);
378 
379     /* Delay 1ms. */
380     OV7725_DelayMs(1);
381 
382     resource->pullPowerDownPin(false);
383 
384     /* Delay 1ms. */
385     OV7725_DelayMs(1);
386 
387     resource->pullResetPin(false);
388 
389     /* Delay 1ms. */
390     OV7725_DelayMs(1);
391 
392     resource->pullResetPin(true);
393 
394     /* Delay 1ms. */
395     OV7725_DelayMs(1);
396 
397     /* Identify the device. */
398     status = OV7725_ReadReg(handle, OV7725_PID_REG, &pid);
399     if (kStatus_Success != status)
400     {
401         return status;
402     }
403 
404     status = OV7725_ReadReg(handle, OV7725_VER_REG, &ver);
405     if (kStatus_Success != status)
406     {
407         return status;
408     }
409 
410     if (OV7725_REVISION != (((uint32_t)pid << 8U) | (uint32_t)ver))
411     {
412         return kStatus_Fail;
413     }
414 
415     /* Device identify OK, perform software reset. */
416     OV7725_CHECK_RET(OV7725_SoftwareReset(handle));
417 
418     /* Delay 2ms. */
419     OV7725_DelayMs(2);
420 
421     /* Start configuration */
422     status = OV7725_WriteRegs(handle, ov7725InitRegs, ARRAY_SIZE(ov7725InitRegs));
423     if (kStatus_Success != status)
424     {
425         return status;
426     }
427 
428     /* Clock setting. */
429     status = OV7725_SetClockConfig(handle, config->framePerSec, resource->inputClockFreq_Hz);
430     if (kStatus_Success != status)
431     {
432         return status;
433     }
434 
435     /* Pixel format setting. */
436     status = OV7725_SetPixelFormat(handle, config->pixelFormat);
437     if (kStatus_Success != status)
438     {
439         return status;
440     }
441 
442     if (kCAMERA_InterfaceCCIR656 == config->interface)
443     {
444         status = OV7725_ModifyReg(handle, OV7725_COM7_REG, (1U << 5), (1U << 5));
445         width += 2U;
446     }
447     else
448     {
449         status = OV7725_ModifyReg(handle, OV7725_COM7_REG, (1U << 5), (0U << 5));
450     }
451 
452     if (kStatus_Success != status)
453     {
454         return status;
455     }
456 
457     if ((uint32_t)kCAMERA_HrefActiveHigh != (config->controlFlags & (uint32_t)kCAMERA_HrefActiveHigh))
458     {
459         com10 |= OV7725_COM10_HREF_REVERSE_MASK;
460     }
461 
462     if ((uint32_t)kCAMERA_VsyncActiveHigh != (config->controlFlags & (uint32_t)kCAMERA_VsyncActiveHigh))
463     {
464         com10 |= OV7725_COM10_VSYNC_NEG_MASK;
465     }
466 
467     if ((uint32_t)kCAMERA_DataLatchOnRisingEdge != (config->controlFlags & (uint32_t)kCAMERA_DataLatchOnRisingEdge))
468     {
469         com10 |= OV7725_COM10_PCLK_REVERSE_MASK;
470     }
471 
472     if (kCAMERA_InterfaceNonGatedClock == config->interface)
473     {
474         com10 |= OV7725_COM10_PCLK_OUT_MASK;
475     }
476 
477     OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_COM10_REG, com10));
478 
479     /* Don't swap output MSB/LSB. */
480     OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_COM3_REG, 0x00));
481 
482     /*
483      * Output drive capability
484      * 0: 1X
485      * 1: 2X
486      * 2: 3X
487      * 3: 4X
488      */
489     OV7725_CHECK_RET(OV7725_ModifyReg(handle, OV7725_COM2_REG, 0x03, 0x03));
490 
491     /* Resolution and timing. */
492     hstart = 0x22U << 2U;
493     vstart = 0x07U << 1U;
494     hsize  = width + 16U;
495 
496     /* Set the window size. */
497     OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_HSTART_REG, (uint8_t)(hstart >> 2U)));
498     OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_HSIZE_REG, (uint8_t)(hsize >> 2U)));
499     OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_VSTART_REG, (uint8_t)(vstart >> 1U)));
500     OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_VSIZE_REG, (uint8_t)(height >> 1U)));
501     OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_HOUTSIZE_REG, (uint8_t)(width >> 2U)));
502     OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_VOUTSIZE_REG, (uint8_t)(height >> 1U)));
503 
504     tmpReg = (((uint8_t)vstart & 1U) << 6U) | (((uint8_t)hstart & 3U) << 4U) | (((uint8_t)height & 1U) << 2U) |
505              (((uint8_t)hsize & 3U) << 0U);
506 
507     OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_HREF_REG, tmpReg));
508 
509     return OV7725_WriteReg(handle, OV7725_EXHCH_REG, (((uint8_t)height & 1U) << 2U) | (((uint8_t)width & 3U) << 0U));
510 }
511 
OV7725_SetSpecialEffect(camera_device_handle_t * handle,int32_t effect)512 status_t OV7725_SetSpecialEffect(camera_device_handle_t *handle, int32_t effect)
513 {
514     uint8_t i;
515     status_t status;
516 
517     for (i = 0; i < ARRAY_SIZE(ov7725SpecialEffectConfigs); i++)
518     {
519         if (effect == (int32_t)ov7725SpecialEffectConfigs[i].effect)
520         {
521             OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_SDE_REG, ov7725SpecialEffectConfigs[i].sde));
522             OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_UFIX_REG, ov7725SpecialEffectConfigs[i].ufix));
523             OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_VFIX_REG, ov7725SpecialEffectConfigs[i].vfix));
524 
525             return OV7725_ModifyReg(handle, OV7725_DSP_CTRL1_REG, 1U << 5, 1U << 5);
526         }
527     }
528 
529     /* No configuration found. */
530     return kStatus_InvalidArgument;
531 }
532 
OV7725_SetContrast(camera_device_handle_t * handle,int32_t contrast)533 status_t OV7725_SetContrast(camera_device_handle_t *handle, int32_t contrast)
534 {
535     if ((contrast < -4) || (contrast > 4))
536     {
537         return kStatus_InvalidArgument;
538     }
539 
540     contrast *= 4;
541     contrast += 0x20;
542 
543     return OV7725_WriteReg(handle, OV7725_CNST_REG, (uint8_t)contrast);
544 }
545 
OV7725_SetBrightness(camera_device_handle_t * handle,int32_t brightness)546 status_t OV7725_SetBrightness(camera_device_handle_t *handle, int32_t brightness)
547 {
548     status_t status;
549 
550     if ((brightness < -4) || (brightness > 4))
551     {
552         return kStatus_InvalidArgument;
553     }
554 
555     if (brightness >= 0)
556     {
557         OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_BRIGHT_REG, 0x08U + (0x10U * (uint8_t)brightness)));
558         return OV7725_WriteReg(handle, OV7725_SIGN_REG, 0x06);
559     }
560     else
561     {
562         brightness = -brightness - 1;
563         OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_BRIGHT_REG, 0x08U + (0x10U * (uint8_t)brightness)));
564         return OV7725_WriteReg(handle, OV7725_SIGN_REG, 0x0e);
565     }
566 }
567 
OV7725_SetSaturation(camera_device_handle_t * handle,int32_t saturation)568 status_t OV7725_SetSaturation(camera_device_handle_t *handle, int32_t saturation)
569 {
570     status_t status;
571 
572     if ((saturation < -4) || (saturation > 4))
573     {
574         return kStatus_InvalidArgument;
575     }
576 
577     saturation += 4;
578     uint8_t val = (uint8_t)saturation * 0x10U;
579 
580     OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_USAT_REG, val));
581     return OV7725_WriteReg(handle, OV7725_VSAT_REG, val);
582 }
583 
OV7725_SetLightMode(camera_device_handle_t * handle,int32_t lightMode)584 status_t OV7725_SetLightMode(camera_device_handle_t *handle, int32_t lightMode)
585 {
586     uint8_t i;
587     status_t status;
588 
589     for (i = 0; i < ARRAY_SIZE(ov7725LightModeConfigs); i++)
590     {
591         if (lightMode == (int32_t)ov7725LightModeConfigs[i].lightMode)
592         {
593             OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_COM8_REG, ov7725LightModeConfigs[i].com8));
594             OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_BLUE_REG, ov7725LightModeConfigs[i].blue));
595             OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_RED_REG, ov7725LightModeConfigs[i].red));
596             OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_COM5_REG, ov7725LightModeConfigs[i].com5));
597             OV7725_CHECK_RET(OV7725_WriteReg(handle, OV7725_ADVFL_REG, 0));
598             return OV7725_WriteReg(handle, OV7725_ADVFH_REG, 0);
599         }
600     }
601 
602     /* No configuration found. */
603     return kStatus_InvalidArgument;
604 }
605 
OV7725_SetNightMode(camera_device_handle_t * handle,int32_t nightMode)606 status_t OV7725_SetNightMode(camera_device_handle_t *handle, int32_t nightMode)
607 {
608     uint8_t i;
609 
610     for (i = 0; i < ARRAY_SIZE(ov7725NightModeConfigs); i++)
611     {
612         if (nightMode == (int32_t)ov7725NightModeConfigs[i].nightMode)
613         {
614             return OV7725_ModifyReg(handle, OV7725_COM5_REG, 0xF0, ov7725NightModeConfigs[i].com5);
615         }
616     }
617 
618     /* No configuration found. */
619     return kStatus_InvalidArgument;
620 }
621 
OV7725_Deinit(camera_device_handle_t * handle)622 status_t OV7725_Deinit(camera_device_handle_t *handle)
623 {
624     ((ov7725_resource_t *)(handle->resource))->pullPowerDownPin(true);
625 
626     return kStatus_Success;
627 }
628 
OV7725_Control(camera_device_handle_t * handle,camera_device_cmd_t cmd,int32_t arg)629 status_t OV7725_Control(camera_device_handle_t *handle, camera_device_cmd_t cmd, int32_t arg)
630 {
631     for (uint8_t i = 0; i < ARRAY_SIZE(ov7725CmdFuncMap); i++)
632     {
633         if (ov7725CmdFuncMap[i].cmd == cmd)
634         {
635             return ov7725CmdFuncMap[i].func(handle, arg);
636         }
637     }
638 
639     return kStatus_InvalidArgument;
640 }
641 
OV7725_Start(camera_device_handle_t * handle)642 status_t OV7725_Start(camera_device_handle_t *handle)
643 {
644     return kStatus_Success;
645 }
646 
OV7725_Stop(camera_device_handle_t * handle)647 status_t OV7725_Stop(camera_device_handle_t *handle)
648 {
649     return kStatus_Success;
650 }
651 
OV7725_InitExt(camera_device_handle_t * handle,const camera_config_t * config,const void * specialConfig)652 status_t OV7725_InitExt(camera_device_handle_t *handle, const camera_config_t *config, const void *specialConfig)
653 {
654     return OV7725_Init(handle, config);
655 }
656