11/*
22 * Copyright 2024 NXP
3+ * Copyright 2021 Arduino SA
4+ * Copyright (c) 2025 Michael Smorto
35 *
46 * SPDX-License-Identifier: Apache-2.0
57 */
1618#include "video_ctrls.h"
1719#include "video_device.h"
1820
19- LOG_MODULE_REGISTER (video_ov7670 , CONFIG_VIDEO_LOG_LEVEL );
21+ LOG_MODULE_REGISTER (video_ov767x , CONFIG_VIDEO_LOG_LEVEL );
2022
21- struct ov7670_config {
23+ struct ov767x_config {
2224 struct i2c_dt_spec bus ;
25+ uint32_t camera_model ;
26+ const struct video_format_cap * fmts ;
2327#if DT_ANY_INST_HAS_PROP_STATUS_OKAY (reset_gpios )
2428 struct gpio_dt_spec reset ;
2529#endif
@@ -28,13 +32,13 @@ struct ov7670_config {
2832#endif
2933};
3034
31- struct ov7670_ctrls {
35+ struct ov767x_ctrls {
3236 struct video_ctrl hflip ;
3337 struct video_ctrl vflip ;
3438};
3539
36- struct ov7670_data {
37- struct ov7670_ctrls ctrls ;
40+ struct ov767x_data {
41+ struct ov767x_ctrls ctrls ;
3842 struct video_format fmt ;
3943};
4044
@@ -133,29 +137,32 @@ struct ov7670_data {
133137#define OV7670_MVFP_HFLIP 0x20
134138#define OV7670_MVFP_VFLIP 0x10
135139
136- #define OV7670_VIDEO_FORMAT_CAP (width , height , format ) \
140+ #define OV767X_MODEL_OV7670 7670
141+ #define OV767X_MODEL_OV7675 7675
142+
143+ #define OV767X_VIDEO_FORMAT_CAP (width , height , format ) \
137144{ \
138145 .pixelformat = (format), .width_min = (width), .width_max = (width), \
139146 .height_min = (height), .height_max = (height), .width_step = 0, .height_step = 0 \
140147}
141148
142- static const struct video_format_cap fmts [] = {
143- OV7670_VIDEO_FORMAT_CAP (176 , 144 , VIDEO_PIX_FMT_RGB565 ), /* QCIF */
144- OV7670_VIDEO_FORMAT_CAP (320 , 240 , VIDEO_PIX_FMT_RGB565 ), /* QVGA */
145- OV7670_VIDEO_FORMAT_CAP (352 , 288 , VIDEO_PIX_FMT_RGB565 ), /* CIF */
146- OV7670_VIDEO_FORMAT_CAP (640 , 480 , VIDEO_PIX_FMT_RGB565 ), /* VGA */
147- OV7670_VIDEO_FORMAT_CAP (176 , 144 , VIDEO_PIX_FMT_YUYV ), /* QCIF */
148- OV7670_VIDEO_FORMAT_CAP (320 , 240 , VIDEO_PIX_FMT_YUYV ), /* QVGA */
149- OV7670_VIDEO_FORMAT_CAP (352 , 288 , VIDEO_PIX_FMT_YUYV ), /* CIF */
150- OV7670_VIDEO_FORMAT_CAP (640 , 480 , VIDEO_PIX_FMT_YUYV ), /* VGA */
149+ static const struct video_format_cap ov7670_fmts [] = {
150+ OV767X_VIDEO_FORMAT_CAP (176 , 144 , VIDEO_PIX_FMT_RGB565 ), /* QCIF */
151+ OV767X_VIDEO_FORMAT_CAP (320 , 240 , VIDEO_PIX_FMT_RGB565 ), /* QVGA */
152+ OV767X_VIDEO_FORMAT_CAP (352 , 288 , VIDEO_PIX_FMT_RGB565 ), /* CIF */
153+ OV767X_VIDEO_FORMAT_CAP (640 , 480 , VIDEO_PIX_FMT_RGB565 ), /* VGA */
154+ OV767X_VIDEO_FORMAT_CAP (176 , 144 , VIDEO_PIX_FMT_YUYV ), /* QCIF */
155+ OV767X_VIDEO_FORMAT_CAP (320 , 240 , VIDEO_PIX_FMT_YUYV ), /* QVGA */
156+ OV767X_VIDEO_FORMAT_CAP (352 , 288 , VIDEO_PIX_FMT_YUYV ), /* CIF */
157+ OV767X_VIDEO_FORMAT_CAP (640 , 480 , VIDEO_PIX_FMT_YUYV ), /* VGA */
151158 {0 }
152159};
153160
154161/*
155162 * This initialization table is based on the MCUX SDK driver for the OV7670.
156163 * Note that this table assumes the camera is fed a 6MHz XCLK signal
157164 */
158- static const struct video_reg8 ov7670_init_regtbl [] = {
165+ static const struct video_reg8 ov767x_init_regtbl [] = {
159166 {OV7670_MVFP , 0x00 }, /* MVFP: Mirror/VFlip,Normal image */
160167
161168 /* configure the output timing */
@@ -354,16 +361,19 @@ static const struct video_reg8 ov7670_regs_vga[] = {
354361 {OV7670_SCALING_PCLK_DELAY , 0x02 },
355362};
356363
357- static int ov7670_get_caps (const struct device * dev , struct video_caps * caps )
364+ static int ov767x_get_caps (const struct device * dev , struct video_caps * caps )
358365{
359- caps -> format_caps = fmts ;
366+ const struct ov767x_config * config = dev -> config ;
367+
368+ caps -> format_caps = config -> fmts ;
360369 return 0 ;
361370}
362371
372+ #if DT_HAS_COMPAT_STATUS_OKAY (ovti_ov7670 )
363373static int ov7670_set_fmt (const struct device * dev , struct video_format * fmt )
364374{
365- const struct ov7670_config * config = dev -> config ;
366- struct ov7670_data * data = dev -> data ;
375+ const struct ov767x_config * config = dev -> config ;
376+ struct ov767x_data * data = dev -> data ;
367377 int ret = - ENOTSUP ;
368378 uint8_t i = 0U ;
369379
@@ -372,20 +382,13 @@ static int ov7670_set_fmt(const struct device *dev, struct video_format *fmt)
372382 return - ENOTSUP ;
373383 }
374384
375- if (!memcmp (& data -> fmt , fmt , sizeof (data -> fmt ))) {
376- /* nothing to do */
377- return 0 ;
378- }
379-
380- memcpy (& data -> fmt , fmt , sizeof (data -> fmt ));
381-
382385 /* Set output resolution */
383- while (fmts [i ].pixelformat ) {
384- if (fmts [i ].width_min == fmt -> width &&
385- fmts [i ].height_min == fmt -> height &&
386- fmts [i ].pixelformat == fmt -> pixelformat ) {
386+ while (config -> fmts [i ].pixelformat ) {
387+ if (config -> fmts [i ].width_min == fmt -> width &&
388+ config -> fmts [i ].height_min == fmt -> height &&
389+ config -> fmts [i ].pixelformat == fmt -> pixelformat ) {
387390 /* Set output format */
388- switch (fmts [i ].width_min ) {
391+ switch (config -> fmts [i ].width_min ) {
389392 case 176 : /* QCIF */
390393 ret = video_write_cci_multiregs8 (& config -> bus , ov7670_regs_qcif ,
391394 ARRAY_SIZE (ov7670_regs_qcif ));
@@ -422,20 +425,40 @@ static int ov7670_set_fmt(const struct device *dev, struct video_format *fmt)
422425
423426 return 0 ;
424427}
428+ #endif
425429
426- static int ov7670_get_fmt (const struct device * dev , struct video_format * fmt )
430+ static int ov767x_set_fmt (const struct device * dev , struct video_format * fmt )
427431{
428- struct ov7670_data * data = dev -> data ;
432+ int ret ;
433+
434+ if (fmt -> pixelformat != VIDEO_PIX_FMT_RGB565 && fmt -> pixelformat != VIDEO_PIX_FMT_YUYV ) {
435+ LOG_ERR ("Only RGB565 and YUYV supported!" );
436+ return - ENOTSUP ;
437+ }
438+
439+ #if DT_HAS_COMPAT_STATUS_OKAY (ovti_ov7670 )
440+ ret = ov7670_set_fmt (dev , fmt );
441+ if (ret < 0 ) {
442+ return ret ;
443+ }
444+ #endif
445+
446+ return 0 ;
447+ }
448+
449+ static int ov767x_get_fmt (const struct device * dev , struct video_format * fmt )
450+ {
451+ struct ov767x_data * data = dev -> data ;
429452
430453 memcpy (fmt , & data -> fmt , sizeof (data -> fmt ));
431454 return 0 ;
432455}
433456
434- static int ov7670_init_controls (const struct device * dev )
457+ static int ov767x_init_controls (const struct device * dev )
435458{
436459 int ret ;
437- struct ov7670_data * drv_data = dev -> data ;
438- struct ov7670_ctrls * ctrls = & drv_data -> ctrls ;
460+ struct ov767x_data * drv_data = dev -> data ;
461+ struct ov767x_ctrls * ctrls = & drv_data -> ctrls ;
439462
440463 ret = video_init_ctrl (& ctrls -> hflip , dev , VIDEO_CID_HFLIP ,
441464 (struct video_ctrl_range ){.min = 0 , .max = 1 , .step = 1 , .def = 0 });
@@ -447,9 +470,9 @@ static int ov7670_init_controls(const struct device *dev)
447470 (struct video_ctrl_range ){.min = 0 , .max = 1 , .step = 1 , .def = 0 });
448471}
449472
450- static int ov7670_init (const struct device * dev )
473+ static int ov767x_init (const struct device * dev )
451474{
452- const struct ov7670_config * config = dev -> config ;
475+ const struct ov767x_config * config = dev -> config ;
453476 int ret ;
454477 uint8_t pid ;
455478 struct video_format fmt = {
@@ -463,7 +486,7 @@ static int ov7670_init(const struct device *dev)
463486 return - ENODEV ;
464487 }
465488
466- #if DT_ANY_INST_HAS_PROP_STATUS_OKAY ( pwdn_gpios )
489+ #if DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY ( ovti_ov7670 , pwdn_gpios )
467490 /* Power up camera module */
468491 if (config -> pwdn .port != NULL ) {
469492 if (!gpio_is_ready_dt (& config -> pwdn )) {
@@ -476,7 +499,8 @@ static int ov7670_init(const struct device *dev)
476499 }
477500 }
478501#endif
479- #if DT_ANY_INST_HAS_PROP_STATUS_OKAY (reset_gpios )
502+
503+ #if DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY (ovti_ov7670 , reset_gpios )
480504 /* Reset camera module */
481505 if (config -> reset .port != NULL ) {
482506 if (!gpio_is_ready_dt (& config -> reset )) {
@@ -528,35 +552,32 @@ static int ov7670_init(const struct device *dev)
528552 }
529553 /* Delay after reset */
530554 k_msleep (5 );
531-
532- ret = ov7670_set_fmt (dev , & fmt );
533-
555+ ret = ov767x_set_fmt (dev , & fmt );
534556 if (ret < 0 ) {
535557 return ret ;
536558 }
537559
538560 /* Write initialization values to OV7670 */
539- ret = video_write_cci_multiregs8 (& config -> bus , ov7670_init_regtbl ,
540- ARRAY_SIZE (ov7670_init_regtbl ));
541-
561+ ret = video_write_cci_multiregs8 (& config -> bus , ov767x_init_regtbl ,
562+ ARRAY_SIZE (ov767x_init_regtbl ));
542563 if (ret < 0 ) {
543564 return ret ;
544565 }
545566
546567 /* Initialize controls */
547- return ov7670_init_controls (dev );
568+ return ov767x_init_controls (dev );
548569}
549570
550- static int ov7670_set_stream (const struct device * dev , bool enable , enum video_buf_type type )
571+ static int ov767x_set_stream (const struct device * dev , bool enable , enum video_buf_type type )
551572{
552573 return 0 ;
553574}
554575
555- static int ov7670_set_ctrl (const struct device * dev , uint32_t id )
576+ static int ov767x_set_ctrl (const struct device * dev , uint32_t id )
556577{
557- const struct ov7670_config * config = dev -> config ;
558- struct ov7670_data * drv_data = dev -> data ;
559- struct ov7670_ctrls * ctrls = & drv_data -> ctrls ;
578+ const struct ov767x_config * config = dev -> config ;
579+ struct ov767x_data * drv_data = dev -> data ;
580+ struct ov767x_ctrls * ctrls = & drv_data -> ctrls ;
560581
561582 switch (id ) {
562583 case VIDEO_CID_HFLIP :
@@ -570,36 +591,41 @@ static int ov7670_set_ctrl(const struct device *dev, uint32_t id)
570591 }
571592}
572593
573- static DEVICE_API (video , ov7670_api ) = {
574- .set_format = ov7670_set_fmt ,
575- .get_format = ov7670_get_fmt ,
576- .get_caps = ov7670_get_caps ,
577- .set_stream = ov7670_set_stream ,
578- .set_ctrl = ov7670_set_ctrl ,
594+ static DEVICE_API (video , ov767x_api ) = {
595+ .set_format = ov767x_set_fmt ,
596+ .get_format = ov767x_get_fmt ,
597+ .get_caps = ov767x_get_caps ,
598+ .set_stream = ov767x_set_stream ,
599+ .set_ctrl = ov767x_set_ctrl ,
579600};
580601
581602#if DT_ANY_INST_HAS_PROP_STATUS_OKAY (reset_gpios )
582- #define OV7670_RESET_GPIO (inst ) .reset = GPIO_DT_SPEC_INST_GET_OR(inst, reset_gpios, {}),
603+ #define OV767X_RESET_GPIO (inst ) .reset = GPIO_DT_SPEC_INST_GET_OR(inst, reset_gpios, {}),
583604#else
584- #define OV7670_RESET_GPIO (inst )
605+ #define OV767X_RESET_GPIO (inst )
585606#endif
586607
587608#if DT_ANY_INST_HAS_PROP_STATUS_OKAY (pwdn_gpios )
588- #define OV7670_PWDN_GPIO (inst ) .pwdn = GPIO_DT_SPEC_INST_GET_OR(inst, pwdn_gpios, {}),
609+ #define OV767X_PWDN_GPIO (inst ) .pwdn = GPIO_DT_SPEC_INST_GET_OR(inst, pwdn_gpios, {}),
589610#else
590- #define OV7670_PWDN_GPIO (inst )
611+ #define OV767X_PWDN_GPIO (inst )
591612#endif
592613
593- #define OV7670_INIT (inst ) \
594- const struct ov7670_config ov7670_config_##inst = {.bus = I2C_DT_SPEC_INST_GET(inst), \
595- OV7670_RESET_GPIO(inst) \
596- OV7670_PWDN_GPIO(inst)}; \
614+ #define OV767X_INIT (inst , id ) \
615+ static const struct ov767x_config ov##id##_config##inst = { \
616+ .bus = I2C_DT_SPEC_INST_GET(inst), \
617+ .camera_model = id, \
618+ .fmts = ov##id##_fmts, \
619+ OV767X_RESET_GPIO(inst) OV767X_PWDN_GPIO(inst)}; \
597620 \
598- struct ov7670_data ov7670_data_## inst; \
621+ static struct ov767x_data ov##id##_data## inst; \
599622 \
600- DEVICE_DT_INST_DEFINE(inst, ov7670_init, NULL, &ov7670_data_##inst, &ov7670_config_##inst, \
601- POST_KERNEL, CONFIG_VIDEO_INIT_PRIORITY, &ov7670_api); \
623+ DEVICE_DT_INST_DEFINE(inst, ov767x_init, NULL, &ov##id##_data##inst, \
624+ &ov##id##_config##inst, POST_KERNEL, CONFIG_VIDEO_INIT_PRIORITY, \
625+ &ov767x_api); \
602626 \
603- VIDEO_DEVICE_DEFINE(ov7670_ ##inst, DEVICE_DT_INST_GET(inst), NULL);
627+ VIDEO_DEVICE_DEFINE(ov##id ##inst, DEVICE_DT_INST_GET(inst), NULL);
604628
605- DT_INST_FOREACH_STATUS_OKAY (OV7670_INIT )
629+ #undef DT_DRV_COMPAT
630+ #define DT_DRV_COMPAT ovti_ov7670
631+ DT_INST_FOREACH_STATUS_OKAY_VARGS (OV767X_INIT , 7670 )
0 commit comments