Skip to content

Commit f93440a

Browse files
committed
drivers: video: Implement video control framework
Implement the video control framework with the following features: - Drivers initialize the control with a valid value range at boot which guides the application developer and the framework. Hence, the video framework could do all common works for drivers e.g., sanity check. - Controls need to be cached to memory. Video framework handles get_ctrl(), drivers don't need to implement this API. It is because reading control value directly from registers are not only inefficient but also sometimes impossible, e.g. controls that scatter through several registers. Only "volatile" control needs to be updated at runtime. - Only the devices (e.g., sensors) owning the controls need to implement set_ctrl(). Other devices of the pipeline do not need to propagate set_ctrl() and hence, do not need to implement this API Signed-off-by: Phi Bang Nguyen <phibang.nguyen@nxp.com>
1 parent a2183f9 commit f93440a

File tree

21 files changed

+603
-358
lines changed

21 files changed

+603
-358
lines changed

drivers/video/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
zephyr_library()
44

55
zephyr_library_sources(video_common.c)
6+
zephyr_library_sources(video_ctrls.c)
67
zephyr_library_sources(video_device.c)
78

89
zephyr_library_sources_ifdef(CONFIG_VIDEO_MCUX_CSI video_mcux_csi.c)

drivers/video/gc2145.c

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
#include <zephyr/logging/log.h>
1717

18+
#include "video_ctrls.h"
1819
#include "video_device.h"
1920

2021
LOG_MODULE_REGISTER(video_gc2145, CONFIG_VIDEO_LOG_LEVEL);
@@ -692,7 +693,13 @@ struct gc2145_config {
692693
#endif
693694
};
694695

696+
struct gc2145_ctrls {
697+
struct video_ctrl hflip;
698+
struct video_ctrl vflip;
699+
};
700+
695701
struct gc2145_data {
702+
struct gc2145_ctrls ctrls;
696703
struct video_format fmt;
697704
};
698705

@@ -1103,13 +1110,13 @@ static int gc2145_get_caps(const struct device *dev, enum video_endpoint_id ep,
11031110
return 0;
11041111
}
11051112

