44 * SPDX-License-Identifier: Apache-2.0
55 */
66
7- #define DT_DRV_COMPAT ovti_ov7670
8-
97#include <zephyr/drivers/gpio.h>
108#include <zephyr/drivers/i2c.h>
119#include <zephyr/drivers/video.h>
1210#include <zephyr/drivers/video-controls.h>
1311#include <zephyr/logging/log.h>
1412
13+ #include "video_common.h"
1514#include "video_ctrls.h"
1615#include "video_device.h"
1716
1817LOG_MODULE_REGISTER (video_ov7670 , CONFIG_VIDEO_LOG_LEVEL );
1918
20- /* Initialization register structure */
21- struct ov7670_reg {
22- uint8_t reg ;
23- uint8_t cmd ;
24- };
25-
2619struct ov7670_config {
2720 struct i2c_dt_spec bus ;
28- #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (reset_gpios )
29- struct gpio_dt_spec reset ;
30- #endif
31- #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (pwdn_gpios )
32- struct gpio_dt_spec pwdn ;
33- #endif
21+ const struct gpio_dt_spec reset ;
22+ const struct gpio_dt_spec pwdn ;
3423};
3524
3625struct ov7670_ctrls {
@@ -43,63 +32,7 @@ struct ov7670_data {
4332 struct video_format fmt ;
4433};
4534
46- struct ov7670_resolution_cfg {
47- uint8_t com7 ;
48- uint8_t com3 ;
49- uint8_t com14 ;
50- uint8_t scaling_xsc ;
51- uint8_t scaling_ysc ;
52- uint8_t dcwctr ;
53- uint8_t pclk_div ;
54- uint8_t pclk_delay ;
55- };
56-
57- /* Resolution settings for camera, based on those present in MCUX SDK */
58- const struct ov7670_resolution_cfg OV7670_RESOLUTION_QCIF = {
59- .com7 = 0x2c ,
60- .com3 = 0x00 ,
61- .com14 = 0x11 ,
62- .scaling_xsc = 0x3a ,
63- .scaling_ysc = 0x35 ,
64- .dcwctr = 0x11 ,
65- .pclk_div = 0xf1 ,
66- .pclk_delay = 0x52
67- };
68-
69- const struct ov7670_resolution_cfg OV7670_RESOLUTION_QVGA = {
70- .com7 = 0x14 ,
71- .com3 = 0x04 ,
72- .com14 = 0x19 ,
73- .scaling_xsc = 0x3a ,
74- .scaling_ysc = 0x35 ,
75- .dcwctr = 0x11 ,
76- .pclk_div = 0xf1 ,
77- .pclk_delay = 0x02
78- };
79-
80- const struct ov7670_resolution_cfg OV7670_RESOLUTION_CIF = {
81- .com7 = 0x24 ,
82- .com3 = 0x08 ,
83- .com14 = 0x11 ,
84- .scaling_xsc = 0x3a ,
85- .scaling_ysc = 0x35 ,
86- .dcwctr = 0x11 ,
87- .pclk_div = 0xf1 ,
88- .pclk_delay = 0x02
89- };
90-
91- const struct ov7670_resolution_cfg OV7670_RESOLUTION_VGA = {
92- .com7 = 0x04 ,
93- .com3 = 0x00 ,
94- .com14 = 0x00 ,
95- .scaling_xsc = 0x3a ,
96- .scaling_ysc = 0x35 ,
97- .dcwctr = 0x11 ,
98- .pclk_div = 0xf0 ,
99- .pclk_delay = 0x02
100- };
101-
102-
35+ #define OV7670_REG8 (addr ) ((addr) | VIDEO_REG_ADDR8_DATA8)
10336/* OV7670 registers */
10437#define OV7670_PID 0x0A
10538#define OV7670_COM7 0x12
@@ -190,37 +123,26 @@ const struct ov7670_resolution_cfg OV7670_RESOLUTION_VGA = {
190123#define OV7670_HAECC6 0xA9
191124
192125/* OV7670 definitions */
193- #define OV7670_PROD_ID 0x76
126+ #define OV7670_PROD_ID 0x76
194127#define OV7670_MVFP_HFLIP 0x20
195128#define OV7670_MVFP_VFLIP 0x10
196129
197- #define OV7670_VIDEO_FORMAT_CAP (width , height , format ) \
130+ #define OV767X_VIDEO_FORMAT_CAP (width , height , format ) \
198131 { \
199132 .pixelformat = (format), .width_min = (width), .width_max = (width), \
200133 .height_min = (height), .height_max = (height), .width_step = 0, .height_step = 0 \
201134 }
202135
203- static const struct video_format_cap fmts [] = {
204- OV7670_VIDEO_FORMAT_CAP (176 , 144 , VIDEO_PIX_FMT_RGB565 ), /* QCIF */
205- OV7670_VIDEO_FORMAT_CAP (320 , 240 , VIDEO_PIX_FMT_RGB565 ), /* QVGA */
206- OV7670_VIDEO_FORMAT_CAP (352 , 288 , VIDEO_PIX_FMT_RGB565 ), /* CIF */
207- OV7670_VIDEO_FORMAT_CAP (640 , 480 , VIDEO_PIX_FMT_RGB565 ), /* VGA */
208- OV7670_VIDEO_FORMAT_CAP (176 , 144 , VIDEO_PIX_FMT_YUYV ), /* QCIF */
209- OV7670_VIDEO_FORMAT_CAP (320 , 240 , VIDEO_PIX_FMT_YUYV ), /* QVGA */
210- OV7670_VIDEO_FORMAT_CAP (352 , 288 , VIDEO_PIX_FMT_YUYV ), /* CIF */
211- OV7670_VIDEO_FORMAT_CAP (640 , 480 , VIDEO_PIX_FMT_YUYV ), /* VGA */
212- {0 }};
213-
214136/*
215137 * This initialization table is based on the MCUX SDK driver for the OV7670.
216138 * Note that this table assumes the camera is fed a 6MHz XCLK signal
217139 */
218- static const struct ov7670_reg ov7670_init_regtbl [] = {
140+ static const struct video_reg8 ov7670_init_regtbl [] = {
219141 {OV7670_MVFP , 0x00 }, /* MVFP: Mirror/VFlip,Normal image */
220142
221143 /* configure the output timing */
222144 /* PCLK does not toggle during horizontal blank, one PCLK, one pixel */
223- {OV7670_COM10 , 0x20 }, /* COM10 */
145+ {OV7670_COM10 , 0x03 }, /* COM10 */
224146 {OV7670_COM12 , 0x00 }, /* COM12,No HREF when VSYNC is low */
225147 /* Brightness Control, with signal -128 to +128, 0x00 is middle value */
226148 {OV7670_BRIGHT , 0x2f },
@@ -369,8 +291,67 @@ static const struct ov7670_reg ov7670_init_regtbl[] = {
369291 {0xb8 , 0x0a },
370292};
371293
294+ #if DT_HAS_COMPAT_STATUS_OKAY (ovti_ov7670 )
295+ /* Resolution settings for camera, based on those present in MCUX SDK */
296+ static const struct video_reg8 ov7670_regs_qcif [] = {
297+ {OV7670_COM7 , 0x2c },
298+ {OV7670_COM3 , 0x00 },
299+ {OV7670_COM14 , 0x11 },
300+ {OV7670_SCALING_XSC , 0x3a },
301+ {OV7670_SCALING_YSC , 0x35 },
302+ {OV7670_SCALING_DCWCTR , 0x11 },
303+ {OV7670_SCALING_PCLK_DIV , 0xf1 },
304+ {OV7670_SCALING_PCLK_DELAY , 0x52 },
305+ };
306+
307+ static const struct video_reg8 ov7670_regs_qvga [] = {
308+ {OV7670_COM7 , 0x14 },
309+ {OV7670_COM3 , 0x04 },
310+ {OV7670_COM14 , 0x19 },
311+ {OV7670_SCALING_XSC , 0x3a },
312+ {OV7670_SCALING_YSC , 0x35 },
313+ {OV7670_SCALING_DCWCTR , 0x11 },
314+ {OV7670_SCALING_PCLK_DIV , 0xf1 },
315+ {OV7670_SCALING_PCLK_DELAY , 0x02 },
316+ };
317+
318+ static const struct video_reg8 ov7670_regs_cif [] = {
319+ {OV7670_COM7 , 0x24 },
320+ {OV7670_COM3 , 0x08 },
321+ {OV7670_COM14 , 0x11 },
322+ {OV7670_SCALING_XSC , 0x3a },
323+ {OV7670_SCALING_YSC , 0x35 },
324+ {OV7670_SCALING_DCWCTR , 0x11 },
325+ {OV7670_SCALING_PCLK_DIV , 0xf1 },
326+ {OV7670_SCALING_PCLK_DELAY , 0x02 },
327+ };
328+
329+ static const struct video_reg8 ov7670_regs_vga [] = {
330+ {OV7670_COM7 , 0x04 },
331+ {OV7670_COM3 , 0x00 },
332+ {OV7670_COM14 , 0x00 },
333+ {OV7670_SCALING_XSC , 0x3a },
334+ {OV7670_SCALING_YSC , 0x35 },
335+ {OV7670_SCALING_DCWCTR , 0x11 },
336+ {OV7670_SCALING_PCLK_DIV , 0xf0 },
337+ {OV7670_SCALING_PCLK_DELAY , 0x02 },
338+ };
339+
340+ static const struct video_format_cap fmts [] = {
341+ OV767X_VIDEO_FORMAT_CAP (176 , 144 , VIDEO_PIX_FMT_RGB565 ), /* QCIF */
342+ OV767X_VIDEO_FORMAT_CAP (320 , 240 , VIDEO_PIX_FMT_RGB565 ), /* QVGA */
343+ OV767X_VIDEO_FORMAT_CAP (352 , 288 , VIDEO_PIX_FMT_RGB565 ), /* CIF */
344+ OV767X_VIDEO_FORMAT_CAP (640 , 480 , VIDEO_PIX_FMT_RGB565 ), /* VGA */
345+ OV767X_VIDEO_FORMAT_CAP (176 , 144 , VIDEO_PIX_FMT_YUYV ), /* QCIF */
346+ OV767X_VIDEO_FORMAT_CAP (320 , 240 , VIDEO_PIX_FMT_YUYV ), /* QVGA */
347+ OV767X_VIDEO_FORMAT_CAP (352 , 288 , VIDEO_PIX_FMT_YUYV ), /* CIF */
348+ OV767X_VIDEO_FORMAT_CAP (640 , 480 , VIDEO_PIX_FMT_YUYV ), /* VGA */
349+ {0 }};
350+ #endif
351+
372352static int ov7670_get_caps (const struct device * dev , struct video_caps * caps )
373353{
354+
374355 caps -> format_caps = fmts ;
375356 return 0 ;
376357}
@@ -379,7 +360,6 @@ static int ov7670_set_fmt(const struct device *dev, struct video_format *fmt)
379360{
380361 const struct ov7670_config * config = dev -> config ;
381362 struct ov7670_data * data = dev -> data ;
382- const struct ov7670_resolution_cfg * resolution ;
383363 int ret ;
384364 uint8_t i = 0U ;
385365
@@ -397,67 +377,38 @@ static int ov7670_set_fmt(const struct device *dev, struct video_format *fmt)
397377
398378 /* Set output resolution */
399379 while (fmts [i ].pixelformat ) {
400- if (fmts [i ].width_min == fmt -> width && fmts [i ].height_min == fmt -> height &&
380+ if (fmts [i ].width_min == fmt -> width &&
381+ fmts [i ].height_min == fmt -> height &&
401382 fmts [i ].pixelformat == fmt -> pixelformat ) {
402383 /* Set output format */
403384 switch (fmts [i ].width_min ) {
404385 case 176 : /* QCIF */
405- resolution = & OV7670_RESOLUTION_QCIF ;
406- break ;
407- case 320 : /* QVGA */
408- resolution = & OV7670_RESOLUTION_QVGA ;
386+ ret = video_write_cci_multiregs8 (& config -> bus , ov7670_regs_qcif ,
387+ ARRAY_SIZE (ov7670_regs_qcif ));
409388 break ;
410389 case 352 : /* CIF */
411- resolution = & OV7670_RESOLUTION_CIF ;
390+ ret = video_write_cci_multiregs8 (& config -> bus , ov7670_regs_cif ,
391+ ARRAY_SIZE (ov7670_regs_cif ));
412392 break ;
393+ case 320 : /* QVGA */
394+ ret = video_write_cci_multiregs8 (& config -> bus , ov7670_regs_qvga ,
395+ ARRAY_SIZE (ov7670_regs_qvga ));
396+ break ;
397+
413398 default : /* VGA */
414- resolution = & OV7670_RESOLUTION_VGA ;
399+ ret = video_write_cci_multiregs8 (& config -> bus , ov7670_regs_vga ,
400+ ARRAY_SIZE (ov7670_regs_vga ));
415401 break ;
416402 }
417- /* Program resolution bytes settings */
418- ret = i2c_reg_write_byte_dt (& config -> bus , OV7670_COM7 ,
419- resolution -> com7 );
420403 if (ret < 0 ) {
404+ LOG_ERR ("Resolution not set or not supported!" );
421405 return ret ;
422406 }
423- ret = i2c_reg_write_byte_dt (& config -> bus , OV7670_COM3 ,
424- resolution -> com3 );
425- if (ret < 0 ) {
426- return ret ;
427- }
428- ret = i2c_reg_write_byte_dt (& config -> bus , OV7670_COM14 ,
429- resolution -> com14 );
430- if (ret < 0 ) {
431- return ret ;
432- }
433- ret = i2c_reg_write_byte_dt (& config -> bus , OV7670_SCALING_XSC ,
434- resolution -> scaling_xsc );
435- if (ret < 0 ) {
436- return ret ;
437- }
438- ret = i2c_reg_write_byte_dt (& config -> bus , OV7670_SCALING_YSC ,
439- resolution -> scaling_ysc );
440- if (ret < 0 ) {
441- return ret ;
442- }
443- ret = i2c_reg_write_byte_dt (& config -> bus , OV7670_SCALING_DCWCTR ,
444- resolution -> dcwctr );
445- if (ret < 0 ) {
446- return ret ;
447- }
448- ret = i2c_reg_write_byte_dt (& config -> bus , OV7670_SCALING_PCLK_DIV ,
449- resolution -> pclk_div );
450- if (ret < 0 ) {
451- return ret ;
452- }
453- return i2c_reg_write_byte_dt (& config -> bus , OV7670_SCALING_PCLK_DELAY ,
454- resolution -> pclk_delay );
455407 }
456408 i ++ ;
457409 }
458410
459- LOG_ERR ("Unsupported format" );
460- return - ENOTSUP ;
411+ return 0 ;
461412}
462413
463414static int ov7670_get_fmt (const struct device * dev , struct video_format * fmt )
@@ -487,14 +438,13 @@ static int ov7670_init_controls(const struct device *dev)
487438static int ov7670_init (const struct device * dev )
488439{
489440 const struct ov7670_config * config = dev -> config ;
490- int ret , i ;
441+ int ret ;
491442 uint8_t pid ;
492443 struct video_format fmt = {
493444 .pixelformat = VIDEO_PIX_FMT_RGB565 ,
494445 .width = 320 ,
495446 .height = 240 ,
496447 };
497- const struct ov7670_reg * reg ;
498448
499449 if (!i2c_is_ready_dt (& config -> bus )) {
500450 /* I2C device is not ready, return */
@@ -559,7 +509,7 @@ static int ov7670_init(const struct device *dev)
559509 }
560510
561511 /* Reset camera registers */
562- ret = i2c_reg_write_byte_dt (& config -> bus , OV7670_COM7 , 0x80 );
512+ ret = video_write_cci_reg (& config -> bus , OV7670_REG8 ( OV7670_COM7 ) , 0x80 );
563513 if (ret < 0 ) {
564514 LOG_ERR ("Could not reset camera: %d" , ret );
565515 return ret ;
@@ -573,12 +523,10 @@ static int ov7670_init(const struct device *dev)
573523 }
574524
575525 /* Write initialization values to OV7670 */
576- for (i = 0 ; i < ARRAY_SIZE (ov7670_init_regtbl ); i ++ ) {
577- reg = & ov7670_init_regtbl [i ];
578- ret = i2c_reg_write_byte_dt (& config -> bus , reg -> reg , reg -> cmd );
579- if (ret < 0 ) {
580- return ret ;
581- }
526+ ret = video_write_cci_multiregs8 (& config -> bus , ov7670_init_regtbl ,
527+ ARRAY_SIZE (ov7670_init_regtbl ));
528+ if (ret < 0 ) {
529+ return ret ;
582530 }
583531
584532 /* Initialize controls */
@@ -616,27 +564,28 @@ static DEVICE_API(video, ov7670_api) = {
616564 .set_ctrl = ov7670_set_ctrl ,
617565};
618566
619- #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (reset_gpios )
620- #define OV7670_RESET_GPIO (inst ) .reset = GPIO_DT_SPEC_INST_GET_OR(inst, reset_gpios, {}),
621- #else
622- #define OV7670_RESET_GPIO (inst )
623- #endif
624-
625- #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (pwdn_gpios )
626- #define OV7670_PWDN_GPIO (inst ) .pwdn = GPIO_DT_SPEC_INST_GET_OR(inst, pwdn_gpios, {}),
627- #else
628- #define OV7670_PWDN_GPIO (inst )
629- #endif
630-
631- #define OV7670_INIT (inst ) \
632- const struct ov7670_config ov7670_config_##inst = {.bus = I2C_DT_SPEC_INST_GET(inst), \
633- OV7670_RESET_GPIO(inst) \
634- OV7670_PWDN_GPIO(inst)}; \
635- struct ov7670_data ov7670_data_##inst; \
636- \
637- DEVICE_DT_INST_DEFINE(inst, ov7670_init, NULL, &ov7670_data_##inst, &ov7670_config_##inst, \
638- POST_KERNEL, CONFIG_VIDEO_INIT_PRIORITY, &ov7670_api); \
639- \
640- VIDEO_DEVICE_DEFINE(ov7670_##inst, DEVICE_DT_INST_GET(inst), NULL);
641-
642- DT_INST_FOREACH_STATUS_OKAY (OV7670_INIT )
567+ #define OV7670_INIT (n , id ) \
568+ static const struct ov7670_config ov7670_config_##n = { \
569+ .bus = I2C_DT_SPEC_INST_GET(n), \
570+ .reset = \
571+ GPIO_DT_SPEC_INST_GET_OR(n, reset_gpios, {}), \
572+ .pwdn = \
573+ GPIO_DT_SPEC_INST_GET_OR(n, pwdn_gpios, {}), \
574+ }; \
575+ \
576+ static struct ov7670_data ov7670_data_##n; \
577+ \
578+ DEVICE_DT_INST_DEFINE(n, \
579+ ov7670_init, \
580+ NULL, \
581+ &ov7670##_data_##n, \
582+ &ov7670##_config_##n, \
583+ POST_KERNEL, CONFIG_VIDEO_INIT_PRIORITY, \
584+ &ov7670_api); \
585+ \
586+ VIDEO_DEVICE_DEFINE(ov7670_##n, DEVICE_DT_INST_GET(n), NULL); \
587+
588+
589+ #undef DT_DRV_COMPAT
590+ #define DT_DRV_COMPAT ovti_ov7670
591+ DT_INST_FOREACH_STATUS_OKAY_VARGS (OV7670_INIT , 7670 )
0 commit comments