Re: [PATCH 4/7] media: atmel: atmel-isc: add support for DO_WHITE_BALANCE

From: Hans Verkuil
Date: Wed Apr 10 2019 - 10:27:05 EST


On 4/9/19 1:07 PM, Eugen.Hristev@xxxxxxxxxxxxx wrote:
> From: Eugen Hristev <eugen.hristev@xxxxxxxxxxxxx>
>
> This adds support for the 'button' control DO_WHITE_BALANCE
> This feature will enable the ISC to compute the white balance coefficients
> in a one time shot, at the user discretion.
> This can be used if a color chart/grey chart is present in front of the camera.
> The ISC will adjust the coefficients and have them fixed until next balance
> or until sensor mode is changed.
> This is particularly useful for white balance adjustment in different
> lighting scenarios, and then taking photos to similar scenery.
> The old auto white balance stays in place, where the ISC will adjust every
> 4 frames to the current scenery lighting, if the scenery is approximately
> grey in average, otherwise grey world algorithm fails.
> One time white balance adjustments needs streaming to be enabled, such that
> capture is enabled and the histogram has data to work with.
> Histogram without capture does not work in this hardware module.
>
> To disable auto white balance feature (first step)
> v4l2-ctl --set-ctrl=white_balance_automatic=0
>
> To start the one time white balance procedure:
> v4l2-ctl --set-ctrl=do_white_balance=1
>
> User controls now include the do_white_balance ctrl:
> User Controls
>
> brightness 0x00980900 (int) : min=-1024 max=1023 step=1 default=0 value=0 flags=slider
> contrast 0x00980901 (int) : min=-2048 max=2047 step=1 default=256 value=256 flags=slider
> white_balance_automatic 0x0098090c (bool) : default=1 value=1
> do_white_balance 0x0098090d (button) : flags=write-only, execute-on-write
> gamma 0x00980910 (int) : min=0 max=2 step=1 default=2 value=2 flags=slider
>
> Signed-off-by: Eugen Hristev <eugen.hristev@xxxxxxxxxxxxx>
> ---
> drivers/media/platform/atmel/atmel-isc.c | 74 +++++++++++++++++++++++++++++---
> 1 file changed, 69 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c
> index f6b8b00e..e516805 100644
> --- a/drivers/media/platform/atmel/atmel-isc.c
> +++ b/drivers/media/platform/atmel/atmel-isc.c
> @@ -167,6 +167,9 @@ struct isc_ctrls {
> u32 brightness;
> u32 contrast;
> u8 gamma_index;
> +#define ISC_WB_NONE 0
> +#define ISC_WB_AUTO 1
> +#define ISC_WB_ONETIME 2
> u8 awb;
>
> /* one for each component : GR, R, GB, B */
> @@ -210,6 +213,7 @@ struct isc_device {
> struct fmt_config try_config;
>
> struct isc_ctrls ctrls;
> + struct v4l2_ctrl *do_wb_ctrl;
> struct work_struct awb_work;
>
> struct mutex lock;
> @@ -809,7 +813,7 @@ static void isc_set_pipeline(struct isc_device *isc, u32 pipeline)
>
> bay_cfg = isc->config.sd_format->cfa_baycfg;
>
> - if (!ctrls->awb)
> + if (ctrls->awb == ISC_WB_NONE)
> isc_reset_awb_ctrls(isc);
>
> regmap_write(regmap, ISC_WB_CFG, bay_cfg);
> @@ -1928,7 +1932,7 @@ static void isc_awb_work(struct work_struct *w)
> baysel = isc->config.sd_format->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT;
>
> /* if no more auto white balance, reset controls. */
> - if (!ctrls->awb)
> + if (ctrls->awb == ISC_WB_NONE)
> isc_reset_awb_ctrls(isc);
>
> pm_runtime_get_sync(isc->dev);
> @@ -1937,7 +1941,7 @@ static void isc_awb_work(struct work_struct *w)
> * only update if we have all the required histograms and controls
> * if awb has been disabled, we need to reset registers as well.
> */
> - if (hist_id == ISC_HIS_CFG_MODE_GR || !ctrls->awb) {
> + if (hist_id == ISC_HIS_CFG_MODE_GR || ctrls->awb == ISC_WB_NONE) {
> /*
> * It may happen that DMA Done IRQ will trigger while we are
> * updating white balance registers here.
> @@ -1947,6 +1951,16 @@ static void isc_awb_work(struct work_struct *w)
> spin_lock_irqsave(&isc->awb_lock, flags);
> isc_update_awb_ctrls(isc);
> spin_unlock_irqrestore(&isc->awb_lock, flags);
> +
> + /*
> + * if we are doing just the one time white balance adjustment,
> + * we are basically done.
> + */
> + if (ctrls->awb == ISC_WB_ONETIME) {
> + v4l2_info(&isc->v4l2_dev,
> + "Completed one time white-balance adjustment.\n");
> + ctrls->awb = ISC_WB_NONE;
> + }
> }
> regmap_write(regmap, ISC_HIS_CFG, hist_id | baysel | ISC_HIS_CFG_RAR);
> isc_update_profile(isc);
> @@ -1974,10 +1988,56 @@ static int isc_s_ctrl(struct v4l2_ctrl *ctrl)
> ctrls->gamma_index = ctrl->val;
> break;
> case V4L2_CID_AUTO_WHITE_BALANCE:
> - ctrls->awb = ctrl->val;
> + if (ctrl->val == 1) {
> + ctrls->awb = ISC_WB_AUTO;
> + v4l2_ctrl_activate(isc->do_wb_ctrl, false);
> + } else {
> + ctrls->awb = ISC_WB_NONE;
> + v4l2_ctrl_activate(isc->do_wb_ctrl, true);
> + }
> + /* we did not configure ISC yet */
> + if (!isc->config.sd_format)
> + break;
> +
> + if (!ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) {
> + v4l2_err(&isc->v4l2_dev,
> + "White balance adjustments available only if sensor is in RAW mode.\n");

This isn't an error, instead if the format isn't raw, then deactivate
the control (see v4l2_ctrl_activate()). That way the control framework
will handle this.

> + return 0;
> + }
> +
> if (ctrls->hist_stat != HIST_ENABLED) {
> isc_reset_awb_ctrls(isc);
> }
> +
> + if (isc->ctrls.awb && vb2_is_streaming(&isc->vb2_vidq) &&
> + ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code))
> + isc_set_histogram(isc, true);
> +
> + break;
> + case V4L2_CID_DO_WHITE_BALANCE:
> + /* we did not configure ISC yet */
> + if (!isc->config.sd_format)
> + break;
> +
> + if (ctrls->awb == ISC_WB_AUTO) {
> + v4l2_err(&isc->v4l2_dev,
> + "To use one time white-balance adjustment, disable auto white balance first.\n");

I'd do this differently: if auto whitebalance is already on, then just do
nothing for V4L2_CID_DO_WHITE_BALANCE.

> + return -EAGAIN;
> + }
> + if (!vb2_is_streaming(&isc->vb2_vidq)) {
> + v4l2_err(&isc->v4l2_dev,
> + "One time white-balance adjustment requires streaming to be enabled.\n");

This too should use v4l2_ctrl_activate(): activate the control in start_streaming,
deactivate in stop_streaming (and when the control is created).

> + return -EAGAIN;
> + }
> +
> + if (!ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) {
> + v4l2_err(&isc->v4l2_dev,
> + "White balance adjustments available only if sensor is in RAW mode.\n");

Same note as above: use v4l2_ctrl_activate() for this.

> + return -EAGAIN;
> + }
> + ctrls->awb = ISC_WB_ONETIME;
> + isc_set_histogram(isc, true);
> + v4l2_info(&isc->v4l2_dev, "One time white-balance started.\n");

Make this v4l2_dbg.

> break;
> default:
> return -EINVAL;
> @@ -2000,7 +2060,7 @@ static int isc_ctrl_init(struct isc_device *isc)
> ctrls->hist_stat = HIST_INIT;
> isc_reset_awb_ctrls(isc);
>
> - ret = v4l2_ctrl_handler_init(hdl, 4);
> + ret = v4l2_ctrl_handler_init(hdl, 5);
> if (ret < 0)
> return ret;
>
> @@ -2012,6 +2072,10 @@ static int isc_ctrl_init(struct isc_device *isc)
> v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAMMA, 0, GAMMA_MAX, 1, 2);
> v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
>
> + /* do_white_balance is a button, so min,max,step,default are ignored */
> + isc->do_wb_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_DO_WHITE_BALANCE,
> + 0, 0, 0, 0);
> +
> v4l2_ctrl_handler_setup(hdl);
>
> return 0;
>

Regards,

Hans