0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/i2c.h>
0013 #include <linux/delay.h>
0014 #include <linux/videodev2.h>
0015 #include <media/v4l2-ctrls.h>
0016
0017 #include "m5mols.h"
0018 #include "m5mols_reg.h"
0019
0020 static struct m5mols_scenemode m5mols_default_scenemode[] = {
0021 [REG_SCENE_NORMAL] = {
0022 REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
0023 REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
0024 REG_AF_NORMAL, REG_FD_OFF,
0025 REG_MCC_NORMAL, REG_LIGHT_OFF, REG_FLASH_OFF,
0026 5, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
0027 },
0028 [REG_SCENE_PORTRAIT] = {
0029 REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
0030 REG_CHROMA_ON, 3, REG_EDGE_ON, 4,
0031 REG_AF_NORMAL, BIT_FD_EN | BIT_FD_DRAW_FACE_FRAME,
0032 REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
0033 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
0034 },
0035 [REG_SCENE_LANDSCAPE] = {
0036 REG_AE_ALL, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
0037 REG_CHROMA_ON, 4, REG_EDGE_ON, 6,
0038 REG_AF_NORMAL, REG_FD_OFF,
0039 REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
0040 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
0041 },
0042 [REG_SCENE_SPORTS] = {
0043 REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
0044 REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
0045 REG_AF_NORMAL, REG_FD_OFF,
0046 REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
0047 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
0048 },
0049 [REG_SCENE_PARTY_INDOOR] = {
0050 REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
0051 REG_CHROMA_ON, 4, REG_EDGE_ON, 5,
0052 REG_AF_NORMAL, REG_FD_OFF,
0053 REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
0054 6, REG_ISO_200, REG_CAP_NONE, REG_WDR_OFF,
0055 },
0056 [REG_SCENE_BEACH_SNOW] = {
0057 REG_AE_CENTER, REG_AE_INDEX_10_POS, REG_AWB_AUTO, 0,
0058 REG_CHROMA_ON, 4, REG_EDGE_ON, 5,
0059 REG_AF_NORMAL, REG_FD_OFF,
0060 REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
0061 6, REG_ISO_50, REG_CAP_NONE, REG_WDR_OFF,
0062 },
0063 [REG_SCENE_SUNSET] = {
0064 REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_PRESET,
0065 REG_AWB_DAYLIGHT,
0066 REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
0067 REG_AF_NORMAL, REG_FD_OFF,
0068 REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
0069 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
0070 },
0071 [REG_SCENE_DAWN_DUSK] = {
0072 REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_PRESET,
0073 REG_AWB_FLUORESCENT_1,
0074 REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
0075 REG_AF_NORMAL, REG_FD_OFF,
0076 REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
0077 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
0078 },
0079 [REG_SCENE_FALL] = {
0080 REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
0081 REG_CHROMA_ON, 5, REG_EDGE_ON, 5,
0082 REG_AF_NORMAL, REG_FD_OFF,
0083 REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
0084 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
0085 },
0086 [REG_SCENE_NIGHT] = {
0087 REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
0088 REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
0089 REG_AF_NORMAL, REG_FD_OFF,
0090 REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
0091 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
0092 },
0093 [REG_SCENE_AGAINST_LIGHT] = {
0094 REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
0095 REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
0096 REG_AF_NORMAL, REG_FD_OFF,
0097 REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
0098 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
0099 },
0100 [REG_SCENE_FIRE] = {
0101 REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
0102 REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
0103 REG_AF_NORMAL, REG_FD_OFF,
0104 REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
0105 6, REG_ISO_50, REG_CAP_NONE, REG_WDR_OFF,
0106 },
0107 [REG_SCENE_TEXT] = {
0108 REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
0109 REG_CHROMA_ON, 3, REG_EDGE_ON, 7,
0110 REG_AF_MACRO, REG_FD_OFF,
0111 REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
0112 6, REG_ISO_AUTO, REG_CAP_ANTI_SHAKE, REG_WDR_ON,
0113 },
0114 [REG_SCENE_CANDLE] = {
0115 REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
0116 REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
0117 REG_AF_NORMAL, REG_FD_OFF,
0118 REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
0119 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
0120 },
0121 };
0122
0123
0124
0125
0126
0127
0128
0129
0130 int m5mols_do_scenemode(struct m5mols_info *info, u8 mode)
0131 {
0132 struct v4l2_subdev *sd = &info->sd;
0133 struct m5mols_scenemode scenemode = m5mols_default_scenemode[mode];
0134 int ret;
0135
0136 if (mode > REG_SCENE_CANDLE)
0137 return -EINVAL;
0138
0139 ret = v4l2_ctrl_s_ctrl(info->lock_3a, 0);
0140 if (!ret)
0141 ret = m5mols_write(sd, AE_EV_PRESET_MONITOR, mode);
0142 if (!ret)
0143 ret = m5mols_write(sd, AE_EV_PRESET_CAPTURE, mode);
0144 if (!ret)
0145 ret = m5mols_write(sd, AE_MODE, scenemode.metering);
0146 if (!ret)
0147 ret = m5mols_write(sd, AE_INDEX, scenemode.ev_bias);
0148 if (!ret)
0149 ret = m5mols_write(sd, AWB_MODE, scenemode.wb_mode);
0150 if (!ret)
0151 ret = m5mols_write(sd, AWB_MANUAL, scenemode.wb_preset);
0152 if (!ret)
0153 ret = m5mols_write(sd, MON_CHROMA_EN, scenemode.chroma_en);
0154 if (!ret)
0155 ret = m5mols_write(sd, MON_CHROMA_LVL, scenemode.chroma_lvl);
0156 if (!ret)
0157 ret = m5mols_write(sd, MON_EDGE_EN, scenemode.edge_en);
0158 if (!ret)
0159 ret = m5mols_write(sd, MON_EDGE_LVL, scenemode.edge_lvl);
0160 if (!ret && is_available_af(info))
0161 ret = m5mols_write(sd, AF_MODE, scenemode.af_range);
0162 if (!ret && is_available_af(info))
0163 ret = m5mols_write(sd, FD_CTL, scenemode.fd_mode);
0164 if (!ret)
0165 ret = m5mols_write(sd, MON_TONE_CTL, scenemode.tone);
0166 if (!ret)
0167 ret = m5mols_write(sd, AE_ISO, scenemode.iso);
0168 if (!ret)
0169 ret = m5mols_set_mode(info, REG_CAPTURE);
0170 if (!ret)
0171 ret = m5mols_write(sd, CAPP_WDR_EN, scenemode.wdr);
0172 if (!ret)
0173 ret = m5mols_write(sd, CAPP_MCC_MODE, scenemode.mcc);
0174 if (!ret)
0175 ret = m5mols_write(sd, CAPP_LIGHT_CTRL, scenemode.light);
0176 if (!ret)
0177 ret = m5mols_write(sd, CAPP_FLASH_CTRL, scenemode.flash);
0178 if (!ret)
0179 ret = m5mols_write(sd, CAPC_MODE, scenemode.capt_mode);
0180 if (!ret)
0181 ret = m5mols_set_mode(info, REG_MONITOR);
0182
0183 return ret;
0184 }
0185
0186 static int m5mols_3a_lock(struct m5mols_info *info, struct v4l2_ctrl *ctrl)
0187 {
0188 bool af_lock = ctrl->val & V4L2_LOCK_FOCUS;
0189 int ret = 0;
0190
0191 if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_EXPOSURE) {
0192 bool ae_lock = ctrl->val & V4L2_LOCK_EXPOSURE;
0193
0194 ret = m5mols_write(&info->sd, AE_LOCK, ae_lock ?
0195 REG_AE_LOCK : REG_AE_UNLOCK);
0196 if (ret)
0197 return ret;
0198 }
0199
0200 if (((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_WHITE_BALANCE)
0201 && info->auto_wb->val) {
0202 bool awb_lock = ctrl->val & V4L2_LOCK_WHITE_BALANCE;
0203
0204 ret = m5mols_write(&info->sd, AWB_LOCK, awb_lock ?
0205 REG_AWB_LOCK : REG_AWB_UNLOCK);
0206 if (ret)
0207 return ret;
0208 }
0209
0210 if (!info->ver.af || !af_lock)
0211 return ret;
0212
0213 if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_FOCUS)
0214 ret = m5mols_write(&info->sd, AF_EXECUTE, REG_AF_STOP);
0215
0216 return ret;
0217 }
0218
0219 static int m5mols_set_metering_mode(struct m5mols_info *info, int mode)
0220 {
0221 unsigned int metering;
0222
0223 switch (mode) {
0224 case V4L2_EXPOSURE_METERING_CENTER_WEIGHTED:
0225 metering = REG_AE_CENTER;
0226 break;
0227 case V4L2_EXPOSURE_METERING_SPOT:
0228 metering = REG_AE_SPOT;
0229 break;
0230 default:
0231 metering = REG_AE_ALL;
0232 break;
0233 }
0234
0235 return m5mols_write(&info->sd, AE_MODE, metering);
0236 }
0237
0238 static int m5mols_set_exposure(struct m5mols_info *info, int exposure)
0239 {
0240 struct v4l2_subdev *sd = &info->sd;
0241 int ret = 0;
0242
0243 if (exposure == V4L2_EXPOSURE_AUTO) {
0244
0245 info->lock_3a->val &= ~V4L2_LOCK_EXPOSURE;
0246 m5mols_3a_lock(info, info->lock_3a);
0247
0248 ret = m5mols_set_metering_mode(info, info->metering->val);
0249 if (ret < 0)
0250 return ret;
0251
0252 v4l2_dbg(1, m5mols_debug, sd,
0253 "%s: exposure bias: %#x, metering: %#x\n",
0254 __func__, info->exposure_bias->val,
0255 info->metering->val);
0256
0257 return m5mols_write(sd, AE_INDEX, info->exposure_bias->val);
0258 }
0259
0260 if (exposure == V4L2_EXPOSURE_MANUAL) {
0261 ret = m5mols_write(sd, AE_MODE, REG_AE_OFF);
0262 if (ret == 0)
0263 ret = m5mols_write(sd, AE_MAN_GAIN_MON,
0264 info->exposure->val);
0265 if (ret == 0)
0266 ret = m5mols_write(sd, AE_MAN_GAIN_CAP,
0267 info->exposure->val);
0268
0269 v4l2_dbg(1, m5mols_debug, sd, "%s: exposure: %#x\n",
0270 __func__, info->exposure->val);
0271 }
0272
0273 return ret;
0274 }
0275
0276 static int m5mols_set_white_balance(struct m5mols_info *info, int val)
0277 {
0278 static const unsigned short wb[][2] = {
0279 { V4L2_WHITE_BALANCE_INCANDESCENT, REG_AWB_INCANDESCENT },
0280 { V4L2_WHITE_BALANCE_FLUORESCENT, REG_AWB_FLUORESCENT_1 },
0281 { V4L2_WHITE_BALANCE_FLUORESCENT_H, REG_AWB_FLUORESCENT_2 },
0282 { V4L2_WHITE_BALANCE_HORIZON, REG_AWB_HORIZON },
0283 { V4L2_WHITE_BALANCE_DAYLIGHT, REG_AWB_DAYLIGHT },
0284 { V4L2_WHITE_BALANCE_FLASH, REG_AWB_LEDLIGHT },
0285 { V4L2_WHITE_BALANCE_CLOUDY, REG_AWB_CLOUDY },
0286 { V4L2_WHITE_BALANCE_SHADE, REG_AWB_SHADE },
0287 { V4L2_WHITE_BALANCE_AUTO, REG_AWB_AUTO },
0288 };
0289 int i;
0290 struct v4l2_subdev *sd = &info->sd;
0291 int ret = -EINVAL;
0292
0293 for (i = 0; i < ARRAY_SIZE(wb); i++) {
0294 int awb;
0295 if (wb[i][0] != val)
0296 continue;
0297
0298 v4l2_dbg(1, m5mols_debug, sd,
0299 "Setting white balance to: %#x\n", wb[i][0]);
0300
0301 awb = wb[i][0] == V4L2_WHITE_BALANCE_AUTO;
0302 ret = m5mols_write(sd, AWB_MODE, awb ? REG_AWB_AUTO :
0303 REG_AWB_PRESET);
0304 if (ret < 0)
0305 return ret;
0306
0307 if (!awb)
0308 ret = m5mols_write(sd, AWB_MANUAL, wb[i][1]);
0309 }
0310
0311 return ret;
0312 }
0313
0314 static int m5mols_set_saturation(struct m5mols_info *info, int val)
0315 {
0316 int ret = m5mols_write(&info->sd, MON_CHROMA_LVL, val);
0317 if (ret < 0)
0318 return ret;
0319
0320 return m5mols_write(&info->sd, MON_CHROMA_EN, REG_CHROMA_ON);
0321 }
0322
0323 static int m5mols_set_color_effect(struct m5mols_info *info, int val)
0324 {
0325 unsigned int m_effect = REG_COLOR_EFFECT_OFF;
0326 unsigned int p_effect = REG_EFFECT_OFF;
0327 unsigned int cfix_r = 0, cfix_b = 0;
0328 struct v4l2_subdev *sd = &info->sd;
0329 int ret = 0;
0330
0331 switch (val) {
0332 case V4L2_COLORFX_BW:
0333 m_effect = REG_COLOR_EFFECT_ON;
0334 break;
0335 case V4L2_COLORFX_NEGATIVE:
0336 p_effect = REG_EFFECT_NEGA;
0337 break;
0338 case V4L2_COLORFX_EMBOSS:
0339 p_effect = REG_EFFECT_EMBOSS;
0340 break;
0341 case V4L2_COLORFX_SEPIA:
0342 m_effect = REG_COLOR_EFFECT_ON;
0343 cfix_r = REG_CFIXR_SEPIA;
0344 cfix_b = REG_CFIXB_SEPIA;
0345 break;
0346 }
0347
0348 ret = m5mols_write(sd, PARM_EFFECT, p_effect);
0349 if (!ret)
0350 ret = m5mols_write(sd, MON_EFFECT, m_effect);
0351
0352 if (ret == 0 && m_effect == REG_COLOR_EFFECT_ON) {
0353 ret = m5mols_write(sd, MON_CFIXR, cfix_r);
0354 if (!ret)
0355 ret = m5mols_write(sd, MON_CFIXB, cfix_b);
0356 }
0357
0358 v4l2_dbg(1, m5mols_debug, sd,
0359 "p_effect: %#x, m_effect: %#x, r: %#x, b: %#x (%d)\n",
0360 p_effect, m_effect, cfix_r, cfix_b, ret);
0361
0362 return ret;
0363 }
0364
0365 static int m5mols_set_iso(struct m5mols_info *info, int auto_iso)
0366 {
0367 u32 iso = auto_iso ? 0 : info->iso->val + 1;
0368
0369 return m5mols_write(&info->sd, AE_ISO, iso);
0370 }
0371
0372 static int m5mols_set_wdr(struct m5mols_info *info, int wdr)
0373 {
0374 int ret;
0375
0376 ret = m5mols_write(&info->sd, MON_TONE_CTL, wdr ? 9 : 5);
0377 if (ret < 0)
0378 return ret;
0379
0380 ret = m5mols_set_mode(info, REG_CAPTURE);
0381 if (ret < 0)
0382 return ret;
0383
0384 return m5mols_write(&info->sd, CAPP_WDR_EN, wdr);
0385 }
0386
0387 static int m5mols_set_stabilization(struct m5mols_info *info, int val)
0388 {
0389 struct v4l2_subdev *sd = &info->sd;
0390 unsigned int evp = val ? 0xe : 0x0;
0391 int ret;
0392
0393 ret = m5mols_write(sd, AE_EV_PRESET_MONITOR, evp);
0394 if (ret < 0)
0395 return ret;
0396
0397 return m5mols_write(sd, AE_EV_PRESET_CAPTURE, evp);
0398 }
0399
0400 static int m5mols_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
0401 {
0402 struct v4l2_subdev *sd = to_sd(ctrl);
0403 struct m5mols_info *info = to_m5mols(sd);
0404 int ret = 0;
0405 u8 status = REG_ISO_AUTO;
0406
0407 v4l2_dbg(1, m5mols_debug, sd, "%s: ctrl: %s (%d)\n",
0408 __func__, ctrl->name, info->isp_ready);
0409
0410 if (!info->isp_ready)
0411 return -EBUSY;
0412
0413 switch (ctrl->id) {
0414 case V4L2_CID_ISO_SENSITIVITY_AUTO:
0415 ret = m5mols_read_u8(sd, AE_ISO, &status);
0416 if (ret == 0)
0417 ctrl->val = !status;
0418 if (status != REG_ISO_AUTO)
0419 info->iso->val = status - 1;
0420 break;
0421
0422 case V4L2_CID_3A_LOCK:
0423 ctrl->val &= ~0x7;
0424
0425 ret = m5mols_read_u8(sd, AE_LOCK, &status);
0426 if (ret)
0427 return ret;
0428 if (status)
0429 info->lock_3a->val |= V4L2_LOCK_EXPOSURE;
0430
0431 ret = m5mols_read_u8(sd, AWB_LOCK, &status);
0432 if (ret)
0433 return ret;
0434 if (status)
0435 info->lock_3a->val |= V4L2_LOCK_EXPOSURE;
0436
0437 ret = m5mols_read_u8(sd, AF_EXECUTE, &status);
0438 if (!status)
0439 info->lock_3a->val |= V4L2_LOCK_EXPOSURE;
0440 break;
0441 }
0442
0443 return ret;
0444 }
0445
0446 static int m5mols_s_ctrl(struct v4l2_ctrl *ctrl)
0447 {
0448 unsigned int ctrl_mode = m5mols_get_ctrl_mode(ctrl);
0449 struct v4l2_subdev *sd = to_sd(ctrl);
0450 struct m5mols_info *info = to_m5mols(sd);
0451 int last_mode = info->mode;
0452 int ret = 0;
0453
0454
0455
0456
0457
0458 if (!info->isp_ready) {
0459 info->ctrl_sync = 0;
0460 return 0;
0461 }
0462
0463 v4l2_dbg(1, m5mols_debug, sd, "%s: %s, val: %d, priv: %p\n",
0464 __func__, ctrl->name, ctrl->val, ctrl->priv);
0465
0466 if (ctrl_mode && ctrl_mode != info->mode) {
0467 ret = m5mols_set_mode(info, ctrl_mode);
0468 if (ret < 0)
0469 return ret;
0470 }
0471
0472 switch (ctrl->id) {
0473 case V4L2_CID_3A_LOCK:
0474 ret = m5mols_3a_lock(info, ctrl);
0475 break;
0476
0477 case V4L2_CID_ZOOM_ABSOLUTE:
0478 ret = m5mols_write(sd, MON_ZOOM, ctrl->val);
0479 break;
0480
0481 case V4L2_CID_EXPOSURE_AUTO:
0482 ret = m5mols_set_exposure(info, ctrl->val);
0483 break;
0484
0485 case V4L2_CID_ISO_SENSITIVITY:
0486 ret = m5mols_set_iso(info, ctrl->val);
0487 break;
0488
0489 case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
0490 ret = m5mols_set_white_balance(info, ctrl->val);
0491 break;
0492
0493 case V4L2_CID_SATURATION:
0494 ret = m5mols_set_saturation(info, ctrl->val);
0495 break;
0496
0497 case V4L2_CID_COLORFX:
0498 ret = m5mols_set_color_effect(info, ctrl->val);
0499 break;
0500
0501 case V4L2_CID_WIDE_DYNAMIC_RANGE:
0502 ret = m5mols_set_wdr(info, ctrl->val);
0503 break;
0504
0505 case V4L2_CID_IMAGE_STABILIZATION:
0506 ret = m5mols_set_stabilization(info, ctrl->val);
0507 break;
0508
0509 case V4L2_CID_JPEG_COMPRESSION_QUALITY:
0510 ret = m5mols_write(sd, CAPP_JPEG_RATIO, ctrl->val);
0511 break;
0512 }
0513
0514 if (ret == 0 && info->mode != last_mode)
0515 ret = m5mols_set_mode(info, last_mode);
0516
0517 return ret;
0518 }
0519
0520 static const struct v4l2_ctrl_ops m5mols_ctrl_ops = {
0521 .g_volatile_ctrl = m5mols_g_volatile_ctrl,
0522 .s_ctrl = m5mols_s_ctrl,
0523 };
0524
0525
0526 static const s64 iso_qmenu[] = {
0527
0528 50000, 100000, 200000, 400000, 800000, 1600000, 3200000
0529 };
0530
0531
0532 static const s64 ev_bias_qmenu[] = {
0533
0534 -2000, -1500, -1000, -500, 0, 500, 1000, 1500, 2000
0535 };
0536
0537 int m5mols_init_controls(struct v4l2_subdev *sd)
0538 {
0539 struct m5mols_info *info = to_m5mols(sd);
0540 u16 exposure_max;
0541 u16 zoom_step;
0542 int ret;
0543
0544
0545 ret = m5mols_read_u16(sd, AE_MAX_GAIN_MON, &exposure_max);
0546 if (ret < 0)
0547 return ret;
0548
0549 zoom_step = is_manufacturer(info, REG_SAMSUNG_OPTICS) ? 31 : 1;
0550 v4l2_ctrl_handler_init(&info->handle, 20);
0551
0552 info->auto_wb = v4l2_ctrl_new_std_menu(&info->handle,
0553 &m5mols_ctrl_ops, V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE,
0554 9, ~0x3fe, V4L2_WHITE_BALANCE_AUTO);
0555
0556
0557 info->auto_exposure = v4l2_ctrl_new_std_menu(&info->handle,
0558 &m5mols_ctrl_ops, V4L2_CID_EXPOSURE_AUTO,
0559 1, ~0x03, V4L2_EXPOSURE_AUTO);
0560
0561 info->exposure = v4l2_ctrl_new_std(&info->handle,
0562 &m5mols_ctrl_ops, V4L2_CID_EXPOSURE,
0563 0, exposure_max, 1, exposure_max / 2);
0564
0565 info->exposure_bias = v4l2_ctrl_new_int_menu(&info->handle,
0566 &m5mols_ctrl_ops, V4L2_CID_AUTO_EXPOSURE_BIAS,
0567 ARRAY_SIZE(ev_bias_qmenu) - 1,
0568 ARRAY_SIZE(ev_bias_qmenu)/2 - 1,
0569 ev_bias_qmenu);
0570
0571 info->metering = v4l2_ctrl_new_std_menu(&info->handle,
0572 &m5mols_ctrl_ops, V4L2_CID_EXPOSURE_METERING,
0573 2, ~0x7, V4L2_EXPOSURE_METERING_AVERAGE);
0574
0575
0576 info->auto_iso = v4l2_ctrl_new_std_menu(&info->handle, &m5mols_ctrl_ops,
0577 V4L2_CID_ISO_SENSITIVITY_AUTO, 1, ~0x03, 1);
0578
0579 info->iso = v4l2_ctrl_new_int_menu(&info->handle, &m5mols_ctrl_ops,
0580 V4L2_CID_ISO_SENSITIVITY, ARRAY_SIZE(iso_qmenu) - 1,
0581 ARRAY_SIZE(iso_qmenu)/2 - 1, iso_qmenu);
0582
0583 info->saturation = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
0584 V4L2_CID_SATURATION, 1, 5, 1, 3);
0585
0586 info->zoom = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
0587 V4L2_CID_ZOOM_ABSOLUTE, 1, 70, zoom_step, 1);
0588
0589 info->colorfx = v4l2_ctrl_new_std_menu(&info->handle, &m5mols_ctrl_ops,
0590 V4L2_CID_COLORFX, 4, 0, V4L2_COLORFX_NONE);
0591
0592 info->wdr = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
0593 V4L2_CID_WIDE_DYNAMIC_RANGE, 0, 1, 1, 0);
0594
0595 info->stabilization = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
0596 V4L2_CID_IMAGE_STABILIZATION, 0, 1, 1, 0);
0597
0598 info->jpeg_quality = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
0599 V4L2_CID_JPEG_COMPRESSION_QUALITY, 1, 100, 1, 80);
0600
0601 info->lock_3a = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
0602 V4L2_CID_3A_LOCK, 0, 0x7, 0, 0);
0603
0604 if (info->handle.error) {
0605 int ret = info->handle.error;
0606 v4l2_err(sd, "Failed to initialize controls: %d\n", ret);
0607 v4l2_ctrl_handler_free(&info->handle);
0608 return ret;
0609 }
0610
0611 v4l2_ctrl_auto_cluster(4, &info->auto_exposure, 1, false);
0612 info->auto_iso->flags |= V4L2_CTRL_FLAG_VOLATILE |
0613 V4L2_CTRL_FLAG_UPDATE;
0614 v4l2_ctrl_auto_cluster(2, &info->auto_iso, 0, false);
0615
0616 info->lock_3a->flags |= V4L2_CTRL_FLAG_VOLATILE;
0617
0618 m5mols_set_ctrl_mode(info->auto_exposure, REG_PARAMETER);
0619 m5mols_set_ctrl_mode(info->auto_wb, REG_PARAMETER);
0620 m5mols_set_ctrl_mode(info->colorfx, REG_MONITOR);
0621
0622 sd->ctrl_handler = &info->handle;
0623
0624 return 0;
0625 }