diff options
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/video/m5mols/m5mols.h | 24 | ||||
-rw-r--r-- | drivers/media/video/m5mols/m5mols_capture.c | 4 | ||||
-rw-r--r-- | drivers/media/video/m5mols/m5mols_controls.c | 227 | ||||
-rw-r--r-- | drivers/media/video/m5mols/m5mols_core.c | 93 |
4 files changed, 198 insertions, 150 deletions
diff --git a/drivers/media/video/m5mols/m5mols.h b/drivers/media/video/m5mols/m5mols.h index 0acc3d69b851..ed75bbeddc15 100644 --- a/drivers/media/video/m5mols/m5mols.h +++ b/drivers/media/video/m5mols/m5mols.h | |||
@@ -160,12 +160,12 @@ struct m5mols_version { | |||
160 | * @irq_waitq: waitqueue for the capture | 160 | * @irq_waitq: waitqueue for the capture |
161 | * @flags: state variable for the interrupt handler | 161 | * @flags: state variable for the interrupt handler |
162 | * @handle: control handler | 162 | * @handle: control handler |
163 | * @autoexposure: Auto Exposure control | 163 | * @auto_exposure: auto/manual exposure control |
164 | * @exposure: Exposure control | 164 | * @exposure: manual exposure control |
165 | * @autowb: Auto White Balance control | 165 | * @autowb: Auto White Balance control |
166 | * @colorfx: Color effect control | 166 | * @colorfx: color effect control |
167 | * @saturation: Saturation control | 167 | * @saturation: saturation control |
168 | * @zoom: Zoom control | 168 | * @zoom: zoom control |
169 | * @ver: information of the version | 169 | * @ver: information of the version |
170 | * @cap: the capture mode attributes | 170 | * @cap: the capture mode attributes |
171 | * @power: current sensor's power status | 171 | * @power: current sensor's power status |
@@ -188,12 +188,13 @@ struct m5mols_info { | |||
188 | atomic_t irq_done; | 188 | atomic_t irq_done; |
189 | 189 | ||
190 | struct v4l2_ctrl_handler handle; | 190 | struct v4l2_ctrl_handler handle; |
191 | struct { | ||
192 | /* exposure/auto-exposure cluster */ | ||
193 | struct v4l2_ctrl *auto_exposure; | ||
194 | struct v4l2_ctrl *exposure; | ||
195 | }; | ||
191 | 196 | ||
192 | /* Autoexposure/exposure control cluster */ | 197 | struct v4l2_ctrl *auto_wb; |
193 | struct v4l2_ctrl *autoexposure; | ||
194 | struct v4l2_ctrl *exposure; | ||
195 | |||
196 | struct v4l2_ctrl *autowb; | ||
197 | struct v4l2_ctrl *colorfx; | 198 | struct v4l2_ctrl *colorfx; |
198 | struct v4l2_ctrl *saturation; | 199 | struct v4l2_ctrl *saturation; |
199 | struct v4l2_ctrl *zoom; | 200 | struct v4l2_ctrl *zoom; |
@@ -277,7 +278,7 @@ int m5mols_busy_wait(struct v4l2_subdev *sd, u32 reg, u32 value, u32 mask, | |||
277 | * The available executing order between each modes are as follows: | 278 | * The available executing order between each modes are as follows: |
278 | * PARAMETER <---> MONITOR <---> CAPTURE | 279 | * PARAMETER <---> MONITOR <---> CAPTURE |
279 | */ | 280 | */ |
280 | int m5mols_mode(struct m5mols_info *info, u8 mode); | 281 | int m5mols_set_mode(struct m5mols_info *info, u8 mode); |
281 | 282 | ||
282 | int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg); | 283 | int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg); |
283 | int m5mols_wait_interrupt(struct v4l2_subdev *sd, u8 condition, u32 timeout); | 284 | 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 | int m5mols_do_scenemode(struct m5mols_info *info, u8 mode); | 287 | int m5mols_do_scenemode(struct m5mols_info *info, u8 mode); |
287 | int m5mols_lock_3a(struct m5mols_info *info, bool lock); | 288 | int m5mols_lock_3a(struct m5mols_info *info, bool lock); |
288 | int m5mols_set_ctrl(struct v4l2_ctrl *ctrl); | 289 | int m5mols_set_ctrl(struct v4l2_ctrl *ctrl); |
290 | int m5mols_init_controls(struct v4l2_subdev *sd); | ||
289 | 291 | ||
290 | /* The firmware function */ | 292 | /* The firmware function */ |
291 | int m5mols_update_fw(struct v4l2_subdev *sd, | 293 | int m5mols_update_fw(struct v4l2_subdev *sd, |
diff --git a/drivers/media/video/m5mols/m5mols_capture.c b/drivers/media/video/m5mols/m5mols_capture.c index ba25e8e2ba4c..4f27aed11722 100644 --- a/drivers/media/video/m5mols/m5mols_capture.c +++ b/drivers/media/video/m5mols/m5mols_capture.c | |||
@@ -114,7 +114,7 @@ int m5mols_start_capture(struct m5mols_info *info) | |||
114 | * format. The frame capture is initiated during switching from Monitor | 114 | * format. The frame capture is initiated during switching from Monitor |
115 | * to Capture mode. | 115 | * to Capture mode. |
116 | */ | 116 | */ |
117 | ret = m5mols_mode(info, REG_MONITOR); | 117 | ret = m5mols_set_mode(info, REG_MONITOR); |
118 | if (!ret) | 118 | if (!ret) |
119 | ret = m5mols_restore_controls(info); | 119 | ret = m5mols_restore_controls(info); |
120 | if (!ret) | 120 | if (!ret) |
@@ -124,7 +124,7 @@ int m5mols_start_capture(struct m5mols_info *info) | |||
124 | if (!ret) | 124 | if (!ret) |
125 | ret = m5mols_lock_3a(info, true); | 125 | ret = m5mols_lock_3a(info, true); |
126 | if (!ret) | 126 | if (!ret) |
127 | ret = m5mols_mode(info, REG_CAPTURE); | 127 | ret = m5mols_set_mode(info, REG_CAPTURE); |
128 | if (!ret) | 128 | if (!ret) |
129 | /* Wait until a frame is captured to ISP internal memory */ | 129 | /* Wait until a frame is captured to ISP internal memory */ |
130 | ret = m5mols_wait_interrupt(sd, REG_INT_CAPTURE, 2000); | 130 | ret = m5mols_wait_interrupt(sd, REG_INT_CAPTURE, 2000); |
diff --git a/drivers/media/video/m5mols/m5mols_controls.c b/drivers/media/video/m5mols/m5mols_controls.c index d135d20d09cf..464ec0cdfb78 100644 --- a/drivers/media/video/m5mols/m5mols_controls.c +++ b/drivers/media/video/m5mols/m5mols_controls.c | |||
@@ -169,7 +169,7 @@ int m5mols_do_scenemode(struct m5mols_info *info, u8 mode) | |||
169 | if (!ret) | 169 | if (!ret) |
170 | ret = m5mols_write(sd, AE_ISO, scenemode.iso); | 170 | ret = m5mols_write(sd, AE_ISO, scenemode.iso); |
171 | if (!ret) | 171 | if (!ret) |
172 | ret = m5mols_mode(info, REG_CAPTURE); | 172 | ret = m5mols_set_mode(info, REG_CAPTURE); |
173 | if (!ret) | 173 | if (!ret) |
174 | ret = m5mols_write(sd, CAPP_WDR_EN, scenemode.wdr); | 174 | ret = m5mols_write(sd, CAPP_WDR_EN, scenemode.wdr); |
175 | if (!ret) | 175 | if (!ret) |
@@ -181,7 +181,7 @@ int m5mols_do_scenemode(struct m5mols_info *info, u8 mode) | |||
181 | if (!ret) | 181 | if (!ret) |
182 | ret = m5mols_write(sd, CAPC_MODE, scenemode.capt_mode); | 182 | ret = m5mols_write(sd, CAPC_MODE, scenemode.capt_mode); |
183 | if (!ret) | 183 | if (!ret) |
184 | ret = m5mols_mode(info, REG_MONITOR); | 184 | ret = m5mols_set_mode(info, REG_MONITOR); |
185 | 185 | ||
186 | return ret; | 186 | return ret; |
187 | } | 187 | } |
@@ -227,73 +227,194 @@ int m5mols_lock_3a(struct m5mols_info *info, bool lock) | |||
227 | return ret; | 227 | return ret; |
228 | } | 228 | } |
229 | 229 | ||
230 | /* m5mols_set_ctrl() - The main s_ctrl function called by m5mols_set_ctrl() */ | 230 | /* Set exposure/auto exposure cluster */ |
231 | int m5mols_set_ctrl(struct v4l2_ctrl *ctrl) | 231 | static int m5mols_set_exposure(struct m5mols_info *info, int exposure) |
232 | { | ||
233 | struct v4l2_subdev *sd = &info->sd; | ||
234 | int ret; | ||
235 | |||
236 | ret = m5mols_lock_ae(info, exposure != V4L2_EXPOSURE_AUTO); | ||
237 | if (ret < 0) | ||
238 | return ret; | ||
239 | |||
240 | if (exposure == V4L2_EXPOSURE_AUTO) { | ||
241 | ret = m5mols_write(sd, AE_MODE, REG_AE_ALL); | ||
242 | if (ret < 0) | ||
243 | return ret; | ||
244 | } | ||
245 | |||
246 | if (exposure == V4L2_EXPOSURE_MANUAL) { | ||
247 | ret = m5mols_write(sd, AE_MODE, REG_AE_OFF); | ||
248 | if (ret == 0) | ||
249 | ret = m5mols_write(sd, AE_MAN_GAIN_MON, | ||
250 | info->exposure->val); | ||
251 | if (ret == 0) | ||
252 | ret = m5mols_write(sd, AE_MAN_GAIN_CAP, | ||
253 | info->exposure->val); | ||
254 | } | ||
255 | |||
256 | return ret; | ||
257 | } | ||
258 | |||
259 | static int m5mols_set_white_balance(struct m5mols_info *info, int awb) | ||
260 | { | ||
261 | int ret; | ||
262 | |||
263 | ret = m5mols_lock_awb(info, !awb); | ||
264 | if (ret < 0) | ||
265 | return ret; | ||
266 | |||
267 | return m5mols_write(&info->sd, AWB_MODE, awb ? REG_AWB_AUTO : | ||
268 | REG_AWB_PRESET); | ||
269 | } | ||
270 | |||
271 | static int m5mols_set_saturation(struct m5mols_info *info, int val) | ||
272 | { | ||
273 | int ret = m5mols_write(&info->sd, MON_CHROMA_LVL, val); | ||
274 | if (ret < 0) | ||
275 | return ret; | ||
276 | |||
277 | return m5mols_write(&info->sd, MON_CHROMA_EN, REG_CHROMA_ON); | ||
278 | } | ||
279 | |||
280 | static int m5mols_set_color_effect(struct m5mols_info *info, int val) | ||
281 | { | ||
282 | unsigned int m_effect = REG_COLOR_EFFECT_OFF; | ||
283 | unsigned int p_effect = REG_EFFECT_OFF; | ||
284 | unsigned int cfix_r = 0, cfix_b = 0; | ||
285 | struct v4l2_subdev *sd = &info->sd; | ||
286 | int ret = 0; | ||
287 | |||
288 | switch (val) { | ||
289 | case V4L2_COLORFX_BW: | ||
290 | m_effect = REG_COLOR_EFFECT_ON; | ||
291 | break; | ||
292 | case V4L2_COLORFX_NEGATIVE: | ||
293 | p_effect = REG_EFFECT_NEGA; | ||
294 | break; | ||
295 | case V4L2_COLORFX_EMBOSS: | ||
296 | p_effect = REG_EFFECT_EMBOSS; | ||
297 | break; | ||
298 | case V4L2_COLORFX_SEPIA: | ||
299 | m_effect = REG_COLOR_EFFECT_ON; | ||
300 | cfix_r = REG_CFIXR_SEPIA; | ||
301 | cfix_b = REG_CFIXB_SEPIA; | ||
302 | break; | ||
303 | } | ||
304 | |||
305 | ret = m5mols_write(sd, PARM_EFFECT, p_effect); | ||
306 | if (!ret) | ||
307 | ret = m5mols_write(sd, MON_EFFECT, m_effect); | ||
308 | |||
309 | if (ret == 0 && m_effect == REG_COLOR_EFFECT_ON) { | ||
310 | ret = m5mols_write(sd, MON_CFIXR, cfix_r); | ||
311 | if (!ret) | ||
312 | ret = m5mols_write(sd, MON_CFIXB, cfix_b); | ||
313 | } | ||
314 | |||
315 | v4l2_dbg(1, m5mols_debug, sd, | ||
316 | "p_effect: %#x, m_effect: %#x, r: %#x, b: %#x (%d)\n", | ||
317 | p_effect, m_effect, cfix_r, cfix_b, ret); | ||
318 | |||
319 | return ret; | ||
320 | } | ||
321 | |||
322 | static int m5mols_s_ctrl(struct v4l2_ctrl *ctrl) | ||
232 | { | 323 | { |
233 | struct v4l2_subdev *sd = to_sd(ctrl); | 324 | struct v4l2_subdev *sd = to_sd(ctrl); |
234 | struct m5mols_info *info = to_m5mols(sd); | 325 | struct m5mols_info *info = to_m5mols(sd); |
326 | int ispstate = info->mode; | ||
235 | int ret; | 327 | int ret; |
236 | 328 | ||
329 | /* | ||
330 | * If needed, defer restoring the controls until | ||
331 | * the device is fully initialized. | ||
332 | */ | ||
333 | if (!info->isp_ready) { | ||
334 | info->ctrl_sync = 0; | ||
335 | return 0; | ||
336 | } | ||
337 | |||
338 | ret = m5mols_mode(info, REG_PARAMETER); | ||
339 | if (ret < 0) | ||
340 | return ret; | ||
341 | |||
237 | switch (ctrl->id) { | 342 | switch (ctrl->id) { |
238 | case V4L2_CID_ZOOM_ABSOLUTE: | 343 | case V4L2_CID_ZOOM_ABSOLUTE: |
239 | return m5mols_write(sd, MON_ZOOM, ctrl->val); | 344 | ret = m5mols_write(sd, MON_ZOOM, ctrl->val); |
345 | break; | ||
240 | 346 | ||
241 | case V4L2_CID_EXPOSURE_AUTO: | 347 | case V4L2_CID_EXPOSURE_AUTO: |
242 | ret = m5mols_lock_ae(info, | 348 | ret = m5mols_set_exposure(info, ctrl->val); |
243 | ctrl->val == V4L2_EXPOSURE_AUTO ? false : true); | 349 | break; |
244 | if (!ret && ctrl->val == V4L2_EXPOSURE_AUTO) | ||
245 | ret = m5mols_write(sd, AE_MODE, REG_AE_ALL); | ||
246 | if (!ret && ctrl->val == V4L2_EXPOSURE_MANUAL) { | ||
247 | int val = info->exposure->val; | ||
248 | ret = m5mols_write(sd, AE_MODE, REG_AE_OFF); | ||
249 | if (!ret) | ||
250 | ret = m5mols_write(sd, AE_MAN_GAIN_MON, val); | ||
251 | if (!ret) | ||
252 | ret = m5mols_write(sd, AE_MAN_GAIN_CAP, val); | ||
253 | } | ||
254 | return ret; | ||
255 | 350 | ||
256 | case V4L2_CID_AUTO_WHITE_BALANCE: | 351 | case V4L2_CID_AUTO_WHITE_BALANCE: |
257 | ret = m5mols_lock_awb(info, ctrl->val ? false : true); | 352 | ret = m5mols_set_white_balance(info, ctrl->val); |
258 | if (!ret) | 353 | break; |
259 | ret = m5mols_write(sd, AWB_MODE, ctrl->val ? | ||
260 | REG_AWB_AUTO : REG_AWB_PRESET); | ||
261 | return ret; | ||
262 | 354 | ||
263 | case V4L2_CID_SATURATION: | 355 | case V4L2_CID_SATURATION: |
264 | ret = m5mols_write(sd, MON_CHROMA_LVL, ctrl->val); | 356 | ret = m5mols_set_saturation(info, ctrl->val); |
265 | if (!ret) | 357 | break; |
266 | ret = m5mols_write(sd, MON_CHROMA_EN, REG_CHROMA_ON); | ||
267 | return ret; | ||
268 | 358 | ||
269 | case V4L2_CID_COLORFX: | 359 | case V4L2_CID_COLORFX: |
270 | /* | 360 | ret = m5mols_set_color_effect(info, ctrl->val); |
271 | * This control uses two kinds of registers: normal & color. | 361 | break; |
272 | * The normal effect belongs to category 1, while the color | 362 | } |
273 | * one belongs to category 2. | 363 | if (ret < 0) |
274 | * | 364 | return ret; |
275 | * The normal effect uses one register: CAT1_EFFECT. | 365 | |
276 | * The color effect uses three registers: | 366 | return m5mols_mode(info, ispstate); |
277 | * CAT2_COLOR_EFFECT, CAT2_CFIXR, CAT2_CFIXB. | 367 | } |
278 | */ | 368 | |
279 | ret = m5mols_write(sd, PARM_EFFECT, | 369 | static const struct v4l2_ctrl_ops m5mols_ctrl_ops = { |
280 | ctrl->val == V4L2_COLORFX_NEGATIVE ? REG_EFFECT_NEGA : | 370 | .s_ctrl = m5mols_s_ctrl, |
281 | ctrl->val == V4L2_COLORFX_EMBOSS ? REG_EFFECT_EMBOSS : | 371 | }; |
282 | REG_EFFECT_OFF); | 372 | |
283 | if (!ret) | 373 | int m5mols_init_controls(struct v4l2_subdev *sd) |
284 | ret = m5mols_write(sd, MON_EFFECT, | 374 | { |
285 | ctrl->val == V4L2_COLORFX_SEPIA ? | 375 | struct m5mols_info *info = to_m5mols(sd); |
286 | REG_COLOR_EFFECT_ON : REG_COLOR_EFFECT_OFF); | 376 | u16 exposure_max; |
287 | if (!ret) | 377 | u16 zoom_step; |
288 | ret = m5mols_write(sd, MON_CFIXR, | 378 | int ret; |
289 | ctrl->val == V4L2_COLORFX_SEPIA ? | 379 | |
290 | REG_CFIXR_SEPIA : 0); | 380 | /* Determine the firmware dependant control range and step values */ |
291 | if (!ret) | 381 | ret = m5mols_read_u16(sd, AE_MAX_GAIN_MON, &exposure_max); |
292 | ret = m5mols_write(sd, MON_CFIXB, | 382 | if (ret < 0) |
293 | ctrl->val == V4L2_COLORFX_SEPIA ? | 383 | return ret; |
294 | REG_CFIXB_SEPIA : 0); | 384 | |
385 | zoom_step = is_manufacturer(info, REG_SAMSUNG_OPTICS) ? 31 : 1; | ||
386 | |||
387 | v4l2_ctrl_handler_init(&info->handle, 6); | ||
388 | |||
389 | info->auto_wb = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops, | ||
390 | V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); | ||
391 | |||
392 | info->auto_exposure = v4l2_ctrl_new_std_menu(&info->handle, | ||
393 | &m5mols_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, | ||
394 | 1, ~0x03, V4L2_EXPOSURE_AUTO); | ||
395 | |||
396 | info->exposure = v4l2_ctrl_new_std(&info->handle, | ||
397 | &m5mols_ctrl_ops, V4L2_CID_EXPOSURE, | ||
398 | 0, exposure_max, 1, exposure_max / 2); | ||
399 | |||
400 | info->saturation = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops, | ||
401 | V4L2_CID_SATURATION, 1, 5, 1, 3); | ||
402 | |||
403 | info->zoom = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops, | ||
404 | V4L2_CID_ZOOM_ABSOLUTE, 1, 70, zoom_step, 1); | ||
405 | |||
406 | info->colorfx = v4l2_ctrl_new_std_menu(&info->handle, &m5mols_ctrl_ops, | ||
407 | V4L2_CID_COLORFX, 4, 0, V4L2_COLORFX_NONE); | ||
408 | |||
409 | if (info->handle.error) { | ||
410 | int ret = info->handle.error; | ||
411 | v4l2_err(sd, "Failed to initialize controls: %d\n", ret); | ||
412 | v4l2_ctrl_handler_free(&info->handle); | ||
295 | return ret; | 413 | return ret; |
296 | } | 414 | } |
297 | 415 | ||
298 | return -EINVAL; | 416 | v4l2_ctrl_auto_cluster(2, &info->auto_exposure, 1, false); |
417 | sd->ctrl_handler = &info->handle; | ||
418 | |||
419 | return 0; | ||
299 | } | 420 | } |
diff --git a/drivers/media/video/m5mols/m5mols_core.c b/drivers/media/video/m5mols/m5mols_core.c index d718aee01c77..ac7d28b6ddf2 100644 --- a/drivers/media/video/m5mols/m5mols_core.c +++ b/drivers/media/video/m5mols/m5mols_core.c | |||
@@ -362,14 +362,14 @@ static int m5mols_reg_mode(struct v4l2_subdev *sd, u8 mode) | |||
362 | } | 362 | } |
363 | 363 | ||
364 | /** | 364 | /** |
365 | * m5mols_mode - manage the M-5MOLS's mode | 365 | * m5mols_set_mode - set the M-5MOLS controller mode |
366 | * @mode: the required operation mode | 366 | * @mode: the required operation mode |
367 | * | 367 | * |
368 | * The commands of M-5MOLS are grouped into specific modes. Each functionality | 368 | * The commands of M-5MOLS are grouped into specific modes. Each functionality |
369 | * can be guaranteed only when the sensor is operating in mode which which | 369 | * can be guaranteed only when the sensor is operating in mode which a command |
370 | * a command belongs to. | 370 | * belongs to. |
371 | */ | 371 | */ |
372 | int m5mols_mode(struct m5mols_info *info, u8 mode) | 372 | int m5mols_set_mode(struct m5mols_info *info, u8 mode) |
373 | { | 373 | { |
374 | struct v4l2_subdev *sd = &info->sd; | 374 | struct v4l2_subdev *sd = &info->sd; |
375 | int ret = -EINVAL; | 375 | int ret = -EINVAL; |
@@ -645,13 +645,13 @@ static int m5mols_start_monitor(struct m5mols_info *info) | |||
645 | struct v4l2_subdev *sd = &info->sd; | 645 | struct v4l2_subdev *sd = &info->sd; |
646 | int ret; | 646 | int ret; |
647 | 647 | ||
648 | ret = m5mols_mode(info, REG_PARAMETER); | 648 | ret = m5mols_set_mode(info, REG_PARAMETER); |
649 | if (!ret) | 649 | if (!ret) |
650 | ret = m5mols_write(sd, PARM_MON_SIZE, info->resolution); | 650 | ret = m5mols_write(sd, PARM_MON_SIZE, info->resolution); |
651 | if (!ret) | 651 | if (!ret) |
652 | ret = m5mols_write(sd, PARM_MON_FPS, REG_FPS_30); | 652 | ret = m5mols_write(sd, PARM_MON_FPS, REG_FPS_30); |
653 | if (!ret) | 653 | if (!ret) |
654 | ret = m5mols_mode(info, REG_MONITOR); | 654 | ret = m5mols_set_mode(info, REG_MONITOR); |
655 | if (!ret) | 655 | if (!ret) |
656 | ret = m5mols_restore_controls(info); | 656 | ret = m5mols_restore_controls(info); |
657 | 657 | ||
@@ -674,42 +674,13 @@ static int m5mols_s_stream(struct v4l2_subdev *sd, int enable) | |||
674 | return ret; | 674 | return ret; |
675 | } | 675 | } |
676 | 676 | ||
677 | return m5mols_mode(info, REG_PARAMETER); | 677 | return m5mols_set_mode(info, REG_PARAMETER); |
678 | } | 678 | } |
679 | 679 | ||
680 | static const struct v4l2_subdev_video_ops m5mols_video_ops = { | 680 | static const struct v4l2_subdev_video_ops m5mols_video_ops = { |
681 | .s_stream = m5mols_s_stream, | 681 | .s_stream = m5mols_s_stream, |
682 | }; | 682 | }; |
683 | 683 | ||
684 | static int m5mols_s_ctrl(struct v4l2_ctrl *ctrl) | ||
685 | { | ||
686 | struct v4l2_subdev *sd = to_sd(ctrl); | ||
687 | struct m5mols_info *info = to_m5mols(sd); | ||
688 | int ispstate = info->mode; | ||
689 | int ret; | ||
690 | |||
691 | /* | ||
692 | * If needed, defer restoring the controls until | ||
693 | * the device is fully initialized. | ||
694 | */ | ||
695 | if (!info->isp_ready) { | ||
696 | info->ctrl_sync = 0; | ||
697 | return 0; | ||
698 | } | ||
699 | |||
700 | ret = m5mols_mode(info, REG_PARAMETER); | ||
701 | if (ret < 0) | ||
702 | return ret; | ||
703 | ret = m5mols_set_ctrl(ctrl); | ||
704 | if (ret < 0) | ||
705 | return ret; | ||
706 | return m5mols_mode(info, ispstate); | ||
707 | } | ||
708 | |||
709 | static const struct v4l2_ctrl_ops m5mols_ctrl_ops = { | ||
710 | .s_ctrl = m5mols_s_ctrl, | ||
711 | }; | ||
712 | |||
713 | static int m5mols_sensor_power(struct m5mols_info *info, bool enable) | 684 | static int m5mols_sensor_power(struct m5mols_info *info, bool enable) |
714 | { | 685 | { |
715 | struct v4l2_subdev *sd = &info->sd; | 686 | struct v4l2_subdev *sd = &info->sd; |
@@ -802,52 +773,6 @@ static int m5mols_fw_start(struct v4l2_subdev *sd) | |||
802 | return ret; | 773 | return ret; |
803 | } | 774 | } |
804 | 775 | ||
805 | static int m5mols_init_controls(struct m5mols_info *info) | ||
806 | { | ||
807 | struct v4l2_subdev *sd = &info->sd; | ||
808 | u16 max_exposure; | ||
809 | u16 step_zoom; | ||
810 | int ret; | ||
811 | |||
812 | /* Determine value's range & step of controls for various FW version */ | ||
813 | ret = m5mols_read_u16(sd, AE_MAX_GAIN_MON, &max_exposure); | ||
814 | if (!ret) | ||
815 | step_zoom = is_manufacturer(info, REG_SAMSUNG_OPTICS) ? 31 : 1; | ||
816 | if (ret) | ||
817 | return ret; | ||
818 | |||
819 | v4l2_ctrl_handler_init(&info->handle, 6); | ||
820 | info->autowb = v4l2_ctrl_new_std(&info->handle, | ||
821 | &m5mols_ctrl_ops, V4L2_CID_AUTO_WHITE_BALANCE, | ||
822 | 0, 1, 1, 0); | ||
823 | info->saturation = v4l2_ctrl_new_std(&info->handle, | ||
824 | &m5mols_ctrl_ops, V4L2_CID_SATURATION, | ||
825 | 1, 5, 1, 3); | ||
826 | info->zoom = v4l2_ctrl_new_std(&info->handle, | ||
827 | &m5mols_ctrl_ops, V4L2_CID_ZOOM_ABSOLUTE, | ||
828 | 1, 70, step_zoom, 1); | ||
829 | info->exposure = v4l2_ctrl_new_std(&info->handle, | ||
830 | &m5mols_ctrl_ops, V4L2_CID_EXPOSURE, | ||
831 | 0, max_exposure, 1, (int)max_exposure/2); | ||
832 | info->colorfx = v4l2_ctrl_new_std_menu(&info->handle, | ||
833 | &m5mols_ctrl_ops, V4L2_CID_COLORFX, | ||
834 | 4, (1 << V4L2_COLORFX_BW), V4L2_COLORFX_NONE); | ||
835 | info->autoexposure = v4l2_ctrl_new_std_menu(&info->handle, | ||
836 | &m5mols_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, | ||
837 | 1, 0, V4L2_EXPOSURE_AUTO); | ||
838 | |||
839 | sd->ctrl_handler = &info->handle; | ||
840 | if (info->handle.error) { | ||
841 | v4l2_err(sd, "Failed to initialize controls: %d\n", ret); | ||
842 | v4l2_ctrl_handler_free(&info->handle); | ||
843 | return info->handle.error; | ||
844 | } | ||
845 | |||
846 | v4l2_ctrl_cluster(2, &info->autoexposure); | ||
847 | |||
848 | return 0; | ||
849 | } | ||
850 | |||
851 | /** | 776 | /** |
852 | * m5mols_s_power - Main sensor power control function | 777 | * m5mols_s_power - Main sensor power control function |
853 | * | 778 | * |
@@ -868,7 +793,7 @@ static int m5mols_s_power(struct v4l2_subdev *sd, int on) | |||
868 | } | 793 | } |
869 | 794 | ||
870 | if (is_manufacturer(info, REG_SAMSUNG_TECHWIN)) { | 795 | if (is_manufacturer(info, REG_SAMSUNG_TECHWIN)) { |
871 | ret = m5mols_mode(info, REG_MONITOR); | 796 | ret = m5mols_set_mode(info, REG_MONITOR); |
872 | if (!ret) | 797 | if (!ret) |
873 | ret = m5mols_write(sd, AF_EXECUTE, REG_AF_STOP); | 798 | ret = m5mols_write(sd, AF_EXECUTE, REG_AF_STOP); |
874 | if (!ret) | 799 | if (!ret) |
@@ -1010,7 +935,7 @@ static int __devinit m5mols_probe(struct i2c_client *client, | |||
1010 | 935 | ||
1011 | ret = m5mols_fw_start(sd); | 936 | ret = m5mols_fw_start(sd); |
1012 | if (!ret) | 937 | if (!ret) |
1013 | ret = m5mols_init_controls(info); | 938 | ret = m5mols_init_controls(sd); |
1014 | 939 | ||
1015 | m5mols_sensor_power(info, false); | 940 | m5mols_sensor_power(info, false); |
1016 | if (!ret) | 941 | if (!ret) |