2 * Controls for M-5MOLS 8M Pixel camera sensor with ISP
4 * Copyright (C) 2011 Samsung Electronics Co., Ltd.
5 * Author: HeungJun Kim <riverful.kim@samsung.com>
7 * Copyright (C) 2009 Samsung Electronics Co., Ltd.
8 * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com>
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.
16 #include <linux/i2c.h>
17 #include <linux/delay.h>
18 #include <linux/videodev2.h>
19 #include <media/v4l2-ctrls.h>
22 #include "m5mols_reg.h"
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
,
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
,
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
,
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
,
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
,
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
,
67 [REG_SCENE_SUNSET
] = {
68 REG_AE_CENTER
, REG_AE_INDEX_00
, REG_AWB_PRESET
,
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
,
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
,
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
,
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
,
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
,
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
,
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
,
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
,
128 * m5mols_do_scenemode() - Change current scenemode
129 * @mode: Desired mode of the scenemode
131 * WARNING: The execution order is important. Do not change the order.
133 int m5mols_do_scenemode(struct m5mols_info
*info
, u8 mode
)
135 struct v4l2_subdev
*sd
= &info
->sd
;
136 struct m5mols_scenemode scenemode
= m5mols_default_scenemode
[mode
];
139 if (mode
> REG_SCENE_CANDLE
)
142 ret
= m5mols_lock_3a(info
, false);
144 ret
= m5mols_write(sd
, AE_EV_PRESET_MONITOR
, mode
);
146 ret
= m5mols_write(sd
, AE_EV_PRESET_CAPTURE
, mode
);
148 ret
= m5mols_write(sd
, AE_MODE
, scenemode
.metering
);
150 ret
= m5mols_write(sd
, AE_INDEX
, scenemode
.ev_bias
);
152 ret
= m5mols_write(sd
, AWB_MODE
, scenemode
.wb_mode
);
154 ret
= m5mols_write(sd
, AWB_MANUAL
, scenemode
.wb_preset
);
156 ret
= m5mols_write(sd
, MON_CHROMA_EN
, scenemode
.chroma_en
);
158 ret
= m5mols_write(sd
, MON_CHROMA_LVL
, scenemode
.chroma_lvl
);
160 ret
= m5mols_write(sd
, MON_EDGE_EN
, scenemode
.edge_en
);
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
);
168 ret
= m5mols_write(sd
, MON_TONE_CTL
, scenemode
.tone
);
170 ret
= m5mols_write(sd
, AE_ISO
, scenemode
.iso
);
172 ret
= m5mols_mode(info
, REG_CAPTURE
);
174 ret
= m5mols_write(sd
, CAPP_WDR_EN
, scenemode
.wdr
);
176 ret
= m5mols_write(sd
, CAPP_MCC_MODE
, scenemode
.mcc
);
178 ret
= m5mols_write(sd
, CAPP_LIGHT_CTRL
, scenemode
.light
);
180 ret
= m5mols_write(sd
, CAPP_FLASH_CTRL
, scenemode
.flash
);
182 ret
= m5mols_write(sd
, CAPC_MODE
, scenemode
.capt_mode
);
184 ret
= m5mols_mode(info
, REG_MONITOR
);
189 static int m5mols_lock_ae(struct m5mols_info
*info
, bool lock
)
193 if (info
->lock_ae
!= lock
)
194 ret
= m5mols_write(&info
->sd
, AE_LOCK
,
195 lock
? REG_AE_LOCK
: REG_AE_UNLOCK
);
197 info
->lock_ae
= lock
;
202 static int m5mols_lock_awb(struct m5mols_info
*info
, bool lock
)
206 if (info
->lock_awb
!= lock
)
207 ret
= m5mols_write(&info
->sd
, AWB_LOCK
,
208 lock
? REG_AWB_LOCK
: REG_AWB_UNLOCK
);
210 info
->lock_awb
= lock
;
215 /* m5mols_lock_3a() - Lock 3A(Auto Exposure, Auto Whitebalance, Auto Focus) */
216 int m5mols_lock_3a(struct m5mols_info
*info
, bool lock
)
220 ret
= m5mols_lock_ae(info
, lock
);
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
);
230 /* m5mols_set_ctrl() - The main s_ctrl function called by m5mols_set_ctrl() */
231 int m5mols_set_ctrl(struct v4l2_ctrl
*ctrl
)
233 struct v4l2_subdev
*sd
= to_sd(ctrl
);
234 struct m5mols_info
*info
= to_m5mols(sd
);
238 case V4L2_CID_ZOOM_ABSOLUTE
:
239 return m5mols_write(sd
, MON_ZOOM
, ctrl
->val
);
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
);
250 ret
= m5mols_write(sd
, AE_MAN_GAIN_MON
, val
);
252 ret
= m5mols_write(sd
, AE_MAN_GAIN_CAP
, val
);
256 case V4L2_CID_AUTO_WHITE_BALANCE
:
257 ret
= m5mols_lock_awb(info
, ctrl
->val
? false : true);
259 ret
= m5mols_write(sd
, AWB_MODE
, ctrl
->val
?
260 REG_AWB_AUTO
: REG_AWB_PRESET
);
263 case V4L2_CID_SATURATION
:
264 ret
= m5mols_write(sd
, MON_CHROMA_LVL
, ctrl
->val
);
266 ret
= m5mols_write(sd
, MON_CHROMA_EN
, REG_CHROMA_ON
);
269 case V4L2_CID_COLORFX
:
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.
275 * The normal effect uses one register: CAT1_EFFECT.
276 * The color effect uses three registers:
277 * CAT2_COLOR_EFFECT, CAT2_CFIXR, CAT2_CFIXB.
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
:
284 ret
= m5mols_write(sd
, MON_EFFECT
,
285 ctrl
->val
== V4L2_COLORFX_SEPIA
?
286 REG_COLOR_EFFECT_ON
: REG_COLOR_EFFECT_OFF
);
288 ret
= m5mols_write(sd
, MON_CFIXR
,
289 ctrl
->val
== V4L2_COLORFX_SEPIA
?
290 REG_CFIXR_SEPIA
: 0);
292 ret
= m5mols_write(sd
, MON_CFIXB
,
293 ctrl
->val
== V4L2_COLORFX_SEPIA
?
294 REG_CFIXB_SEPIA
: 0);