Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
m5mols_controls.c
Go to the documentation of this file.
1 /*
2  * Controls for M-5MOLS 8M Pixel camera sensor with ISP
3  *
4  * Copyright (C) 2011 Samsung Electronics Co., Ltd.
5  * Author: HeungJun Kim <[email protected]>
6  *
7  * Copyright (C) 2009 Samsung Electronics Co., Ltd.
8  * Author: Dongsoo Nathaniel Kim <[email protected]>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  */
15 
16 #include <linux/i2c.h>
17 #include <linux/delay.h>
18 #include <linux/videodev2.h>
19 #include <media/v4l2-ctrls.h>
20 
21 #include "m5mols.h"
22 #include "m5mols_reg.h"
23 
24 static struct m5mols_scenemode m5mols_default_scenemode[] = {
25  [REG_SCENE_NORMAL] = {
31  },
32  [REG_SCENE_PORTRAIT] = {
38  },
45  },
46  [REG_SCENE_SPORTS] = {
52  },
59  },
66  },
67  [REG_SCENE_SUNSET] = {
74  },
82  },
83  [REG_SCENE_FALL] = {
89  },
90  [REG_SCENE_NIGHT] = {
96  },
103  },
104  [REG_SCENE_FIRE] = {
106  REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
110  },
111  [REG_SCENE_TEXT] = {
113  REG_CHROMA_ON, 3, REG_EDGE_ON, 7,
117  },
118  [REG_SCENE_CANDLE] = {
120  REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
124  },
125 };
126 
134 {
135  struct v4l2_subdev *sd = &info->sd;
136  struct m5mols_scenemode scenemode = m5mols_default_scenemode[mode];
137  int ret;
138 
139  if (mode > REG_SCENE_CANDLE)
140  return -EINVAL;
141 
142  ret = v4l2_ctrl_s_ctrl(info->lock_3a, 0);
143  if (!ret)
144  ret = m5mols_write(sd, AE_EV_PRESET_MONITOR, mode);
145  if (!ret)
146  ret = m5mols_write(sd, AE_EV_PRESET_CAPTURE, mode);
147  if (!ret)
148  ret = m5mols_write(sd, AE_MODE, scenemode.metering);
149  if (!ret)
150  ret = m5mols_write(sd, AE_INDEX, scenemode.ev_bias);
151  if (!ret)
152  ret = m5mols_write(sd, AWB_MODE, scenemode.wb_mode);
153  if (!ret)
154  ret = m5mols_write(sd, AWB_MANUAL, scenemode.wb_preset);
155  if (!ret)
156  ret = m5mols_write(sd, MON_CHROMA_EN, scenemode.chroma_en);
157  if (!ret)
158  ret = m5mols_write(sd, MON_CHROMA_LVL, scenemode.chroma_lvl);
159  if (!ret)
160  ret = m5mols_write(sd, MON_EDGE_EN, scenemode.edge_en);
161  if (!ret)
162  ret = m5mols_write(sd, MON_EDGE_LVL, scenemode.edge_lvl);
163  if (!ret && is_available_af(info))
164  ret = m5mols_write(sd, AF_MODE, scenemode.af_range);
165  if (!ret && is_available_af(info))
166  ret = m5mols_write(sd, FD_CTL, scenemode.fd_mode);
167  if (!ret)
168  ret = m5mols_write(sd, MON_TONE_CTL, scenemode.tone);
169  if (!ret)
170  ret = m5mols_write(sd, AE_ISO, scenemode.iso);
171  if (!ret)
172  ret = m5mols_set_mode(info, REG_CAPTURE);
173  if (!ret)
174  ret = m5mols_write(sd, CAPP_WDR_EN, scenemode.wdr);
175  if (!ret)
176  ret = m5mols_write(sd, CAPP_MCC_MODE, scenemode.mcc);
177  if (!ret)
178  ret = m5mols_write(sd, CAPP_LIGHT_CTRL, scenemode.light);
179  if (!ret)
180  ret = m5mols_write(sd, CAPP_FLASH_CTRL, scenemode.flash);
181  if (!ret)
182  ret = m5mols_write(sd, CAPC_MODE, scenemode.capt_mode);
183  if (!ret)
184  ret = m5mols_set_mode(info, REG_MONITOR);
185 
186  return ret;
187 }
188 
189 static int m5mols_3a_lock(struct m5mols_info *info, struct v4l2_ctrl *ctrl)
190 {
191  bool af_lock = ctrl->val & V4L2_LOCK_FOCUS;
192  int ret = 0;
193 
194  if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_EXPOSURE) {
195  bool ae_lock = ctrl->val & V4L2_LOCK_EXPOSURE;
196 
197  ret = m5mols_write(&info->sd, AE_LOCK, ae_lock ?
199  if (ret)
200  return ret;
201  }
202 
203  if (((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_WHITE_BALANCE)
204  && info->auto_wb->val) {
205  bool awb_lock = ctrl->val & V4L2_LOCK_WHITE_BALANCE;
206 
207  ret = m5mols_write(&info->sd, AWB_LOCK, awb_lock ?
209  if (ret)
210  return ret;
211  }
212 
213  if (!info->ver.af || !af_lock)
214  return ret;
215 
216  if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_FOCUS)
217  ret = m5mols_write(&info->sd, AF_EXECUTE, REG_AF_STOP);
218 
219  return ret;
220 }
221 
222 static int m5mols_set_metering_mode(struct m5mols_info *info, int mode)
223 {
224  unsigned int metering;
225 
226  switch (mode) {
228  metering = REG_AE_CENTER;
229  break;
231  metering = REG_AE_SPOT;
232  break;
233  default:
234  metering = REG_AE_ALL;
235  break;
236  }
237 
238  return m5mols_write(&info->sd, AE_MODE, metering);
239 }
240 
241 static int m5mols_set_exposure(struct m5mols_info *info, int exposure)
242 {
243  struct v4l2_subdev *sd = &info->sd;
244  int ret = 0;
245 
246  if (exposure == V4L2_EXPOSURE_AUTO) {
247  /* Unlock auto exposure */
248  info->lock_3a->val &= ~V4L2_LOCK_EXPOSURE;
249  m5mols_3a_lock(info, info->lock_3a);
250 
251  ret = m5mols_set_metering_mode(info, info->metering->val);
252  if (ret < 0)
253  return ret;
254 
255  v4l2_dbg(1, m5mols_debug, sd,
256  "%s: exposure bias: %#x, metering: %#x\n",
257  __func__, info->exposure_bias->val,
258  info->metering->val);
259 
260  return m5mols_write(sd, AE_INDEX, info->exposure_bias->val);
261  }
262 
263  if (exposure == V4L2_EXPOSURE_MANUAL) {
264  ret = m5mols_write(sd, AE_MODE, REG_AE_OFF);
265  if (ret == 0)
266  ret = m5mols_write(sd, AE_MAN_GAIN_MON,
267  info->exposure->val);
268  if (ret == 0)
269  ret = m5mols_write(sd, AE_MAN_GAIN_CAP,
270  info->exposure->val);
271 
272  v4l2_dbg(1, m5mols_debug, sd, "%s: exposure: %#x\n",
273  __func__, info->exposure->val);
274  }
275 
276  return ret;
277 }
278 
279 static int m5mols_set_white_balance(struct m5mols_info *info, int val)
280 {
281  static const unsigned short wb[][2] = {
291  };
292  int i;
293  struct v4l2_subdev *sd = &info->sd;
294  int ret = -EINVAL;
295 
296  for (i = 0; i < ARRAY_SIZE(wb); i++) {
297  int awb;
298  if (wb[i][0] != val)
299  continue;
300 
301  v4l2_dbg(1, m5mols_debug, sd,
302  "Setting white balance to: %#x\n", wb[i][0]);
303 
304  awb = wb[i][0] == V4L2_WHITE_BALANCE_AUTO;
305  ret = m5mols_write(sd, AWB_MODE, awb ? REG_AWB_AUTO :
307  if (ret < 0)
308  return ret;
309 
310  if (!awb)
311  ret = m5mols_write(sd, AWB_MANUAL, wb[i][1]);
312  }
313 
314  return ret;
315 }
316 
317 static int m5mols_set_saturation(struct m5mols_info *info, int val)
318 {
319  int ret = m5mols_write(&info->sd, MON_CHROMA_LVL, val);
320  if (ret < 0)
321  return ret;
322 
323  return m5mols_write(&info->sd, MON_CHROMA_EN, REG_CHROMA_ON);
324 }
325 
326 static int m5mols_set_color_effect(struct m5mols_info *info, int val)
327 {
328  unsigned int m_effect = REG_COLOR_EFFECT_OFF;
329  unsigned int p_effect = REG_EFFECT_OFF;
330  unsigned int cfix_r = 0, cfix_b = 0;
331  struct v4l2_subdev *sd = &info->sd;
332  int ret = 0;
333 
334  switch (val) {
335  case V4L2_COLORFX_BW:
336  m_effect = REG_COLOR_EFFECT_ON;
337  break;
339  p_effect = REG_EFFECT_NEGA;
340  break;
341  case V4L2_COLORFX_EMBOSS:
342  p_effect = REG_EFFECT_EMBOSS;
343  break;
344  case V4L2_COLORFX_SEPIA:
345  m_effect = REG_COLOR_EFFECT_ON;
346  cfix_r = REG_CFIXR_SEPIA;
347  cfix_b = REG_CFIXB_SEPIA;
348  break;
349  }
350 
351  ret = m5mols_write(sd, PARM_EFFECT, p_effect);
352  if (!ret)
353  ret = m5mols_write(sd, MON_EFFECT, m_effect);
354 
355  if (ret == 0 && m_effect == REG_COLOR_EFFECT_ON) {
356  ret = m5mols_write(sd, MON_CFIXR, cfix_r);
357  if (!ret)
358  ret = m5mols_write(sd, MON_CFIXB, cfix_b);
359  }
360 
361  v4l2_dbg(1, m5mols_debug, sd,
362  "p_effect: %#x, m_effect: %#x, r: %#x, b: %#x (%d)\n",
363  p_effect, m_effect, cfix_r, cfix_b, ret);
364 
365  return ret;
366 }
367 
368 static int m5mols_set_iso(struct m5mols_info *info, int auto_iso)
369 {
370  u32 iso = auto_iso ? 0 : info->iso->val + 1;
371 
372  return m5mols_write(&info->sd, AE_ISO, iso);
373 }
374 
375 static int m5mols_set_wdr(struct m5mols_info *info, int wdr)
376 {
377  int ret;
378 
379  ret = m5mols_write(&info->sd, MON_TONE_CTL, wdr ? 9 : 5);
380  if (ret < 0)
381  return ret;
382 
383  ret = m5mols_set_mode(info, REG_CAPTURE);
384  if (ret < 0)
385  return ret;
386 
387  return m5mols_write(&info->sd, CAPP_WDR_EN, wdr);
388 }
389 
390 static int m5mols_set_stabilization(struct m5mols_info *info, int val)
391 {
392  struct v4l2_subdev *sd = &info->sd;
393  unsigned int evp = val ? 0xe : 0x0;
394  int ret;
395 
396  ret = m5mols_write(sd, AE_EV_PRESET_MONITOR, evp);
397  if (ret < 0)
398  return ret;
399 
400  return m5mols_write(sd, AE_EV_PRESET_CAPTURE, evp);
401 }
402 
403 static int m5mols_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
404 {
405  struct v4l2_subdev *sd = to_sd(ctrl);
406  struct m5mols_info *info = to_m5mols(sd);
407  int ret = 0;
408  u8 status;
409 
410  v4l2_dbg(1, m5mols_debug, sd, "%s: ctrl: %s (%d)\n",
411  __func__, ctrl->name, info->isp_ready);
412 
413  if (!info->isp_ready)
414  return -EBUSY;
415 
416  switch (ctrl->id) {
418  ret = m5mols_read_u8(sd, AE_ISO, &status);
419  if (ret == 0)
420  ctrl->val = !status;
421  if (status != REG_ISO_AUTO)
422  info->iso->val = status - 1;
423  break;
424 
425  case V4L2_CID_3A_LOCK:
426  ctrl->val &= ~0x7;
427 
428  ret = m5mols_read_u8(sd, AE_LOCK, &status);
429  if (ret)
430  return ret;
431  if (status)
432  info->lock_3a->val |= V4L2_LOCK_EXPOSURE;
433 
434  ret = m5mols_read_u8(sd, AWB_LOCK, &status);
435  if (ret)
436  return ret;
437  if (status)
438  info->lock_3a->val |= V4L2_LOCK_EXPOSURE;
439 
440  ret = m5mols_read_u8(sd, AF_EXECUTE, &status);
441  if (!status)
442  info->lock_3a->val |= V4L2_LOCK_EXPOSURE;
443  break;
444  }
445 
446  return ret;
447 }
448 
449 static int m5mols_s_ctrl(struct v4l2_ctrl *ctrl)
450 {
451  unsigned int ctrl_mode = m5mols_get_ctrl_mode(ctrl);
452  struct v4l2_subdev *sd = to_sd(ctrl);
453  struct m5mols_info *info = to_m5mols(sd);
454  int last_mode = info->mode;
455  int ret = 0;
456 
457  /*
458  * If needed, defer restoring the controls until
459  * the device is fully initialized.
460  */
461  if (!info->isp_ready) {
462  info->ctrl_sync = 0;
463  return 0;
464  }
465 
466  v4l2_dbg(1, m5mols_debug, sd, "%s: %s, val: %d, priv: %p\n",
467  __func__, ctrl->name, ctrl->val, ctrl->priv);
468 
469  if (ctrl_mode && ctrl_mode != info->mode) {
470  ret = m5mols_set_mode(info, ctrl_mode);
471  if (ret < 0)
472  return ret;
473  }
474 
475  switch (ctrl->id) {
476  case V4L2_CID_3A_LOCK:
477  ret = m5mols_3a_lock(info, ctrl);
478  break;
479 
481  ret = m5mols_write(sd, MON_ZOOM, ctrl->val);
482  break;
483 
485  ret = m5mols_set_exposure(info, ctrl->val);
486  break;
487 
489  ret = m5mols_set_iso(info, ctrl->val);
490  break;
491 
493  ret = m5mols_set_white_balance(info, ctrl->val);
494  break;
495 
496  case V4L2_CID_SATURATION:
497  ret = m5mols_set_saturation(info, ctrl->val);
498  break;
499 
500  case V4L2_CID_COLORFX:
501  ret = m5mols_set_color_effect(info, ctrl->val);
502  break;
503 
505  ret = m5mols_set_wdr(info, ctrl->val);
506  break;
507 
509  ret = m5mols_set_stabilization(info, ctrl->val);
510  break;
511 
513  ret = m5mols_write(sd, CAPP_JPEG_RATIO, ctrl->val);
514  break;
515  }
516 
517  if (ret == 0 && info->mode != last_mode)
518  ret = m5mols_set_mode(info, last_mode);
519 
520  return ret;
521 }
522 
523 static const struct v4l2_ctrl_ops m5mols_ctrl_ops = {
524  .g_volatile_ctrl = m5mols_g_volatile_ctrl,
525  .s_ctrl = m5mols_s_ctrl,
526 };
527 
528 /* Supported manual ISO values */
529 static const s64 iso_qmenu[] = {
530  /* AE_ISO: 0x01...0x07 (ISO: 50...3200) */
531  50000, 100000, 200000, 400000, 800000, 1600000, 3200000
532 };
533 
534 /* Supported Exposure Bias values, -2.0EV...+2.0EV */
535 static const s64 ev_bias_qmenu[] = {
536  /* AE_INDEX: 0x00...0x08 */
537  -2000, -1500, -1000, -500, 0, 500, 1000, 1500, 2000
538 };
539 
541 {
542  struct m5mols_info *info = to_m5mols(sd);
543  u16 exposure_max;
544  u16 zoom_step;
545  int ret;
546 
547  /* Determine the firmware dependant control range and step values */
548  ret = m5mols_read_u16(sd, AE_MAX_GAIN_MON, &exposure_max);
549  if (ret < 0)
550  return ret;
551 
552  zoom_step = is_manufacturer(info, REG_SAMSUNG_OPTICS) ? 31 : 1;
553  v4l2_ctrl_handler_init(&info->handle, 20);
554 
555  info->auto_wb = v4l2_ctrl_new_std_menu(&info->handle,
556  &m5mols_ctrl_ops, V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE,
557  9, ~0x3fe, V4L2_WHITE_BALANCE_AUTO);
558 
559  /* Exposure control cluster */
561  &m5mols_ctrl_ops, V4L2_CID_EXPOSURE_AUTO,
562  1, ~0x03, V4L2_EXPOSURE_AUTO);
563 
564  info->exposure = v4l2_ctrl_new_std(&info->handle,
565  &m5mols_ctrl_ops, V4L2_CID_EXPOSURE,
566  0, exposure_max, 1, exposure_max / 2);
567 
569  &m5mols_ctrl_ops, V4L2_CID_AUTO_EXPOSURE_BIAS,
570  ARRAY_SIZE(ev_bias_qmenu) - 1,
571  ARRAY_SIZE(ev_bias_qmenu)/2 - 1,
572  ev_bias_qmenu);
573 
574  info->metering = v4l2_ctrl_new_std_menu(&info->handle,
575  &m5mols_ctrl_ops, V4L2_CID_EXPOSURE_METERING,
577 
578  /* ISO control cluster */
579  info->auto_iso = v4l2_ctrl_new_std_menu(&info->handle, &m5mols_ctrl_ops,
580  V4L2_CID_ISO_SENSITIVITY_AUTO, 1, ~0x03, 1);
581 
582  info->iso = v4l2_ctrl_new_int_menu(&info->handle, &m5mols_ctrl_ops,
583  V4L2_CID_ISO_SENSITIVITY, ARRAY_SIZE(iso_qmenu) - 1,
584  ARRAY_SIZE(iso_qmenu)/2 - 1, iso_qmenu);
585 
586  info->saturation = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
587  V4L2_CID_SATURATION, 1, 5, 1, 3);
588 
589  info->zoom = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
590  V4L2_CID_ZOOM_ABSOLUTE, 1, 70, zoom_step, 1);
591 
592  info->colorfx = v4l2_ctrl_new_std_menu(&info->handle, &m5mols_ctrl_ops,
594 
595  info->wdr = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
596  V4L2_CID_WIDE_DYNAMIC_RANGE, 0, 1, 1, 0);
597 
598  info->stabilization = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
599  V4L2_CID_IMAGE_STABILIZATION, 0, 1, 1, 0);
600 
601  info->jpeg_quality = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
602  V4L2_CID_JPEG_COMPRESSION_QUALITY, 1, 100, 1, 80);
603 
604  info->lock_3a = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
605  V4L2_CID_3A_LOCK, 0, 0x7, 0, 0);
606 
607  if (info->handle.error) {
608  int ret = info->handle.error;
609  v4l2_err(sd, "Failed to initialize controls: %d\n", ret);
611  return ret;
612  }
613 
614  v4l2_ctrl_auto_cluster(4, &info->auto_exposure, 1, false);
615  info->auto_iso->flags |= V4L2_CTRL_FLAG_VOLATILE |
617  v4l2_ctrl_auto_cluster(2, &info->auto_iso, 0, false);
618 
619  info->lock_3a->flags |= V4L2_CTRL_FLAG_VOLATILE;
620 
621  m5mols_set_ctrl_mode(info->auto_exposure, REG_PARAMETER);
622  m5mols_set_ctrl_mode(info->auto_wb, REG_PARAMETER);
623  m5mols_set_ctrl_mode(info->colorfx, REG_MONITOR);
624 
625  sd->ctrl_handler = &info->handle;
626 
627  return 0;
628 }