diff options
Diffstat (limited to 'drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c')
-rw-r--r-- | drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c | 563 |
1 files changed, 563 insertions, 0 deletions
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c b/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c new file mode 100644 index 000000000000..8001cde1db1e --- /dev/null +++ b/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c | |||
@@ -0,0 +1,563 @@ | |||
1 | /* | ||
2 | * Samsung LSI S5C73M3 8M pixel camera driver | ||
3 | * | ||
4 | * Copyright (C) 2012, Samsung Electronics, Co., Ltd. | ||
5 | * Sylwester Nawrocki <s.nawrocki@samsung.com> | ||
6 | * Andrzej Hajda <a.hajda@samsung.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/sizes.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/firmware.h> | ||
21 | #include <linux/gpio.h> | ||
22 | #include <linux/i2c.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/media.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/regulator/consumer.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/spi/spi.h> | ||
29 | #include <linux/videodev2.h> | ||
30 | #include <media/media-entity.h> | ||
31 | #include <media/v4l2-ctrls.h> | ||
32 | #include <media/v4l2-device.h> | ||
33 | #include <media/v4l2-subdev.h> | ||
34 | #include <media/v4l2-mediabus.h> | ||
35 | #include <media/s5c73m3.h> | ||
36 | |||
37 | #include "s5c73m3.h" | ||
38 | |||
39 | static int s5c73m3_get_af_status(struct s5c73m3 *state, struct v4l2_ctrl *ctrl) | ||
40 | { | ||
41 | u16 reg = REG_AF_STATUS_UNFOCUSED; | ||
42 | |||
43 | int ret = s5c73m3_read(state, REG_AF_STATUS, ®); | ||
44 | |||
45 | switch (reg) { | ||
46 | case REG_CAF_STATUS_FIND_SEARCH_DIR: | ||
47 | case REG_AF_STATUS_FOCUSING: | ||
48 | case REG_CAF_STATUS_FOCUSING: | ||
49 | ctrl->val = V4L2_AUTO_FOCUS_STATUS_BUSY; | ||
50 | break; | ||
51 | case REG_CAF_STATUS_FOCUSED: | ||
52 | case REG_AF_STATUS_FOCUSED: | ||
53 | ctrl->val = V4L2_AUTO_FOCUS_STATUS_REACHED; | ||
54 | break; | ||
55 | default: | ||
56 | v4l2_info(&state->sensor_sd, "Unknown AF status %#x\n", reg); | ||
57 | /* Fall through */ | ||
58 | case REG_CAF_STATUS_UNFOCUSED: | ||
59 | case REG_AF_STATUS_UNFOCUSED: | ||
60 | case REG_AF_STATUS_INVALID: | ||
61 | ctrl->val = V4L2_AUTO_FOCUS_STATUS_FAILED; | ||
62 | break; | ||
63 | } | ||
64 | |||
65 | return ret; | ||
66 | } | ||
67 | |||
68 | static int s5c73m3_g_volatile_ctrl(struct v4l2_ctrl *ctrl) | ||
69 | { | ||
70 | struct v4l2_subdev *sd = ctrl_to_sensor_sd(ctrl); | ||
71 | struct s5c73m3 *state = sensor_sd_to_s5c73m3(sd); | ||
72 | int ret; | ||
73 | |||
74 | if (state->power == 0) | ||
75 | return -EBUSY; | ||
76 | |||
77 | switch (ctrl->id) { | ||
78 | case V4L2_CID_FOCUS_AUTO: | ||
79 | ret = s5c73m3_get_af_status(state, state->ctrls.af_status); | ||
80 | if (ret) | ||
81 | return ret; | ||
82 | break; | ||
83 | } | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static int s5c73m3_set_colorfx(struct s5c73m3 *state, int val) | ||
89 | { | ||
90 | static const unsigned short colorfx[][2] = { | ||
91 | { V4L2_COLORFX_NONE, COMM_IMAGE_EFFECT_NONE }, | ||
92 | { V4L2_COLORFX_BW, COMM_IMAGE_EFFECT_MONO }, | ||
93 | { V4L2_COLORFX_SEPIA, COMM_IMAGE_EFFECT_SEPIA }, | ||
94 | { V4L2_COLORFX_NEGATIVE, COMM_IMAGE_EFFECT_NEGATIVE }, | ||
95 | { V4L2_COLORFX_AQUA, COMM_IMAGE_EFFECT_AQUA }, | ||
96 | }; | ||
97 | int i; | ||
98 | |||
99 | for (i = 0; i < ARRAY_SIZE(colorfx); i++) { | ||
100 | if (colorfx[i][0] != val) | ||
101 | continue; | ||
102 | |||
103 | v4l2_dbg(1, s5c73m3_dbg, &state->sensor_sd, | ||
104 | "Setting %s color effect\n", | ||
105 | v4l2_ctrl_get_menu(state->ctrls.colorfx->id)[i]); | ||
106 | |||
107 | return s5c73m3_isp_command(state, COMM_IMAGE_EFFECT, | ||
108 | colorfx[i][1]); | ||
109 | } | ||
110 | return -EINVAL; | ||
111 | } | ||
112 | |||
113 | /* Set exposure metering/exposure bias */ | ||
114 | static int s5c73m3_set_exposure(struct s5c73m3 *state, int auto_exp) | ||
115 | { | ||
116 | struct v4l2_subdev *sd = &state->sensor_sd; | ||
117 | struct s5c73m3_ctrls *ctrls = &state->ctrls; | ||
118 | int ret = 0; | ||
119 | |||
120 | if (ctrls->exposure_metering->is_new) { | ||
121 | u16 metering; | ||
122 | |||
123 | switch (ctrls->exposure_metering->val) { | ||
124 | case V4L2_EXPOSURE_METERING_CENTER_WEIGHTED: | ||
125 | metering = COMM_METERING_CENTER; | ||
126 | break; | ||
127 | case V4L2_EXPOSURE_METERING_SPOT: | ||
128 | metering = COMM_METERING_SPOT; | ||
129 | break; | ||
130 | default: | ||
131 | metering = COMM_METERING_AVERAGE; | ||
132 | break; | ||
133 | } | ||
134 | |||
135 | ret = s5c73m3_isp_command(state, COMM_METERING, metering); | ||
136 | } | ||
137 | |||
138 | if (!ret && ctrls->exposure_bias->is_new) { | ||
139 | u16 exp_bias = ctrls->exposure_bias->val; | ||
140 | ret = s5c73m3_isp_command(state, COMM_EV, exp_bias); | ||
141 | } | ||
142 | |||
143 | v4l2_dbg(1, s5c73m3_dbg, sd, | ||
144 | "%s: exposure bias: %#x, metering: %#x (%d)\n", __func__, | ||
145 | ctrls->exposure_bias->val, ctrls->exposure_metering->val, ret); | ||
146 | |||
147 | return ret; | ||
148 | } | ||
149 | |||
150 | static int s5c73m3_set_white_balance(struct s5c73m3 *state, int val) | ||
151 | { | ||
152 | static const unsigned short wb[][2] = { | ||
153 | { V4L2_WHITE_BALANCE_INCANDESCENT, COMM_AWB_MODE_INCANDESCENT}, | ||
154 | { V4L2_WHITE_BALANCE_FLUORESCENT, COMM_AWB_MODE_FLUORESCENT1}, | ||
155 | { V4L2_WHITE_BALANCE_FLUORESCENT_H, COMM_AWB_MODE_FLUORESCENT2}, | ||
156 | { V4L2_WHITE_BALANCE_CLOUDY, COMM_AWB_MODE_CLOUDY}, | ||
157 | { V4L2_WHITE_BALANCE_DAYLIGHT, COMM_AWB_MODE_DAYLIGHT}, | ||
158 | { V4L2_WHITE_BALANCE_AUTO, COMM_AWB_MODE_AUTO}, | ||
159 | }; | ||
160 | int i; | ||
161 | |||
162 | for (i = 0; i < ARRAY_SIZE(wb); i++) { | ||
163 | if (wb[i][0] != val) | ||
164 | continue; | ||
165 | |||
166 | v4l2_dbg(1, s5c73m3_dbg, &state->sensor_sd, | ||
167 | "Setting white balance to: %s\n", | ||
168 | v4l2_ctrl_get_menu(state->ctrls.auto_wb->id)[i]); | ||
169 | |||
170 | return s5c73m3_isp_command(state, COMM_AWB_MODE, wb[i][1]); | ||
171 | } | ||
172 | |||
173 | return -EINVAL; | ||
174 | } | ||
175 | |||
176 | static int s5c73m3_af_run(struct s5c73m3 *state, bool on) | ||
177 | { | ||
178 | struct s5c73m3_ctrls *c = &state->ctrls; | ||
179 | |||
180 | if (!on) | ||
181 | return s5c73m3_isp_command(state, COMM_AF_CON, | ||
182 | COMM_AF_CON_STOP); | ||
183 | |||
184 | if (c->focus_auto->val) | ||
185 | return s5c73m3_isp_command(state, COMM_AF_MODE, | ||
186 | COMM_AF_MODE_PREVIEW_CAF_START); | ||
187 | |||
188 | return s5c73m3_isp_command(state, COMM_AF_CON, COMM_AF_CON_START); | ||
189 | } | ||
190 | |||
191 | static int s5c73m3_3a_lock(struct s5c73m3 *state, struct v4l2_ctrl *ctrl) | ||
192 | { | ||
193 | bool awb_lock = ctrl->val & V4L2_LOCK_WHITE_BALANCE; | ||
194 | bool ae_lock = ctrl->val & V4L2_LOCK_EXPOSURE; | ||
195 | bool af_lock = ctrl->val & V4L2_LOCK_FOCUS; | ||
196 | int ret = 0; | ||
197 | |||
198 | if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_EXPOSURE) { | ||
199 | ret = s5c73m3_isp_command(state, COMM_AE_CON, | ||
200 | ae_lock ? COMM_AE_STOP : COMM_AE_START); | ||
201 | if (ret) | ||
202 | return ret; | ||
203 | } | ||
204 | |||
205 | if (((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_WHITE_BALANCE) | ||
206 | && state->ctrls.auto_wb->val) { | ||
207 | ret = s5c73m3_isp_command(state, COMM_AWB_CON, | ||
208 | awb_lock ? COMM_AWB_STOP : COMM_AWB_START); | ||
209 | if (ret) | ||
210 | return ret; | ||
211 | } | ||
212 | |||
213 | if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_FOCUS) | ||
214 | ret = s5c73m3_af_run(state, ~af_lock); | ||
215 | |||
216 | return ret; | ||
217 | } | ||
218 | |||
219 | static int s5c73m3_set_auto_focus(struct s5c73m3 *state, int caf) | ||
220 | { | ||
221 | struct s5c73m3_ctrls *c = &state->ctrls; | ||
222 | int ret = 1; | ||
223 | |||
224 | if (c->af_distance->is_new) { | ||
225 | u16 mode = (c->af_distance->val == V4L2_AUTO_FOCUS_RANGE_MACRO) | ||
226 | ? COMM_AF_MODE_MACRO : COMM_AF_MODE_NORMAL; | ||
227 | ret = s5c73m3_isp_command(state, COMM_AF_MODE, mode); | ||
228 | if (ret != 0) | ||
229 | return ret; | ||
230 | } | ||
231 | |||
232 | if (!ret || (c->focus_auto->is_new && c->focus_auto->val) || | ||
233 | c->af_start->is_new) | ||
234 | ret = s5c73m3_af_run(state, 1); | ||
235 | else if ((c->focus_auto->is_new && !c->focus_auto->val) || | ||
236 | c->af_stop->is_new) | ||
237 | ret = s5c73m3_af_run(state, 0); | ||
238 | else | ||
239 | ret = 0; | ||
240 | |||
241 | return ret; | ||
242 | } | ||
243 | |||
244 | static int s5c73m3_set_contrast(struct s5c73m3 *state, int val) | ||
245 | { | ||
246 | u16 reg = (val < 0) ? -val + 2 : val; | ||
247 | return s5c73m3_isp_command(state, COMM_CONTRAST, reg); | ||
248 | } | ||
249 | |||
250 | static int s5c73m3_set_saturation(struct s5c73m3 *state, int val) | ||
251 | { | ||
252 | u16 reg = (val < 0) ? -val + 2 : val; | ||
253 | return s5c73m3_isp_command(state, COMM_SATURATION, reg); | ||
254 | } | ||
255 | |||
256 | static int s5c73m3_set_sharpness(struct s5c73m3 *state, int val) | ||
257 | { | ||
258 | u16 reg = (val < 0) ? -val + 2 : val; | ||
259 | return s5c73m3_isp_command(state, COMM_SHARPNESS, reg); | ||
260 | } | ||
261 | |||
262 | static int s5c73m3_set_iso(struct s5c73m3 *state, int val) | ||
263 | { | ||
264 | u32 iso; | ||
265 | |||
266 | if (val == V4L2_ISO_SENSITIVITY_MANUAL) | ||
267 | iso = state->ctrls.iso->val + 1; | ||
268 | else | ||
269 | iso = 0; | ||
270 | |||
271 | return s5c73m3_isp_command(state, COMM_ISO, iso); | ||
272 | } | ||
273 | |||
274 | static int s5c73m3_set_stabilization(struct s5c73m3 *state, int val) | ||
275 | { | ||
276 | struct v4l2_subdev *sd = &state->sensor_sd; | ||
277 | |||
278 | v4l2_dbg(1, s5c73m3_dbg, sd, "Image stabilization: %d\n", val); | ||
279 | |||
280 | return s5c73m3_isp_command(state, COMM_FRAME_RATE, val ? | ||
281 | COMM_FRAME_RATE_ANTI_SHAKE : COMM_FRAME_RATE_AUTO_SET); | ||
282 | } | ||
283 | |||
284 | static int s5c73m3_set_jpeg_quality(struct s5c73m3 *state, int quality) | ||
285 | { | ||
286 | int reg; | ||
287 | |||
288 | if (quality <= 65) | ||
289 | reg = COMM_IMAGE_QUALITY_NORMAL; | ||
290 | else if (quality <= 75) | ||
291 | reg = COMM_IMAGE_QUALITY_FINE; | ||
292 | else | ||
293 | reg = COMM_IMAGE_QUALITY_SUPERFINE; | ||
294 | |||
295 | return s5c73m3_isp_command(state, COMM_IMAGE_QUALITY, reg); | ||
296 | } | ||
297 | |||
298 | static int s5c73m3_set_scene_program(struct s5c73m3 *state, int val) | ||
299 | { | ||
300 | static const unsigned short scene_lookup[] = { | ||
301 | COMM_SCENE_MODE_NONE, /* V4L2_SCENE_MODE_NONE */ | ||
302 | COMM_SCENE_MODE_AGAINST_LIGHT,/* V4L2_SCENE_MODE_BACKLIGHT */ | ||
303 | COMM_SCENE_MODE_BEACH, /* V4L2_SCENE_MODE_BEACH_SNOW */ | ||
304 | COMM_SCENE_MODE_CANDLE, /* V4L2_SCENE_MODE_CANDLE_LIGHT */ | ||
305 | COMM_SCENE_MODE_DAWN, /* V4L2_SCENE_MODE_DAWN_DUSK */ | ||
306 | COMM_SCENE_MODE_FALL, /* V4L2_SCENE_MODE_FALL_COLORS */ | ||
307 | COMM_SCENE_MODE_FIRE, /* V4L2_SCENE_MODE_FIREWORKS */ | ||
308 | COMM_SCENE_MODE_LANDSCAPE, /* V4L2_SCENE_MODE_LANDSCAPE */ | ||
309 | COMM_SCENE_MODE_NIGHT, /* V4L2_SCENE_MODE_NIGHT */ | ||
310 | COMM_SCENE_MODE_INDOOR, /* V4L2_SCENE_MODE_PARTY_INDOOR */ | ||
311 | COMM_SCENE_MODE_PORTRAIT, /* V4L2_SCENE_MODE_PORTRAIT */ | ||
312 | COMM_SCENE_MODE_SPORTS, /* V4L2_SCENE_MODE_SPORTS */ | ||
313 | COMM_SCENE_MODE_SUNSET, /* V4L2_SCENE_MODE_SUNSET */ | ||
314 | COMM_SCENE_MODE_TEXT, /* V4L2_SCENE_MODE_TEXT */ | ||
315 | }; | ||
316 | |||
317 | v4l2_dbg(1, s5c73m3_dbg, &state->sensor_sd, "Setting %s scene mode\n", | ||
318 | v4l2_ctrl_get_menu(state->ctrls.scene_mode->id)[val]); | ||
319 | |||
320 | return s5c73m3_isp_command(state, COMM_SCENE_MODE, scene_lookup[val]); | ||
321 | } | ||
322 | |||
323 | static int s5c73m3_set_power_line_freq(struct s5c73m3 *state, int val) | ||
324 | { | ||
325 | unsigned int pwr_line_freq = COMM_FLICKER_NONE; | ||
326 | |||
327 | switch (val) { | ||
328 | case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED: | ||
329 | pwr_line_freq = COMM_FLICKER_NONE; | ||
330 | break; | ||
331 | case V4L2_CID_POWER_LINE_FREQUENCY_50HZ: | ||
332 | pwr_line_freq = COMM_FLICKER_AUTO_50HZ; | ||
333 | break; | ||
334 | case V4L2_CID_POWER_LINE_FREQUENCY_60HZ: | ||
335 | pwr_line_freq = COMM_FLICKER_AUTO_60HZ; | ||
336 | break; | ||
337 | default: | ||
338 | case V4L2_CID_POWER_LINE_FREQUENCY_AUTO: | ||
339 | pwr_line_freq = COMM_FLICKER_NONE; | ||
340 | } | ||
341 | |||
342 | return s5c73m3_isp_command(state, COMM_FLICKER_MODE, pwr_line_freq); | ||
343 | } | ||
344 | |||
345 | static int s5c73m3_s_ctrl(struct v4l2_ctrl *ctrl) | ||
346 | { | ||
347 | struct v4l2_subdev *sd = ctrl_to_sensor_sd(ctrl); | ||
348 | struct s5c73m3 *state = sensor_sd_to_s5c73m3(sd); | ||
349 | int ret = 0; | ||
350 | |||
351 | v4l2_dbg(1, s5c73m3_dbg, sd, "set_ctrl: %s, value: %d\n", | ||
352 | ctrl->name, ctrl->val); | ||
353 | |||
354 | mutex_lock(&state->lock); | ||
355 | /* | ||
356 | * If the device is not powered up by the host driver do | ||
357 | * not apply any controls to H/W at this time. Instead | ||
358 | * the controls will be restored right after power-up. | ||
359 | */ | ||
360 | if (state->power == 0) | ||
361 | goto unlock; | ||
362 | |||
363 | if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE) { | ||
364 | ret = -EINVAL; | ||
365 | goto unlock; | ||
366 | } | ||
367 | |||
368 | switch (ctrl->id) { | ||
369 | case V4L2_CID_3A_LOCK: | ||
370 | ret = s5c73m3_3a_lock(state, ctrl); | ||
371 | break; | ||
372 | |||
373 | case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: | ||
374 | ret = s5c73m3_set_white_balance(state, ctrl->val); | ||
375 | break; | ||
376 | |||
377 | case V4L2_CID_CONTRAST: | ||
378 | ret = s5c73m3_set_contrast(state, ctrl->val); | ||
379 | break; | ||
380 | |||
381 | case V4L2_CID_COLORFX: | ||
382 | ret = s5c73m3_set_colorfx(state, ctrl->val); | ||
383 | break; | ||
384 | |||
385 | case V4L2_CID_EXPOSURE_AUTO: | ||
386 | ret = s5c73m3_set_exposure(state, ctrl->val); | ||
387 | break; | ||
388 | |||
389 | case V4L2_CID_FOCUS_AUTO: | ||
390 | ret = s5c73m3_set_auto_focus(state, ctrl->val); | ||
391 | break; | ||
392 | |||
393 | case V4L2_CID_IMAGE_STABILIZATION: | ||
394 | ret = s5c73m3_set_stabilization(state, ctrl->val); | ||
395 | break; | ||
396 | |||
397 | case V4L2_CID_ISO_SENSITIVITY: | ||
398 | ret = s5c73m3_set_iso(state, ctrl->val); | ||
399 | break; | ||
400 | |||
401 | case V4L2_CID_JPEG_COMPRESSION_QUALITY: | ||
402 | ret = s5c73m3_set_jpeg_quality(state, ctrl->val); | ||
403 | break; | ||
404 | |||
405 | case V4L2_CID_POWER_LINE_FREQUENCY: | ||
406 | ret = s5c73m3_set_power_line_freq(state, ctrl->val); | ||
407 | break; | ||
408 | |||
409 | case V4L2_CID_SATURATION: | ||
410 | ret = s5c73m3_set_saturation(state, ctrl->val); | ||
411 | break; | ||
412 | |||
413 | case V4L2_CID_SCENE_MODE: | ||
414 | ret = s5c73m3_set_scene_program(state, ctrl->val); | ||
415 | break; | ||
416 | |||
417 | case V4L2_CID_SHARPNESS: | ||
418 | ret = s5c73m3_set_sharpness(state, ctrl->val); | ||
419 | break; | ||
420 | |||
421 | case V4L2_CID_WIDE_DYNAMIC_RANGE: | ||
422 | ret = s5c73m3_isp_command(state, COMM_WDR, !!ctrl->val); | ||
423 | break; | ||
424 | |||
425 | case V4L2_CID_ZOOM_ABSOLUTE: | ||
426 | ret = s5c73m3_isp_command(state, COMM_ZOOM_STEP, ctrl->val); | ||
427 | break; | ||
428 | } | ||
429 | unlock: | ||
430 | mutex_unlock(&state->lock); | ||
431 | return ret; | ||
432 | } | ||
433 | |||
434 | static const struct v4l2_ctrl_ops s5c73m3_ctrl_ops = { | ||
435 | .g_volatile_ctrl = s5c73m3_g_volatile_ctrl, | ||
436 | .s_ctrl = s5c73m3_s_ctrl, | ||
437 | }; | ||
438 | |||
439 | /* Supported manual ISO values */ | ||
440 | static const s64 iso_qmenu[] = { | ||
441 | /* COMM_ISO: 0x0001...0x0004 */ | ||
442 | 100, 200, 400, 800, | ||
443 | }; | ||
444 | |||
445 | /* Supported exposure bias values (-2.0EV...+2.0EV) */ | ||
446 | static const s64 ev_bias_qmenu[] = { | ||
447 | /* COMM_EV: 0x0000...0x0008 */ | ||
448 | -2000, -1500, -1000, -500, 0, 500, 1000, 1500, 2000 | ||
449 | }; | ||
450 | |||
451 | int s5c73m3_init_controls(struct s5c73m3 *state) | ||
452 | { | ||
453 | const struct v4l2_ctrl_ops *ops = &s5c73m3_ctrl_ops; | ||
454 | struct s5c73m3_ctrls *ctrls = &state->ctrls; | ||
455 | struct v4l2_ctrl_handler *hdl = &ctrls->handler; | ||
456 | |||
457 | int ret = v4l2_ctrl_handler_init(hdl, 22); | ||
458 | if (ret) | ||
459 | return ret; | ||
460 | |||
461 | /* White balance */ | ||
462 | ctrls->auto_wb = v4l2_ctrl_new_std_menu(hdl, ops, | ||
463 | V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE, | ||
464 | 9, ~0x15e, V4L2_WHITE_BALANCE_AUTO); | ||
465 | |||
466 | /* Exposure (only automatic exposure) */ | ||
467 | ctrls->auto_exposure = v4l2_ctrl_new_std_menu(hdl, ops, | ||
468 | V4L2_CID_EXPOSURE_AUTO, 0, ~0x01, V4L2_EXPOSURE_AUTO); | ||
469 | |||
470 | ctrls->exposure_bias = v4l2_ctrl_new_int_menu(hdl, ops, | ||
471 | V4L2_CID_AUTO_EXPOSURE_BIAS, | ||
472 | ARRAY_SIZE(ev_bias_qmenu) - 1, | ||
473 | ARRAY_SIZE(ev_bias_qmenu)/2 - 1, | ||
474 | ev_bias_qmenu); | ||
475 | |||
476 | ctrls->exposure_metering = v4l2_ctrl_new_std_menu(hdl, ops, | ||
477 | V4L2_CID_EXPOSURE_METERING, | ||
478 | 2, ~0x7, V4L2_EXPOSURE_METERING_AVERAGE); | ||
479 | |||
480 | /* Auto focus */ | ||
481 | ctrls->focus_auto = v4l2_ctrl_new_std(hdl, ops, | ||
482 | V4L2_CID_FOCUS_AUTO, 0, 1, 1, 0); | ||
483 | |||
484 | ctrls->af_start = v4l2_ctrl_new_std(hdl, ops, | ||
485 | V4L2_CID_AUTO_FOCUS_START, 0, 1, 1, 0); | ||
486 | |||
487 | ctrls->af_stop = v4l2_ctrl_new_std(hdl, ops, | ||
488 | V4L2_CID_AUTO_FOCUS_STOP, 0, 1, 1, 0); | ||
489 | |||
490 | ctrls->af_status = v4l2_ctrl_new_std(hdl, ops, | ||
491 | V4L2_CID_AUTO_FOCUS_STATUS, 0, | ||
492 | (V4L2_AUTO_FOCUS_STATUS_BUSY | | ||
493 | V4L2_AUTO_FOCUS_STATUS_REACHED | | ||
494 | V4L2_AUTO_FOCUS_STATUS_FAILED), | ||
495 | 0, V4L2_AUTO_FOCUS_STATUS_IDLE); | ||
496 | |||
497 | ctrls->af_distance = v4l2_ctrl_new_std_menu(hdl, ops, | ||
498 | V4L2_CID_AUTO_FOCUS_RANGE, | ||
499 | V4L2_AUTO_FOCUS_RANGE_MACRO, | ||
500 | ~(1 << V4L2_AUTO_FOCUS_RANGE_NORMAL | | ||
501 | 1 << V4L2_AUTO_FOCUS_RANGE_MACRO), | ||
502 | V4L2_AUTO_FOCUS_RANGE_NORMAL); | ||
503 | /* ISO sensitivity */ | ||
504 | ctrls->auto_iso = v4l2_ctrl_new_std_menu(hdl, ops, | ||
505 | V4L2_CID_ISO_SENSITIVITY_AUTO, 1, 0, | ||
506 | V4L2_ISO_SENSITIVITY_AUTO); | ||
507 | |||
508 | ctrls->iso = v4l2_ctrl_new_int_menu(hdl, ops, | ||
509 | V4L2_CID_ISO_SENSITIVITY, ARRAY_SIZE(iso_qmenu) - 1, | ||
510 | ARRAY_SIZE(iso_qmenu)/2 - 1, iso_qmenu); | ||
511 | |||
512 | ctrls->contrast = v4l2_ctrl_new_std(hdl, ops, | ||
513 | V4L2_CID_CONTRAST, -2, 2, 1, 0); | ||
514 | |||
515 | ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, | ||
516 | V4L2_CID_SATURATION, -2, 2, 1, 0); | ||
517 | |||
518 | ctrls->sharpness = v4l2_ctrl_new_std(hdl, ops, | ||
519 | V4L2_CID_SHARPNESS, -2, 2, 1, 0); | ||
520 | |||
521 | ctrls->zoom = v4l2_ctrl_new_std(hdl, ops, | ||
522 | V4L2_CID_ZOOM_ABSOLUTE, 0, 30, 1, 0); | ||
523 | |||
524 | ctrls->colorfx = v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_COLORFX, | ||
525 | V4L2_COLORFX_AQUA, ~0x40f, V4L2_COLORFX_NONE); | ||
526 | |||
527 | ctrls->wdr = v4l2_ctrl_new_std(hdl, ops, | ||
528 | V4L2_CID_WIDE_DYNAMIC_RANGE, 0, 1, 1, 0); | ||
529 | |||
530 | ctrls->stabilization = v4l2_ctrl_new_std(hdl, ops, | ||
531 | V4L2_CID_IMAGE_STABILIZATION, 0, 1, 1, 0); | ||
532 | |||
533 | v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_POWER_LINE_FREQUENCY, | ||
534 | V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0, | ||
535 | V4L2_CID_POWER_LINE_FREQUENCY_AUTO); | ||
536 | |||
537 | ctrls->jpeg_quality = v4l2_ctrl_new_std(hdl, ops, | ||
538 | V4L2_CID_JPEG_COMPRESSION_QUALITY, 1, 100, 1, 80); | ||
539 | |||
540 | ctrls->scene_mode = v4l2_ctrl_new_std_menu(hdl, ops, | ||
541 | V4L2_CID_SCENE_MODE, V4L2_SCENE_MODE_TEXT, ~0x3fff, | ||
542 | V4L2_SCENE_MODE_NONE); | ||
543 | |||
544 | ctrls->aaa_lock = v4l2_ctrl_new_std(hdl, ops, | ||
545 | V4L2_CID_3A_LOCK, 0, 0x7, 0, 0); | ||
546 | |||
547 | if (hdl->error) { | ||
548 | ret = hdl->error; | ||
549 | v4l2_ctrl_handler_free(hdl); | ||
550 | return ret; | ||
551 | } | ||
552 | |||
553 | v4l2_ctrl_auto_cluster(3, &ctrls->auto_exposure, 0, false); | ||
554 | ctrls->auto_iso->flags |= V4L2_CTRL_FLAG_VOLATILE | | ||
555 | V4L2_CTRL_FLAG_UPDATE; | ||
556 | v4l2_ctrl_auto_cluster(2, &ctrls->auto_iso, 0, false); | ||
557 | ctrls->af_status->flags |= V4L2_CTRL_FLAG_VOLATILE; | ||
558 | v4l2_ctrl_cluster(6, &ctrls->focus_auto); | ||
559 | |||
560 | state->sensor_sd.ctrl_handler = hdl; | ||
561 | |||
562 | return 0; | ||
563 | } | ||