1 // SPDX-License-Identifier: GPL-2.0-only
3 * Samsung LSI S5C73M3 8M pixel camera driver
5 * Copyright (C) 2012, Samsung Electronics, Co., Ltd.
6 * Sylwester Nawrocki <s.nawrocki@samsung.com>
7 * Andrzej Hajda <a.hajda@samsung.com>
10 #include <linux/sizes.h>
11 #include <linux/delay.h>
12 #include <linux/firmware.h>
13 #include <linux/i2c.h>
14 #include <linux/init.h>
15 #include <linux/media.h>
16 #include <linux/module.h>
17 #include <linux/regulator/consumer.h>
18 #include <linux/slab.h>
19 #include <linux/spi/spi.h>
20 #include <linux/videodev2.h>
21 #include <media/media-entity.h>
22 #include <media/v4l2-ctrls.h>
23 #include <media/v4l2-device.h>
24 #include <media/v4l2-subdev.h>
25 #include <media/v4l2-mediabus.h>
29 static int s5c73m3_get_af_status(struct s5c73m3
*state
, struct v4l2_ctrl
*ctrl
)
31 u16 reg
= REG_AF_STATUS_UNFOCUSED
;
33 int ret
= s5c73m3_read(state
, REG_AF_STATUS
, ®
);
36 case REG_CAF_STATUS_FIND_SEARCH_DIR
:
37 case REG_AF_STATUS_FOCUSING
:
38 case REG_CAF_STATUS_FOCUSING
:
39 ctrl
->val
= V4L2_AUTO_FOCUS_STATUS_BUSY
;
41 case REG_CAF_STATUS_FOCUSED
:
42 case REG_AF_STATUS_FOCUSED
:
43 ctrl
->val
= V4L2_AUTO_FOCUS_STATUS_REACHED
;
46 v4l2_info(&state
->sensor_sd
, "Unknown AF status %#x\n", reg
);
48 case REG_CAF_STATUS_UNFOCUSED
:
49 case REG_AF_STATUS_UNFOCUSED
:
50 case REG_AF_STATUS_INVALID
:
51 ctrl
->val
= V4L2_AUTO_FOCUS_STATUS_FAILED
;
58 static int s5c73m3_g_volatile_ctrl(struct v4l2_ctrl
*ctrl
)
60 struct v4l2_subdev
*sd
= ctrl_to_sensor_sd(ctrl
);
61 struct s5c73m3
*state
= sensor_sd_to_s5c73m3(sd
);
64 if (state
->power
== 0)
68 case V4L2_CID_FOCUS_AUTO
:
69 ret
= s5c73m3_get_af_status(state
, state
->ctrls
.af_status
);
78 static int s5c73m3_set_colorfx(struct s5c73m3
*state
, int val
)
80 static const unsigned short colorfx
[][2] = {
81 { V4L2_COLORFX_NONE
, COMM_IMAGE_EFFECT_NONE
},
82 { V4L2_COLORFX_BW
, COMM_IMAGE_EFFECT_MONO
},
83 { V4L2_COLORFX_SEPIA
, COMM_IMAGE_EFFECT_SEPIA
},
84 { V4L2_COLORFX_NEGATIVE
, COMM_IMAGE_EFFECT_NEGATIVE
},
85 { V4L2_COLORFX_AQUA
, COMM_IMAGE_EFFECT_AQUA
},
89 for (i
= 0; i
< ARRAY_SIZE(colorfx
); i
++) {
90 if (colorfx
[i
][0] != val
)
93 v4l2_dbg(1, s5c73m3_dbg
, &state
->sensor_sd
,
94 "Setting %s color effect\n",
95 v4l2_ctrl_get_menu(state
->ctrls
.colorfx
->id
)[i
]);
97 return s5c73m3_isp_command(state
, COMM_IMAGE_EFFECT
,
103 /* Set exposure metering/exposure bias */
104 static int s5c73m3_set_exposure(struct s5c73m3
*state
, int auto_exp
)
106 struct v4l2_subdev
*sd
= &state
->sensor_sd
;
107 struct s5c73m3_ctrls
*ctrls
= &state
->ctrls
;
110 if (ctrls
->exposure_metering
->is_new
) {
113 switch (ctrls
->exposure_metering
->val
) {
114 case V4L2_EXPOSURE_METERING_CENTER_WEIGHTED
:
115 metering
= COMM_METERING_CENTER
;
117 case V4L2_EXPOSURE_METERING_SPOT
:
118 metering
= COMM_METERING_SPOT
;
121 metering
= COMM_METERING_AVERAGE
;
125 ret
= s5c73m3_isp_command(state
, COMM_METERING
, metering
);
128 if (!ret
&& ctrls
->exposure_bias
->is_new
) {
129 u16 exp_bias
= ctrls
->exposure_bias
->val
;
130 ret
= s5c73m3_isp_command(state
, COMM_EV
, exp_bias
);
133 v4l2_dbg(1, s5c73m3_dbg
, sd
,
134 "%s: exposure bias: %#x, metering: %#x (%d)\n", __func__
,
135 ctrls
->exposure_bias
->val
, ctrls
->exposure_metering
->val
, ret
);
140 static int s5c73m3_set_white_balance(struct s5c73m3
*state
, int val
)
142 static const unsigned short wb
[][2] = {
143 { V4L2_WHITE_BALANCE_INCANDESCENT
, COMM_AWB_MODE_INCANDESCENT
},
144 { V4L2_WHITE_BALANCE_FLUORESCENT
, COMM_AWB_MODE_FLUORESCENT1
},
145 { V4L2_WHITE_BALANCE_FLUORESCENT_H
, COMM_AWB_MODE_FLUORESCENT2
},
146 { V4L2_WHITE_BALANCE_CLOUDY
, COMM_AWB_MODE_CLOUDY
},
147 { V4L2_WHITE_BALANCE_DAYLIGHT
, COMM_AWB_MODE_DAYLIGHT
},
148 { V4L2_WHITE_BALANCE_AUTO
, COMM_AWB_MODE_AUTO
},
152 for (i
= 0; i
< ARRAY_SIZE(wb
); i
++) {
156 v4l2_dbg(1, s5c73m3_dbg
, &state
->sensor_sd
,
157 "Setting white balance to: %s\n",
158 v4l2_ctrl_get_menu(state
->ctrls
.auto_wb
->id
)[i
]);
160 return s5c73m3_isp_command(state
, COMM_AWB_MODE
, wb
[i
][1]);
166 static int s5c73m3_af_run(struct s5c73m3
*state
, bool on
)
168 struct s5c73m3_ctrls
*c
= &state
->ctrls
;
171 return s5c73m3_isp_command(state
, COMM_AF_CON
,
174 if (c
->focus_auto
->val
)
175 return s5c73m3_isp_command(state
, COMM_AF_MODE
,
176 COMM_AF_MODE_PREVIEW_CAF_START
);
178 return s5c73m3_isp_command(state
, COMM_AF_CON
, COMM_AF_CON_START
);
181 static int s5c73m3_3a_lock(struct s5c73m3
*state
, struct v4l2_ctrl
*ctrl
)
183 bool awb_lock
= ctrl
->val
& V4L2_LOCK_WHITE_BALANCE
;
184 bool ae_lock
= ctrl
->val
& V4L2_LOCK_EXPOSURE
;
185 bool af_lock
= ctrl
->val
& V4L2_LOCK_FOCUS
;
188 if ((ctrl
->val
^ ctrl
->cur
.val
) & V4L2_LOCK_EXPOSURE
) {
189 ret
= s5c73m3_isp_command(state
, COMM_AE_CON
,
190 ae_lock
? COMM_AE_STOP
: COMM_AE_START
);
195 if (((ctrl
->val
^ ctrl
->cur
.val
) & V4L2_LOCK_WHITE_BALANCE
)
196 && state
->ctrls
.auto_wb
->val
) {
197 ret
= s5c73m3_isp_command(state
, COMM_AWB_CON
,
198 awb_lock
? COMM_AWB_STOP
: COMM_AWB_START
);
203 if ((ctrl
->val
^ ctrl
->cur
.val
) & V4L2_LOCK_FOCUS
)
204 ret
= s5c73m3_af_run(state
, !af_lock
);
209 static int s5c73m3_set_auto_focus(struct s5c73m3
*state
, int caf
)
211 struct s5c73m3_ctrls
*c
= &state
->ctrls
;
214 if (c
->af_distance
->is_new
) {
215 u16 mode
= (c
->af_distance
->val
== V4L2_AUTO_FOCUS_RANGE_MACRO
)
216 ? COMM_AF_MODE_MACRO
: COMM_AF_MODE_NORMAL
;
217 ret
= s5c73m3_isp_command(state
, COMM_AF_MODE
, mode
);
222 if (!ret
|| (c
->focus_auto
->is_new
&& c
->focus_auto
->val
) ||
224 ret
= s5c73m3_af_run(state
, 1);
225 else if ((c
->focus_auto
->is_new
&& !c
->focus_auto
->val
) ||
227 ret
= s5c73m3_af_run(state
, 0);
234 static int s5c73m3_set_contrast(struct s5c73m3
*state
, int val
)
236 u16 reg
= (val
< 0) ? -val
+ 2 : val
;
237 return s5c73m3_isp_command(state
, COMM_CONTRAST
, reg
);
240 static int s5c73m3_set_saturation(struct s5c73m3
*state
, int val
)
242 u16 reg
= (val
< 0) ? -val
+ 2 : val
;
243 return s5c73m3_isp_command(state
, COMM_SATURATION
, reg
);
246 static int s5c73m3_set_sharpness(struct s5c73m3
*state
, int val
)
248 u16 reg
= (val
< 0) ? -val
+ 2 : val
;
249 return s5c73m3_isp_command(state
, COMM_SHARPNESS
, reg
);
252 static int s5c73m3_set_iso(struct s5c73m3
*state
, int val
)
256 if (val
== V4L2_ISO_SENSITIVITY_MANUAL
)
257 iso
= state
->ctrls
.iso
->val
+ 1;
261 return s5c73m3_isp_command(state
, COMM_ISO
, iso
);
264 static int s5c73m3_set_stabilization(struct s5c73m3
*state
, int val
)
266 struct v4l2_subdev
*sd
= &state
->sensor_sd
;
268 v4l2_dbg(1, s5c73m3_dbg
, sd
, "Image stabilization: %d\n", val
);
270 return s5c73m3_isp_command(state
, COMM_FRAME_RATE
, val
?
271 COMM_FRAME_RATE_ANTI_SHAKE
: COMM_FRAME_RATE_AUTO_SET
);
274 static int s5c73m3_set_jpeg_quality(struct s5c73m3
*state
, int quality
)
279 reg
= COMM_IMAGE_QUALITY_NORMAL
;
280 else if (quality
<= 75)
281 reg
= COMM_IMAGE_QUALITY_FINE
;
283 reg
= COMM_IMAGE_QUALITY_SUPERFINE
;
285 return s5c73m3_isp_command(state
, COMM_IMAGE_QUALITY
, reg
);
288 static int s5c73m3_set_scene_program(struct s5c73m3
*state
, int val
)
290 static const unsigned short scene_lookup
[] = {
291 COMM_SCENE_MODE_NONE
, /* V4L2_SCENE_MODE_NONE */
292 COMM_SCENE_MODE_AGAINST_LIGHT
,/* V4L2_SCENE_MODE_BACKLIGHT */
293 COMM_SCENE_MODE_BEACH
, /* V4L2_SCENE_MODE_BEACH_SNOW */
294 COMM_SCENE_MODE_CANDLE
, /* V4L2_SCENE_MODE_CANDLE_LIGHT */
295 COMM_SCENE_MODE_DAWN
, /* V4L2_SCENE_MODE_DAWN_DUSK */
296 COMM_SCENE_MODE_FALL
, /* V4L2_SCENE_MODE_FALL_COLORS */
297 COMM_SCENE_MODE_FIRE
, /* V4L2_SCENE_MODE_FIREWORKS */
298 COMM_SCENE_MODE_LANDSCAPE
, /* V4L2_SCENE_MODE_LANDSCAPE */
299 COMM_SCENE_MODE_NIGHT
, /* V4L2_SCENE_MODE_NIGHT */
300 COMM_SCENE_MODE_INDOOR
, /* V4L2_SCENE_MODE_PARTY_INDOOR */
301 COMM_SCENE_MODE_PORTRAIT
, /* V4L2_SCENE_MODE_PORTRAIT */
302 COMM_SCENE_MODE_SPORTS
, /* V4L2_SCENE_MODE_SPORTS */
303 COMM_SCENE_MODE_SUNSET
, /* V4L2_SCENE_MODE_SUNSET */
304 COMM_SCENE_MODE_TEXT
, /* V4L2_SCENE_MODE_TEXT */
307 v4l2_dbg(1, s5c73m3_dbg
, &state
->sensor_sd
, "Setting %s scene mode\n",
308 v4l2_ctrl_get_menu(state
->ctrls
.scene_mode
->id
)[val
]);
310 return s5c73m3_isp_command(state
, COMM_SCENE_MODE
, scene_lookup
[val
]);
313 static int s5c73m3_set_power_line_freq(struct s5c73m3
*state
, int val
)
315 unsigned int pwr_line_freq
= COMM_FLICKER_NONE
;
318 case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED
:
319 pwr_line_freq
= COMM_FLICKER_NONE
;
321 case V4L2_CID_POWER_LINE_FREQUENCY_50HZ
:
322 pwr_line_freq
= COMM_FLICKER_AUTO_50HZ
;
324 case V4L2_CID_POWER_LINE_FREQUENCY_60HZ
:
325 pwr_line_freq
= COMM_FLICKER_AUTO_60HZ
;
328 case V4L2_CID_POWER_LINE_FREQUENCY_AUTO
:
329 pwr_line_freq
= COMM_FLICKER_NONE
;
332 return s5c73m3_isp_command(state
, COMM_FLICKER_MODE
, pwr_line_freq
);
335 static int s5c73m3_s_ctrl(struct v4l2_ctrl
*ctrl
)
337 struct v4l2_subdev
*sd
= ctrl_to_sensor_sd(ctrl
);
338 struct s5c73m3
*state
= sensor_sd_to_s5c73m3(sd
);
341 v4l2_dbg(1, s5c73m3_dbg
, sd
, "set_ctrl: %s, value: %d\n",
342 ctrl
->name
, ctrl
->val
);
344 mutex_lock(&state
->lock
);
346 * If the device is not powered up by the host driver do
347 * not apply any controls to H/W at this time. Instead
348 * the controls will be restored right after power-up.
350 if (state
->power
== 0)
353 if (ctrl
->flags
& V4L2_CTRL_FLAG_INACTIVE
) {
359 case V4L2_CID_3A_LOCK
:
360 ret
= s5c73m3_3a_lock(state
, ctrl
);
363 case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE
:
364 ret
= s5c73m3_set_white_balance(state
, ctrl
->val
);
367 case V4L2_CID_CONTRAST
:
368 ret
= s5c73m3_set_contrast(state
, ctrl
->val
);
371 case V4L2_CID_COLORFX
:
372 ret
= s5c73m3_set_colorfx(state
, ctrl
->val
);
375 case V4L2_CID_EXPOSURE_AUTO
:
376 ret
= s5c73m3_set_exposure(state
, ctrl
->val
);
379 case V4L2_CID_FOCUS_AUTO
:
380 ret
= s5c73m3_set_auto_focus(state
, ctrl
->val
);
383 case V4L2_CID_IMAGE_STABILIZATION
:
384 ret
= s5c73m3_set_stabilization(state
, ctrl
->val
);
387 case V4L2_CID_ISO_SENSITIVITY
:
388 ret
= s5c73m3_set_iso(state
, ctrl
->val
);
391 case V4L2_CID_JPEG_COMPRESSION_QUALITY
:
392 ret
= s5c73m3_set_jpeg_quality(state
, ctrl
->val
);
395 case V4L2_CID_POWER_LINE_FREQUENCY
:
396 ret
= s5c73m3_set_power_line_freq(state
, ctrl
->val
);
399 case V4L2_CID_SATURATION
:
400 ret
= s5c73m3_set_saturation(state
, ctrl
->val
);
403 case V4L2_CID_SCENE_MODE
:
404 ret
= s5c73m3_set_scene_program(state
, ctrl
->val
);
407 case V4L2_CID_SHARPNESS
:
408 ret
= s5c73m3_set_sharpness(state
, ctrl
->val
);
411 case V4L2_CID_WIDE_DYNAMIC_RANGE
:
412 ret
= s5c73m3_isp_command(state
, COMM_WDR
, !!ctrl
->val
);
415 case V4L2_CID_ZOOM_ABSOLUTE
:
416 ret
= s5c73m3_isp_command(state
, COMM_ZOOM_STEP
, ctrl
->val
);
420 mutex_unlock(&state
->lock
);
424 static const struct v4l2_ctrl_ops s5c73m3_ctrl_ops
= {
425 .g_volatile_ctrl
= s5c73m3_g_volatile_ctrl
,
426 .s_ctrl
= s5c73m3_s_ctrl
,
429 /* Supported manual ISO values */
430 static const s64 iso_qmenu
[] = {
431 /* COMM_ISO: 0x0001...0x0004 */
435 /* Supported exposure bias values (-2.0EV...+2.0EV) */
436 static const s64 ev_bias_qmenu
[] = {
437 /* COMM_EV: 0x0000...0x0008 */
438 -2000, -1500, -1000, -500, 0, 500, 1000, 1500, 2000
441 int s5c73m3_init_controls(struct s5c73m3
*state
)
443 const struct v4l2_ctrl_ops
*ops
= &s5c73m3_ctrl_ops
;
444 struct s5c73m3_ctrls
*ctrls
= &state
->ctrls
;
445 struct v4l2_ctrl_handler
*hdl
= &ctrls
->handler
;
447 int ret
= v4l2_ctrl_handler_init(hdl
, 22);
452 ctrls
->auto_wb
= v4l2_ctrl_new_std_menu(hdl
, ops
,
453 V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE
,
454 9, ~0x15e, V4L2_WHITE_BALANCE_AUTO
);
456 /* Exposure (only automatic exposure) */
457 ctrls
->auto_exposure
= v4l2_ctrl_new_std_menu(hdl
, ops
,
458 V4L2_CID_EXPOSURE_AUTO
, 0, ~0x01, V4L2_EXPOSURE_AUTO
);
460 ctrls
->exposure_bias
= v4l2_ctrl_new_int_menu(hdl
, ops
,
461 V4L2_CID_AUTO_EXPOSURE_BIAS
,
462 ARRAY_SIZE(ev_bias_qmenu
) - 1,
463 ARRAY_SIZE(ev_bias_qmenu
)/2 - 1,
466 ctrls
->exposure_metering
= v4l2_ctrl_new_std_menu(hdl
, ops
,
467 V4L2_CID_EXPOSURE_METERING
,
468 2, ~0x7, V4L2_EXPOSURE_METERING_AVERAGE
);
471 ctrls
->focus_auto
= v4l2_ctrl_new_std(hdl
, ops
,
472 V4L2_CID_FOCUS_AUTO
, 0, 1, 1, 0);
474 ctrls
->af_start
= v4l2_ctrl_new_std(hdl
, ops
,
475 V4L2_CID_AUTO_FOCUS_START
, 0, 1, 1, 0);
477 ctrls
->af_stop
= v4l2_ctrl_new_std(hdl
, ops
,
478 V4L2_CID_AUTO_FOCUS_STOP
, 0, 1, 1, 0);
480 ctrls
->af_status
= v4l2_ctrl_new_std(hdl
, ops
,
481 V4L2_CID_AUTO_FOCUS_STATUS
, 0,
482 (V4L2_AUTO_FOCUS_STATUS_BUSY
|
483 V4L2_AUTO_FOCUS_STATUS_REACHED
|
484 V4L2_AUTO_FOCUS_STATUS_FAILED
),
485 0, V4L2_AUTO_FOCUS_STATUS_IDLE
);
487 ctrls
->af_distance
= v4l2_ctrl_new_std_menu(hdl
, ops
,
488 V4L2_CID_AUTO_FOCUS_RANGE
,
489 V4L2_AUTO_FOCUS_RANGE_MACRO
,
490 ~(1 << V4L2_AUTO_FOCUS_RANGE_NORMAL
|
491 1 << V4L2_AUTO_FOCUS_RANGE_MACRO
),
492 V4L2_AUTO_FOCUS_RANGE_NORMAL
);
493 /* ISO sensitivity */
494 ctrls
->auto_iso
= v4l2_ctrl_new_std_menu(hdl
, ops
,
495 V4L2_CID_ISO_SENSITIVITY_AUTO
, 1, 0,
496 V4L2_ISO_SENSITIVITY_AUTO
);
498 ctrls
->iso
= v4l2_ctrl_new_int_menu(hdl
, ops
,
499 V4L2_CID_ISO_SENSITIVITY
, ARRAY_SIZE(iso_qmenu
) - 1,
500 ARRAY_SIZE(iso_qmenu
)/2 - 1, iso_qmenu
);
502 ctrls
->contrast
= v4l2_ctrl_new_std(hdl
, ops
,
503 V4L2_CID_CONTRAST
, -2, 2, 1, 0);
505 ctrls
->saturation
= v4l2_ctrl_new_std(hdl
, ops
,
506 V4L2_CID_SATURATION
, -2, 2, 1, 0);
508 ctrls
->sharpness
= v4l2_ctrl_new_std(hdl
, ops
,
509 V4L2_CID_SHARPNESS
, -2, 2, 1, 0);
511 ctrls
->zoom
= v4l2_ctrl_new_std(hdl
, ops
,
512 V4L2_CID_ZOOM_ABSOLUTE
, 0, 30, 1, 0);
514 ctrls
->colorfx
= v4l2_ctrl_new_std_menu(hdl
, ops
, V4L2_CID_COLORFX
,
515 V4L2_COLORFX_AQUA
, ~0x40f, V4L2_COLORFX_NONE
);
517 ctrls
->wdr
= v4l2_ctrl_new_std(hdl
, ops
,
518 V4L2_CID_WIDE_DYNAMIC_RANGE
, 0, 1, 1, 0);
520 ctrls
->stabilization
= v4l2_ctrl_new_std(hdl
, ops
,
521 V4L2_CID_IMAGE_STABILIZATION
, 0, 1, 1, 0);
523 v4l2_ctrl_new_std_menu(hdl
, ops
, V4L2_CID_POWER_LINE_FREQUENCY
,
524 V4L2_CID_POWER_LINE_FREQUENCY_AUTO
, 0,
525 V4L2_CID_POWER_LINE_FREQUENCY_AUTO
);
527 ctrls
->jpeg_quality
= v4l2_ctrl_new_std(hdl
, ops
,
528 V4L2_CID_JPEG_COMPRESSION_QUALITY
, 1, 100, 1, 80);
530 ctrls
->scene_mode
= v4l2_ctrl_new_std_menu(hdl
, ops
,
531 V4L2_CID_SCENE_MODE
, V4L2_SCENE_MODE_TEXT
, ~0x3fff,
532 V4L2_SCENE_MODE_NONE
);
534 ctrls
->aaa_lock
= v4l2_ctrl_new_std(hdl
, ops
,
535 V4L2_CID_3A_LOCK
, 0, 0x7, 0, 0);
539 v4l2_ctrl_handler_free(hdl
);
543 v4l2_ctrl_auto_cluster(3, &ctrls
->auto_exposure
, 0, false);
544 ctrls
->auto_iso
->flags
|= V4L2_CTRL_FLAG_VOLATILE
|
545 V4L2_CTRL_FLAG_UPDATE
;
546 v4l2_ctrl_auto_cluster(2, &ctrls
->auto_iso
, 0, false);
547 ctrls
->af_status
->flags
|= V4L2_CTRL_FLAG_VOLATILE
;
548 v4l2_ctrl_cluster(5, &ctrls
->focus_auto
);
550 state
->sensor_sd
.ctrl_handler
= hdl
;