Commit 3c5da0ba authored by Sylwester Nawrocki's avatar Sylwester Nawrocki Committed by Mauro Carvalho Chehab

[media] m5mols: Refactored controls handling

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: default avatarSylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: default avatarKyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 91f4eb0a
...@@ -160,12 +160,12 @@ struct m5mols_version { ...@@ -160,12 +160,12 @@ struct m5mols_version {
* @irq_waitq: waitqueue for the capture * @irq_waitq: waitqueue for the capture
* @flags: state variable for the interrupt handler * @flags: state variable for the interrupt handler
* @handle: control handler * @handle: control handler
* @autoexposure: Auto Exposure control * @auto_exposure: auto/manual exposure control
* @exposure: Exposure control * @exposure: manual exposure control
* @autowb: Auto White Balance control * @autowb: Auto White Balance control
* @colorfx: Color effect control * @colorfx: color effect control
* @saturation: Saturation control * @saturation: saturation control
* @zoom: Zoom control * @zoom: zoom control
* @ver: information of the version * @ver: information of the version
* @cap: the capture mode attributes * @cap: the capture mode attributes
* @power: current sensor's power status * @power: current sensor's power status
...@@ -188,12 +188,13 @@ struct m5mols_info { ...@@ -188,12 +188,13 @@ struct m5mols_info {
atomic_t irq_done; atomic_t irq_done;
struct v4l2_ctrl_handler handle; struct v4l2_ctrl_handler handle;
struct {
/* Autoexposure/exposure control cluster */ /* exposure/auto-exposure cluster */
struct v4l2_ctrl *autoexposure; struct v4l2_ctrl *auto_exposure;
struct v4l2_ctrl *exposure; struct v4l2_ctrl *exposure;
};
struct v4l2_ctrl *autowb; struct v4l2_ctrl *auto_wb;
struct v4l2_ctrl *colorfx; struct v4l2_ctrl *colorfx;
struct v4l2_ctrl *saturation; struct v4l2_ctrl *saturation;
struct v4l2_ctrl *zoom; struct v4l2_ctrl *zoom;
...@@ -277,7 +278,7 @@ int m5mols_busy_wait(struct v4l2_subdev *sd, u32 reg, u32 value, u32 mask, ...@@ -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: * The available executing order between each modes are as follows:
* PARAMETER <---> MONITOR <---> CAPTURE * 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_enable_interrupt(struct v4l2_subdev *sd, u8 reg);
int m5mols_wait_interrupt(struct v4l2_subdev *sd, u8 condition, u32 timeout); int m5mols_wait_interrupt(struct v4l2_subdev *sd, u8 condition, u32 timeout);
...@@ -286,6 +287,7 @@ int m5mols_start_capture(struct m5mols_info *info); ...@@ -286,6 +287,7 @@ int m5mols_start_capture(struct m5mols_info *info);
int m5mols_do_scenemode(struct m5mols_info *info, u8 mode); int m5mols_do_scenemode(struct m5mols_info *info, u8 mode);
int m5mols_lock_3a(struct m5mols_info *info, bool lock); int m5mols_lock_3a(struct m5mols_info *info, bool lock);
int m5mols_set_ctrl(struct v4l2_ctrl *ctrl); int m5mols_set_ctrl(struct v4l2_ctrl *ctrl);
int m5mols_init_controls(struct v4l2_subdev *sd);
/* The firmware function */ /* The firmware function */
int m5mols_update_fw(struct v4l2_subdev *sd, int m5mols_update_fw(struct v4l2_subdev *sd,
......
...@@ -114,7 +114,7 @@ int m5mols_start_capture(struct m5mols_info *info) ...@@ -114,7 +114,7 @@ int m5mols_start_capture(struct m5mols_info *info)
* format. The frame capture is initiated during switching from Monitor * format. The frame capture is initiated during switching from Monitor
* to Capture mode. * to Capture mode.
*/ */
ret = m5mols_mode(info, REG_MONITOR); ret = m5mols_set_mode(info, REG_MONITOR);
if (!ret) if (!ret)
ret = m5mols_restore_controls(info); ret = m5mols_restore_controls(info);
if (!ret) if (!ret)
...@@ -124,7 +124,7 @@ int m5mols_start_capture(struct m5mols_info *info) ...@@ -124,7 +124,7 @@ int m5mols_start_capture(struct m5mols_info *info)
if (!ret) if (!ret)
ret = m5mols_lock_3a(info, true); ret = m5mols_lock_3a(info, true);
if (!ret) if (!ret)
ret = m5mols_mode(info, REG_CAPTURE); ret = m5mols_set_mode(info, REG_CAPTURE);
if (!ret) if (!ret)
/* Wait until a frame is captured to ISP internal memory */ /* Wait until a frame is captured to ISP internal memory */
ret = m5mols_wait_interrupt(sd, REG_INT_CAPTURE, 2000); ret = m5mols_wait_interrupt(sd, REG_INT_CAPTURE, 2000);
......
...@@ -169,7 +169,7 @@ int m5mols_do_scenemode(struct m5mols_info *info, u8 mode) ...@@ -169,7 +169,7 @@ int m5mols_do_scenemode(struct m5mols_info *info, u8 mode)
if (!ret) if (!ret)
ret = m5mols_write(sd, AE_ISO, scenemode.iso); ret = m5mols_write(sd, AE_ISO, scenemode.iso);
if (!ret) if (!ret)
ret = m5mols_mode(info, REG_CAPTURE); ret = m5mols_set_mode(info, REG_CAPTURE);
if (!ret) if (!ret)
ret = m5mols_write(sd, CAPP_WDR_EN, scenemode.wdr); ret = m5mols_write(sd, CAPP_WDR_EN, scenemode.wdr);
if (!ret) if (!ret)
...@@ -181,7 +181,7 @@ int m5mols_do_scenemode(struct m5mols_info *info, u8 mode) ...@@ -181,7 +181,7 @@ int m5mols_do_scenemode(struct m5mols_info *info, u8 mode)
if (!ret) if (!ret)
ret = m5mols_write(sd, CAPC_MODE, scenemode.capt_mode); ret = m5mols_write(sd, CAPC_MODE, scenemode.capt_mode);
if (!ret) if (!ret)
ret = m5mols_mode(info, REG_MONITOR); ret = m5mols_set_mode(info, REG_MONITOR);
return ret; return ret;
} }
...@@ -227,73 +227,194 @@ int m5mols_lock_3a(struct m5mols_info *info, bool lock) ...@@ -227,73 +227,194 @@ int m5mols_lock_3a(struct m5mols_info *info, bool lock)
return ret; return ret;
} }
/* m5mols_set_ctrl() - The main s_ctrl function called by m5mols_set_ctrl() */ /* Set exposure/auto exposure cluster */
int m5mols_set_ctrl(struct v4l2_ctrl *ctrl) static int m5mols_set_exposure(struct m5mols_info *info, int exposure)
{ {
struct v4l2_subdev *sd = to_sd(ctrl); struct v4l2_subdev *sd = &info->sd;
struct m5mols_info *info = to_m5mols(sd);
int ret; int ret;
switch (ctrl->id) { ret = m5mols_lock_ae(info, exposure != V4L2_EXPOSURE_AUTO);
case V4L2_CID_ZOOM_ABSOLUTE: if (ret < 0)
return m5mols_write(sd, MON_ZOOM, ctrl->val); return ret;
case V4L2_CID_EXPOSURE_AUTO: if (exposure == V4L2_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); ret = m5mols_write(sd, AE_MODE, REG_AE_ALL);
if (!ret && ctrl->val == V4L2_EXPOSURE_MANUAL) { if (ret < 0)
int val = info->exposure->val; return ret;
}
if (exposure == V4L2_EXPOSURE_MANUAL) {
ret = m5mols_write(sd, AE_MODE, REG_AE_OFF); ret = m5mols_write(sd, AE_MODE, REG_AE_OFF);
if (!ret) if (ret == 0)
ret = m5mols_write(sd, AE_MAN_GAIN_MON, val); ret = m5mols_write(sd, AE_MAN_GAIN_MON,
if (!ret) info->exposure->val);
ret = m5mols_write(sd, AE_MAN_GAIN_CAP, val); if (ret == 0)
ret = m5mols_write(sd, AE_MAN_GAIN_CAP,
info->exposure->val);
} }
return ret; return ret;
}
case V4L2_CID_AUTO_WHITE_BALANCE: static int m5mols_set_white_balance(struct m5mols_info *info, int awb)
ret = m5mols_lock_awb(info, ctrl->val ? false : true); {
if (!ret) int ret;
ret = m5mols_write(sd, AWB_MODE, ctrl->val ?
REG_AWB_AUTO : REG_AWB_PRESET); ret = m5mols_lock_awb(info, !awb);
if (ret < 0)
return ret; return ret;
case V4L2_CID_SATURATION: return m5mols_write(&info->sd, AWB_MODE, awb ? REG_AWB_AUTO :
ret = m5mols_write(sd, MON_CHROMA_LVL, ctrl->val); 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) if (!ret)
ret = m5mols_write(sd, MON_CHROMA_EN, REG_CHROMA_ON); 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; 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;
case V4L2_CID_COLORFX:
/* /*
* This control uses two kinds of registers: normal & color. * If needed, defer restoring the controls until
* The normal effect belongs to category 1, while the color * the device is fully initialized.
* 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, if (!info->isp_ready) {
ctrl->val == V4L2_COLORFX_NEGATIVE ? REG_EFFECT_NEGA : info->ctrl_sync = 0;
ctrl->val == V4L2_COLORFX_EMBOSS ? REG_EFFECT_EMBOSS : return 0;
REG_EFFECT_OFF); }
if (!ret)
ret = m5mols_write(sd, MON_EFFECT, ret = m5mols_mode(info, REG_PARAMETER);
ctrl->val == V4L2_COLORFX_SEPIA ? if (ret < 0)
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);
return ret; return ret;
switch (ctrl->id) {
case V4L2_CID_ZOOM_ABSOLUTE:
ret = m5mols_write(sd, MON_ZOOM, ctrl->val);
break;
case V4L2_CID_EXPOSURE_AUTO:
ret = m5mols_set_exposure(info, ctrl->val);
break;
case V4L2_CID_AUTO_WHITE_BALANCE:
ret = m5mols_set_white_balance(info, ctrl->val);
break;
case V4L2_CID_SATURATION:
ret = m5mols_set_saturation(info, ctrl->val);
break;
case V4L2_CID_COLORFX:
ret = m5mols_set_color_effect(info, ctrl->val);
break;
} }
if (ret < 0)
return ret;
return -EINVAL; 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;
}
v4l2_ctrl_auto_cluster(2, &info->auto_exposure, 1, false);
sd->ctrl_handler = &info->handle;
return 0;
} }
...@@ -362,14 +362,14 @@ static int m5mols_reg_mode(struct v4l2_subdev *sd, u8 mode) ...@@ -362,14 +362,14 @@ static int m5mols_reg_mode(struct v4l2_subdev *sd, u8 mode)
} }
/** /**
* m5mols_mode - manage the M-5MOLS's mode * m5mols_set_mode - set the M-5MOLS controller mode
* @mode: the required operation mode * @mode: the required operation mode
* *
* The commands of M-5MOLS are grouped into specific modes. Each functionality * The commands of M-5MOLS are grouped into specific modes. Each functionality
* can be guaranteed only when the sensor is operating in mode which which * can be guaranteed only when the sensor is operating in mode which a command
* a command belongs to. * belongs to.
*/ */
int m5mols_mode(struct m5mols_info *info, u8 mode) int m5mols_set_mode(struct m5mols_info *info, u8 mode)
{ {
struct v4l2_subdev *sd = &info->sd; struct v4l2_subdev *sd = &info->sd;
int ret = -EINVAL; int ret = -EINVAL;
...@@ -645,13 +645,13 @@ static int m5mols_start_monitor(struct m5mols_info *info) ...@@ -645,13 +645,13 @@ static int m5mols_start_monitor(struct m5mols_info *info)
struct v4l2_subdev *sd = &info->sd; struct v4l2_subdev *sd = &info->sd;
int ret; int ret;
ret = m5mols_mode(info, REG_PARAMETER); ret = m5mols_set_mode(info, REG_PARAMETER);
if (!ret) if (!ret)
ret = m5mols_write(sd, PARM_MON_SIZE, info->resolution); ret = m5mols_write(sd, PARM_MON_SIZE, info->resolution);
if (!ret) if (!ret)
ret = m5mols_write(sd, PARM_MON_FPS, REG_FPS_30); ret = m5mols_write(sd, PARM_MON_FPS, REG_FPS_30);
if (!ret) if (!ret)
ret = m5mols_mode(info, REG_MONITOR); ret = m5mols_set_mode(info, REG_MONITOR);
if (!ret) if (!ret)
ret = m5mols_restore_controls(info); ret = m5mols_restore_controls(info);
...@@ -674,42 +674,13 @@ static int m5mols_s_stream(struct v4l2_subdev *sd, int enable) ...@@ -674,42 +674,13 @@ static int m5mols_s_stream(struct v4l2_subdev *sd, int enable)
return ret; return ret;
} }
return m5mols_mode(info, REG_PARAMETER); return m5mols_set_mode(info, REG_PARAMETER);
} }
static const struct v4l2_subdev_video_ops m5mols_video_ops = { static const struct v4l2_subdev_video_ops m5mols_video_ops = {
.s_stream = m5mols_s_stream, .s_stream = m5mols_s_stream,
}; };
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;
ret = m5mols_set_ctrl(ctrl);
if (ret < 0)
return ret;
return m5mols_mode(info, ispstate);
}
static const struct v4l2_ctrl_ops m5mols_ctrl_ops = {
.s_ctrl = m5mols_s_ctrl,
};
static int m5mols_sensor_power(struct m5mols_info *info, bool enable) static int m5mols_sensor_power(struct m5mols_info *info, bool enable)
{ {
struct v4l2_subdev *sd = &info->sd; struct v4l2_subdev *sd = &info->sd;
...@@ -802,52 +773,6 @@ static int m5mols_fw_start(struct v4l2_subdev *sd) ...@@ -802,52 +773,6 @@ static int m5mols_fw_start(struct v4l2_subdev *sd)
return ret; return ret;
} }
static int m5mols_init_controls(struct m5mols_info *info)
{
struct v4l2_subdev *sd = &info->sd;
u16 max_exposure;
u16 step_zoom;
int ret;
/* Determine value's range & step of controls for various FW version */
ret = m5mols_read_u16(sd, AE_MAX_GAIN_MON, &max_exposure);
if (!ret)
step_zoom = is_manufacturer(info, REG_SAMSUNG_OPTICS) ? 31 : 1;
if (ret)
return ret;
v4l2_ctrl_handler_init(&info->handle, 6);
info->autowb = v4l2_ctrl_new_std(&info->handle,
&m5mols_ctrl_ops, V4L2_CID_AUTO_WHITE_BALANCE,
0, 1, 1, 0);
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, step_zoom, 1);
info->exposure = v4l2_ctrl_new_std(&info->handle,
&m5mols_ctrl_ops, V4L2_CID_EXPOSURE,
0, max_exposure, 1, (int)max_exposure/2);
info->colorfx = v4l2_ctrl_new_std_menu(&info->handle,
&m5mols_ctrl_ops, V4L2_CID_COLORFX,
4, (1 << V4L2_COLORFX_BW), V4L2_COLORFX_NONE);
info->autoexposure = v4l2_ctrl_new_std_menu(&info->handle,
&m5mols_ctrl_ops, V4L2_CID_EXPOSURE_AUTO,
1, 0, V4L2_EXPOSURE_AUTO);
sd->ctrl_handler = &info->handle;
if (info->handle.error) {
v4l2_err(sd, "Failed to initialize controls: %d\n", ret);
v4l2_ctrl_handler_free(&info->handle);
return info->handle.error;
}
v4l2_ctrl_cluster(2, &info->autoexposure);
return 0;
}
/** /**
* m5mols_s_power - Main sensor power control function * m5mols_s_power - Main sensor power control function
* *
...@@ -868,7 +793,7 @@ static int m5mols_s_power(struct v4l2_subdev *sd, int on) ...@@ -868,7 +793,7 @@ static int m5mols_s_power(struct v4l2_subdev *sd, int on)
} }
if (is_manufacturer(info, REG_SAMSUNG_TECHWIN)) { if (is_manufacturer(info, REG_SAMSUNG_TECHWIN)) {
ret = m5mols_mode(info, REG_MONITOR); ret = m5mols_set_mode(info, REG_MONITOR);
if (!ret) if (!ret)
ret = m5mols_write(sd, AF_EXECUTE, REG_AF_STOP); ret = m5mols_write(sd, AF_EXECUTE, REG_AF_STOP);
if (!ret) if (!ret)
...@@ -1010,7 +935,7 @@ static int __devinit m5mols_probe(struct i2c_client *client, ...@@ -1010,7 +935,7 @@ static int __devinit m5mols_probe(struct i2c_client *client,
ret = m5mols_fw_start(sd); ret = m5mols_fw_start(sd);
if (!ret) if (!ret)
ret = m5mols_init_controls(info); ret = m5mols_init_controls(sd);
m5mols_sensor_power(info, false); m5mols_sensor_power(info, false);
if (!ret) if (!ret)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment