From f2c62992fab8b29b96fb7ad2baa34f9e4fb72aca Mon Sep 17 00:00:00 2001 From: Mike S Date: Mon, 13 Oct 2025 08:42:08 -0400 Subject: [PATCH 1/5] drivers: video: Restructure OV760.c driver before adding OV7675 support drivers: video: Restructure OV760.c driver before adding OV7675 support Modifications for use of video cci helpers in video_common.h. Signed-off-by: Mike S --- drivers/video/ov7670.c | 217 +++++++++++++++++------------------------ 1 file changed, 90 insertions(+), 127 deletions(-) diff --git a/drivers/video/ov7670.c b/drivers/video/ov7670.c index 448b0e659bcf3..a6b450ea95424 100644 --- a/drivers/video/ov7670.c +++ b/drivers/video/ov7670.c @@ -12,17 +12,12 @@ #include #include +#include "video_common.h" #include "video_ctrls.h" #include "video_device.h" LOG_MODULE_REGISTER(video_ov7670, CONFIG_VIDEO_LOG_LEVEL); -/* Initialization register structure */ -struct ov7670_reg { - uint8_t reg; - uint8_t cmd; -}; - struct ov7670_config { struct i2c_dt_spec bus; #if DT_ANY_INST_HAS_PROP_STATUS_OKAY(reset_gpios) @@ -43,63 +38,7 @@ struct ov7670_data { struct video_format fmt; }; -struct ov7670_resolution_cfg { - uint8_t com7; - uint8_t com3; - uint8_t com14; - uint8_t scaling_xsc; - uint8_t scaling_ysc; - uint8_t dcwctr; - uint8_t pclk_div; - uint8_t pclk_delay; -}; - -/* Resolution settings for camera, based on those present in MCUX SDK */ -const struct ov7670_resolution_cfg OV7670_RESOLUTION_QCIF = { - .com7 = 0x2c, - .com3 = 0x00, - .com14 = 0x11, - .scaling_xsc = 0x3a, - .scaling_ysc = 0x35, - .dcwctr = 0x11, - .pclk_div = 0xf1, - .pclk_delay = 0x52 -}; - -const struct ov7670_resolution_cfg OV7670_RESOLUTION_QVGA = { - .com7 = 0x14, - .com3 = 0x04, - .com14 = 0x19, - .scaling_xsc = 0x3a, - .scaling_ysc = 0x35, - .dcwctr = 0x11, - .pclk_div = 0xf1, - .pclk_delay = 0x02 -}; - -const struct ov7670_resolution_cfg OV7670_RESOLUTION_CIF = { - .com7 = 0x24, - .com3 = 0x08, - .com14 = 0x11, - .scaling_xsc = 0x3a, - .scaling_ysc = 0x35, - .dcwctr = 0x11, - .pclk_div = 0xf1, - .pclk_delay = 0x02 -}; - -const struct ov7670_resolution_cfg OV7670_RESOLUTION_VGA = { - .com7 = 0x04, - .com3 = 0x00, - .com14 = 0x00, - .scaling_xsc = 0x3a, - .scaling_ysc = 0x35, - .dcwctr = 0x11, - .pclk_div = 0xf0, - .pclk_delay = 0x02 -}; - - +#define OV7670_REG8(addr) ((addr) | VIDEO_REG_ADDR8_DATA8) /* OV7670 registers */ #define OV7670_PID 0x0A #define OV7670_COM7 0x12 @@ -195,10 +134,10 @@ const struct ov7670_resolution_cfg OV7670_RESOLUTION_VGA = { #define OV7670_MVFP_VFLIP 0x10 #define OV7670_VIDEO_FORMAT_CAP(width, height, format) \ - { \ - .pixelformat = (format), .width_min = (width), .width_max = (width), \ - .height_min = (height), .height_max = (height), .width_step = 0, .height_step = 0 \ - } +{ \ + .pixelformat = (format), .width_min = (width), .width_max = (width), \ + .height_min = (height), .height_max = (height), .width_step = 0, .height_step = 0 \ +} static const struct video_format_cap fmts[] = { OV7670_VIDEO_FORMAT_CAP(176, 144, VIDEO_PIX_FMT_RGB565), /* QCIF */ @@ -209,13 +148,14 @@ static const struct video_format_cap fmts[] = { OV7670_VIDEO_FORMAT_CAP(320, 240, VIDEO_PIX_FMT_YUYV), /* QVGA */ OV7670_VIDEO_FORMAT_CAP(352, 288, VIDEO_PIX_FMT_YUYV), /* CIF */ OV7670_VIDEO_FORMAT_CAP(640, 480, VIDEO_PIX_FMT_YUYV), /* VGA */ - {0}}; + {0} +}; /* * This initialization table is based on the MCUX SDK driver for the OV7670. * Note that this table assumes the camera is fed a 6MHz XCLK signal */ -static const struct ov7670_reg ov7670_init_regtbl[] = { +static const struct video_reg8 ov7670_init_regtbl[] = { {OV7670_MVFP, 0x00}, /* MVFP: Mirror/VFlip,Normal image */ /* configure the output timing */ @@ -369,6 +309,51 @@ static const struct ov7670_reg ov7670_init_regtbl[] = { {0xb8, 0x0a}, }; +/* Resolution settings for camera, based on those present in MCUX SDK */ +static const struct video_reg8 ov7670_regs_qcif[] = { + {OV7670_COM7, 0x2c}, + {OV7670_COM3, 0x00}, + {OV7670_COM14, 0x11}, + {OV7670_SCALING_XSC, 0x3a}, + {OV7670_SCALING_YSC, 0x35}, + {OV7670_SCALING_DCWCTR, 0x11}, + {OV7670_SCALING_PCLK_DIV, 0xf1}, + {OV7670_SCALING_PCLK_DELAY, 0x52}, +}; + +static const struct video_reg8 ov7670_regs_qvga[] = { + {OV7670_COM7, 0x14}, + {OV7670_COM3, 0x04}, + {OV7670_COM14, 0x19}, + {OV7670_SCALING_XSC, 0x3a}, + {OV7670_SCALING_YSC, 0x35}, + {OV7670_SCALING_DCWCTR, 0x11}, + {OV7670_SCALING_PCLK_DIV, 0xf1}, + {OV7670_SCALING_PCLK_DELAY, 0x02}, +}; + +static const struct video_reg8 ov7670_regs_cif[] = { + {OV7670_COM7, 0x24}, + {OV7670_COM3, 0x08}, + {OV7670_COM14, 0x11}, + {OV7670_SCALING_XSC, 0x3a}, + {OV7670_SCALING_YSC, 0x35}, + {OV7670_SCALING_DCWCTR, 0x11}, + {OV7670_SCALING_PCLK_DIV, 0xf1}, + {OV7670_SCALING_PCLK_DELAY, 0x02}, +}; + +static const struct video_reg8 ov7670_regs_vga[] = { + {OV7670_COM7, 0x04}, + {OV7670_COM3, 0x00}, + {OV7670_COM14, 0x00}, + {OV7670_SCALING_XSC, 0x3a}, + {OV7670_SCALING_YSC, 0x35}, + {OV7670_SCALING_DCWCTR, 0x11}, + {OV7670_SCALING_PCLK_DIV, 0xf0}, + {OV7670_SCALING_PCLK_DELAY, 0x02}, +}; + static int ov7670_get_caps(const struct device *dev, struct video_caps *caps) { caps->format_caps = fmts; @@ -379,8 +364,7 @@ static int ov7670_set_fmt(const struct device *dev, struct video_format *fmt) { const struct ov7670_config *config = dev->config; struct ov7670_data *data = dev->data; - const struct ov7670_resolution_cfg *resolution; - int ret; + int ret = -ENOTSUP; uint8_t i = 0U; if (fmt->pixelformat != VIDEO_PIX_FMT_RGB565 && fmt->pixelformat != VIDEO_PIX_FMT_YUYV) { @@ -397,67 +381,46 @@ static int ov7670_set_fmt(const struct device *dev, struct video_format *fmt) /* Set output resolution */ while (fmts[i].pixelformat) { - if (fmts[i].width_min == fmt->width && fmts[i].height_min == fmt->height && - fmts[i].pixelformat == fmt->pixelformat) { + if (fmts[i].width_min == fmt->width && + fmts[i].height_min == fmt->height && + fmts[i].pixelformat == fmt->pixelformat) { /* Set output format */ switch (fmts[i].width_min) { case 176: /* QCIF */ - resolution = &OV7670_RESOLUTION_QCIF; + ret = video_write_cci_multiregs8(&config->bus, ov7670_regs_qcif, + ARRAY_SIZE(ov7670_regs_qcif)); + break; + case 352: /* QCIF */ + ret = video_write_cci_multiregs8(&config->bus, ov7670_regs_cif, + ARRAY_SIZE(ov7670_regs_cif)); break; case 320: /* QVGA */ - resolution = &OV7670_RESOLUTION_QVGA; + ret = video_write_cci_multiregs8(&config->bus, ov7670_regs_qvga, + ARRAY_SIZE(ov7670_regs_qvga)); break; - case 352: /* CIF */ - resolution = &OV7670_RESOLUTION_CIF; + case 640: /* VGA */ + ret = video_write_cci_multiregs8(&config->bus, ov7670_regs_vga, + ARRAY_SIZE(ov7670_regs_vga)); break; - default: /* VGA */ - resolution = &OV7670_RESOLUTION_VGA; + default: /* QVGA */ + ret = video_write_cci_multiregs8(&config->bus, ov7670_regs_qvga, + ARRAY_SIZE(ov7670_regs_vga)); break; } - /* Program resolution bytes settings */ - ret = i2c_reg_write_byte_dt(&config->bus, OV7670_COM7, - resolution->com7); - if (ret < 0) { - return ret; - } - ret = i2c_reg_write_byte_dt(&config->bus, OV7670_COM3, - resolution->com3); - if (ret < 0) { - return ret; - } - ret = i2c_reg_write_byte_dt(&config->bus, OV7670_COM14, - resolution->com14); - if (ret < 0) { - return ret; - } - ret = i2c_reg_write_byte_dt(&config->bus, OV7670_SCALING_XSC, - resolution->scaling_xsc); - if (ret < 0) { - return ret; - } - ret = i2c_reg_write_byte_dt(&config->bus, OV7670_SCALING_YSC, - resolution->scaling_ysc); - if (ret < 0) { - return ret; - } - ret = i2c_reg_write_byte_dt(&config->bus, OV7670_SCALING_DCWCTR, - resolution->dcwctr); if (ret < 0) { + LOG_ERR("Resolution not set!"); return ret; } - ret = i2c_reg_write_byte_dt(&config->bus, OV7670_SCALING_PCLK_DIV, - resolution->pclk_div); - if (ret < 0) { - return ret; - } - return i2c_reg_write_byte_dt(&config->bus, OV7670_SCALING_PCLK_DELAY, - resolution->pclk_delay); } i++; } - LOG_ERR("Unsupported format"); - return -ENOTSUP; + if (ret < 0) { + LOG_ERR("Resolution not supported!"); + return ret; + } + + return 0; } static int ov7670_get_fmt(const struct device *dev, struct video_format *fmt) @@ -487,14 +450,13 @@ static int ov7670_init_controls(const struct device *dev) static int ov7670_init(const struct device *dev) { const struct ov7670_config *config = dev->config; - int ret, i; + int ret; uint8_t pid; struct video_format fmt = { .pixelformat = VIDEO_PIX_FMT_RGB565, .width = 320, .height = 240, }; - const struct ov7670_reg *reg; if (!i2c_is_ready_dt(&config->bus)) { /* I2C device is not ready, return */ @@ -559,7 +521,7 @@ static int ov7670_init(const struct device *dev) } /* Reset camera registers */ - ret = i2c_reg_write_byte_dt(&config->bus, OV7670_COM7, 0x80); + ret = video_write_cci_reg(&config->bus, OV7670_REG8(OV7670_COM7), 0x80); if (ret < 0) { LOG_ERR("Could not reset camera: %d", ret); return ret; @@ -568,17 +530,17 @@ static int ov7670_init(const struct device *dev) k_msleep(5); ret = ov7670_set_fmt(dev, &fmt); + if (ret < 0) { return ret; } /* Write initialization values to OV7670 */ - for (i = 0; i < ARRAY_SIZE(ov7670_init_regtbl); i++) { - reg = &ov7670_init_regtbl[i]; - ret = i2c_reg_write_byte_dt(&config->bus, reg->reg, reg->cmd); - if (ret < 0) { - return ret; - } + ret = video_write_cci_multiregs8(&config->bus, ov7670_init_regtbl, + ARRAY_SIZE(ov7670_init_regtbl)); + + if (ret < 0) { + return ret; } /* Initialize controls */ @@ -631,7 +593,8 @@ static DEVICE_API(video, ov7670_api) = { #define OV7670_INIT(inst) \ const struct ov7670_config ov7670_config_##inst = {.bus = I2C_DT_SPEC_INST_GET(inst), \ OV7670_RESET_GPIO(inst) \ - OV7670_PWDN_GPIO(inst)}; \ + OV7670_PWDN_GPIO(inst)}; \ + \ struct ov7670_data ov7670_data_##inst; \ \ DEVICE_DT_INST_DEFINE(inst, ov7670_init, NULL, &ov7670_data_##inst, &ov7670_config_##inst, \ @@ -639,4 +602,4 @@ static DEVICE_API(video, ov7670_api) = { \ VIDEO_DEVICE_DEFINE(ov7670_##inst, DEVICE_DT_INST_GET(inst), NULL); -DT_INST_FOREACH_STATUS_OKAY(OV7670_INIT) +DT_INST_FOREACH_STATUS_OKAY(OV7670_INIT) \ No newline at end of file From 39aeac472859570fadf3081a4dde1ee0fae67943 Mon Sep 17 00:00:00 2001 From: Mike S Date: Mon, 13 Oct 2025 09:05:49 -0400 Subject: [PATCH 2/5] drivers: video: Update OV7670 to use generic ov767x functions drivers: video: Update OV7670 to use generic ov767x functions Minimal changes to OV760 drive to use generic ov767x structures. - This includes changes to function names. - Includes changes to defines as necessary. - Deleted camera_id as no longer required Signed-off-by: Mike S --- drivers/video/ov7670.c | 185 ++++++++++++++++++++++++----------------- 1 file changed, 108 insertions(+), 77 deletions(-) diff --git a/drivers/video/ov7670.c b/drivers/video/ov7670.c index a6b450ea95424..22f3c3ce0efdd 100644 --- a/drivers/video/ov7670.c +++ b/drivers/video/ov7670.c @@ -1,5 +1,7 @@ /* * Copyright 2024 NXP + * Copyright 2021 Arduino SA + * Copyright (c) 2025 Michael Smorto * * SPDX-License-Identifier: Apache-2.0 */ @@ -16,10 +18,12 @@ #include "video_ctrls.h" #include "video_device.h" -LOG_MODULE_REGISTER(video_ov7670, CONFIG_VIDEO_LOG_LEVEL); +LOG_MODULE_REGISTER(video_ov767x, CONFIG_VIDEO_LOG_LEVEL); -struct ov7670_config { +struct ov767x_config { struct i2c_dt_spec bus; + uint32_t camera_model; + const struct video_format_cap *fmts; #if DT_ANY_INST_HAS_PROP_STATUS_OKAY(reset_gpios) struct gpio_dt_spec reset; #endif @@ -28,13 +32,13 @@ struct ov7670_config { #endif }; -struct ov7670_ctrls { +struct ov767x_ctrls { struct video_ctrl hflip; struct video_ctrl vflip; }; -struct ov7670_data { - struct ov7670_ctrls ctrls; +struct ov767x_data { + struct ov767x_ctrls ctrls; struct video_format fmt; }; @@ -133,21 +137,24 @@ struct ov7670_data { #define OV7670_MVFP_HFLIP 0x20 #define OV7670_MVFP_VFLIP 0x10 -#define OV7670_VIDEO_FORMAT_CAP(width, height, format) \ +#define OV767X_MODEL_OV7670 7670 +#define OV767X_MODEL_OV7675 7675 + +#define OV767X_VIDEO_FORMAT_CAP(width, height, format) \ { \ .pixelformat = (format), .width_min = (width), .width_max = (width), \ .height_min = (height), .height_max = (height), .width_step = 0, .height_step = 0 \ } -static const struct video_format_cap fmts[] = { - OV7670_VIDEO_FORMAT_CAP(176, 144, VIDEO_PIX_FMT_RGB565), /* QCIF */ - OV7670_VIDEO_FORMAT_CAP(320, 240, VIDEO_PIX_FMT_RGB565), /* QVGA */ - OV7670_VIDEO_FORMAT_CAP(352, 288, VIDEO_PIX_FMT_RGB565), /* CIF */ - OV7670_VIDEO_FORMAT_CAP(640, 480, VIDEO_PIX_FMT_RGB565), /* VGA */ - OV7670_VIDEO_FORMAT_CAP(176, 144, VIDEO_PIX_FMT_YUYV), /* QCIF */ - OV7670_VIDEO_FORMAT_CAP(320, 240, VIDEO_PIX_FMT_YUYV), /* QVGA */ - OV7670_VIDEO_FORMAT_CAP(352, 288, VIDEO_PIX_FMT_YUYV), /* CIF */ - OV7670_VIDEO_FORMAT_CAP(640, 480, VIDEO_PIX_FMT_YUYV), /* VGA */ +static const struct video_format_cap ov7670_fmts[] = { + OV767X_VIDEO_FORMAT_CAP(176, 144, VIDEO_PIX_FMT_RGB565), /* QCIF */ + OV767X_VIDEO_FORMAT_CAP(320, 240, VIDEO_PIX_FMT_RGB565), /* QVGA */ + OV767X_VIDEO_FORMAT_CAP(352, 288, VIDEO_PIX_FMT_RGB565), /* CIF */ + OV767X_VIDEO_FORMAT_CAP(640, 480, VIDEO_PIX_FMT_RGB565), /* VGA */ + OV767X_VIDEO_FORMAT_CAP(176, 144, VIDEO_PIX_FMT_YUYV), /* QCIF */ + OV767X_VIDEO_FORMAT_CAP(320, 240, VIDEO_PIX_FMT_YUYV), /* QVGA */ + OV767X_VIDEO_FORMAT_CAP(352, 288, VIDEO_PIX_FMT_YUYV), /* CIF */ + OV767X_VIDEO_FORMAT_CAP(640, 480, VIDEO_PIX_FMT_YUYV), /* VGA */ {0} }; @@ -155,7 +162,7 @@ static const struct video_format_cap fmts[] = { * This initialization table is based on the MCUX SDK driver for the OV7670. * Note that this table assumes the camera is fed a 6MHz XCLK signal */ -static const struct video_reg8 ov7670_init_regtbl[] = { +static const struct video_reg8 ov767x_init_regtbl[] = { {OV7670_MVFP, 0x00}, /* MVFP: Mirror/VFlip,Normal image */ /* configure the output timing */ @@ -354,38 +361,29 @@ static const struct video_reg8 ov7670_regs_vga[] = { {OV7670_SCALING_PCLK_DELAY, 0x02}, }; -static int ov7670_get_caps(const struct device *dev, struct video_caps *caps) +static int ov767x_get_caps(const struct device *dev, struct video_caps *caps) { - caps->format_caps = fmts; + const struct ov767x_config *config = dev->config; + + caps->format_caps = config->fmts; return 0; } +#if DT_HAS_COMPAT_STATUS_OKAY(ovti_ov7670) static int ov7670_set_fmt(const struct device *dev, struct video_format *fmt) { - const struct ov7670_config *config = dev->config; - struct ov7670_data *data = dev->data; + const struct ov767x_config *config = dev->config; + struct ov767x_data *data = dev->data; int ret = -ENOTSUP; uint8_t i = 0U; - if (fmt->pixelformat != VIDEO_PIX_FMT_RGB565 && fmt->pixelformat != VIDEO_PIX_FMT_YUYV) { - LOG_ERR("Only RGB565 and YUYV supported!"); - return -ENOTSUP; - } - - if (!memcmp(&data->fmt, fmt, sizeof(data->fmt))) { - /* nothing to do */ - return 0; - } - - memcpy(&data->fmt, fmt, sizeof(data->fmt)); - /* Set output resolution */ - while (fmts[i].pixelformat) { - if (fmts[i].width_min == fmt->width && - fmts[i].height_min == fmt->height && - fmts[i].pixelformat == fmt->pixelformat) { + while (config->fmts[i].pixelformat) { + if (config->fmts[i].width_min == fmt->width && + config->fmts[i].height_min == fmt->height && + config->fmts[i].pixelformat == fmt->pixelformat) { /* Set output format */ - switch (fmts[i].width_min) { + switch (config->fmts[i].width_min) { case 176: /* QCIF */ ret = video_write_cci_multiregs8(&config->bus, ov7670_regs_qcif, ARRAY_SIZE(ov7670_regs_qcif)); @@ -422,20 +420,49 @@ static int ov7670_set_fmt(const struct device *dev, struct video_format *fmt) return 0; } +#endif -static int ov7670_get_fmt(const struct device *dev, struct video_format *fmt) +static int ov767x_set_fmt(const struct device *dev, struct video_format *fmt) { - struct ov7670_data *data = dev->data; + const struct ov767x_config *config = dev->config; + struct ov767x_data *data = dev->data; + int ret; + + if (fmt->pixelformat != VIDEO_PIX_FMT_RGB565 && fmt->pixelformat != VIDEO_PIX_FMT_YUYV) { + LOG_ERR("Only RGB565 and YUYV supported!"); + return -ENOTSUP; + } + + if (!memcmp(&data->fmt, fmt, sizeof(data->fmt))) { + /* nothing to do */ + return 0; + } + + memcpy(&data->fmt, fmt, sizeof(data->fmt)); + +#if DT_HAS_COMPAT_STATUS_OKAY(ovti_ov7670) + ret = ov7670_set_fmt(dev, fmt); + if (ret < 0) { + return ret; + } +#endif + + return 0; +} + +static int ov767x_get_fmt(const struct device *dev, struct video_format *fmt) +{ + struct ov767x_data *data = dev->data; memcpy(fmt, &data->fmt, sizeof(data->fmt)); return 0; } -static int ov7670_init_controls(const struct device *dev) +static int ov767x_init_controls(const struct device *dev) { int ret; - struct ov7670_data *drv_data = dev->data; - struct ov7670_ctrls *ctrls = &drv_data->ctrls; + struct ov767x_data *drv_data = dev->data; + struct ov767x_ctrls *ctrls = &drv_data->ctrls; ret = video_init_ctrl(&ctrls->hflip, dev, VIDEO_CID_HFLIP, (struct video_ctrl_range){.min = 0, .max = 1, .step = 1, .def = 0}); @@ -447,9 +474,9 @@ static int ov7670_init_controls(const struct device *dev) (struct video_ctrl_range){.min = 0, .max = 1, .step = 1, .def = 0}); } -static int ov7670_init(const struct device *dev) +static int ov767x_init(const struct device *dev) { - const struct ov7670_config *config = dev->config; + const struct ov767x_config *config = dev->config; int ret; uint8_t pid; struct video_format fmt = { @@ -463,7 +490,7 @@ static int ov7670_init(const struct device *dev) return -ENODEV; } -#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(pwdn_gpios) +#if DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(ovti_ov7670, pwdn_gpios) /* Power up camera module */ if (config->pwdn.port != NULL) { if (!gpio_is_ready_dt(&config->pwdn)) { @@ -476,7 +503,8 @@ static int ov7670_init(const struct device *dev) } } #endif -#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(reset_gpios) + +#if DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(ovti_ov7670, reset_gpios) /* Reset camera module */ if (config->reset.port != NULL) { if (!gpio_is_ready_dt(&config->reset)) { @@ -528,35 +556,32 @@ static int ov7670_init(const struct device *dev) } /* Delay after reset */ k_msleep(5); - - ret = ov7670_set_fmt(dev, &fmt); - + ret = ov767x_set_fmt(dev, &fmt); if (ret < 0) { return ret; } /* Write initialization values to OV7670 */ - ret = video_write_cci_multiregs8(&config->bus, ov7670_init_regtbl, - ARRAY_SIZE(ov7670_init_regtbl)); - + ret = video_write_cci_multiregs8(&config->bus, ov767x_init_regtbl, + ARRAY_SIZE(ov767x_init_regtbl)); if (ret < 0) { return ret; } /* Initialize controls */ - return ov7670_init_controls(dev); + return ov767x_init_controls(dev); } -static int ov7670_set_stream(const struct device *dev, bool enable, enum video_buf_type type) +static int ov767x_set_stream(const struct device *dev, bool enable, enum video_buf_type type) { return 0; } -static int ov7670_set_ctrl(const struct device *dev, uint32_t id) +static int ov767x_set_ctrl(const struct device *dev, uint32_t id) { - const struct ov7670_config *config = dev->config; - struct ov7670_data *drv_data = dev->data; - struct ov7670_ctrls *ctrls = &drv_data->ctrls; + const struct ov767x_config *config = dev->config; + struct ov767x_data *drv_data = dev->data; + struct ov767x_ctrls *ctrls = &drv_data->ctrls; switch (id) { case VIDEO_CID_HFLIP: @@ -570,36 +595,42 @@ static int ov7670_set_ctrl(const struct device *dev, uint32_t id) } } -static DEVICE_API(video, ov7670_api) = { - .set_format = ov7670_set_fmt, - .get_format = ov7670_get_fmt, - .get_caps = ov7670_get_caps, - .set_stream = ov7670_set_stream, - .set_ctrl = ov7670_set_ctrl, +static DEVICE_API(video, ov767x_api) = { + .set_format = ov767x_set_fmt, + .get_format = ov767x_get_fmt, + .get_caps = ov767x_get_caps, + .set_stream = ov767x_set_stream, + .set_ctrl = ov767x_set_ctrl, }; #if DT_ANY_INST_HAS_PROP_STATUS_OKAY(reset_gpios) -#define OV7670_RESET_GPIO(inst) .reset = GPIO_DT_SPEC_INST_GET_OR(inst, reset_gpios, {}), +#define OV767X_RESET_GPIO(inst) .reset = GPIO_DT_SPEC_INST_GET_OR(inst, reset_gpios, {}), #else -#define OV7670_RESET_GPIO(inst) +#define OV767X_RESET_GPIO(inst) #endif #if DT_ANY_INST_HAS_PROP_STATUS_OKAY(pwdn_gpios) -#define OV7670_PWDN_GPIO(inst) .pwdn = GPIO_DT_SPEC_INST_GET_OR(inst, pwdn_gpios, {}), +#define OV767X_PWDN_GPIO(inst) .pwdn = GPIO_DT_SPEC_INST_GET_OR(inst, pwdn_gpios, {}), #else -#define OV7670_PWDN_GPIO(inst) +#define OV767X_PWDN_GPIO(inst) #endif -#define OV7670_INIT(inst) \ - const struct ov7670_config ov7670_config_##inst = {.bus = I2C_DT_SPEC_INST_GET(inst), \ - OV7670_RESET_GPIO(inst) \ - OV7670_PWDN_GPIO(inst)}; \ +#define OV767X_INIT(inst, id) \ + static const struct ov767x_config ov##id##_config##inst = { \ + .bus = I2C_DT_SPEC_INST_GET(inst), \ + .camera_model = id, \ + .fmts = ov##id##_fmts, \ + OV767X_RESET_GPIO(inst) \ + OV767X_PWDN_GPIO(inst)}; \ \ - struct ov7670_data ov7670_data_##inst; \ + static struct ov767x_data ov##id##_data##inst; \ \ - DEVICE_DT_INST_DEFINE(inst, ov7670_init, NULL, &ov7670_data_##inst, &ov7670_config_##inst, \ - POST_KERNEL, CONFIG_VIDEO_INIT_PRIORITY, &ov7670_api); \ + DEVICE_DT_INST_DEFINE(inst, ov767x_init, NULL, &ov##id##_data##inst, \ + &ov##id##_config##inst, POST_KERNEL, CONFIG_VIDEO_INIT_PRIORITY, \ + &ov767x_api); \ \ - VIDEO_DEVICE_DEFINE(ov7670_##inst, DEVICE_DT_INST_GET(inst), NULL); + VIDEO_DEVICE_DEFINE(ov##id##inst, DEVICE_DT_INST_GET(inst), NULL); -DT_INST_FOREACH_STATUS_OKAY(OV7670_INIT) \ No newline at end of file +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT ovti_ov7670 +DT_INST_FOREACH_STATUS_OKAY_VARGS(OV767X_INIT, 7670) From f2469692dc81928e0589c4ddbd4237688c07ebdf Mon Sep 17 00:00:00 2001 From: Mike S Date: Mon, 13 Oct 2025 09:29:19 -0400 Subject: [PATCH 3/5] drivers: video Changes ov7670 driver name to ov767x.c drivers: video Changes ov7670 driver name to ov767x.c Changes driver name from ov7670.c to ov767x.c. Signed-off-by: Mike S --- drivers/video/CMakeLists.txt | 2 +- drivers/video/{ov7670.c => ov767x.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename drivers/video/{ov7670.c => ov767x.c} (100%) diff --git a/drivers/video/CMakeLists.txt b/drivers/video/CMakeLists.txt index fbe85f808bdad..66d1671b9289d 100644 --- a/drivers/video/CMakeLists.txt +++ b/drivers/video/CMakeLists.txt @@ -17,7 +17,7 @@ zephyr_library_sources_ifdef(CONFIG_VIDEO_GC2145 gc2145.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_STM32_DCMI video_stm32_dcmi.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_STM32_VENC video_stm32_venc.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_OV5640 ov5640.c) -zephyr_library_sources_ifdef(CONFIG_VIDEO_OV7670 ov7670.c) +zephyr_library_sources_ifdef(CONFIG_VIDEO_OV7670 ov767x.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_OV9655 ov9655.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_ESP32 video_esp32_dvp.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_MCUX_SDMA video_mcux_smartdma.c) diff --git a/drivers/video/ov7670.c b/drivers/video/ov767x.c similarity index 100% rename from drivers/video/ov7670.c rename to drivers/video/ov767x.c From 022c38b1f5d54c0af62547a98908ef005c4153d9 Mon Sep 17 00:00:00 2001 From: Mike S Date: Mon, 13 Oct 2025 09:38:58 -0400 Subject: [PATCH 4/5] drivers: video Add OV7675 changes to OV767x drivers: video Add OV7675 changes to OV767x This commit adds in support for the OV7675 camera. Signed-off-by: Mike S --- drivers/video/CMakeLists.txt | 1 + drivers/video/Kconfig | 2 + drivers/video/Kconfig.ov7675 | 10 + drivers/video/ov767x.c | 239 ++++++++++++++++++++-- dts/bindings/video/ovti,ov7675.yaml | 24 +++ tests/drivers/build_all/video/app.overlay | 8 +- 6 files changed, 265 insertions(+), 19 deletions(-) create mode 100644 drivers/video/Kconfig.ov7675 create mode 100644 dts/bindings/video/ovti,ov7675.yaml diff --git a/drivers/video/CMakeLists.txt b/drivers/video/CMakeLists.txt index 66d1671b9289d..07961d29839c0 100644 --- a/drivers/video/CMakeLists.txt +++ b/drivers/video/CMakeLists.txt @@ -19,6 +19,7 @@ zephyr_library_sources_ifdef(CONFIG_VIDEO_STM32_VENC video_stm32_venc.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_OV5640 ov5640.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_OV7670 ov767x.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_OV9655 ov9655.c) +zephyr_library_sources_ifdef(CONFIG_VIDEO_OV7675 ov767x.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_ESP32 video_esp32_dvp.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_MCUX_SDMA video_mcux_smartdma.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_EMUL_IMAGER video_emul_imager.c) diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index e9b12334e09a4..af3cd8c9e83c3 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -88,6 +88,8 @@ source "drivers/video/Kconfig.ov5640" source "drivers/video/Kconfig.ov7670" +source "drivers/video/Kconfig.ov7675" + source "drivers/video/Kconfig.ov9655" source "drivers/video/Kconfig.gc2145" diff --git a/drivers/video/Kconfig.ov7675 b/drivers/video/Kconfig.ov7675 new file mode 100644 index 0000000000000..d72468ab7fbbf --- /dev/null +++ b/drivers/video/Kconfig.ov7675 @@ -0,0 +1,10 @@ +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +config VIDEO_OV7675 + bool "OV7675 CMOS digital image sensor" + select I2C + depends on DT_HAS_OVTI_OV7675_ENABLED + default y + help + Enable driver for OV7675 CMOS digital image sensor device. diff --git a/drivers/video/ov767x.c b/drivers/video/ov767x.c index 22f3c3ce0efdd..c9302fc0dd06f 100644 --- a/drivers/video/ov767x.c +++ b/drivers/video/ov767x.c @@ -1,6 +1,7 @@ /* * Copyright 2024 NXP * Copyright 2021 Arduino SA + * Copyright (c) 2017 OpenMV * Copyright (c) 2025 Michael Smorto * * SPDX-License-Identifier: Apache-2.0 @@ -24,10 +25,12 @@ struct ov767x_config { struct i2c_dt_spec bus; uint32_t camera_model; const struct video_format_cap *fmts; -#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(reset_gpios) +#if DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(ovti_ov7670, reset_gpios) || \ + DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(ovti_ov7675, reset_gpios) struct gpio_dt_spec reset; #endif -#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(pwdn_gpios) +#if DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(ovti_ov7670, pwdn_gpios) || \ + DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(ovti_ov7675, pwdn_gpios) struct gpio_dt_spec pwdn; #endif }; @@ -132,6 +135,17 @@ struct ov767x_data { #define OV7670_HAECC5 0xA8 #define OV7670_HAECC6 0xA9 +/* Addition defines to support OV7675 */ +#define OV7670_RGB444 0x8C /* REG444 */ +#define OV7675_COM3_DCW_EN 0x04 /* DCW enable */ +#define OV7670_COM1 0x04 /*Com Cntrl1 */ +#define OV7675_COM7_RGB_FMT 0x04 /* Output format RGB */ +#define OV7675_COM13_GAMMA_EN 0x80 /* Gamma enable */ +#define OV7675_COM13_UVSAT_AUTO 0x40 /* UV saturation level - UV auto adjustment. */ +#define OV7675_COM15_OUT_00_FF 0xC0 /* Output data range 00 to FF */ +#define OV7675_COM15_FMT_RGB_NORMAL 0x00 /* Normal RGB normal output */ +#define OV7675_COM15_FMT_RGB565 0x10 /* Normal RGB 565 output */ + /* OV7670 definitions */ #define OV7670_PROD_ID 0x76 #define OV7670_MVFP_HFLIP 0x20 @@ -141,11 +155,12 @@ struct ov767x_data { #define OV767X_MODEL_OV7675 7675 #define OV767X_VIDEO_FORMAT_CAP(width, height, format) \ -{ \ - .pixelformat = (format), .width_min = (width), .width_max = (width), \ - .height_min = (height), .height_max = (height), .width_step = 0, .height_step = 0 \ -} + { \ + .pixelformat = (format), .width_min = (width), .width_max = (width), \ + .height_min = (height), .height_max = (height), .width_step = 0, .height_step = 0 \ + } +#if DT_HAS_COMPAT_STATUS_OKAY(ovti_ov7670) static const struct video_format_cap ov7670_fmts[] = { OV767X_VIDEO_FORMAT_CAP(176, 144, VIDEO_PIX_FMT_RGB565), /* QCIF */ OV767X_VIDEO_FORMAT_CAP(320, 240, VIDEO_PIX_FMT_RGB565), /* QVGA */ @@ -157,6 +172,19 @@ static const struct video_format_cap ov7670_fmts[] = { OV767X_VIDEO_FORMAT_CAP(640, 480, VIDEO_PIX_FMT_YUYV), /* VGA */ {0} }; +#endif + +#if DT_HAS_COMPAT_STATUS_OKAY(ovti_ov7675) +static const struct video_format_cap ov7675_fmts[] = { + OV767X_VIDEO_FORMAT_CAP(160, 120, VIDEO_PIX_FMT_RGB565), /* QQVGA */ + OV767X_VIDEO_FORMAT_CAP(320, 240, VIDEO_PIX_FMT_RGB565), /* QVGA */ + OV767X_VIDEO_FORMAT_CAP(640, 480, VIDEO_PIX_FMT_RGB565), /* VGA */ + OV767X_VIDEO_FORMAT_CAP(160, 120, VIDEO_PIX_FMT_YUYV), /* QQVGA */ + OV767X_VIDEO_FORMAT_CAP(320, 240, VIDEO_PIX_FMT_YUYV), /* QVGA */ + OV767X_VIDEO_FORMAT_CAP(640, 480, VIDEO_PIX_FMT_YUYV), /* VGA */ + {0} +}; +#endif /* * This initialization table is based on the MCUX SDK driver for the OV7670. @@ -171,8 +199,6 @@ static const struct video_reg8 ov767x_init_regtbl[] = { {OV7670_COM12, 0x00}, /* COM12,No HREF when VSYNC is low */ /* Brightness Control, with signal -128 to +128, 0x00 is middle value */ {OV7670_BRIGHT, 0x2f}, - - /* Internal clock pre-scalar,F(internal clock) = F(input clock)/(Bit[5:0]+1) */ {OV7670_CLKRC, 0x81}, /* Clock Div, Input/(n+1), bit6 set to 1 to disable divider */ /* SCALING_PCLK_DIV */ @@ -316,6 +342,38 @@ static const struct video_reg8 ov767x_init_regtbl[] = { {0xb8, 0x0a}, }; +/* TODO: These registers probably need to be fixed too. */ +static const struct video_reg8 ov767x_yuv422_regs[] = { + {OV7670_COM7, 0x00}, /* Selects YUV mode */ + {OV7670_RGB444, 0x00}, /* No RGB444 please */ + {OV7670_COM1, 0x00}, /* CCIR601 */ + {OV7670_COM15, OV7675_COM15_OUT_00_FF}, + {OV7670_COM9, 0x48}, /* 32x gain ceiling; 0x8 is reserved bit */ + {0x4f, 0x80}, /* "matrix coefficient 1" */ + {0x50, 0x80}, /* "matrix coefficient 2" */ + {0x51, 0x00}, /* vb */ + {0x52, 0x22}, /* "matrix coefficient 4" */ + {0x53, 0x5e}, /* "matrix coefficient 5" */ + {0x54, 0x80}, /* "matrix coefficient 6" */ + {OV7670_COM13, OV7675_COM13_GAMMA_EN | OV7675_COM13_UVSAT_AUTO}, +}; + +#if DT_HAS_COMPAT_STATUS_OKAY(ovti_ov7670) +static const struct video_reg8 ov7670_rgb565_regs[] = { + {OV7670_COM7, OV7675_COM7_RGB_FMT}, /* Selects RGB mode */ + {OV7670_RGB444, 0x00}, /* No RGB444 please */ + {OV7670_COM1, 0x00}, /* CCIR601 */ + {OV7670_COM15, OV7675_COM15_OUT_00_FF | OV7675_COM15_FMT_RGB565}, + {OV7670_COM9, 0x6a}, /* 16x gain ceiling; 0x8 is reserved bit */ + {0x4f, 0xb3}, /* "matrix coefficient 1" */ + {0x50, 0xb3}, /* "matrix coefficient 2" */ + {0x51, 0x00}, /* "matrix Coefficient 3" */ + {0x52, 0x3d}, /* "matrix coefficient 4" */ + {0x53, 0xa7}, /* "matrix coefficient 5" */ + {0x54, 0xe4}, /* "matrix coefficient 6" */ + {OV7670_COM13, OV7675_COM13_UVSAT_AUTO}, +}; + /* Resolution settings for camera, based on those present in MCUX SDK */ static const struct video_reg8 ov7670_regs_qcif[] = { {OV7670_COM7, 0x2c}, @@ -360,6 +418,57 @@ static const struct video_reg8 ov7670_regs_vga[] = { {OV7670_SCALING_PCLK_DIV, 0xf0}, {OV7670_SCALING_PCLK_DELAY, 0x02}, }; +#endif + +#if DT_HAS_COMPAT_STATUS_OKAY(ovti_ov7675) +static const struct video_reg8 ov7675_rgb565_regs[] = { + {OV7670_COM7, OV7675_COM7_RGB_FMT}, /* Selects RGB mode */ + {OV7670_RGB444, 0x00}, /* No RGB444 please */ + {OV7670_COM1, 0x00}, /* CCIR601 */ + {OV7670_COM15, OV7675_COM15_OUT_00_FF | OV7675_COM15_FMT_RGB565}, + {OV7670_COM9, 0x38}, /* 16x gain ceiling; 0x8 is reserved bit */ + {0x4f, 0xb3}, /* "matrix coefficient 1" */ + {0x50, 0xb3}, /* "matrix coefficient 2" */ + {0x51, 0x00}, /* "matrix Coefficient 3" */ + {0x52, 0x3d}, /* "matrix coefficient 4" */ + {0x53, 0xa7}, /* "matrix coefficient 5" */ + {0x54, 0xe4}, /* "matrix coefficient 6" */ + {OV7670_COM13, OV7675_COM13_GAMMA_EN | OV7675_COM13_UVSAT_AUTO}, +}; + +static const struct video_reg8 ov7675_regs_vga[] = { + {OV7670_COM3, 0x00}, {OV7670_COM14, 0x00}, {0x72, 0x11}, /* downsample by 4 */ + {0x73, 0xf0}, /* divide by 4 */ + {OV7670_HSTART, 0x12}, {OV7670_HSTOP, 0x00}, {OV7670_HREF, 0xb6}, + {OV7670_VSTRT, 0x02}, {OV7670_VSTOP, 0x7a}, {OV7670_VREF, 0x00}, +}; + +static const struct video_reg8 ov7675_regs_qvga[] = { + {OV7670_COM3, OV7675_COM3_DCW_EN}, + {OV7670_COM14, 0x11}, /* Divide by 2 */ + {0x72, 0x22}, + {0x73, 0xf2}, + {OV7670_HSTART, 0x15}, + {OV7670_HSTOP, 0x03}, + {OV7670_HREF, 0xC0}, + {OV7670_VSTRT, 0x03}, + {OV7670_VSTOP, 0x7B}, + {OV7670_VREF, 0xF0}, +}; + +static const struct video_reg8 ov7675_regs_qqvga[] = { + {OV7670_COM3, OV7675_COM3_DCW_EN}, + {OV7670_COM14, 0x11}, /* Divide by 2 */ + {0x72, 0x22}, + {0x73, 0xf2}, + {OV7670_HSTART, 0x16}, + {OV7670_HSTOP, 0x04}, + {OV7670_HREF, 0xa4}, + {OV7670_VSTRT, 0x22}, + {OV7670_VSTOP, 0x7a}, + {OV7670_VREF, 0xfa}, +}; +#endif static int ov767x_get_caps(const struct device *dev, struct video_caps *caps) { @@ -373,10 +482,25 @@ static int ov767x_get_caps(const struct device *dev, struct video_caps *caps) static int ov7670_set_fmt(const struct device *dev, struct video_format *fmt) { const struct ov767x_config *config = dev->config; - struct ov767x_data *data = dev->data; int ret = -ENOTSUP; uint8_t i = 0U; + /* Set RGB Format */ + if (fmt->pixelformat == VIDEO_PIX_FMT_RGB565) { + ret = video_write_cci_multiregs8(&config->bus, ov7670_rgb565_regs, + ARRAY_SIZE(ov7670_rgb565_regs)); + } else if (fmt->pixelformat == VIDEO_PIX_FMT_YUYV) { + ret = video_write_cci_multiregs8(&config->bus, ov767x_yuv422_regs, + ARRAY_SIZE(ov767x_yuv422_regs)); + } else { + LOG_ERR("Image format not supported"); + ret = -ENOTSUP; + } + if (ret < 0) { + LOG_ERR("Format not set!"); + return ret; + } + /* Set output resolution */ while (config->fmts[i].pixelformat) { if (config->fmts[i].width_min == fmt->width && @@ -412,7 +536,69 @@ static int ov7670_set_fmt(const struct device *dev, struct video_format *fmt) } i++; } + if (ret < 0) { + LOG_ERR("Resolution not supported!"); + return ret; + } + return 0; +} +#endif + +#if DT_HAS_COMPAT_STATUS_OKAY(ovti_ov7675) +static int ov7675_set_fmt(const struct device *dev, struct video_format *fmt) +{ + const struct ov767x_config *config = dev->config; + int ret = -ENOTSUP; + uint8_t i = 0U; + + /* Set RGB Format */ + if (fmt->pixelformat == VIDEO_PIX_FMT_RGB565) { + ret = video_write_cci_multiregs8(&config->bus, ov7675_rgb565_regs, + ARRAY_SIZE(ov7675_rgb565_regs)); + } else if (fmt->pixelformat == VIDEO_PIX_FMT_YUYV) { + ret = video_write_cci_multiregs8(&config->bus, ov767x_yuv422_regs, + ARRAY_SIZE(ov767x_yuv422_regs)); + } else { + LOG_ERR("Image format not supported"); + ret = -ENOTSUP; + } + + if (ret < 0) { + LOG_ERR("Format not set!"); + return ret; + } + + while (config->fmts[i].pixelformat) { + if (config->fmts[i].width_min == fmt->width && + config->fmts[i].height_min == fmt->height && + config->fmts[i].pixelformat == fmt->pixelformat) { + /* Set output format */ + switch (config->fmts[i].width_min) { + case 160: /* QQVGA */ + ret = video_write_cci_multiregs8(&config->bus, ov7675_regs_qqvga, + ARRAY_SIZE(ov7675_regs_qqvga)); + break; + case 320: /* QVGA */ + ret = video_write_cci_multiregs8(&config->bus, ov7675_regs_qvga, + ARRAY_SIZE(ov7675_regs_qvga)); + break; + case 640: /* VGA */ + ret = video_write_cci_multiregs8(&config->bus, ov7675_regs_vga, + ARRAY_SIZE(ov7675_regs_vga)); + break; + default: /* QVGA */ + ret = video_write_cci_multiregs8(&config->bus, ov7675_regs_qvga, + ARRAY_SIZE(ov7675_regs_qvga)); + break; + } + if (ret < 0) { + LOG_ERR("Resolution not set!"); + return ret; + } + } + i++; + } if (ret < 0) { LOG_ERR("Resolution not supported!"); return ret; @@ -424,9 +610,10 @@ static int ov7670_set_fmt(const struct device *dev, struct video_format *fmt) static int ov767x_set_fmt(const struct device *dev, struct video_format *fmt) { - const struct ov767x_config *config = dev->config; + const struct ov767x_config __maybe_unused *config = dev->config; struct ov767x_data *data = dev->data; - int ret; + + int ret __maybe_unused; if (fmt->pixelformat != VIDEO_PIX_FMT_RGB565 && fmt->pixelformat != VIDEO_PIX_FMT_YUYV) { LOG_ERR("Only RGB565 and YUYV supported!"); @@ -441,9 +628,19 @@ static int ov767x_set_fmt(const struct device *dev, struct video_format *fmt) memcpy(&data->fmt, fmt, sizeof(data->fmt)); #if DT_HAS_COMPAT_STATUS_OKAY(ovti_ov7670) - ret = ov7670_set_fmt(dev, fmt); - if (ret < 0) { - return ret; + if (config->camera_model == OV767X_MODEL_OV7670) { + ret = ov7670_set_fmt(dev, fmt); + if (ret < 0) { + return ret; + } + } +#endif +#if DT_HAS_COMPAT_STATUS_OKAY(ovti_ov7675) + if (config->camera_model == OV767X_MODEL_OV7675) { + ret = ov7675_set_fmt(dev, fmt); + if (ret < 0) { + return ret; + } } #endif @@ -490,7 +687,8 @@ static int ov767x_init(const struct device *dev) return -ENODEV; } -#if DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(ovti_ov7670, pwdn_gpios) +#if DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(ovti_ov7670, pwdn_gpios) || \ + DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(ovti_ov7675, pwdn_gpios) /* Power up camera module */ if (config->pwdn.port != NULL) { if (!gpio_is_ready_dt(&config->pwdn)) { @@ -504,7 +702,8 @@ static int ov767x_init(const struct device *dev) } #endif -#if DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(ovti_ov7670, reset_gpios) +#if DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(ovti_ov7670, reset_gpios) || \ + DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(ovti_ov7675, reset_gpios) /* Reset camera module */ if (config->reset.port != NULL) { if (!gpio_is_ready_dt(&config->reset)) { @@ -556,6 +755,7 @@ static int ov767x_init(const struct device *dev) } /* Delay after reset */ k_msleep(5); + ret = ov767x_set_fmt(dev, &fmt); if (ret < 0) { return ret; @@ -620,8 +820,7 @@ static DEVICE_API(video, ov767x_api) = { .bus = I2C_DT_SPEC_INST_GET(inst), \ .camera_model = id, \ .fmts = ov##id##_fmts, \ - OV767X_RESET_GPIO(inst) \ - OV767X_PWDN_GPIO(inst)}; \ + OV767X_RESET_GPIO(inst) OV767X_PWDN_GPIO(inst)}; \ \ static struct ov767x_data ov##id##_data##inst; \ \ @@ -634,3 +833,7 @@ static DEVICE_API(video, ov767x_api) = { #undef DT_DRV_COMPAT #define DT_DRV_COMPAT ovti_ov7670 DT_INST_FOREACH_STATUS_OKAY_VARGS(OV767X_INIT, 7670) + +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT ovti_ov7675 +DT_INST_FOREACH_STATUS_OKAY_VARGS(OV767X_INIT, 7675) diff --git a/dts/bindings/video/ovti,ov7675.yaml b/dts/bindings/video/ovti,ov7675.yaml new file mode 100644 index 0000000000000..17616ea397887 --- /dev/null +++ b/dts/bindings/video/ovti,ov7675.yaml @@ -0,0 +1,24 @@ +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: OV7675 CMOS video sensor + +compatible: "ovti,ov7675" + +properties: + reset-gpios: + type: phandle-array + description: | + The RESETn pin is asserted to disable the sensor causing a hard + reset. The sensor receives this as an active-low signal. + pwdn-gpios: + type: phandle-array + description: | + The PWDN pin is asserted to power down the sensor. The sensor + receives this as an active high signal + +include: i2c-device.yaml + +child-binding: + child-binding: + include: video-interfaces.yaml diff --git a/tests/drivers/build_all/video/app.overlay b/tests/drivers/build_all/video/app.overlay index 55bcf3863e110..85cabd24b4f97 100644 --- a/tests/drivers/build_all/video/app.overlay +++ b/tests/drivers/build_all/video/app.overlay @@ -144,7 +144,13 @@ }; }; }; - }; + + test_i2c_ov7675: ov7675@21 { + compatible = "ovti,ov7675"; + reg = <0x21>; + reset-gpios = <&test_gpio 0 0>; + pwdn-gpios = <&test_gpio 1 0>; + }; test_video_emul_rx: video_emul_rx@10003000 { compatible = "zephyr,video-emul-rx"; From 962b6b1def3ec762490fdf9b33c609eb401936bc Mon Sep 17 00:00:00 2001 From: Mike S Date: Mon, 27 Oct 2025 13:11:49 -0400 Subject: [PATCH 5/5] drivers: video Updates to use Single Kconfig/Cmakelists drivers: video Updates to use Single Kconfig/Cmakelists Updates to use Single Kconfig/Cmakelists. Signed-off-by: Mike S --- drivers/video/CMakeLists.txt | 9 +++------ drivers/video/Kconfig | 18 +++--------------- drivers/video/Kconfig.ov7670 | 10 ---------- drivers/video/Kconfig.ov7675 | 10 ---------- drivers/video/Kconfig.ov767x | 13 +++++++++++++ 5 files changed, 19 insertions(+), 41 deletions(-) delete mode 100644 drivers/video/Kconfig.ov7670 delete mode 100644 drivers/video/Kconfig.ov7675 create mode 100644 drivers/video/Kconfig.ov767x diff --git a/drivers/video/CMakeLists.txt b/drivers/video/CMakeLists.txt index 07961d29839c0..d6effbdd5c312 100644 --- a/drivers/video/CMakeLists.txt +++ b/drivers/video/CMakeLists.txt @@ -15,11 +15,11 @@ zephyr_library_sources_ifdef(CONFIG_VIDEO_OV7725 ov7725.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_OV2640 ov2640.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_GC2145 gc2145.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_STM32_DCMI video_stm32_dcmi.c) -zephyr_library_sources_ifdef(CONFIG_VIDEO_STM32_VENC video_stm32_venc.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_OV5640 ov5640.c) -zephyr_library_sources_ifdef(CONFIG_VIDEO_OV7670 ov767x.c) +zephyr_library_sources_ifdef(CONFIG_VIDEO_OV767X ov767x.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_OV9655 ov9655.c) -zephyr_library_sources_ifdef(CONFIG_VIDEO_OV7675 ov767x.c) +zephyr_library_sources_ifdef(CONFIG_VIDEO_HM0360 hm0360_1.c) +zephyr_library_sources_ifdef(CONFIG_VIDEO_HIMAX_HM01B0 hm01b0.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_ESP32 video_esp32_dvp.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_MCUX_SDMA video_mcux_smartdma.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_EMUL_IMAGER video_emul_imager.c) @@ -27,8 +27,5 @@ zephyr_library_sources_ifdef(CONFIG_VIDEO_EMUL_RX video_emul_rx.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_IMX335 imx335.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_ST_MIPID02 video_st_mipid02.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_STM32_DCMIPP video_stm32_dcmipp.c) -zephyr_library_sources_ifdef(CONFIG_VIDEO_RENESAS_RA_CEU video_renesas_ra_ceu.c) -zephyr_library_sources_ifdef(CONFIG_VIDEO_STM32_JPEG video_stm32_jpeg.c) -zephyr_library_sources_ifdef(CONFIG_VIDEO_HIMAX_HM01B0 hm01b0.c) zephyr_linker_sources(DATA_SECTIONS video.ld) diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index af3cd8c9e83c3..a44e8cbede049 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -58,12 +58,6 @@ config VIDEO_I2C_RETRY_NUM The default is to not retry. Board configuration files or user project can then use the number of retries that matches their situation. -config VIDEO_ENCODER_H264 - bool "H264 video encoder support" - -config VIDEO_ENCODER_JPEG - bool "JPEG video encoder support" - source "drivers/video/Kconfig.esp32_dvp" source "drivers/video/Kconfig.mcux_csi" @@ -82,18 +76,16 @@ source "drivers/video/Kconfig.ov2640" source "drivers/video/Kconfig.stm32_dcmi" -source "drivers/video/Kconfig.stm32_venc" - source "drivers/video/Kconfig.ov5640" -source "drivers/video/Kconfig.ov7670" - -source "drivers/video/Kconfig.ov7675" +source "drivers/video/Kconfig.ov767x" source "drivers/video/Kconfig.ov9655" source "drivers/video/Kconfig.gc2145" +source "drivers/video/Kconfig.hm0360" + source "drivers/video/Kconfig.hm01b0" source "drivers/video/Kconfig.mcux_sdma" @@ -108,8 +100,4 @@ source "drivers/video/Kconfig.st_mipid02" source "drivers/video/Kconfig.stm32_dcmipp" -source "drivers/video/Kconfig.renesas_ra_ceu" - -source "drivers/video/Kconfig.stm32_jpeg" - endif # VIDEO diff --git a/drivers/video/Kconfig.ov7670 b/drivers/video/Kconfig.ov7670 deleted file mode 100644 index 9a2a1d70f3d90..0000000000000 --- a/drivers/video/Kconfig.ov7670 +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright 2024 NXP -# SPDX-License-Identifier: Apache-2.0 - -config VIDEO_OV7670 - bool "OV7670 CMOS digital image sensor" - select I2C - depends on DT_HAS_OVTI_OV7670_ENABLED - default y - help - Enable driver for OV7670 CMOS digital image sensor device. diff --git a/drivers/video/Kconfig.ov7675 b/drivers/video/Kconfig.ov7675 deleted file mode 100644 index d72468ab7fbbf..0000000000000 --- a/drivers/video/Kconfig.ov7675 +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright 2024 NXP -# SPDX-License-Identifier: Apache-2.0 - -config VIDEO_OV7675 - bool "OV7675 CMOS digital image sensor" - select I2C - depends on DT_HAS_OVTI_OV7675_ENABLED - default y - help - Enable driver for OV7675 CMOS digital image sensor device. diff --git a/drivers/video/Kconfig.ov767x b/drivers/video/Kconfig.ov767x new file mode 100644 index 0000000000000..55984b117e7f8 --- /dev/null +++ b/drivers/video/Kconfig.ov767x @@ -0,0 +1,13 @@ +# OV767X CMOS digital image sensor configuration options + +# Copyright (c) 2025 Michael Smorto +# SPDX-License-Identifier: Apache-2.0 + +config VIDEO_OV767X + bool "OV767X CMOS digital image sensor" + select I2C + depends on DT_HAS_OVTI_OV7670_ENABLED || DT_HAS_OVTI_OV7675_ENABLED + default y + help + Enable driver for OV7670 / OV7675 CMOS digital image sensor. +