1106-
static int gc2145_set_ctrl(const struct device *dev, unsigned int cid, void *value)
1113+
static int gc2145_set_ctrl(const struct device *dev, struct video_control *ctrl)
11071114
{
1108-
switch (cid) {
1115+
switch (ctrl->id) {
11091116
case VIDEO_CID_HFLIP:
1110-
return gc2145_set_ctrl_hmirror(dev, (int)value);
1117+
return gc2145_set_ctrl_hmirror(dev, ctrl->val);
11111118
case VIDEO_CID_VFLIP:
1112-
return gc2145_set_ctrl_vflip(dev, (int)value);
1119+
return gc2145_set_ctrl_vflip(dev, ctrl->val);
11131120
default:
11141121
return -ENOTSUP;
11151122
}
@@ -1123,6 +1130,20 @@ static DEVICE_API(video, gc2145_driver_api) = {
11231130
.set_ctrl = gc2145_set_ctrl,
11241131
};
11251132

1133+
static int gc2145_init_controls(const struct device *dev)
1134+
{
1135+
int ret;
1136+
struct gc2145_data *drv_data = dev->data;
1137+
struct gc2145_ctrls *ctrls = &drv_data->ctrls;
1138+
1139+
ret = video_init_ctrl(&ctrls->hflip, dev, VIDEO_CID_HFLIP, 0, 1, 1, 0);
1140+
if (ret) {
1141+
return ret;
1142+
}
1143+
1144+
return video_init_ctrl(&ctrls->vflip, dev, VIDEO_CID_VFLIP, 0, 1, 1, 0);
1145+
}
1146+
11261147
static int gc2145_init(const struct device *dev)
11271148
{
11281149
struct video_format fmt;
@@ -1169,7 +1190,8 @@ static int gc2145_init(const struct device *dev)
11691190
return ret;
11701191
}
11711192

1172-
return 0;
1193+
/* Initialize controls */
1194+
return gc2145_init_controls(dev);
11731195
}
11741196

11751197
/* Unique Instance */

drivers/video/mt9m114.c

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <zephyr/drivers/video-controls.h>
1616
#include <zephyr/drivers/i2c.h>
1717

18+
#include "video_ctrls.h"
1819
#include "video_device.h"
1920

2021
LOG_MODULE_REGISTER(video_mt9m114, CONFIG_VIDEO_LOG_LEVEL);
@@ -65,7 +66,13 @@ struct mt9m114_config {
6566
struct i2c_dt_spec i2c;
6667
};
6768

69+
struct mt9m114_ctrls {
70+
struct video_ctrl hflip;
71+
struct video_ctrl vflip;
72+
};
73+
6874
struct mt9m114_data {
75+
struct mt9m114_ctrls ctrls;
6976
struct video_format fmt;
7077
};
7178

@@ -466,20 +473,20 @@ static int mt9m114_get_caps(const struct device *dev, enum video_endpoint_id ep,
466473
return 0;
467474
}
468475

469-
static int mt9m114_set_ctrl(const struct device *dev, unsigned int cid, void *value)
476+
static int mt9m114_set_ctrl(const struct device *dev, struct video_control *ctrl)
470477
{
471478
int ret = 0;
472479

473-
switch (cid) {
480+
switch (ctrl->id) {
474481
case VIDEO_CID_HFLIP:
475482
ret = mt9m114_modify_reg(dev, MT9M114_CAM_SENSOR_CTRL_READ_MODE, 2,
476483
MT9M114_CAM_SENSOR_CTRL_HORZ_FLIP_EN,
477-
(int)value ? MT9M114_CAM_SENSOR_CTRL_HORZ_FLIP_EN : 0);
484+
ctrl->val ? MT9M114_CAM_SENSOR_CTRL_HORZ_FLIP_EN : 0);
478485
break;
479486
case VIDEO_CID_VFLIP:
480487
ret = mt9m114_modify_reg(dev, MT9M114_CAM_SENSOR_CTRL_READ_MODE, 2,
481488
MT9M114_CAM_SENSOR_CTRL_VERT_FLIP_EN,
482-
(int)value ? MT9M114_CAM_SENSOR_CTRL_VERT_FLIP_EN : 0);
489+
ctrl->val ? MT9M114_CAM_SENSOR_CTRL_VERT_FLIP_EN : 0);
483490
break;
484491
default:
485492
return -ENOTSUP;
@@ -501,6 +508,21 @@ static DEVICE_API(video, mt9m114_driver_api) = {
501508
.set_ctrl = mt9m114_set_ctrl,
502509
};
503510

511+
static int mt9m114_init_controls(const struct device *dev)
512+
{
513+
int ret;
514+
struct mt9m114_data *drv_data = dev->data;
515+
struct mt9m114_ctrls *ctrls = &drv_data->ctrls;
516+
517+
518+
ret = video_init_ctrl(&ctrls->hflip, dev, VIDEO_CID_HFLIP, 0, 1, 1, 0);
519+
if (ret) {
520+
return ret;
521+
}
522+
523+
return video_init_ctrl(&ctrls->vflip, dev, VIDEO_CID_VFLIP, 0, 1, 1, 0);
524+
}
525+
504526
static int mt9m114_init(const struct device *dev)
505527
{
506528
struct video_format fmt;
@@ -546,7 +568,8 @@ static int mt9m114_init(const struct device *dev)
546568
/* Suspend any stream */
547569
mt9m114_set_state(dev, MT9M114_SYS_STATE_ENTER_SUSPEND);
548570

549-
return 0;
571+
/* Initialize controls */
572+
return mt9m114_init_controls(dev);
550573
}
551574

552575
#if 1 /* Unique Instance */

drivers/video/ov2640.c

Lines changed: 95 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <zephyr/drivers/i2c.h>
1515
#include <zephyr/drivers/gpio.h>
1616

17+
#include "video_ctrls.h"
1718
#include "video_device.h"
1819

1920
LOG_MODULE_REGISTER(video_ov2640, CONFIG_VIDEO_LOG_LEVEL);
@@ -441,7 +442,21 @@ struct ov2640_config {
441442
uint8_t clock_rate_control;
442443
};
443444

445+
struct ov2640_ctrls {
446+
struct video_ctrl hflip;
447+
struct video_ctrl vflip;
448+
struct video_ctrl ae;
449+
struct video_ctrl awb;
450+
struct video_ctrl gain;
451+
struct video_ctrl contrast;
452+
struct video_ctrl brightness;
453+
struct video_ctrl saturation;
454+
struct video_ctrl jpeg;
455+
struct video_ctrl test_pattern;
456+
};
457+
444458
struct ov2640_data {
459+
struct ov2640_ctrls ctrls;
445460
struct video_format fmt;
446461
};
447462

@@ -565,10 +580,7 @@ static int ov2640_set_level(const struct device *dev, int level,
565580
int ret = 0;
566581
const struct ov2640_config *cfg = dev->config;
567582

568-
level += (max_level / 2 + 1);
569-
if (level < 0 || level > max_level) {
570-
return -ENOTSUP;
571-
}
583+
level += max_level / 2 + 1;
572584

573585
/* Switch to DSP register bank */
574586
ret |= ov2640_write_reg(&cfg->i2c, BANK_SEL, BANK_SEL_DSP);
@@ -580,48 +592,6 @@ static int ov2640_set_level(const struct device *dev, int level,
580592
return ret;
581593
}
582594

583-
static int ov2640_set_brightness(const struct device *dev, int level)
584-
{
585-
int ret = 0;
586-
587-
ret = ov2640_set_level(dev, level, NUM_BRIGHTNESS_LEVELS,
588-
ARRAY_SIZE(brightness_regs[0]), brightness_regs);
589-
590-
if (ret == -ENOTSUP) {
591-
LOG_ERR("Brightness level %d not supported", level);
592-
}
593-
594-
return ret;
595-
}
596-
597-
static int ov2640_set_saturation(const struct device *dev, int level)
598-
{
599-
int ret = 0;
600-
601-
ret = ov2640_set_level(dev, level, NUM_SATURATION_LEVELS,
602-
ARRAY_SIZE(saturation_regs[0]), saturation_regs);
603-
604-
if (ret == -ENOTSUP) {
605-
LOG_ERR("Saturation level %d not supported", level);
606-
}
607-
608-
return ret;
609-
}
610-
611-
static int ov2640_set_contrast(const struct device *dev, int level)
612-
{
613-
int ret = 0;
614-
615-
ret = ov2640_set_level(dev, level, NUM_CONTRAST_LEVELS,
616-
ARRAY_SIZE(contrast_regs[0]), contrast_regs);
617-
618-
if (ret == -ENOTSUP) {
619-
LOG_ERR("Contrast level %d not supported", level);
620-
}
621-
622-
return ret;
623-
}
624-
625595
static int ov2640_set_output_format(const struct device *dev,
626596
int output_format)
627597
{
@@ -925,47 +895,35 @@ static int ov2640_get_caps(const struct device *dev,
925895
return 0;
926896
}
927897

928-
static int ov2640_set_ctrl(const struct device *dev,
929-
unsigned int cid, void *value)
898+
static int ov2640_set_ctrl(const struct device *dev, struct video_control *ctrl)
930899
{
931-
int ret = 0;
932-
933-
switch (cid) {
900+
switch (ctrl->id) {
934901
case VIDEO_CID_HFLIP:
935-
ret |= ov2640_set_horizontal_mirror(dev, (int)value);
936-
break;
902+
return ov2640_set_horizontal_mirror(dev, ctrl->val);
937903
case VIDEO_CID_VFLIP:
938-
ret |= ov2640_set_vertical_flip(dev, (int)value);
939-
break;
904+
return ov2640_set_vertical_flip(dev, ctrl->val);
940905
case VIDEO_CID_EXPOSURE:
941-
ret |= ov2640_set_exposure_ctrl(dev, (int)value);
942-
break;
906+
return ov2640_set_exposure_ctrl(dev, ctrl->val);
907+
case VIDEO_CID_WHITE_BALANCE_TEMPERATURE:
908+
return ov2640_set_white_bal(dev, ctrl->val);
943909
case VIDEO_CID_GAIN:
944-
ret |= ov2640_set_gain_ctrl(dev, (int)value);
945-
break;
910+
return ov2640_set_gain_ctrl(dev, ctrl->val);
946911
case VIDEO_CID_BRIGHTNESS:
947-
ret |= ov2640_set_brightness(dev, (int)value);
948-
break;
949-
case VIDEO_CID_SATURATION:
950-
ret |= ov2640_set_saturation(dev, (int)value);
951-
break;
952-
case VIDEO_CID_WHITE_BALANCE_TEMPERATURE:
953-
ret |= ov2640_set_white_bal(dev, (int)value);
954-
break;
912+
return ov2640_set_level(dev, ctrl->val, NUM_BRIGHTNESS_LEVELS,
913+
ARRAY_SIZE(brightness_regs[0]), brightness_regs);
955914
case VIDEO_CID_CONTRAST:
956-
ret |= ov2640_set_contrast(dev, (int)value);
957-
break;
958-
case VIDEO_CID_TEST_PATTERN:
959-
ret |= ov2640_set_colorbar(dev, (int)value);
960-
break;
915+
return ov2640_set_level(dev, ctrl->val, NUM_CONTRAST_LEVELS,
916+
ARRAY_SIZE(contrast_regs[0]), contrast_regs);
917+
case VIDEO_CID_SATURATION:
918+
return ov2640_set_level(dev, ctrl->val, NUM_SATURATION_LEVELS,
919+
ARRAY_SIZE(saturation_regs[0]), saturation_regs);
961920
case VIDEO_CID_JPEG_COMPRESSION_QUALITY:
962-
ret |= ov2640_set_quality(dev, (int)value);
963-
break;
921+
return ov2640_set_quality(dev, ctrl->val);
922+
case VIDEO_CID_TEST_PATTERN:
923+
return ov2640_set_colorbar(dev, ctrl->val);
964924
default:
965925
return -ENOTSUP;
966926
}
967-
968-
return ret;
969927
}
970928

971929
static DEVICE_API(video, ov2640_driver_api) = {
@@ -976,6 +934,61 @@ static DEVICE_API(video, ov2640_driver_api) = {
976934
.set_ctrl = ov2640_set_ctrl,
977935
};
978936

937+
static int ov2640_init_controls(const struct device *dev)
938+
{
939+
int ret;
940+
struct ov2640_data *drv_data = dev->data;
941+
struct ov2640_ctrls *ctrls = &drv_data->ctrls;
942+
943+
ret = video_init_ctrl(&ctrls->hflip, dev, VIDEO_CID_HFLIP, 0, 1, 1, 0);
944+
if (ret) {
945+
return ret;
946+
}
947+
948+
ret = video_init_ctrl(&ctrls->vflip, dev, VIDEO_CID_VFLIP, 0, 1, 1, 0);
949+
if (ret) {
950+
return ret;
951+
}
952+
953+
ret = video_init_ctrl(&ctrls->ae, dev, VIDEO_CID_EXPOSURE, 0, 1, 1, 1);
954+
if (ret) {
955+
return ret;
956+
}
957+
958+
ret = video_init_ctrl(&ctrls->awb, dev, VIDEO_CID_WHITE_BALANCE_TEMPERATURE, 0, 1, 1, 1);
959+
if (ret) {
960+
return ret;
961+
}
962+
963+
ret = video_init_ctrl(&ctrls->gain, dev, VIDEO_CID_GAIN, 0, 1, 1, 1);
964+
if (ret) {
965+
return ret;
966+
}
967+
968+
ret = video_init_ctrl(&ctrls->brightness, dev, VIDEO_CID_BRIGHTNESS, -2, 2, 1, 0);
969+
if (ret) {
970+
return ret;
971+
}
972+
973+
ret = video_init_ctrl(&ctrls->contrast, dev, VIDEO_CID_CONTRAST, -2, 2, 1, 0);
974+
if (ret) {
975+
return ret;
976+
}
977+
978+
ret = video_init_ctrl(&ctrls->saturation, dev, VIDEO_CID_SATURATION, -2, 2, 1, 0);
979+
if (ret) {
980+
return ret;
981+
}
982+
983+
ret = video_init_ctrl(&ctrls->saturation, dev, VIDEO_CID_JPEG_COMPRESSION_QUALITY, 5, 100,
984+
1, 50);
985+
if (ret) {
986+
return ret;
987+
}
988+
989+
return video_init_ctrl(&ctrls->test_pattern, dev, VIDEO_CID_TEST_PATTERN, 0, 1, 1, 0);
990+
}
991+
979992
static int ov2640_init(const struct device *dev)
980993
{
981994
struct video_format fmt;
@@ -1020,7 +1033,12 @@ static int ov2640_init(const struct device *dev)
10201033
ret |= ov2640_set_exposure_ctrl(dev, 1);
10211034
ret |= ov2640_set_white_bal(dev, 1);
10221035

1023-
return ret;
1036+
if (ret) {
1037+
return ret;
1038+
}
1039+
1040+
/* Initialize controls */
1041+
return ov2640_init_controls(dev);
10241042
}
10251043

10261044
/* Unique Instance */

0 commit comments

Comments
 (0)