18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Controls for M-5MOLS 8M Pixel camera sensor with ISP 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2011 Samsung Electronics Co., Ltd. 68c2ecf20Sopenharmony_ci * Author: HeungJun Kim <riverful.kim@samsung.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Copyright (C) 2009 Samsung Electronics Co., Ltd. 98c2ecf20Sopenharmony_ci * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com> 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/i2c.h> 138c2ecf20Sopenharmony_ci#include <linux/delay.h> 148c2ecf20Sopenharmony_ci#include <linux/videodev2.h> 158c2ecf20Sopenharmony_ci#include <media/v4l2-ctrls.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "m5mols.h" 188c2ecf20Sopenharmony_ci#include "m5mols_reg.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic struct m5mols_scenemode m5mols_default_scenemode[] = { 218c2ecf20Sopenharmony_ci [REG_SCENE_NORMAL] = { 228c2ecf20Sopenharmony_ci REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, 238c2ecf20Sopenharmony_ci REG_CHROMA_ON, 3, REG_EDGE_ON, 5, 248c2ecf20Sopenharmony_ci REG_AF_NORMAL, REG_FD_OFF, 258c2ecf20Sopenharmony_ci REG_MCC_NORMAL, REG_LIGHT_OFF, REG_FLASH_OFF, 268c2ecf20Sopenharmony_ci 5, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, 278c2ecf20Sopenharmony_ci }, 288c2ecf20Sopenharmony_ci [REG_SCENE_PORTRAIT] = { 298c2ecf20Sopenharmony_ci REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, 308c2ecf20Sopenharmony_ci REG_CHROMA_ON, 3, REG_EDGE_ON, 4, 318c2ecf20Sopenharmony_ci REG_AF_NORMAL, BIT_FD_EN | BIT_FD_DRAW_FACE_FRAME, 328c2ecf20Sopenharmony_ci REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, 338c2ecf20Sopenharmony_ci 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, 348c2ecf20Sopenharmony_ci }, 358c2ecf20Sopenharmony_ci [REG_SCENE_LANDSCAPE] = { 368c2ecf20Sopenharmony_ci REG_AE_ALL, REG_AE_INDEX_00, REG_AWB_AUTO, 0, 378c2ecf20Sopenharmony_ci REG_CHROMA_ON, 4, REG_EDGE_ON, 6, 388c2ecf20Sopenharmony_ci REG_AF_NORMAL, REG_FD_OFF, 398c2ecf20Sopenharmony_ci REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, 408c2ecf20Sopenharmony_ci 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, 418c2ecf20Sopenharmony_ci }, 428c2ecf20Sopenharmony_ci [REG_SCENE_SPORTS] = { 438c2ecf20Sopenharmony_ci REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, 448c2ecf20Sopenharmony_ci REG_CHROMA_ON, 3, REG_EDGE_ON, 5, 458c2ecf20Sopenharmony_ci REG_AF_NORMAL, REG_FD_OFF, 468c2ecf20Sopenharmony_ci REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, 478c2ecf20Sopenharmony_ci 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, 488c2ecf20Sopenharmony_ci }, 498c2ecf20Sopenharmony_ci [REG_SCENE_PARTY_INDOOR] = { 508c2ecf20Sopenharmony_ci REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, 518c2ecf20Sopenharmony_ci REG_CHROMA_ON, 4, REG_EDGE_ON, 5, 528c2ecf20Sopenharmony_ci REG_AF_NORMAL, REG_FD_OFF, 538c2ecf20Sopenharmony_ci REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, 548c2ecf20Sopenharmony_ci 6, REG_ISO_200, REG_CAP_NONE, REG_WDR_OFF, 558c2ecf20Sopenharmony_ci }, 568c2ecf20Sopenharmony_ci [REG_SCENE_BEACH_SNOW] = { 578c2ecf20Sopenharmony_ci REG_AE_CENTER, REG_AE_INDEX_10_POS, REG_AWB_AUTO, 0, 588c2ecf20Sopenharmony_ci REG_CHROMA_ON, 4, REG_EDGE_ON, 5, 598c2ecf20Sopenharmony_ci REG_AF_NORMAL, REG_FD_OFF, 608c2ecf20Sopenharmony_ci REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, 618c2ecf20Sopenharmony_ci 6, REG_ISO_50, REG_CAP_NONE, REG_WDR_OFF, 628c2ecf20Sopenharmony_ci }, 638c2ecf20Sopenharmony_ci [REG_SCENE_SUNSET] = { 648c2ecf20Sopenharmony_ci REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_PRESET, 658c2ecf20Sopenharmony_ci REG_AWB_DAYLIGHT, 668c2ecf20Sopenharmony_ci REG_CHROMA_ON, 3, REG_EDGE_ON, 5, 678c2ecf20Sopenharmony_ci REG_AF_NORMAL, REG_FD_OFF, 688c2ecf20Sopenharmony_ci REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, 698c2ecf20Sopenharmony_ci 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, 708c2ecf20Sopenharmony_ci }, 718c2ecf20Sopenharmony_ci [REG_SCENE_DAWN_DUSK] = { 728c2ecf20Sopenharmony_ci REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_PRESET, 738c2ecf20Sopenharmony_ci REG_AWB_FLUORESCENT_1, 748c2ecf20Sopenharmony_ci REG_CHROMA_ON, 3, REG_EDGE_ON, 5, 758c2ecf20Sopenharmony_ci REG_AF_NORMAL, REG_FD_OFF, 768c2ecf20Sopenharmony_ci REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, 778c2ecf20Sopenharmony_ci 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, 788c2ecf20Sopenharmony_ci }, 798c2ecf20Sopenharmony_ci [REG_SCENE_FALL] = { 808c2ecf20Sopenharmony_ci REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, 818c2ecf20Sopenharmony_ci REG_CHROMA_ON, 5, REG_EDGE_ON, 5, 828c2ecf20Sopenharmony_ci REG_AF_NORMAL, REG_FD_OFF, 838c2ecf20Sopenharmony_ci REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, 848c2ecf20Sopenharmony_ci 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, 858c2ecf20Sopenharmony_ci }, 868c2ecf20Sopenharmony_ci [REG_SCENE_NIGHT] = { 878c2ecf20Sopenharmony_ci REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, 888c2ecf20Sopenharmony_ci REG_CHROMA_ON, 3, REG_EDGE_ON, 5, 898c2ecf20Sopenharmony_ci REG_AF_NORMAL, REG_FD_OFF, 908c2ecf20Sopenharmony_ci REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, 918c2ecf20Sopenharmony_ci 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, 928c2ecf20Sopenharmony_ci }, 938c2ecf20Sopenharmony_ci [REG_SCENE_AGAINST_LIGHT] = { 948c2ecf20Sopenharmony_ci REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, 958c2ecf20Sopenharmony_ci REG_CHROMA_ON, 3, REG_EDGE_ON, 5, 968c2ecf20Sopenharmony_ci REG_AF_NORMAL, REG_FD_OFF, 978c2ecf20Sopenharmony_ci REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, 988c2ecf20Sopenharmony_ci 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, 998c2ecf20Sopenharmony_ci }, 1008c2ecf20Sopenharmony_ci [REG_SCENE_FIRE] = { 1018c2ecf20Sopenharmony_ci REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, 1028c2ecf20Sopenharmony_ci REG_CHROMA_ON, 3, REG_EDGE_ON, 5, 1038c2ecf20Sopenharmony_ci REG_AF_NORMAL, REG_FD_OFF, 1048c2ecf20Sopenharmony_ci REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, 1058c2ecf20Sopenharmony_ci 6, REG_ISO_50, REG_CAP_NONE, REG_WDR_OFF, 1068c2ecf20Sopenharmony_ci }, 1078c2ecf20Sopenharmony_ci [REG_SCENE_TEXT] = { 1088c2ecf20Sopenharmony_ci REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, 1098c2ecf20Sopenharmony_ci REG_CHROMA_ON, 3, REG_EDGE_ON, 7, 1108c2ecf20Sopenharmony_ci REG_AF_MACRO, REG_FD_OFF, 1118c2ecf20Sopenharmony_ci REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, 1128c2ecf20Sopenharmony_ci 6, REG_ISO_AUTO, REG_CAP_ANTI_SHAKE, REG_WDR_ON, 1138c2ecf20Sopenharmony_ci }, 1148c2ecf20Sopenharmony_ci [REG_SCENE_CANDLE] = { 1158c2ecf20Sopenharmony_ci REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, 1168c2ecf20Sopenharmony_ci REG_CHROMA_ON, 3, REG_EDGE_ON, 5, 1178c2ecf20Sopenharmony_ci REG_AF_NORMAL, REG_FD_OFF, 1188c2ecf20Sopenharmony_ci REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, 1198c2ecf20Sopenharmony_ci 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, 1208c2ecf20Sopenharmony_ci }, 1218c2ecf20Sopenharmony_ci}; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci/** 1248c2ecf20Sopenharmony_ci * m5mols_do_scenemode() - Change current scenemode 1258c2ecf20Sopenharmony_ci * @info: M-5MOLS driver data structure 1268c2ecf20Sopenharmony_ci * @mode: Desired mode of the scenemode 1278c2ecf20Sopenharmony_ci * 1288c2ecf20Sopenharmony_ci * WARNING: The execution order is important. Do not change the order. 1298c2ecf20Sopenharmony_ci */ 1308c2ecf20Sopenharmony_ciint m5mols_do_scenemode(struct m5mols_info *info, u8 mode) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = &info->sd; 1338c2ecf20Sopenharmony_ci struct m5mols_scenemode scenemode = m5mols_default_scenemode[mode]; 1348c2ecf20Sopenharmony_ci int ret; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci if (mode > REG_SCENE_CANDLE) 1378c2ecf20Sopenharmony_ci return -EINVAL; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci ret = v4l2_ctrl_s_ctrl(info->lock_3a, 0); 1408c2ecf20Sopenharmony_ci if (!ret) 1418c2ecf20Sopenharmony_ci ret = m5mols_write(sd, AE_EV_PRESET_MONITOR, mode); 1428c2ecf20Sopenharmony_ci if (!ret) 1438c2ecf20Sopenharmony_ci ret = m5mols_write(sd, AE_EV_PRESET_CAPTURE, mode); 1448c2ecf20Sopenharmony_ci if (!ret) 1458c2ecf20Sopenharmony_ci ret = m5mols_write(sd, AE_MODE, scenemode.metering); 1468c2ecf20Sopenharmony_ci if (!ret) 1478c2ecf20Sopenharmony_ci ret = m5mols_write(sd, AE_INDEX, scenemode.ev_bias); 1488c2ecf20Sopenharmony_ci if (!ret) 1498c2ecf20Sopenharmony_ci ret = m5mols_write(sd, AWB_MODE, scenemode.wb_mode); 1508c2ecf20Sopenharmony_ci if (!ret) 1518c2ecf20Sopenharmony_ci ret = m5mols_write(sd, AWB_MANUAL, scenemode.wb_preset); 1528c2ecf20Sopenharmony_ci if (!ret) 1538c2ecf20Sopenharmony_ci ret = m5mols_write(sd, MON_CHROMA_EN, scenemode.chroma_en); 1548c2ecf20Sopenharmony_ci if (!ret) 1558c2ecf20Sopenharmony_ci ret = m5mols_write(sd, MON_CHROMA_LVL, scenemode.chroma_lvl); 1568c2ecf20Sopenharmony_ci if (!ret) 1578c2ecf20Sopenharmony_ci ret = m5mols_write(sd, MON_EDGE_EN, scenemode.edge_en); 1588c2ecf20Sopenharmony_ci if (!ret) 1598c2ecf20Sopenharmony_ci ret = m5mols_write(sd, MON_EDGE_LVL, scenemode.edge_lvl); 1608c2ecf20Sopenharmony_ci if (!ret && is_available_af(info)) 1618c2ecf20Sopenharmony_ci ret = m5mols_write(sd, AF_MODE, scenemode.af_range); 1628c2ecf20Sopenharmony_ci if (!ret && is_available_af(info)) 1638c2ecf20Sopenharmony_ci ret = m5mols_write(sd, FD_CTL, scenemode.fd_mode); 1648c2ecf20Sopenharmony_ci if (!ret) 1658c2ecf20Sopenharmony_ci ret = m5mols_write(sd, MON_TONE_CTL, scenemode.tone); 1668c2ecf20Sopenharmony_ci if (!ret) 1678c2ecf20Sopenharmony_ci ret = m5mols_write(sd, AE_ISO, scenemode.iso); 1688c2ecf20Sopenharmony_ci if (!ret) 1698c2ecf20Sopenharmony_ci ret = m5mols_set_mode(info, REG_CAPTURE); 1708c2ecf20Sopenharmony_ci if (!ret) 1718c2ecf20Sopenharmony_ci ret = m5mols_write(sd, CAPP_WDR_EN, scenemode.wdr); 1728c2ecf20Sopenharmony_ci if (!ret) 1738c2ecf20Sopenharmony_ci ret = m5mols_write(sd, CAPP_MCC_MODE, scenemode.mcc); 1748c2ecf20Sopenharmony_ci if (!ret) 1758c2ecf20Sopenharmony_ci ret = m5mols_write(sd, CAPP_LIGHT_CTRL, scenemode.light); 1768c2ecf20Sopenharmony_ci if (!ret) 1778c2ecf20Sopenharmony_ci ret = m5mols_write(sd, CAPP_FLASH_CTRL, scenemode.flash); 1788c2ecf20Sopenharmony_ci if (!ret) 1798c2ecf20Sopenharmony_ci ret = m5mols_write(sd, CAPC_MODE, scenemode.capt_mode); 1808c2ecf20Sopenharmony_ci if (!ret) 1818c2ecf20Sopenharmony_ci ret = m5mols_set_mode(info, REG_MONITOR); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci return ret; 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic int m5mols_3a_lock(struct m5mols_info *info, struct v4l2_ctrl *ctrl) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci bool af_lock = ctrl->val & V4L2_LOCK_FOCUS; 1898c2ecf20Sopenharmony_ci int ret = 0; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_EXPOSURE) { 1928c2ecf20Sopenharmony_ci bool ae_lock = ctrl->val & V4L2_LOCK_EXPOSURE; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci ret = m5mols_write(&info->sd, AE_LOCK, ae_lock ? 1958c2ecf20Sopenharmony_ci REG_AE_LOCK : REG_AE_UNLOCK); 1968c2ecf20Sopenharmony_ci if (ret) 1978c2ecf20Sopenharmony_ci return ret; 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_WHITE_BALANCE) 2018c2ecf20Sopenharmony_ci && info->auto_wb->val) { 2028c2ecf20Sopenharmony_ci bool awb_lock = ctrl->val & V4L2_LOCK_WHITE_BALANCE; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci ret = m5mols_write(&info->sd, AWB_LOCK, awb_lock ? 2058c2ecf20Sopenharmony_ci REG_AWB_LOCK : REG_AWB_UNLOCK); 2068c2ecf20Sopenharmony_ci if (ret) 2078c2ecf20Sopenharmony_ci return ret; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (!info->ver.af || !af_lock) 2118c2ecf20Sopenharmony_ci return ret; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_FOCUS) 2148c2ecf20Sopenharmony_ci ret = m5mols_write(&info->sd, AF_EXECUTE, REG_AF_STOP); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci return ret; 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistatic int m5mols_set_metering_mode(struct m5mols_info *info, int mode) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci unsigned int metering; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci switch (mode) { 2248c2ecf20Sopenharmony_ci case V4L2_EXPOSURE_METERING_CENTER_WEIGHTED: 2258c2ecf20Sopenharmony_ci metering = REG_AE_CENTER; 2268c2ecf20Sopenharmony_ci break; 2278c2ecf20Sopenharmony_ci case V4L2_EXPOSURE_METERING_SPOT: 2288c2ecf20Sopenharmony_ci metering = REG_AE_SPOT; 2298c2ecf20Sopenharmony_ci break; 2308c2ecf20Sopenharmony_ci default: 2318c2ecf20Sopenharmony_ci metering = REG_AE_ALL; 2328c2ecf20Sopenharmony_ci break; 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci return m5mols_write(&info->sd, AE_MODE, metering); 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic int m5mols_set_exposure(struct m5mols_info *info, int exposure) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = &info->sd; 2418c2ecf20Sopenharmony_ci int ret = 0; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci if (exposure == V4L2_EXPOSURE_AUTO) { 2448c2ecf20Sopenharmony_ci /* Unlock auto exposure */ 2458c2ecf20Sopenharmony_ci info->lock_3a->val &= ~V4L2_LOCK_EXPOSURE; 2468c2ecf20Sopenharmony_ci m5mols_3a_lock(info, info->lock_3a); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci ret = m5mols_set_metering_mode(info, info->metering->val); 2498c2ecf20Sopenharmony_ci if (ret < 0) 2508c2ecf20Sopenharmony_ci return ret; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci v4l2_dbg(1, m5mols_debug, sd, 2538c2ecf20Sopenharmony_ci "%s: exposure bias: %#x, metering: %#x\n", 2548c2ecf20Sopenharmony_ci __func__, info->exposure_bias->val, 2558c2ecf20Sopenharmony_ci info->metering->val); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci return m5mols_write(sd, AE_INDEX, info->exposure_bias->val); 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci if (exposure == V4L2_EXPOSURE_MANUAL) { 2618c2ecf20Sopenharmony_ci ret = m5mols_write(sd, AE_MODE, REG_AE_OFF); 2628c2ecf20Sopenharmony_ci if (ret == 0) 2638c2ecf20Sopenharmony_ci ret = m5mols_write(sd, AE_MAN_GAIN_MON, 2648c2ecf20Sopenharmony_ci info->exposure->val); 2658c2ecf20Sopenharmony_ci if (ret == 0) 2668c2ecf20Sopenharmony_ci ret = m5mols_write(sd, AE_MAN_GAIN_CAP, 2678c2ecf20Sopenharmony_ci info->exposure->val); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci v4l2_dbg(1, m5mols_debug, sd, "%s: exposure: %#x\n", 2708c2ecf20Sopenharmony_ci __func__, info->exposure->val); 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci return ret; 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistatic int m5mols_set_white_balance(struct m5mols_info *info, int val) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci static const unsigned short wb[][2] = { 2798c2ecf20Sopenharmony_ci { V4L2_WHITE_BALANCE_INCANDESCENT, REG_AWB_INCANDESCENT }, 2808c2ecf20Sopenharmony_ci { V4L2_WHITE_BALANCE_FLUORESCENT, REG_AWB_FLUORESCENT_1 }, 2818c2ecf20Sopenharmony_ci { V4L2_WHITE_BALANCE_FLUORESCENT_H, REG_AWB_FLUORESCENT_2 }, 2828c2ecf20Sopenharmony_ci { V4L2_WHITE_BALANCE_HORIZON, REG_AWB_HORIZON }, 2838c2ecf20Sopenharmony_ci { V4L2_WHITE_BALANCE_DAYLIGHT, REG_AWB_DAYLIGHT }, 2848c2ecf20Sopenharmony_ci { V4L2_WHITE_BALANCE_FLASH, REG_AWB_LEDLIGHT }, 2858c2ecf20Sopenharmony_ci { V4L2_WHITE_BALANCE_CLOUDY, REG_AWB_CLOUDY }, 2868c2ecf20Sopenharmony_ci { V4L2_WHITE_BALANCE_SHADE, REG_AWB_SHADE }, 2878c2ecf20Sopenharmony_ci { V4L2_WHITE_BALANCE_AUTO, REG_AWB_AUTO }, 2888c2ecf20Sopenharmony_ci }; 2898c2ecf20Sopenharmony_ci int i; 2908c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = &info->sd; 2918c2ecf20Sopenharmony_ci int ret = -EINVAL; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(wb); i++) { 2948c2ecf20Sopenharmony_ci int awb; 2958c2ecf20Sopenharmony_ci if (wb[i][0] != val) 2968c2ecf20Sopenharmony_ci continue; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci v4l2_dbg(1, m5mols_debug, sd, 2998c2ecf20Sopenharmony_ci "Setting white balance to: %#x\n", wb[i][0]); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci awb = wb[i][0] == V4L2_WHITE_BALANCE_AUTO; 3028c2ecf20Sopenharmony_ci ret = m5mols_write(sd, AWB_MODE, awb ? REG_AWB_AUTO : 3038c2ecf20Sopenharmony_ci REG_AWB_PRESET); 3048c2ecf20Sopenharmony_ci if (ret < 0) 3058c2ecf20Sopenharmony_ci return ret; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if (!awb) 3088c2ecf20Sopenharmony_ci ret = m5mols_write(sd, AWB_MANUAL, wb[i][1]); 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci return ret; 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic int m5mols_set_saturation(struct m5mols_info *info, int val) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci int ret = m5mols_write(&info->sd, MON_CHROMA_LVL, val); 3178c2ecf20Sopenharmony_ci if (ret < 0) 3188c2ecf20Sopenharmony_ci return ret; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci return m5mols_write(&info->sd, MON_CHROMA_EN, REG_CHROMA_ON); 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cistatic int m5mols_set_color_effect(struct m5mols_info *info, int val) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci unsigned int m_effect = REG_COLOR_EFFECT_OFF; 3268c2ecf20Sopenharmony_ci unsigned int p_effect = REG_EFFECT_OFF; 3278c2ecf20Sopenharmony_ci unsigned int cfix_r = 0, cfix_b = 0; 3288c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = &info->sd; 3298c2ecf20Sopenharmony_ci int ret = 0; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci switch (val) { 3328c2ecf20Sopenharmony_ci case V4L2_COLORFX_BW: 3338c2ecf20Sopenharmony_ci m_effect = REG_COLOR_EFFECT_ON; 3348c2ecf20Sopenharmony_ci break; 3358c2ecf20Sopenharmony_ci case V4L2_COLORFX_NEGATIVE: 3368c2ecf20Sopenharmony_ci p_effect = REG_EFFECT_NEGA; 3378c2ecf20Sopenharmony_ci break; 3388c2ecf20Sopenharmony_ci case V4L2_COLORFX_EMBOSS: 3398c2ecf20Sopenharmony_ci p_effect = REG_EFFECT_EMBOSS; 3408c2ecf20Sopenharmony_ci break; 3418c2ecf20Sopenharmony_ci case V4L2_COLORFX_SEPIA: 3428c2ecf20Sopenharmony_ci m_effect = REG_COLOR_EFFECT_ON; 3438c2ecf20Sopenharmony_ci cfix_r = REG_CFIXR_SEPIA; 3448c2ecf20Sopenharmony_ci cfix_b = REG_CFIXB_SEPIA; 3458c2ecf20Sopenharmony_ci break; 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci ret = m5mols_write(sd, PARM_EFFECT, p_effect); 3498c2ecf20Sopenharmony_ci if (!ret) 3508c2ecf20Sopenharmony_ci ret = m5mols_write(sd, MON_EFFECT, m_effect); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci if (ret == 0 && m_effect == REG_COLOR_EFFECT_ON) { 3538c2ecf20Sopenharmony_ci ret = m5mols_write(sd, MON_CFIXR, cfix_r); 3548c2ecf20Sopenharmony_ci if (!ret) 3558c2ecf20Sopenharmony_ci ret = m5mols_write(sd, MON_CFIXB, cfix_b); 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci v4l2_dbg(1, m5mols_debug, sd, 3598c2ecf20Sopenharmony_ci "p_effect: %#x, m_effect: %#x, r: %#x, b: %#x (%d)\n", 3608c2ecf20Sopenharmony_ci p_effect, m_effect, cfix_r, cfix_b, ret); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci return ret; 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cistatic int m5mols_set_iso(struct m5mols_info *info, int auto_iso) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci u32 iso = auto_iso ? 0 : info->iso->val + 1; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci return m5mols_write(&info->sd, AE_ISO, iso); 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_cistatic int m5mols_set_wdr(struct m5mols_info *info, int wdr) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci int ret; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci ret = m5mols_write(&info->sd, MON_TONE_CTL, wdr ? 9 : 5); 3778c2ecf20Sopenharmony_ci if (ret < 0) 3788c2ecf20Sopenharmony_ci return ret; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci ret = m5mols_set_mode(info, REG_CAPTURE); 3818c2ecf20Sopenharmony_ci if (ret < 0) 3828c2ecf20Sopenharmony_ci return ret; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci return m5mols_write(&info->sd, CAPP_WDR_EN, wdr); 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic int m5mols_set_stabilization(struct m5mols_info *info, int val) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = &info->sd; 3908c2ecf20Sopenharmony_ci unsigned int evp = val ? 0xe : 0x0; 3918c2ecf20Sopenharmony_ci int ret; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci ret = m5mols_write(sd, AE_EV_PRESET_MONITOR, evp); 3948c2ecf20Sopenharmony_ci if (ret < 0) 3958c2ecf20Sopenharmony_ci return ret; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci return m5mols_write(sd, AE_EV_PRESET_CAPTURE, evp); 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cistatic int m5mols_g_volatile_ctrl(struct v4l2_ctrl *ctrl) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = to_sd(ctrl); 4038c2ecf20Sopenharmony_ci struct m5mols_info *info = to_m5mols(sd); 4048c2ecf20Sopenharmony_ci int ret = 0; 4058c2ecf20Sopenharmony_ci u8 status = REG_ISO_AUTO; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci v4l2_dbg(1, m5mols_debug, sd, "%s: ctrl: %s (%d)\n", 4088c2ecf20Sopenharmony_ci __func__, ctrl->name, info->isp_ready); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci if (!info->isp_ready) 4118c2ecf20Sopenharmony_ci return -EBUSY; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci switch (ctrl->id) { 4148c2ecf20Sopenharmony_ci case V4L2_CID_ISO_SENSITIVITY_AUTO: 4158c2ecf20Sopenharmony_ci ret = m5mols_read_u8(sd, AE_ISO, &status); 4168c2ecf20Sopenharmony_ci if (ret == 0) 4178c2ecf20Sopenharmony_ci ctrl->val = !status; 4188c2ecf20Sopenharmony_ci if (status != REG_ISO_AUTO) 4198c2ecf20Sopenharmony_ci info->iso->val = status - 1; 4208c2ecf20Sopenharmony_ci break; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci case V4L2_CID_3A_LOCK: 4238c2ecf20Sopenharmony_ci ctrl->val &= ~0x7; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci ret = m5mols_read_u8(sd, AE_LOCK, &status); 4268c2ecf20Sopenharmony_ci if (ret) 4278c2ecf20Sopenharmony_ci return ret; 4288c2ecf20Sopenharmony_ci if (status) 4298c2ecf20Sopenharmony_ci info->lock_3a->val |= V4L2_LOCK_EXPOSURE; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci ret = m5mols_read_u8(sd, AWB_LOCK, &status); 4328c2ecf20Sopenharmony_ci if (ret) 4338c2ecf20Sopenharmony_ci return ret; 4348c2ecf20Sopenharmony_ci if (status) 4358c2ecf20Sopenharmony_ci info->lock_3a->val |= V4L2_LOCK_EXPOSURE; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci ret = m5mols_read_u8(sd, AF_EXECUTE, &status); 4388c2ecf20Sopenharmony_ci if (!status) 4398c2ecf20Sopenharmony_ci info->lock_3a->val |= V4L2_LOCK_EXPOSURE; 4408c2ecf20Sopenharmony_ci break; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci return ret; 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_cistatic int m5mols_s_ctrl(struct v4l2_ctrl *ctrl) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci unsigned int ctrl_mode = m5mols_get_ctrl_mode(ctrl); 4498c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = to_sd(ctrl); 4508c2ecf20Sopenharmony_ci struct m5mols_info *info = to_m5mols(sd); 4518c2ecf20Sopenharmony_ci int last_mode = info->mode; 4528c2ecf20Sopenharmony_ci int ret = 0; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci /* 4558c2ecf20Sopenharmony_ci * If needed, defer restoring the controls until 4568c2ecf20Sopenharmony_ci * the device is fully initialized. 4578c2ecf20Sopenharmony_ci */ 4588c2ecf20Sopenharmony_ci if (!info->isp_ready) { 4598c2ecf20Sopenharmony_ci info->ctrl_sync = 0; 4608c2ecf20Sopenharmony_ci return 0; 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci v4l2_dbg(1, m5mols_debug, sd, "%s: %s, val: %d, priv: %p\n", 4648c2ecf20Sopenharmony_ci __func__, ctrl->name, ctrl->val, ctrl->priv); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci if (ctrl_mode && ctrl_mode != info->mode) { 4678c2ecf20Sopenharmony_ci ret = m5mols_set_mode(info, ctrl_mode); 4688c2ecf20Sopenharmony_ci if (ret < 0) 4698c2ecf20Sopenharmony_ci return ret; 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci switch (ctrl->id) { 4738c2ecf20Sopenharmony_ci case V4L2_CID_3A_LOCK: 4748c2ecf20Sopenharmony_ci ret = m5mols_3a_lock(info, ctrl); 4758c2ecf20Sopenharmony_ci break; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci case V4L2_CID_ZOOM_ABSOLUTE: 4788c2ecf20Sopenharmony_ci ret = m5mols_write(sd, MON_ZOOM, ctrl->val); 4798c2ecf20Sopenharmony_ci break; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci case V4L2_CID_EXPOSURE_AUTO: 4828c2ecf20Sopenharmony_ci ret = m5mols_set_exposure(info, ctrl->val); 4838c2ecf20Sopenharmony_ci break; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci case V4L2_CID_ISO_SENSITIVITY: 4868c2ecf20Sopenharmony_ci ret = m5mols_set_iso(info, ctrl->val); 4878c2ecf20Sopenharmony_ci break; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: 4908c2ecf20Sopenharmony_ci ret = m5mols_set_white_balance(info, ctrl->val); 4918c2ecf20Sopenharmony_ci break; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci case V4L2_CID_SATURATION: 4948c2ecf20Sopenharmony_ci ret = m5mols_set_saturation(info, ctrl->val); 4958c2ecf20Sopenharmony_ci break; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci case V4L2_CID_COLORFX: 4988c2ecf20Sopenharmony_ci ret = m5mols_set_color_effect(info, ctrl->val); 4998c2ecf20Sopenharmony_ci break; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci case V4L2_CID_WIDE_DYNAMIC_RANGE: 5028c2ecf20Sopenharmony_ci ret = m5mols_set_wdr(info, ctrl->val); 5038c2ecf20Sopenharmony_ci break; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci case V4L2_CID_IMAGE_STABILIZATION: 5068c2ecf20Sopenharmony_ci ret = m5mols_set_stabilization(info, ctrl->val); 5078c2ecf20Sopenharmony_ci break; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci case V4L2_CID_JPEG_COMPRESSION_QUALITY: 5108c2ecf20Sopenharmony_ci ret = m5mols_write(sd, CAPP_JPEG_RATIO, ctrl->val); 5118c2ecf20Sopenharmony_ci break; 5128c2ecf20Sopenharmony_ci } 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci if (ret == 0 && info->mode != last_mode) 5158c2ecf20Sopenharmony_ci ret = m5mols_set_mode(info, last_mode); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci return ret; 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_ops m5mols_ctrl_ops = { 5218c2ecf20Sopenharmony_ci .g_volatile_ctrl = m5mols_g_volatile_ctrl, 5228c2ecf20Sopenharmony_ci .s_ctrl = m5mols_s_ctrl, 5238c2ecf20Sopenharmony_ci}; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci/* Supported manual ISO values */ 5268c2ecf20Sopenharmony_cistatic const s64 iso_qmenu[] = { 5278c2ecf20Sopenharmony_ci /* AE_ISO: 0x01...0x07 (ISO: 50...3200) */ 5288c2ecf20Sopenharmony_ci 50000, 100000, 200000, 400000, 800000, 1600000, 3200000 5298c2ecf20Sopenharmony_ci}; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci/* Supported Exposure Bias values, -2.0EV...+2.0EV */ 5328c2ecf20Sopenharmony_cistatic const s64 ev_bias_qmenu[] = { 5338c2ecf20Sopenharmony_ci /* AE_INDEX: 0x00...0x08 */ 5348c2ecf20Sopenharmony_ci -2000, -1500, -1000, -500, 0, 500, 1000, 1500, 2000 5358c2ecf20Sopenharmony_ci}; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ciint m5mols_init_controls(struct v4l2_subdev *sd) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci struct m5mols_info *info = to_m5mols(sd); 5408c2ecf20Sopenharmony_ci u16 exposure_max; 5418c2ecf20Sopenharmony_ci u16 zoom_step; 5428c2ecf20Sopenharmony_ci int ret; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci /* Determine the firmware dependent control range and step values */ 5458c2ecf20Sopenharmony_ci ret = m5mols_read_u16(sd, AE_MAX_GAIN_MON, &exposure_max); 5468c2ecf20Sopenharmony_ci if (ret < 0) 5478c2ecf20Sopenharmony_ci return ret; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci zoom_step = is_manufacturer(info, REG_SAMSUNG_OPTICS) ? 31 : 1; 5508c2ecf20Sopenharmony_ci v4l2_ctrl_handler_init(&info->handle, 20); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci info->auto_wb = v4l2_ctrl_new_std_menu(&info->handle, 5538c2ecf20Sopenharmony_ci &m5mols_ctrl_ops, V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE, 5548c2ecf20Sopenharmony_ci 9, ~0x3fe, V4L2_WHITE_BALANCE_AUTO); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci /* Exposure control cluster */ 5578c2ecf20Sopenharmony_ci info->auto_exposure = v4l2_ctrl_new_std_menu(&info->handle, 5588c2ecf20Sopenharmony_ci &m5mols_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 5598c2ecf20Sopenharmony_ci 1, ~0x03, V4L2_EXPOSURE_AUTO); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci info->exposure = v4l2_ctrl_new_std(&info->handle, 5628c2ecf20Sopenharmony_ci &m5mols_ctrl_ops, V4L2_CID_EXPOSURE, 5638c2ecf20Sopenharmony_ci 0, exposure_max, 1, exposure_max / 2); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci info->exposure_bias = v4l2_ctrl_new_int_menu(&info->handle, 5668c2ecf20Sopenharmony_ci &m5mols_ctrl_ops, V4L2_CID_AUTO_EXPOSURE_BIAS, 5678c2ecf20Sopenharmony_ci ARRAY_SIZE(ev_bias_qmenu) - 1, 5688c2ecf20Sopenharmony_ci ARRAY_SIZE(ev_bias_qmenu)/2 - 1, 5698c2ecf20Sopenharmony_ci ev_bias_qmenu); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci info->metering = v4l2_ctrl_new_std_menu(&info->handle, 5728c2ecf20Sopenharmony_ci &m5mols_ctrl_ops, V4L2_CID_EXPOSURE_METERING, 5738c2ecf20Sopenharmony_ci 2, ~0x7, V4L2_EXPOSURE_METERING_AVERAGE); 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci /* ISO control cluster */ 5768c2ecf20Sopenharmony_ci info->auto_iso = v4l2_ctrl_new_std_menu(&info->handle, &m5mols_ctrl_ops, 5778c2ecf20Sopenharmony_ci V4L2_CID_ISO_SENSITIVITY_AUTO, 1, ~0x03, 1); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci info->iso = v4l2_ctrl_new_int_menu(&info->handle, &m5mols_ctrl_ops, 5808c2ecf20Sopenharmony_ci V4L2_CID_ISO_SENSITIVITY, ARRAY_SIZE(iso_qmenu) - 1, 5818c2ecf20Sopenharmony_ci ARRAY_SIZE(iso_qmenu)/2 - 1, iso_qmenu); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci info->saturation = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops, 5848c2ecf20Sopenharmony_ci V4L2_CID_SATURATION, 1, 5, 1, 3); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci info->zoom = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops, 5878c2ecf20Sopenharmony_ci V4L2_CID_ZOOM_ABSOLUTE, 1, 70, zoom_step, 1); 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci info->colorfx = v4l2_ctrl_new_std_menu(&info->handle, &m5mols_ctrl_ops, 5908c2ecf20Sopenharmony_ci V4L2_CID_COLORFX, 4, 0, V4L2_COLORFX_NONE); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci info->wdr = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops, 5938c2ecf20Sopenharmony_ci V4L2_CID_WIDE_DYNAMIC_RANGE, 0, 1, 1, 0); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci info->stabilization = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops, 5968c2ecf20Sopenharmony_ci V4L2_CID_IMAGE_STABILIZATION, 0, 1, 1, 0); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci info->jpeg_quality = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops, 5998c2ecf20Sopenharmony_ci V4L2_CID_JPEG_COMPRESSION_QUALITY, 1, 100, 1, 80); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci info->lock_3a = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops, 6028c2ecf20Sopenharmony_ci V4L2_CID_3A_LOCK, 0, 0x7, 0, 0); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci if (info->handle.error) { 6058c2ecf20Sopenharmony_ci int ret = info->handle.error; 6068c2ecf20Sopenharmony_ci v4l2_err(sd, "Failed to initialize controls: %d\n", ret); 6078c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(&info->handle); 6088c2ecf20Sopenharmony_ci return ret; 6098c2ecf20Sopenharmony_ci } 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci v4l2_ctrl_auto_cluster(4, &info->auto_exposure, 1, false); 6128c2ecf20Sopenharmony_ci info->auto_iso->flags |= V4L2_CTRL_FLAG_VOLATILE | 6138c2ecf20Sopenharmony_ci V4L2_CTRL_FLAG_UPDATE; 6148c2ecf20Sopenharmony_ci v4l2_ctrl_auto_cluster(2, &info->auto_iso, 0, false); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci info->lock_3a->flags |= V4L2_CTRL_FLAG_VOLATILE; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci m5mols_set_ctrl_mode(info->auto_exposure, REG_PARAMETER); 6198c2ecf20Sopenharmony_ci m5mols_set_ctrl_mode(info->auto_wb, REG_PARAMETER); 6208c2ecf20Sopenharmony_ci m5mols_set_ctrl_mode(info->colorfx, REG_MONITOR); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci sd->ctrl_handler = &info->handle; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci return 0; 6258c2ecf20Sopenharmony_ci} 626