diff options
author | kyoungho.yun <kyoungho.yun@samsung.com> | 2011-10-06 15:09:58 +0900 |
---|---|---|
committer | Arve Hjønnevåg <arve@android.com> | 2011-11-17 17:54:47 -0800 |
commit | f4c4316f7e5fbb8418e3994e849c95ed1ac495d7 (patch) | |
tree | 234e404c1bc995fd7c3442ae1726cbd3d2f828a6 | |
parent | ff5e8ff7f6fb47de7bbc283c86fa7d1bc3d8cbd1 (diff) | |
download | kernel_samsung_crespo-f4c4316f7e5fbb8418e3994e849c95ed1ac495d7.zip kernel_samsung_crespo-f4c4316f7e5fbb8418e3994e849c95ed1ac495d7.tar.gz kernel_samsung_crespo-f4c4316f7e5fbb8418e3994e849c95ed1ac495d7.tar.bz2 |
S5PC11X: CAMERA: Remove AF polling code
Preview is paused during auto focus.
To fix this problem, move polling code from driver to HAL.
Change-Id: I4b4e961cc5614579dfe419f14cc67bed6c6dda41
Signed-off-by: kyoungho.yun <kyoungho.yun@samsung.com>
-rwxr-xr-x | drivers/media/video/s5k4ecgx.c | 207 | ||||
-rwxr-xr-x | include/linux/videodev2_samsung.h | 4 |
2 files changed, 99 insertions, 112 deletions
diff --git a/drivers/media/video/s5k4ecgx.c b/drivers/media/video/s5k4ecgx.c index ead8835..bf93035 100755 --- a/drivers/media/video/s5k4ecgx.c +++ b/drivers/media/video/s5k4ecgx.c @@ -90,6 +90,7 @@ enum af_operation_status { AF_NONE = 0, AF_START, AF_CANCEL, + AF_INITIAL, }; enum s5k4ecgx_oprmode { @@ -961,6 +962,7 @@ static int s5k4ecgx_start_capture(struct v4l2_subdev *sd) } else state->restore_preview_size_needed = false; + msleep(50); light_level = s5k4ecgx_get_light_level(sd); dev_dbg(&client->dev, "%s: light_level = %d\n", __func__, @@ -1310,13 +1312,39 @@ enable_af_low_light_mode: s5k4ecgx_set_from_table(sd, "single af start", &state->regs->single_af_start, 1, 0); - state->af_status = AF_START; + state->af_status = AF_INITIAL; INIT_COMPLETION(state->af_complete); dev_dbg(&client->dev, "%s: af_status set to start\n", __func__); return 0; } +/* called by HAL after auto focus was finished. + * it might off the assist flash + */ +static int s5k4ecgx_finish_auto_focus(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + + /* restore write mode */ + s5k4ecgx_i2c_write_twobyte(client, 0x0028, 0x7000); + + if (state->flash_on) { + struct s5k4ecgx_platform_data *pd = client->dev.platform_data; + s5k4ecgx_set_from_table(sd, "AF assist flash end", + &state->regs->af_assist_flash_end, 1, 0); + state->flash_on = false; + pd->af_assist_onoff(0); + } + + dev_dbg(&client->dev, "%s: single AF finished\n", __func__); + state->af_status = AF_NONE; + complete(&state->af_complete); + return 0; +} + static int s5k4ecgx_stop_auto_focus(struct v4l2_subdev *sd) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -1336,6 +1364,8 @@ static int s5k4ecgx_stop_auto_focus(struct v4l2_subdev *sd) s5k4ecgx_set_from_table(sd, "ae awb lock off", &state->regs->ae_awb_lock_off, 1, 0); + if (state->flash_on) + s5k4ecgx_finish_auto_focus(sd); if (state->af_status != AF_START) { /* we weren't in the middle auto focus operation, we're done */ @@ -1356,7 +1386,8 @@ static int s5k4ecgx_stop_auto_focus(struct v4l2_subdev *sd) } /* auto focus was in progress. the other thread - * is either in the middle of get_auto_focus_result() + * is either in the middle of s5k4ecgx_get_auto_focus_result_first(), + * s5k4ecgx_get_auto_focus_result_second() * or will call it shortly. set a flag to have * it abort it's polling. that thread will * also do cleanup like restore focus position. @@ -1389,133 +1420,81 @@ static int s5k4ecgx_stop_auto_focus(struct v4l2_subdev *sd) return 0; } -/* called by HAL after auto focus was started to get the result. - * it might be aborted asynchronously by a call to set_auto_focus - */ -static int s5k4ecgx_get_auto_focus_result(struct v4l2_subdev *sd, +/* called by HAL after auto focus was started to get the first search result*/ +static int s5k4ecgx_get_auto_focus_result_first(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct s5k4ecgx_state *state = container_of(sd, struct s5k4ecgx_state, sd); - int err, count; u16 read_value; - dev_dbg(&client->dev, "%s: Check AF Result\n", __func__); - - if (state->af_status == AF_NONE) { - dev_dbg(&client->dev, - "%s: auto focus never started, returning 0x2\n", - __func__); - ctrl->value = AUTO_FOCUS_CANCELLED; - return 0; - } - - /* must delay 2 frame times before checking result of 1st phase */ - mutex_unlock(&state->ctrl_lock); - msleep(state->one_frame_delay_ms*2); - mutex_lock(&state->ctrl_lock); - - /* lock AE and AWB after first AF search */ - s5k4ecgx_set_from_table(sd, "ae awb lock on", - &state->regs->ae_awb_lock_on, 1, 0); - - dev_dbg(&client->dev, "%s: 1st AF search\n", __func__); - /* enter read mode */ - s5k4ecgx_i2c_write_twobyte(client, 0x002C, 0x7000); - for (count = 0; count < FIRST_AF_SEARCH_COUNT; count++) { - if (state->af_status == AF_CANCEL) { + if (state->af_status == AF_INITIAL) { + dev_dbg(&client->dev, "%s: Check AF Result\n", __func__); + if (state->af_status == AF_NONE) { dev_dbg(&client->dev, - "%s: AF is cancelled while doing\n", __func__); + "%s: auto focus never started, returning 0x2\n", + __func__); ctrl->value = AUTO_FOCUS_CANCELLED; - goto check_flash; + return 0; } - s5k4ecgx_set_from_table(sd, "get 1st af search status", - &state->regs->get_1st_af_search_status, - 1, 0); - s5k4ecgx_i2c_read_twobyte(client, 0x0F12, &read_value); - dev_dbg(&client->dev, - "%s: 1st i2c_read --- read_value == 0x%x\n", - __func__, read_value); - /* check for success and failure cases. 0x1 is - * auto focus still in progress. 0x2 is success. - * 0x0,0x3,0x4,0x6,0x8 are all failures cases - */ - if (read_value != 0x01) - break; + /* must delay 2 frame times before checking result of 1st phase */ mutex_unlock(&state->ctrl_lock); - msleep(50); + msleep(state->one_frame_delay_ms*2); mutex_lock(&state->ctrl_lock); - } - if ((count >= FIRST_AF_SEARCH_COUNT) || (read_value != 0x02)) { - dev_dbg(&client->dev, - "%s: 1st scan timed out or failed\n", __func__); - ctrl->value = AUTO_FOCUS_FAILED; - goto check_flash; - } - - dev_dbg(&client->dev, "%s: 2nd AF search\n", __func__); + /* lock AE and AWB after first AF search */ + s5k4ecgx_set_from_table(sd, "ae awb lock on", + &state->regs->ae_awb_lock_on, 1, 0); - /* delay 1 frame time before checking for 2nd AF completion */ - mutex_unlock(&state->ctrl_lock); - msleep(state->one_frame_delay_ms); - mutex_lock(&state->ctrl_lock); - - /* this is the long portion of AF, can take a second or more. - * we poll and wakeup more frequently than 1 second mainly - * to see if a cancel was requested - */ - for (count = 0; count < SECOND_AF_SEARCH_COUNT; count++) { - if (state->af_status == AF_CANCEL) { - dev_dbg(&client->dev, - "%s: AF is cancelled while doing\n", __func__); - ctrl->value = AUTO_FOCUS_CANCELLED; - goto check_flash; - } - s5k4ecgx_set_from_table(sd, "get 2nd af search status", - &state->regs->get_2nd_af_search_status, - 1, 0); - s5k4ecgx_i2c_read_twobyte(client, 0x0F12, &read_value); + dev_dbg(&client->dev, "%s: 1st AF search\n", __func__); + /* enter read mode */ + s5k4ecgx_i2c_write_twobyte(client, 0x002C, 0x7000); + state->af_status = AF_START; + } else if (state->af_status == AF_CANCEL) { dev_dbg(&client->dev, - "%s: 2nd i2c_read --- read_value == 0x%x\n", - __func__, read_value); - - /* low byte is garbage. done when high byte is 0x0 */ - if (!(read_value & 0xff00)) - break; - - mutex_unlock(&state->ctrl_lock); - msleep(50); - mutex_lock(&state->ctrl_lock); - } - - if (count >= SECOND_AF_SEARCH_COUNT) { - dev_dbg(&client->dev, "%s: 2nd scan timed out\n", __func__); - ctrl->value = AUTO_FOCUS_FAILED; - goto check_flash; + "%s: AF is cancelled while doing\n", __func__); + ctrl->value = AUTO_FOCUS_CANCELLED; + s5k4ecgx_finish_auto_focus(sd); + return 0; } + s5k4ecgx_set_from_table(sd, "get 1st af search status", + &state->regs->get_1st_af_search_status, + 1, 0); + s5k4ecgx_i2c_read_twobyte(client, 0x0F12, &read_value); + dev_dbg(&client->dev, + "%s: 1st i2c_read --- read_value == 0x%x\n", + __func__, read_value); + ctrl->value = read_value; + return 0; +} - dev_dbg(&client->dev, "%s: AF is success\n", __func__); - ctrl->value = AUTO_FOCUS_DONE; - -check_flash: - /* restore write mode */ - s5k4ecgx_i2c_write_twobyte(client, 0x0028, 0x7000); +/* called by HAL after first search was succeed to get the second search result*/ +static int s5k4ecgx_get_auto_focus_result_second(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct s5k4ecgx_state *state = + container_of(sd, struct s5k4ecgx_state, sd); + u16 read_value; - if (state->flash_on) { - struct s5k4ecgx_platform_data *pd = client->dev.platform_data; - s5k4ecgx_set_from_table(sd, "AF assist flash end", - &state->regs->af_assist_flash_end, 1, 0); - state->flash_on = false; - pd->af_assist_onoff(0); + if (state->af_status == AF_CANCEL) { + dev_dbg(&client->dev, + "%s: AF is cancelled while doing\n", __func__); + ctrl->value = AUTO_FOCUS_CANCELLED; + s5k4ecgx_finish_auto_focus(sd); + return 0; } - - dev_dbg(&client->dev, "%s: single AF finished\n", __func__); - state->af_status = AF_NONE; - complete(&state->af_complete); - return err; + s5k4ecgx_set_from_table(sd, "get 2nd af search status", + &state->regs->get_2nd_af_search_status, + 1, 0); + s5k4ecgx_i2c_read_twobyte(client, 0x0F12, &read_value); + dev_dbg(&client->dev, + "%s: 2nd i2c_read --- read_value == 0x%x\n", + __func__, read_value); + ctrl->value = read_value; + return 0; } static void s5k4ecgx_init_parameters(struct v4l2_subdev *sd) @@ -2076,8 +2055,11 @@ static int s5k4ecgx_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) case V4L2_CID_CAM_JPEG_QUALITY: ctrl->value = state->jpeg.quality; break; - case V4L2_CID_CAMERA_AUTO_FOCUS_RESULT: - err = s5k4ecgx_get_auto_focus_result(sd, ctrl); + case V4L2_CID_CAMERA_AUTO_FOCUS_RESULT_FIRST: + err = s5k4ecgx_get_auto_focus_result_first(sd, ctrl); + break; + case V4L2_CID_CAMERA_AUTO_FOCUS_RESULT_SECOND: + err = s5k4ecgx_get_auto_focus_result_second(sd, ctrl); break; case V4L2_CID_CAM_DATE_INFO_YEAR: ctrl->value = 2010; @@ -2363,6 +2345,9 @@ static int s5k4ecgx_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) if (parms->focus_mode != FOCUS_MODE_MACRO) err = s5k4ecgx_return_focus(sd); break; + case V4L2_CID_CAMERA_FINISH_AUTO_FOCUS: + err = s5k4ecgx_finish_auto_focus(sd); + break; default: dev_err(&client->dev, "%s: unknown set ctrl id 0x%x\n", __func__, ctrl->id); diff --git a/include/linux/videodev2_samsung.h b/include/linux/videodev2_samsung.h index 032f300..9a5ff62 100755 --- a/include/linux/videodev2_samsung.h +++ b/include/linux/videodev2_samsung.h @@ -419,7 +419,9 @@ enum v4l2_caf_start_stop { CAF_MAX, }; -#define V4L2_CID_CAMERA_AUTO_FOCUS_RESULT (V4L2_CID_PRIVATE_BASE + 103) +#define V4L2_CID_CAMERA_AUTO_FOCUS_RESULT_FIRST (V4L2_CID_PRIVATE_BASE + 103) +#define V4L2_CID_CAMERA_AUTO_FOCUS_RESULT_SECOND (V4L2_CID_PRIVATE_BASE + 120) +#define V4L2_CID_CAMERA_FINISH_AUTO_FOCUS (V4L2_CID_PRIVATE_BASE + 121) #define V4L2_CID_CAMERA_FRAME_RATE (V4L2_CID_PRIVATE_BASE + 104) enum v4l2_frame_rate { FRAME_RATE_AUTO = 0, |