Skip to content

Commit

Permalink
[media] m5mols: Refactored controls handling
Browse files Browse the repository at this point in the history
This patch is a prerequisite for the new controls addition. It consolidates
the control handling code, which is moved to m5mols_controls.c and
staticized. The controls initialization is reordered to better reflect
the control clusters and make the diffs smaller when new controls are added.
To make the code easier to follow when more controls is added use separate
set function for each control.

Rewrite the image effect registers handling.

Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
  • Loading branch information
Sylwester Nawrocki authored and Mauro Carvalho Chehab committed May 14, 2012
1 parent 91f4eb0 commit 3c5da0b
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 150 deletions.
24 changes: 13 additions & 11 deletions drivers/media/video/m5mols/m5mols.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,12 +160,12 @@ struct m5mols_version {
* @irq_waitq: waitqueue for the capture
* @flags: state variable for the interrupt handler
* @handle: control handler
* @autoexposure: Auto Exposure control
* @exposure: Exposure control
* @auto_exposure: auto/manual exposure control
* @exposure: manual exposure control
* @autowb: Auto White Balance control
* @colorfx: Color effect control
* @saturation: Saturation control
* @zoom: Zoom control
* @colorfx: color effect control
* @saturation: saturation control
* @zoom: zoom control
* @ver: information of the version
* @cap: the capture mode attributes
* @power: current sensor's power status
Expand All @@ -188,12 +188,13 @@ struct m5mols_info {
atomic_t irq_done;

struct v4l2_ctrl_handler handle;
struct {
/* exposure/auto-exposure cluster */
struct v4l2_ctrl *auto_exposure;
struct v4l2_ctrl *exposure;
};

/* Autoexposure/exposure control cluster */
struct v4l2_ctrl *autoexposure;
struct v4l2_ctrl *exposure;

struct v4l2_ctrl *autowb;
struct v4l2_ctrl *auto_wb;
struct v4l2_ctrl *colorfx;
struct v4l2_ctrl *saturation;
struct v4l2_ctrl *zoom;
Expand Down Expand Up @@ -277,7 +278,7 @@ int m5mols_busy_wait(struct v4l2_subdev *sd, u32 reg, u32 value, u32 mask,
* The available executing order between each modes are as follows:
* PARAMETER <---> MONITOR <---> CAPTURE
*/
int m5mols_mode(struct m5mols_info *info, u8 mode);
int m5mols_set_mode(struct m5mols_info *info, u8 mode);

int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg);
int m5mols_wait_interrupt(struct v4l2_subdev *sd, u8 condition, u32 timeout);
Expand All @@ -286,6 +287,7 @@ int m5mols_start_capture(struct m5mols_info *info);
int m5mols_do_scenemode(struct m5mols_info *info, u8 mode);
int m5mols_lock_3a(struct m5mols_info *info, bool lock);
int m5mols_set_ctrl(struct v4l2_ctrl *ctrl);
int m5mols_init_controls(struct v4l2_subdev *sd);

/* The firmware function */
int m5mols_update_fw(struct v4l2_subdev *sd,
Expand Down
4 changes: 2 additions & 2 deletions drivers/media/video/m5mols/m5mols_capture.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ int m5mols_start_capture(struct m5mols_info *info)
* format. The frame capture is initiated during switching from Monitor
* to Capture mode.
*/
ret = m5mols_mode(info, REG_MONITOR);
ret = m5mols_set_mode(info, REG_MONITOR);
if (!ret)
ret = m5mols_restore_controls(info);
if (!ret)
Expand All @@ -124,7 +124,7 @@ int m5mols_start_capture(struct m5mols_info *info)
if (!ret)
ret = m5mols_lock_3a(info, true);
if (!ret)
ret = m5mols_mode(info, REG_CAPTURE);
ret = m5mols_set_mode(info, REG_CAPTURE);
if (!ret)
/* Wait until a frame is captured to ISP internal memory */
ret = m5mols_wait_interrupt(sd, REG_INT_CAPTURE, 2000);
Expand Down
227 changes: 174 additions & 53 deletions drivers/media/video/m5mols/m5mols_controls.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ int m5mols_do_scenemode(struct m5mols_info *info, u8 mode)
if (!ret)
ret = m5mols_write(sd, AE_ISO, scenemode.iso);
if (!ret)
ret = m5mols_mode(info, REG_CAPTURE);
ret = m5mols_set_mode(info, REG_CAPTURE);
if (!ret)
ret = m5mols_write(sd, CAPP_WDR_EN, scenemode.wdr);
if (!ret)
Expand All @@ -181,7 +181,7 @@ int m5mols_do_scenemode(struct m5mols_info *info, u8 mode)
if (!ret)
ret = m5mols_write(sd, CAPC_MODE, scenemode.capt_mode);
if (!ret)
ret = m5mols_mode(info, REG_MONITOR);
ret = m5mols_set_mode(info, REG_MONITOR);

return ret;
}
Expand Down Expand Up @@ -227,73 +227,194 @@ int m5mols_lock_3a(struct m5mols_info *info, bool lock)
return ret;
}

/* m5mols_set_ctrl() - The main s_ctrl function called by m5mols_set_ctrl() */
int m5mols_set_ctrl(struct v4l2_ctrl *ctrl)
/* Set exposure/auto exposure cluster */
static int m5mols_set_exposure(struct m5mols_info *info, int exposure)
{
struct v4l2_subdev *sd = &info->sd;
int ret;

ret = m5mols_lock_ae(info, exposure != V4L2_EXPOSURE_AUTO);
if (ret < 0)
return ret;

if (exposure == V4L2_EXPOSURE_AUTO) {
ret = m5mols_write(sd, AE_MODE, REG_AE_ALL);
if (ret < 0)
return ret;
}

if (exposure == V4L2_EXPOSURE_MANUAL) {
ret = m5mols_write(sd, AE_MODE, REG_AE_OFF);
if (ret == 0)
ret = m5mols_write(sd, AE_MAN_GAIN_MON,
info->exposure->val);
if (ret == 0)
ret = m5mols_write(sd, AE_MAN_GAIN_CAP,
info->exposure->val);
}

return ret;
}

static int m5mols_set_white_balance(struct m5mols_info *info, int awb)
{
int ret;

ret = m5mols_lock_awb(info, !awb);
if (ret < 0)
return ret;

return m5mols_write(&info->sd, AWB_MODE, awb ? REG_AWB_AUTO :
REG_AWB_PRESET);
}

static int m5mols_set_saturation(struct m5mols_info *info, int val)
{
int ret = m5mols_write(&info->sd, MON_CHROMA_LVL, val);
if (ret < 0)
return ret;

return m5mols_write(&info->sd, MON_CHROMA_EN, REG_CHROMA_ON);
}

static int m5mols_set_color_effect(struct m5mols_info *info, int val)
{
unsigned int m_effect = REG_COLOR_EFFECT_OFF;
unsigned int p_effect = REG_EFFECT_OFF;
unsigned int cfix_r = 0, cfix_b = 0;
struct v4l2_subdev *sd = &info->sd;
int ret = 0;

switch (val) {
case V4L2_COLORFX_BW:
m_effect = REG_COLOR_EFFECT_ON;
break;
case V4L2_COLORFX_NEGATIVE:
p_effect = REG_EFFECT_NEGA;
break;
case V4L2_COLORFX_EMBOSS:
p_effect = REG_EFFECT_EMBOSS;
break;
case V4L2_COLORFX_SEPIA:
m_effect = REG_COLOR_EFFECT_ON;
cfix_r = REG_CFIXR_SEPIA;
cfix_b = REG_CFIXB_SEPIA;
break;
}

ret = m5mols_write(sd, PARM_EFFECT, p_effect);
if (!ret)
ret = m5mols_write(sd, MON_EFFECT, m_effect);

if (ret == 0 && m_effect == REG_COLOR_EFFECT_ON) {
ret = m5mols_write(sd, MON_CFIXR, cfix_r);
if (!ret)
ret = m5mols_write(sd, MON_CFIXB, cfix_b);
}

v4l2_dbg(1, m5mols_debug, sd,
"p_effect: %#x, m_effect: %#x, r: %#x, b: %#x (%d)\n",
p_effect, m_effect, cfix_r, cfix_b, ret);

return ret;
}

static int m5mols_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct v4l2_subdev *sd = to_sd(ctrl);
struct m5mols_info *info = to_m5mols(sd);
int ispstate = info->mode;
int ret;

/*
* If needed, defer restoring the controls until
* the device is fully initialized.
*/
if (!info->isp_ready) {
info->ctrl_sync = 0;
return 0;
}

ret = m5mols_mode(info, REG_PARAMETER);
if (ret < 0)
return ret;

switch (ctrl->id) {
case V4L2_CID_ZOOM_ABSOLUTE:
return m5mols_write(sd, MON_ZOOM, ctrl->val);
ret = m5mols_write(sd, MON_ZOOM, ctrl->val);
break;

case V4L2_CID_EXPOSURE_AUTO:
ret = m5mols_lock_ae(info,
ctrl->val == V4L2_EXPOSURE_AUTO ? false : true);
if (!ret && ctrl->val == V4L2_EXPOSURE_AUTO)
ret = m5mols_write(sd, AE_MODE, REG_AE_ALL);
if (!ret && ctrl->val == V4L2_EXPOSURE_MANUAL) {
int val = info->exposure->val;
ret = m5mols_write(sd, AE_MODE, REG_AE_OFF);
if (!ret)
ret = m5mols_write(sd, AE_MAN_GAIN_MON, val);
if (!ret)
ret = m5mols_write(sd, AE_MAN_GAIN_CAP, val);
}
return ret;
ret = m5mols_set_exposure(info, ctrl->val);
break;

case V4L2_CID_AUTO_WHITE_BALANCE:
ret = m5mols_lock_awb(info, ctrl->val ? false : true);
if (!ret)
ret = m5mols_write(sd, AWB_MODE, ctrl->val ?
REG_AWB_AUTO : REG_AWB_PRESET);
return ret;
ret = m5mols_set_white_balance(info, ctrl->val);
break;

case V4L2_CID_SATURATION:
ret = m5mols_write(sd, MON_CHROMA_LVL, ctrl->val);
if (!ret)
ret = m5mols_write(sd, MON_CHROMA_EN, REG_CHROMA_ON);
return ret;
ret = m5mols_set_saturation(info, ctrl->val);
break;

case V4L2_CID_COLORFX:
/*
* This control uses two kinds of registers: normal & color.
* The normal effect belongs to category 1, while the color
* one belongs to category 2.
*
* The normal effect uses one register: CAT1_EFFECT.
* The color effect uses three registers:
* CAT2_COLOR_EFFECT, CAT2_CFIXR, CAT2_CFIXB.
*/
ret = m5mols_write(sd, PARM_EFFECT,
ctrl->val == V4L2_COLORFX_NEGATIVE ? REG_EFFECT_NEGA :
ctrl->val == V4L2_COLORFX_EMBOSS ? REG_EFFECT_EMBOSS :
REG_EFFECT_OFF);
if (!ret)
ret = m5mols_write(sd, MON_EFFECT,
ctrl->val == V4L2_COLORFX_SEPIA ?
REG_COLOR_EFFECT_ON : REG_COLOR_EFFECT_OFF);
if (!ret)
ret = m5mols_write(sd, MON_CFIXR,
ctrl->val == V4L2_COLORFX_SEPIA ?
REG_CFIXR_SEPIA : 0);
if (!ret)
ret = m5mols_write(sd, MON_CFIXB,
ctrl->val == V4L2_COLORFX_SEPIA ?
REG_CFIXB_SEPIA : 0);
ret = m5mols_set_color_effect(info, ctrl->val);
break;
}
if (ret < 0)
return ret;

return m5mols_mode(info, ispstate);
}

static const struct v4l2_ctrl_ops m5mols_ctrl_ops = {
.s_ctrl = m5mols_s_ctrl,
};

int m5mols_init_controls(struct v4l2_subdev *sd)
{
struct m5mols_info *info = to_m5mols(sd);
u16 exposure_max;
u16 zoom_step;
int ret;

/* Determine the firmware dependant control range and step values */
ret = m5mols_read_u16(sd, AE_MAX_GAIN_MON, &exposure_max);
if (ret < 0)
return ret;

zoom_step = is_manufacturer(info, REG_SAMSUNG_OPTICS) ? 31 : 1;

v4l2_ctrl_handler_init(&info->handle, 6);

info->auto_wb = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);

info->auto_exposure = v4l2_ctrl_new_std_menu(&info->handle,
&m5mols_ctrl_ops, V4L2_CID_EXPOSURE_AUTO,
1, ~0x03, V4L2_EXPOSURE_AUTO);

info->exposure = v4l2_ctrl_new_std(&info->handle,
&m5mols_ctrl_ops, V4L2_CID_EXPOSURE,
0, exposure_max, 1, exposure_max / 2);

info->saturation = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
V4L2_CID_SATURATION, 1, 5, 1, 3);

info->zoom = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
V4L2_CID_ZOOM_ABSOLUTE, 1, 70, zoom_step, 1);

info->colorfx = v4l2_ctrl_new_std_menu(&info->handle, &m5mols_ctrl_ops,
V4L2_CID_COLORFX, 4, 0, V4L2_COLORFX_NONE);

if (info->handle.error) {
int ret = info->handle.error;
v4l2_err(sd, "Failed to initialize controls: %d\n", ret);
v4l2_ctrl_handler_free(&info->handle);
return ret;
}

return -EINVAL;
v4l2_ctrl_auto_cluster(2, &info->auto_exposure, 1, false);
sd->ctrl_handler = &info->handle;

return 0;
}
Loading

0 comments on commit 3c5da0b

Please sign in to comment.