drivers: video: Add support for composite controls
For controls that are dependent from others, we need to "cluster" them. Whenever one or more controls of the same cluster are set or gotten, only the callback of the 1st control of the cluster, i.e. the master control, is called. The master control is the one that represents the whole cluster. A common type of control cluster is "auto"-cluster, e.g. auto_gain/gain, auto_exposure/exposure, auto_white_balance/red_balance/blue_balance, etc. If the cluster is in automatic mode, then the manual controls are marked inactive and volatile which are read via get_volatile_ctrl(). If the cluster is put in manual mode, then the manual controls should become active again and the volatile flag is cleared. Re-implement the ov5640's autogain/analogue_gain controls with the new auto cluster mechanism so that it work correctly and fully. Signed-off-by: Phi Bang Nguyen <phibang.nguyen@nxp.com>
This commit is contained in:
parent
cbf104f3d0
commit
3378d683e9
10 changed files with 278 additions and 72 deletions
|
@ -1110,13 +1110,15 @@ static int gc2145_get_caps(const struct device *dev, enum video_endpoint_id ep,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int gc2145_set_ctrl(const struct device *dev, struct video_control *ctrl)
|
||||
static int gc2145_set_ctrl(const struct device *dev, uint32_t id)
|
||||
{
|
||||
switch (ctrl->id) {
|
||||
struct gc2145_data *drv_data = dev->data;
|
||||
|
||||
switch (id) {
|
||||
case VIDEO_CID_HFLIP:
|
||||
return gc2145_set_ctrl_hmirror(dev, ctrl->val);
|
||||
return gc2145_set_ctrl_hmirror(dev, drv_data->ctrls.hflip.val);
|
||||
case VIDEO_CID_VFLIP:
|
||||
return gc2145_set_ctrl_vflip(dev, ctrl->val);
|
||||
return gc2145_set_ctrl_vflip(dev, drv_data->ctrls.vflip.val);
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
|
|
@ -473,20 +473,23 @@ static int mt9m114_get_caps(const struct device *dev, enum video_endpoint_id ep,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int mt9m114_set_ctrl(const struct device *dev, struct video_control *ctrl)
|
||||
static int mt9m114_set_ctrl(const struct device *dev, uint32_t id)
|
||||
{
|
||||
int ret = 0;
|
||||
struct mt9m114_data *drv_data = dev->data;
|
||||
|
||||
switch (ctrl->id) {
|
||||
switch (id) {
|
||||
case VIDEO_CID_HFLIP:
|
||||
ret = mt9m114_modify_reg(dev, MT9M114_CAM_SENSOR_CTRL_READ_MODE, 2,
|
||||
MT9M114_CAM_SENSOR_CTRL_HORZ_FLIP_EN,
|
||||
ctrl->val ? MT9M114_CAM_SENSOR_CTRL_HORZ_FLIP_EN : 0);
|
||||
ret = mt9m114_modify_reg(
|
||||
dev, MT9M114_CAM_SENSOR_CTRL_READ_MODE, 2,
|
||||
MT9M114_CAM_SENSOR_CTRL_HORZ_FLIP_EN,
|
||||
drv_data->ctrls.hflip.val ? MT9M114_CAM_SENSOR_CTRL_HORZ_FLIP_EN : 0);
|
||||
break;
|
||||
case VIDEO_CID_VFLIP:
|
||||
ret = mt9m114_modify_reg(dev, MT9M114_CAM_SENSOR_CTRL_READ_MODE, 2,
|
||||
MT9M114_CAM_SENSOR_CTRL_VERT_FLIP_EN,
|
||||
ctrl->val ? MT9M114_CAM_SENSOR_CTRL_VERT_FLIP_EN : 0);
|
||||
ret = mt9m114_modify_reg(
|
||||
dev, MT9M114_CAM_SENSOR_CTRL_READ_MODE, 2,
|
||||
MT9M114_CAM_SENSOR_CTRL_VERT_FLIP_EN,
|
||||
drv_data->ctrls.vflip.val ? MT9M114_CAM_SENSOR_CTRL_VERT_FLIP_EN : 0);
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
|
|
|
@ -895,32 +895,35 @@ static int ov2640_get_caps(const struct device *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ov2640_set_ctrl(const struct device *dev, struct video_control *ctrl)
|
||||
static int ov2640_set_ctrl(const struct device *dev, uint32_t id)
|
||||
{
|
||||
switch (ctrl->id) {
|
||||
struct ov2640_data *drv_data = dev->data;
|
||||
struct ov2640_ctrls *ctrls = &drv_data->ctrls;
|
||||
|
||||
switch (id) {
|
||||
case VIDEO_CID_HFLIP:
|
||||
return ov2640_set_horizontal_mirror(dev, ctrl->val);
|
||||
return ov2640_set_horizontal_mirror(dev, ctrls->hflip.val);
|
||||
case VIDEO_CID_VFLIP:
|
||||
return ov2640_set_vertical_flip(dev, ctrl->val);
|
||||
return ov2640_set_vertical_flip(dev, ctrls->vflip.val);
|
||||
case VIDEO_CID_EXPOSURE:
|
||||
return ov2640_set_exposure_ctrl(dev, ctrl->val);
|
||||
return ov2640_set_exposure_ctrl(dev, ctrls->ae.val);
|
||||
case VIDEO_CID_WHITE_BALANCE_TEMPERATURE:
|
||||
return ov2640_set_white_bal(dev, ctrl->val);
|
||||
return ov2640_set_white_bal(dev, ctrls->awb.val);
|
||||
case VIDEO_CID_GAIN:
|
||||
return ov2640_set_gain_ctrl(dev, ctrl->val);
|
||||
return ov2640_set_gain_ctrl(dev, ctrls->gain.val);
|
||||
case VIDEO_CID_BRIGHTNESS:
|
||||
return ov2640_set_level(dev, ctrl->val, NUM_BRIGHTNESS_LEVELS,
|
||||
return ov2640_set_level(dev, ctrls->brightness.val, NUM_BRIGHTNESS_LEVELS,
|
||||
ARRAY_SIZE(brightness_regs[0]), brightness_regs);
|
||||
case VIDEO_CID_CONTRAST:
|
||||
return ov2640_set_level(dev, ctrl->val, NUM_CONTRAST_LEVELS,
|
||||
return ov2640_set_level(dev, ctrls->contrast.val, NUM_CONTRAST_LEVELS,
|
||||
ARRAY_SIZE(contrast_regs[0]), contrast_regs);
|
||||
case VIDEO_CID_SATURATION:
|
||||
return ov2640_set_level(dev, ctrl->val, NUM_SATURATION_LEVELS,
|
||||
return ov2640_set_level(dev, ctrls->saturation.val, NUM_SATURATION_LEVELS,
|
||||
ARRAY_SIZE(saturation_regs[0]), saturation_regs);
|
||||
case VIDEO_CID_JPEG_COMPRESSION_QUALITY:
|
||||
return ov2640_set_quality(dev, ctrl->val);
|
||||
return ov2640_set_quality(dev, ctrls->jpeg.val);
|
||||
case VIDEO_CID_TEST_PATTERN:
|
||||
return ov2640_set_colorbar(dev, ctrl->val);
|
||||
return ov2640_set_colorbar(dev, ctrls->test_pattern.val);
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
|
|
@ -145,7 +145,11 @@ struct ov5640_mode_config {
|
|||
};
|
||||
|
||||
struct ov5640_ctrls {
|
||||
struct video_ctrl gain;
|
||||
/* gain auto-cluster */
|
||||
struct {
|
||||
struct video_ctrl auto_gain;
|
||||
struct video_ctrl gain;
|
||||
};
|
||||
struct video_ctrl brightness;
|
||||
struct video_ctrl contrast;
|
||||
struct video_ctrl hue;
|
||||
|
@ -1034,24 +1038,30 @@ static int ov5640_set_ctrl_contrast(const struct device *dev, int value)
|
|||
return ov5640_write_reg(&cfg->i2c, SDE_CTRL6_REG, value & 0xff);
|
||||
}
|
||||
|
||||
static int ov5640_set_ctrl_gain(const struct device *dev, int value)
|
||||
static int ov5640_set_ctrl_gain(const struct device *dev)
|
||||
{
|
||||
const struct ov5640_config *cfg = dev->config;
|
||||
struct ov5640_data *drv_data = dev->data;
|
||||
struct ov5640_ctrls *ctrls = &drv_data->ctrls;
|
||||
|
||||
if (value) {
|
||||
int ret = ov5640_modify_reg(&cfg->i2c, AEC_PK_MANUAL, BIT(1), BIT(0));
|
||||
int ret = ov5640_modify_reg(&cfg->i2c, AEC_PK_MANUAL, BIT(1),
|
||||
ctrls->auto_gain.val ? 0 : BIT(1));
|
||||
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!ctrls->auto_gain.val) {
|
||||
ret = ov5640_modify_reg(&cfg->i2c, AEC_PK_REAL_GAIN, 0x03,
|
||||
(ctrls->gain.val >> 8) & 0x03);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct ov5640_reg gain_params[] = {{AEC_PK_REAL_GAIN, value >> 8},
|
||||
{AEC_PK_REAL_GAIN + 1, value & 0xff}};
|
||||
|
||||
return ov5640_write_multi_regs(&cfg->i2c, gain_params, ARRAY_SIZE(gain_params));
|
||||
} else {
|
||||
return ov5640_write_reg(&cfg->i2c, AEC_PK_MANUAL, 0);
|
||||
ret = ov5640_write_reg(&cfg->i2c, AEC_PK_REAL_GAIN + 1, ctrls->gain.val & 0xff);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ov5640_set_ctrl_hflip(const struct device *dev, int value)
|
||||
|
@ -1096,32 +1106,68 @@ static int ov5640_set_ctrl_power_line_freq(const struct device *dev, int value)
|
|||
return ov5640_modify_reg(&cfg->i2c, HZ5060_CTRL01_REG, BIT(7), BIT(7));
|
||||
}
|
||||
|
||||
static int ov5640_set_ctrl(const struct device *dev, struct video_control *ctrl)
|
||||
static int ov5640_set_ctrl(const struct device *dev, uint32_t id)
|
||||
{
|
||||
switch (ctrl->id) {
|
||||
struct ov5640_data *drv_data = dev->data;
|
||||
struct ov5640_ctrls *ctrls = &drv_data->ctrls;
|
||||
|
||||
switch (id) {
|
||||
case VIDEO_CID_TEST_PATTERN:
|
||||
return ov5640_set_ctrl_test_pattern(dev, ctrl->val);
|
||||
return ov5640_set_ctrl_test_pattern(dev, ctrls->test_pattern.val);
|
||||
case VIDEO_CID_HUE:
|
||||
return ov5640_set_ctrl_hue(dev, ctrl->val);
|
||||
return ov5640_set_ctrl_hue(dev, ctrls->hue.val);
|
||||
case VIDEO_CID_SATURATION:
|
||||
return ov5640_set_ctrl_saturation(dev, ctrl->val);
|
||||
return ov5640_set_ctrl_saturation(dev, ctrls->saturation.val);
|
||||
case VIDEO_CID_BRIGHTNESS:
|
||||
return ov5640_set_ctrl_brightness(dev, ctrl->val);
|
||||
return ov5640_set_ctrl_brightness(dev, ctrls->brightness.val);
|
||||
case VIDEO_CID_CONTRAST:
|
||||
return ov5640_set_ctrl_contrast(dev, ctrl->val);
|
||||
case VIDEO_CID_GAIN:
|
||||
return ov5640_set_ctrl_gain(dev, ctrl->val);
|
||||
return ov5640_set_ctrl_contrast(dev, ctrls->contrast.val);
|
||||
case VIDEO_CID_AUTOGAIN:
|
||||
return ov5640_set_ctrl_gain(dev);
|
||||
case VIDEO_CID_HFLIP:
|
||||
return ov5640_set_ctrl_hflip(dev, ctrl->val);
|
||||
return ov5640_set_ctrl_hflip(dev, ctrls->hflip.val);
|
||||
case VIDEO_CID_VFLIP:
|
||||
return ov5640_set_ctrl_vflip(dev, ctrl->val);
|
||||
return ov5640_set_ctrl_vflip(dev, ctrls->vflip.val);
|
||||
case VIDEO_CID_POWER_LINE_FREQUENCY:
|
||||
return ov5640_set_ctrl_power_line_freq(dev, ctrl->val);
|
||||
return ov5640_set_ctrl_power_line_freq(dev, ctrls->light_freq.val);
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
}
|
||||
|
||||
static int ov5640_get_gain(const struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
uint16_t gain;
|
||||
const struct ov5640_config *cfg = dev->config;
|
||||
|
||||
ret = ov5640_read_reg(&cfg->i2c, AEC_PK_REAL_GAIN, &gain, sizeof(gain));
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return gain & 0x3ff;
|
||||
}
|
||||
|
||||
static int ov5640_get_volatile_ctrl(const struct device *dev, uint32_t id)
|
||||
{
|
||||
int val;
|
||||
struct ov5640_data *drv_data = dev->data;
|
||||
struct ov5640_ctrls *ctrls = &drv_data->ctrls;
|
||||
|
||||
switch (id) {
|
||||
case VIDEO_CID_AUTOGAIN:
|
||||
val = ov5640_get_gain(dev);
|
||||
if (val < 0) {
|
||||
return val;
|
||||
}
|
||||
ctrls->gain.val = val;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ov5640_get_frmival(const struct device *dev, enum video_endpoint_id ep,
|
||||
struct video_frmival *frmival)
|
||||
{
|
||||
|
@ -1171,6 +1217,7 @@ static DEVICE_API(video, ov5640_driver_api) = {
|
|||
.get_caps = ov5640_get_caps,
|
||||
.set_stream = ov5640_set_stream,
|
||||
.set_ctrl = ov5640_set_ctrl,
|
||||
.get_volatile_ctrl = ov5640_get_volatile_ctrl,
|
||||
.set_frmival = ov5640_set_frmival,
|
||||
.get_frmival = ov5640_get_frmival,
|
||||
.enum_frmival = ov5640_enum_frmival,
|
||||
|
@ -1182,13 +1229,21 @@ static int ov5640_init_controls(const struct device *dev)
|
|||
struct ov5640_data *drv_data = dev->data;
|
||||
struct ov5640_ctrls *ctrls = &drv_data->ctrls;
|
||||
|
||||
ret = video_init_ctrl(&ctrls->auto_gain, dev, VIDEO_CID_AUTOGAIN,
|
||||
(struct video_ctrl_range){.min = 0, .max = 1, .step = 1, .def = 1});
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = video_init_ctrl(
|
||||
&ctrls->gain, dev, VIDEO_CID_GAIN,
|
||||
&ctrls->gain, dev, VIDEO_CID_ANALOGUE_GAIN,
|
||||
(struct video_ctrl_range){.min = 0, .max = 1023, .step = 1, .def = 0});
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
video_auto_cluster_ctrl(&ctrls->auto_gain, 2, true);
|
||||
|
||||
ret = video_init_ctrl(
|
||||
&ctrls->brightness, dev, VIDEO_CID_BRIGHTNESS,
|
||||
(struct video_ctrl_range){.min = -15, .max = 15, .step = 1, .def = 0});
|
||||
|
|
|
@ -581,17 +581,19 @@ static int ov7670_set_stream(const struct device *dev, bool enable)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ov7670_set_ctrl(const struct device *dev, struct video_control *ctrl)
|
||||
static int ov7670_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;
|
||||
|
||||
switch (ctrl->id) {
|
||||
switch (id) {
|
||||
case VIDEO_CID_HFLIP:
|
||||
return i2c_reg_update_byte_dt(&config->bus, OV7670_MVFP,
|
||||
OV7670_MVFP_HFLIP, ctrl->val ? OV7670_MVFP_HFLIP : 0);
|
||||
return i2c_reg_update_byte_dt(&config->bus, OV7670_MVFP, OV7670_MVFP_HFLIP,
|
||||
ctrls->hflip.val ? OV7670_MVFP_HFLIP : 0);
|
||||
case VIDEO_CID_VFLIP:
|
||||
return i2c_reg_update_byte_dt(&config->bus, OV7670_MVFP,
|
||||
OV7670_MVFP_VFLIP, ctrl->val ? OV7670_MVFP_VFLIP : 0);
|
||||
return i2c_reg_update_byte_dt(&config->bus, OV7670_MVFP, OV7670_MVFP_VFLIP,
|
||||
ctrls->vflip.val ? OV7670_MVFP_VFLIP : 0);
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
|
|
@ -94,6 +94,10 @@ int video_init_ctrl(struct video_ctrl *ctrl, const struct device *dev, uint32_t
|
|||
return ret;
|
||||
}
|
||||
|
||||
ctrl->cluster_sz = 0;
|
||||
ctrl->cluster = NULL;
|
||||
ctrl->is_auto = false;
|
||||
ctrl->has_volatiles = false;
|
||||
ctrl->vdev = vdev;
|
||||
ctrl->id = id;
|
||||
ctrl->type = type;
|
||||
|
@ -119,6 +123,50 @@ int video_init_ctrl(struct video_ctrl *ctrl, const struct device *dev, uint32_t
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* By definition, the cluster is in manual mode if the master control value is 0 */
|
||||
static inline bool is_cluster_manual(const struct video_ctrl *master)
|
||||
{
|
||||
return master->type == VIDEO_CTRL_TYPE_INTEGER64 ? master->val64 == 0 : master->val == 0;
|
||||
}
|
||||
|
||||
void video_cluster_ctrl(struct video_ctrl *ctrls, uint8_t sz)
|
||||
{
|
||||
bool has_volatiles = false;
|
||||
|
||||
__ASSERT(!sz && !ctrls, "The 1st control, i.e. the master, must not be NULL");
|
||||
|
||||
for (uint8_t i = 0; i < sz; i++) {
|
||||
ctrls[i].cluster_sz = sz;
|
||||
ctrls[i].cluster = ctrls;
|
||||
if (ctrls[i].flags & VIDEO_CTRL_FLAG_VOLATILE) {
|
||||
has_volatiles = true;
|
||||
}
|
||||
}
|
||||
|
||||
ctrls->has_volatiles = has_volatiles;
|
||||
}
|
||||
|
||||
void video_auto_cluster_ctrl(struct video_ctrl *ctrls, uint8_t sz, bool set_volatile)
|
||||
{
|
||||
video_cluster_ctrl(ctrls, sz);
|
||||
|
||||
__ASSERT(sz > 1, "Control auto cluster size must be > 1");
|
||||
__ASSERT(!(set_volatile && !DEVICE_API_GET(video, ctrls->vdev->dev)->get_volatile_ctrl),
|
||||
"Volatile is set but no ops");
|
||||
|
||||
ctrls->is_auto = true;
|
||||
ctrls->has_volatiles = set_volatile;
|
||||
ctrls->flags |= VIDEO_CTRL_FLAG_UPDATE;
|
||||
|
||||
/* If the cluster is in automatic mode, mark all manual controls inactive and volatile */
|
||||
for (uint8_t i = 1; i < sz; i++) {
|
||||
if (!is_cluster_manual(ctrls)) {
|
||||
ctrls[i].flags |= VIDEO_CTRL_FLAG_INACTIVE |
|
||||
(set_volatile ? VIDEO_CTRL_FLAG_VOLATILE : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int video_find_ctrl(const struct device *dev, uint32_t id, struct video_ctrl **ctrl)
|
||||
{
|
||||
struct video_device *vdev = video_find_vdev(dev);
|
||||
|
@ -157,11 +205,15 @@ int video_get_ctrl(const struct device *dev, struct video_control *control)
|
|||
}
|
||||
|
||||
/* Call driver's get_volatile_ctrl */
|
||||
return DEVICE_API_GET(video, ctrl->vdev->dev)
|
||||
->get_volatile_ctrl(ctrl->vdev->dev, control);
|
||||
ret = DEVICE_API_GET(video, ctrl->vdev->dev)
|
||||
->get_volatile_ctrl(ctrl->vdev->dev,
|
||||
ctrl->cluster ? ctrl->cluster->id : ctrl->id);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read control value in cache memory */
|
||||
/* Give the control's current value to user */
|
||||
if (ctrl->type == VIDEO_CTRL_TYPE_INTEGER64) {
|
||||
control->val64 = ctrl->val64;
|
||||
} else {
|
||||
|
@ -174,8 +226,10 @@ int video_get_ctrl(const struct device *dev, struct video_control *control)
|
|||
int video_set_ctrl(const struct device *dev, struct video_control *control)
|
||||
{
|
||||
struct video_ctrl *ctrl = NULL;
|
||||
|
||||
int ret = video_find_ctrl(dev, control->id, &ctrl);
|
||||
uint8_t i = 0;
|
||||
int32_t val = 0;
|
||||
int64_t val64 = 0;
|
||||
|
||||
if (ret) {
|
||||
return ret;
|
||||
|
@ -186,6 +240,11 @@ int video_set_ctrl(const struct device *dev, struct video_control *control)
|
|||
return -EACCES;
|
||||
}
|
||||
|
||||
if (ctrl->flags & VIDEO_CTRL_FLAG_INACTIVE) {
|
||||
LOG_ERR("Control id 0x%x is inactive\n", control->id);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
if (ctrl->type == VIDEO_CTRL_TYPE_INTEGER64
|
||||
? !IN_RANGE(control->val64, ctrl->range.min64, ctrl->range.max64)
|
||||
: !IN_RANGE(control->val, ctrl->range.min, ctrl->range.max)) {
|
||||
|
@ -193,25 +252,81 @@ int video_set_ctrl(const struct device *dev, struct video_control *control)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (DEVICE_API_GET(video, ctrl->vdev->dev)->set_ctrl == NULL) {
|
||||
goto update;
|
||||
/* No new value */
|
||||
if (ctrl->type == VIDEO_CTRL_TYPE_INTEGER64 ? ctrl->val64 == control->val64
|
||||
: ctrl->val == control->val) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Call driver's set_ctrl */
|
||||
ret = DEVICE_API_GET(video, ctrl->vdev->dev)->set_ctrl(ctrl->vdev->dev, control);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
update:
|
||||
/* Only update the ctrl in memory once everything is OK */
|
||||
/* Backup the control's value then set it to the new value */
|
||||
if (ctrl->type == VIDEO_CTRL_TYPE_INTEGER64) {
|
||||
val64 = ctrl->val64;
|
||||
ctrl->val64 = control->val64;
|
||||
} else {
|
||||
val = ctrl->val;
|
||||
ctrl->val = control->val;
|
||||
}
|
||||
|
||||
/*
|
||||
* For auto-clusters having volatiles, before switching to manual mode, get the current
|
||||
* volatile values since those will become the initial manual values after this switch.
|
||||
*/
|
||||
if (ctrl == ctrl->cluster && ctrl->is_auto && ctrl->has_volatiles &&
|
||||
is_cluster_manual(ctrl)) {
|
||||
|
||||
if (DEVICE_API_GET(video, ctrl->vdev->dev)->get_volatile_ctrl == NULL) {
|
||||
ret = -ENOSYS;
|
||||
goto restore;
|
||||
}
|
||||
|
||||
ret = DEVICE_API_GET(video, ctrl->vdev->dev)
|
||||
->get_volatile_ctrl(ctrl->vdev->dev, ctrl->id);
|
||||
if (ret) {
|
||||
goto restore;
|
||||
}
|
||||
}
|
||||
|
||||
/* Call driver's set_ctrl */
|
||||
if (DEVICE_API_GET(video, ctrl->vdev->dev)->set_ctrl) {
|
||||
ret = DEVICE_API_GET(video, ctrl->vdev->dev)
|
||||
->set_ctrl(ctrl->vdev->dev, ctrl->cluster ? ctrl->cluster->id : ctrl->id);
|
||||
if (ret) {
|
||||
goto restore;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the manual controls' flags of the cluster */
|
||||
if (ctrl->cluster && ctrl->cluster->is_auto) {
|
||||
for (i = 1; i < ctrl->cluster_sz; i++) {
|
||||
if (!is_cluster_manual(ctrl->cluster)) {
|
||||
/* Automatic mode: set the inactive and volatile flags of the manual
|
||||
* controls
|
||||
*/
|
||||
ctrl->cluster[i].flags |=
|
||||
VIDEO_CTRL_FLAG_INACTIVE |
|
||||
(ctrl->cluster->has_volatiles ? VIDEO_CTRL_FLAG_VOLATILE
|
||||
: 0);
|
||||
} else {
|
||||
/* Manual mode: clear the inactive and volatile flags of the manual
|
||||
* controls
|
||||
*/
|
||||
ctrl->cluster[i].flags &=
|
||||
~(VIDEO_CTRL_FLAG_INACTIVE | VIDEO_CTRL_FLAG_VOLATILE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
restore:
|
||||
/* Restore the old control's value */
|
||||
if (ctrl->type == VIDEO_CTRL_TYPE_INTEGER64) {
|
||||
ctrl->val64 = val64;
|
||||
} else {
|
||||
ctrl->val = val;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline const char *video_get_ctrl_name(uint32_t id)
|
||||
|
@ -228,8 +343,12 @@ static inline const char *video_get_ctrl_name(uint32_t id)
|
|||
return "Hue";
|
||||
case VIDEO_CID_EXPOSURE:
|
||||
return "Exposure";
|
||||
case VIDEO_CID_AUTOGAIN:
|
||||
return "Gain, Automatic";
|
||||
case VIDEO_CID_GAIN:
|
||||
return "Gain";
|
||||
case VIDEO_CID_ANALOGUE_GAIN:
|
||||
return "Analogue Gain";
|
||||
case VIDEO_CID_HFLIP:
|
||||
return "Horizontal Flip";
|
||||
case VIDEO_CID_VFLIP:
|
||||
|
|
|
@ -39,6 +39,12 @@ struct video_device;
|
|||
* @see video_control for the struct used in public API
|
||||
*/
|
||||
struct video_ctrl {
|
||||
/* Fields should not touched by drivers, used only for the 1st control of a cluster */
|
||||
struct video_ctrl *cluster;
|
||||
uint8_t cluster_sz;
|
||||
bool is_auto;
|
||||
bool has_volatiles;
|
||||
|
||||
const struct video_device *vdev;
|
||||
uint32_t id;
|
||||
enum video_ctrl_type type;
|
||||
|
@ -54,4 +60,8 @@ struct video_ctrl {
|
|||
int video_init_ctrl(struct video_ctrl *ctrl, const struct device *dev, uint32_t id,
|
||||
struct video_ctrl_range range);
|
||||
|
||||
void video_cluster_ctrl(struct video_ctrl *ctrls, uint8_t sz);
|
||||
|
||||
void video_auto_cluster_ctrl(struct video_ctrl *ctrls, uint8_t sz, bool set_volatile);
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_DRIVERS_VIDEO_VIDEO_CTRLS_H_ */
|
||||
|
|
|
@ -193,9 +193,11 @@ static int emul_imager_write_multi(const struct device *const dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int emul_imager_set_ctrl(const struct device *dev, struct video_control *ctrl)
|
||||
static int emul_imager_set_ctrl(const struct device *dev, uint32_t id)
|
||||
{
|
||||
return emul_imager_write_reg(dev, EMUL_IMAGER_REG_CUSTOM, ctrl->val);
|
||||
struct emul_imager_data *data = dev->data;
|
||||
|
||||
return emul_imager_write_reg(dev, EMUL_IMAGER_REG_CUSTOM, data->ctrls.custom.val);
|
||||
}
|
||||
|
||||
/* Customize this function according to your "struct emul_imager_mode". */
|
||||
|
|
|
@ -57,7 +57,13 @@ extern "C" {
|
|||
/** Amount of time an image sensor is exposed to light, affecting the brightness */
|
||||
#define VIDEO_CID_EXPOSURE (VIDEO_CID_BASE + 17)
|
||||
|
||||
/** Amount of amplification performed to each pixel electrical signal, affecting the brightness */
|
||||
/** Automatic gain control */
|
||||
#define VIDEO_CID_AUTOGAIN (VIDEO_CID_BASE + 18)
|
||||
|
||||
/** Gain control. Most devices control only digital gain with this control.
|
||||
* Devices that recognise the difference between digital and analogue gain use
|
||||
* VIDEO_CID_DIGITAL_GAIN and VIDEO_CID_ANALOGUE_GAIN.
|
||||
*/
|
||||
#define VIDEO_CID_GAIN (VIDEO_CID_BASE + 19)
|
||||
|
||||
/** Flip the image horizontally: the left side becomes the right side */
|
||||
|
@ -137,6 +143,9 @@ enum video_power_line_frequency {
|
|||
*/
|
||||
#define VIDEO_CID_IMAGE_SOURCE_CLASS_BASE 0x009e0900
|
||||
|
||||
/** Analogue gain control. */
|
||||
#define VIDEO_CID_ANALOGUE_GAIN (VIDEO_CID_IMAGE_SOURCE_CLASS_BASE + 3)
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
|
|
@ -321,9 +321,10 @@ typedef int (*video_api_set_stream_t)(const struct device *dev, bool enable);
|
|||
* @typedef video_api_ctrl_t
|
||||
* @brief Set/Get a video control value.
|
||||
*
|
||||
* See video_set_ctrl() or video_get_ctrl() for argument descriptions.
|
||||
* @param dev Pointer to the device structure.
|
||||
* @param cid Id of the control to set/get its value.
|
||||
*/
|
||||
typedef int (*video_api_ctrl_t)(const struct device *dev, struct video_control *ctrl);
|
||||
typedef int (*video_api_ctrl_t)(const struct device *dev, uint32_t cid);
|
||||
|
||||
/**
|
||||
* @typedef video_api_get_caps_t
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue