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 <riverful.kim@samsung.com>
6  *
7  * Copyright (C) 2009 Samsung Electronics Co., Ltd.
8  * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com>
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] = {
26 		REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
27 		REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
28 		REG_AF_NORMAL, REG_FD_OFF,
29 		REG_MCC_NORMAL, REG_LIGHT_OFF, REG_FLASH_OFF,
30 		5, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
31 	},
32 	[REG_SCENE_PORTRAIT] = {
33 		REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
34 		REG_CHROMA_ON, 3, REG_EDGE_ON, 4,
35 		REG_AF_NORMAL, BIT_FD_EN | BIT_FD_DRAW_FACE_FRAME,
36 		REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
37 		6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
38 	},
39 	[REG_SCENE_LANDSCAPE] = {
40 		REG_AE_ALL, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
41 		REG_CHROMA_ON, 4, REG_EDGE_ON, 6,
42 		REG_AF_NORMAL, REG_FD_OFF,
43 		REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
44 		6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
45 	},
46 	[REG_SCENE_SPORTS] = {
47 		REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
48 		REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
49 		REG_AF_NORMAL, REG_FD_OFF,
50 		REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
51 		6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
52 	},
53 	[REG_SCENE_PARTY_INDOOR] = {
54 		REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
55 		REG_CHROMA_ON, 4, REG_EDGE_ON, 5,
56 		REG_AF_NORMAL, REG_FD_OFF,
57 		REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
58 		6, REG_ISO_200, REG_CAP_NONE, REG_WDR_OFF,
59 	},
60 	[REG_SCENE_BEACH_SNOW] = {
61 		REG_AE_CENTER, REG_AE_INDEX_10_POS, REG_AWB_AUTO, 0,
62 		REG_CHROMA_ON, 4, REG_EDGE_ON, 5,
63 		REG_AF_NORMAL, REG_FD_OFF,
64 		REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
65 		6, REG_ISO_50, REG_CAP_NONE, REG_WDR_OFF,
66 	},
67 	[REG_SCENE_SUNSET] = {
68 		REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_PRESET,
69 		REG_AWB_DAYLIGHT,
70 		REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
71 		REG_AF_NORMAL, REG_FD_OFF,
72 		REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
73 		6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
74 	},
75 	[REG_SCENE_DAWN_DUSK] = {
76 		REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_PRESET,
77 		REG_AWB_FLUORESCENT_1,
78 		REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
79 		REG_AF_NORMAL, REG_FD_OFF,
80 		REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
81 		6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
82 	},
83 	[REG_SCENE_FALL] = {
84 		REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
85 		REG_CHROMA_ON, 5, REG_EDGE_ON, 5,
86 		REG_AF_NORMAL, REG_FD_OFF,
87 		REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
88 		6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
89 	},
90 	[REG_SCENE_NIGHT] = {
91 		REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
92 		REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
93 		REG_AF_NORMAL, REG_FD_OFF,
94 		REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
95 		6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
96 	},
97 	[REG_SCENE_AGAINST_LIGHT] = {
98 		REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
99 		REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
100 		REG_AF_NORMAL, REG_FD_OFF,
101 		REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
102 		6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
103 	},
104 	[REG_SCENE_FIRE] = {
105 		REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
106 		REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
107 		REG_AF_NORMAL, REG_FD_OFF,
108 		REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
109 		6, REG_ISO_50, REG_CAP_NONE, REG_WDR_OFF,
110 	},
111 	[REG_SCENE_TEXT] = {
112 		REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
113 		REG_CHROMA_ON, 3, REG_EDGE_ON, 7,
114 		REG_AF_MACRO, REG_FD_OFF,
115 		REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
116 		6, REG_ISO_AUTO, REG_CAP_ANTI_SHAKE, REG_WDR_ON,
117 	},
118 	[REG_SCENE_CANDLE] = {
119 		REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
120 		REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
121 		REG_AF_NORMAL, REG_FD_OFF,
122 		REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
123 		6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
124 	},
125 };
126 
127 /**
128  * m5mols_do_scenemode() - Change current scenemode
129  * @mode:	Desired mode of the scenemode
130  *
131  * WARNING: The execution order is important. Do not change the order.
132  */
m5mols_do_scenemode(struct m5mols_info * info,u8 mode)133 int m5mols_do_scenemode(struct m5mols_info *info, u8 mode)
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 = m5mols_lock_3a(info, false);
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_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_mode(info, REG_MONITOR);
185 
186 	return ret;
187 }
188 
m5mols_lock_ae(struct m5mols_info * info,bool lock)189 static int m5mols_lock_ae(struct m5mols_info *info, bool lock)
190 {
191 	int ret = 0;
192 
193 	if (info->lock_ae != lock)
194 		ret = m5mols_write(&info->sd, AE_LOCK,
195 				lock ? REG_AE_LOCK : REG_AE_UNLOCK);
196 	if (!ret)
197 		info->lock_ae = lock;
198 
199 	return ret;
200 }
201 
m5mols_lock_awb(struct m5mols_info * info,bool lock)202 static int m5mols_lock_awb(struct m5mols_info *info, bool lock)
203 {
204 	int ret = 0;
205 
206 	if (info->lock_awb != lock)
207 		ret = m5mols_write(&info->sd, AWB_LOCK,
208 				lock ? REG_AWB_LOCK : REG_AWB_UNLOCK);
209 	if (!ret)
210 		info->lock_awb = lock;
211 
212 	return ret;
213 }
214 
215 /* m5mols_lock_3a() - Lock 3A(Auto Exposure, Auto Whitebalance, Auto Focus) */
m5mols_lock_3a(struct m5mols_info * info,bool lock)216 int m5mols_lock_3a(struct m5mols_info *info, bool lock)
217 {
218 	int ret;
219 
220 	ret = m5mols_lock_ae(info, lock);
221 	if (!ret)
222 		ret = m5mols_lock_awb(info, lock);
223 	/* Don't need to handle unlocking AF */
224 	if (!ret && is_available_af(info) && lock)
225 		ret = m5mols_write(&info->sd, AF_EXECUTE, REG_AF_STOP);
226 
227 	return ret;
228 }
229 
230 /* m5mols_set_ctrl() - The main s_ctrl function called by m5mols_set_ctrl() */
m5mols_set_ctrl(struct v4l2_ctrl * ctrl)231 int m5mols_set_ctrl(struct v4l2_ctrl *ctrl)
232 {
233 	struct v4l2_subdev *sd = to_sd(ctrl);
234 	struct m5mols_info *info = to_m5mols(sd);
235 	int ret;
236 
237 	switch (ctrl->id) {
238 	case V4L2_CID_ZOOM_ABSOLUTE:
239 		return m5mols_write(sd, MON_ZOOM, ctrl->val);
240 
241 	case V4L2_CID_EXPOSURE_AUTO:
242 		ret = m5mols_lock_ae(info,
243 			ctrl->val == V4L2_EXPOSURE_AUTO ? false : true);
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 
256 	case V4L2_CID_AUTO_WHITE_BALANCE:
257 		ret = m5mols_lock_awb(info, ctrl->val ? false : true);
258 		if (!ret)
259 			ret = m5mols_write(sd, AWB_MODE, ctrl->val ?
260 				REG_AWB_AUTO : REG_AWB_PRESET);
261 		return ret;
262 
263 	case V4L2_CID_SATURATION:
264 		ret = m5mols_write(sd, MON_CHROMA_LVL, ctrl->val);
265 		if (!ret)
266 			ret = m5mols_write(sd, MON_CHROMA_EN, REG_CHROMA_ON);
267 		return ret;
268 
269 	case V4L2_CID_COLORFX:
270 		/*
271 		 * This control uses two kinds of registers: normal & color.
272 		 * The normal effect belongs to category 1, while the color
273 		 * one belongs to category 2.
274 		 *
275 		 * The normal effect uses one register: CAT1_EFFECT.
276 		 * The color effect uses three registers:
277 		 * CAT2_COLOR_EFFECT, CAT2_CFIXR, CAT2_CFIXB.
278 		 */
279 		ret = m5mols_write(sd, PARM_EFFECT,
280 			ctrl->val == V4L2_COLORFX_NEGATIVE ? REG_EFFECT_NEGA :
281 			ctrl->val == V4L2_COLORFX_EMBOSS ? REG_EFFECT_EMBOSS :
282 			REG_EFFECT_OFF);
283 		if (!ret)
284 			ret = m5mols_write(sd, MON_EFFECT,
285 				ctrl->val == V4L2_COLORFX_SEPIA ?
286 				REG_COLOR_EFFECT_ON : REG_COLOR_EFFECT_OFF);
287 		if (!ret)
288 			ret = m5mols_write(sd, MON_CFIXR,
289 				ctrl->val == V4L2_COLORFX_SEPIA ?
290 				REG_CFIXR_SEPIA : 0);
291 		if (!ret)
292 			ret = m5mols_write(sd, MON_CFIXB,
293 				ctrl->val == V4L2_COLORFX_SEPIA ?
294 				REG_CFIXB_SEPIA : 0);
295 		return ret;
296 	}
297 
298 	return -EINVAL;
299 }
300