aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkyoungho.yun <kyoungho.yun@samsung.com>2011-10-06 15:09:58 +0900
committerArve Hjønnevåg <arve@android.com>2011-11-17 17:54:47 -0800
commitf4c4316f7e5fbb8418e3994e849c95ed1ac495d7 (patch)
tree234e404c1bc995fd7c3442ae1726cbd3d2f828a6
parentff5e8ff7f6fb47de7bbc283c86fa7d1bc3d8cbd1 (diff)
downloadkernel_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-xdrivers/media/video/s5k4ecgx.c207
-rwxr-xr-xinclude/linux/videodev2_samsung.h4
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,