diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-08-14 15:23:43 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-08-15 15:42:14 -0400 |
commit | cb7a01ac324bf2ee2c666f37ac867e4135f9785a (patch) | |
tree | 7246b915a9334d4bc823c93ba9acab65ef882678 /drivers/media/i2c/m5mols | |
parent | f0af8fa4dad0839f844fd0633e1936493f6d685a (diff) |
[media] move i2c files into drivers/media/i2c
Move ancillary I2C drivers into drivers/media/i2c, in order to
better organize them.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/i2c/m5mols')
-rw-r--r-- | drivers/media/i2c/m5mols/Kconfig | 6 | ||||
-rw-r--r-- | drivers/media/i2c/m5mols/Makefile | 3 | ||||
-rw-r--r-- | drivers/media/i2c/m5mols/m5mols.h | 334 | ||||
-rw-r--r-- | drivers/media/i2c/m5mols/m5mols_capture.c | 155 | ||||
-rw-r--r-- | drivers/media/i2c/m5mols/m5mols_controls.c | 628 | ||||
-rw-r--r-- | drivers/media/i2c/m5mols/m5mols_core.c | 990 | ||||
-rw-r--r-- | drivers/media/i2c/m5mols/m5mols_reg.h | 362 |
7 files changed, 2478 insertions, 0 deletions
diff --git a/drivers/media/i2c/m5mols/Kconfig b/drivers/media/i2c/m5mols/Kconfig new file mode 100644 index 000000000000..dc8c2505907e --- /dev/null +++ b/drivers/media/i2c/m5mols/Kconfig | |||
@@ -0,0 +1,6 @@ | |||
1 | config VIDEO_M5MOLS | ||
2 | tristate "Fujitsu M-5MOLS 8MP sensor support" | ||
3 | depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API | ||
4 | depends on MEDIA_CAMERA_SUPPORT | ||
5 | ---help--- | ||
6 | This driver supports Fujitsu M-5MOLS camera sensor with ISP | ||
diff --git a/drivers/media/i2c/m5mols/Makefile b/drivers/media/i2c/m5mols/Makefile new file mode 100644 index 000000000000..0a44e028edc7 --- /dev/null +++ b/drivers/media/i2c/m5mols/Makefile | |||
@@ -0,0 +1,3 @@ | |||
1 | m5mols-objs := m5mols_core.o m5mols_controls.o m5mols_capture.o | ||
2 | |||
3 | obj-$(CONFIG_VIDEO_M5MOLS) += m5mols.o | ||
diff --git a/drivers/media/i2c/m5mols/m5mols.h b/drivers/media/i2c/m5mols/m5mols.h new file mode 100644 index 000000000000..bb589917b65b --- /dev/null +++ b/drivers/media/i2c/m5mols/m5mols.h | |||
@@ -0,0 +1,334 @@ | |||
1 | /* | ||
2 | * Header 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 | #ifndef M5MOLS_H | ||
17 | #define M5MOLS_H | ||
18 | |||
19 | #include <media/v4l2-subdev.h> | ||
20 | #include "m5mols_reg.h" | ||
21 | |||
22 | extern int m5mols_debug; | ||
23 | |||
24 | enum m5mols_restype { | ||
25 | M5MOLS_RESTYPE_MONITOR, | ||
26 | M5MOLS_RESTYPE_CAPTURE, | ||
27 | M5MOLS_RESTYPE_MAX, | ||
28 | }; | ||
29 | |||
30 | /** | ||
31 | * struct m5mols_resolution - structure for the resolution | ||
32 | * @type: resolution type according to the pixel code | ||
33 | * @width: width of the resolution | ||
34 | * @height: height of the resolution | ||
35 | * @reg: resolution preset register value | ||
36 | */ | ||
37 | struct m5mols_resolution { | ||
38 | u8 reg; | ||
39 | enum m5mols_restype type; | ||
40 | u16 width; | ||
41 | u16 height; | ||
42 | }; | ||
43 | |||
44 | /** | ||
45 | * struct m5mols_exif - structure for the EXIF information of M-5MOLS | ||
46 | * @exposure_time: exposure time register value | ||
47 | * @shutter_speed: speed of the shutter register value | ||
48 | * @aperture: aperture register value | ||
49 | * @exposure_bias: it calls also EV bias | ||
50 | * @iso_speed: ISO register value | ||
51 | * @flash: status register value of the flash | ||
52 | * @sdr: status register value of the Subject Distance Range | ||
53 | * @qval: not written exact meaning in document | ||
54 | */ | ||
55 | struct m5mols_exif { | ||
56 | u32 exposure_time; | ||
57 | u32 shutter_speed; | ||
58 | u32 aperture; | ||
59 | u32 brightness; | ||
60 | u32 exposure_bias; | ||
61 | u16 iso_speed; | ||
62 | u16 flash; | ||
63 | u16 sdr; | ||
64 | u16 qval; | ||
65 | }; | ||
66 | |||
67 | /** | ||
68 | * struct m5mols_capture - Structure for the capture capability | ||
69 | * @exif: EXIF information | ||
70 | * @main: size in bytes of the main image | ||
71 | * @thumb: size in bytes of the thumb image, if it was accompanied | ||
72 | * @total: total size in bytes of the produced image | ||
73 | */ | ||
74 | struct m5mols_capture { | ||
75 | struct m5mols_exif exif; | ||
76 | u32 main; | ||
77 | u32 thumb; | ||
78 | u32 total; | ||
79 | }; | ||
80 | |||
81 | /** | ||
82 | * struct m5mols_scenemode - structure for the scenemode capability | ||
83 | * @metering: metering light register value | ||
84 | * @ev_bias: EV bias register value | ||
85 | * @wb_mode: mode which means the WhiteBalance is Auto or Manual | ||
86 | * @wb_preset: whitebalance preset register value in the Manual mode | ||
87 | * @chroma_en: register value whether the Chroma capability is enabled or not | ||
88 | * @chroma_lvl: chroma's level register value | ||
89 | * @edge_en: register value Whether the Edge capability is enabled or not | ||
90 | * @edge_lvl: edge's level register value | ||
91 | * @af_range: Auto Focus's range | ||
92 | * @fd_mode: Face Detection mode | ||
93 | * @mcc: Multi-axis Color Conversion which means emotion color | ||
94 | * @light: status of the Light | ||
95 | * @flash: status of the Flash | ||
96 | * @tone: Tone color which means Contrast | ||
97 | * @iso: ISO register value | ||
98 | * @capt_mode: Mode of the Image Stabilization while the camera capturing | ||
99 | * @wdr: Wide Dynamic Range register value | ||
100 | * | ||
101 | * The each value according to each scenemode is recommended in the documents. | ||
102 | */ | ||
103 | struct m5mols_scenemode { | ||
104 | u8 metering; | ||
105 | u8 ev_bias; | ||
106 | u8 wb_mode; | ||
107 | u8 wb_preset; | ||
108 | u8 chroma_en; | ||
109 | u8 chroma_lvl; | ||
110 | u8 edge_en; | ||
111 | u8 edge_lvl; | ||
112 | u8 af_range; | ||
113 | u8 fd_mode; | ||
114 | u8 mcc; | ||
115 | u8 light; | ||
116 | u8 flash; | ||
117 | u8 tone; | ||
118 | u8 iso; | ||
119 | u8 capt_mode; | ||
120 | u8 wdr; | ||
121 | }; | ||
122 | |||
123 | /** | ||
124 | * struct m5mols_version - firmware version information | ||
125 | * @customer: customer information | ||
126 | * @project: version of project information according to customer | ||
127 | * @fw: firmware revision | ||
128 | * @hw: hardware revision | ||
129 | * @param: version of the parameter | ||
130 | * @awb: Auto WhiteBalance algorithm version | ||
131 | * @str: information about manufacturer and packaging vendor | ||
132 | * @af: Auto Focus version | ||
133 | * | ||
134 | * The register offset starts the customer version at 0x0, and it ends | ||
135 | * the awb version at 0x09. The customer, project information occupies 1 bytes | ||
136 | * each. And also the fw, hw, param, awb each requires 2 bytes. The str is | ||
137 | * unique string associated with firmware's version. It includes information | ||
138 | * about manufacturer and the vendor of the sensor's packaging. The least | ||
139 | * significant 2 bytes of the string indicate packaging manufacturer. | ||
140 | */ | ||
141 | #define VERSION_STRING_SIZE 22 | ||
142 | struct m5mols_version { | ||
143 | u8 customer; | ||
144 | u8 project; | ||
145 | u16 fw; | ||
146 | u16 hw; | ||
147 | u16 param; | ||
148 | u16 awb; | ||
149 | u8 str[VERSION_STRING_SIZE]; | ||
150 | u8 af; | ||
151 | }; | ||
152 | |||
153 | /** | ||
154 | * struct m5mols_info - M-5MOLS driver data structure | ||
155 | * @pdata: platform data | ||
156 | * @sd: v4l-subdev instance | ||
157 | * @pad: media pad | ||
158 | * @ffmt: current fmt according to resolution type | ||
159 | * @res_type: current resolution type | ||
160 | * @irq_waitq: waitqueue for the capture | ||
161 | * @irq_done: set to 1 in the interrupt handler | ||
162 | * @handle: control handler | ||
163 | * @auto_exposure: auto/manual exposure control | ||
164 | * @exposure_bias: exposure compensation control | ||
165 | * @exposure: manual exposure control | ||
166 | * @metering: exposure metering control | ||
167 | * @auto_iso: auto/manual ISO sensitivity control | ||
168 | * @iso: manual ISO sensitivity control | ||
169 | * @auto_wb: auto white balance control | ||
170 | * @lock_3a: 3A lock control | ||
171 | * @colorfx: color effect control | ||
172 | * @saturation: saturation control | ||
173 | * @zoom: zoom control | ||
174 | * @wdr: wide dynamic range control | ||
175 | * @stabilization: image stabilization control | ||
176 | * @jpeg_quality: JPEG compression quality control | ||
177 | * @ver: information of the version | ||
178 | * @cap: the capture mode attributes | ||
179 | * @isp_ready: 1 when the ISP controller has completed booting | ||
180 | * @power: current sensor's power status | ||
181 | * @ctrl_sync: 1 when the control handler state is restored in H/W | ||
182 | * @resolution: register value for current resolution | ||
183 | * @mode: register value for current operation mode | ||
184 | * @set_power: optional power callback to the board code | ||
185 | */ | ||
186 | struct m5mols_info { | ||
187 | const struct m5mols_platform_data *pdata; | ||
188 | struct v4l2_subdev sd; | ||
189 | struct media_pad pad; | ||
190 | struct v4l2_mbus_framefmt ffmt[M5MOLS_RESTYPE_MAX]; | ||
191 | int res_type; | ||
192 | |||
193 | wait_queue_head_t irq_waitq; | ||
194 | atomic_t irq_done; | ||
195 | |||
196 | struct v4l2_ctrl_handler handle; | ||
197 | struct { | ||
198 | /* exposure/exposure bias/auto exposure cluster */ | ||
199 | struct v4l2_ctrl *auto_exposure; | ||
200 | struct v4l2_ctrl *exposure_bias; | ||
201 | struct v4l2_ctrl *exposure; | ||
202 | struct v4l2_ctrl *metering; | ||
203 | }; | ||
204 | struct { | ||
205 | /* iso/auto iso cluster */ | ||
206 | struct v4l2_ctrl *auto_iso; | ||
207 | struct v4l2_ctrl *iso; | ||
208 | }; | ||
209 | struct v4l2_ctrl *auto_wb; | ||
210 | |||
211 | struct v4l2_ctrl *lock_3a; | ||
212 | struct v4l2_ctrl *colorfx; | ||
213 | struct v4l2_ctrl *saturation; | ||
214 | struct v4l2_ctrl *zoom; | ||
215 | struct v4l2_ctrl *wdr; | ||
216 | struct v4l2_ctrl *stabilization; | ||
217 | struct v4l2_ctrl *jpeg_quality; | ||
218 | |||
219 | struct m5mols_version ver; | ||
220 | struct m5mols_capture cap; | ||
221 | |||
222 | unsigned int isp_ready:1; | ||
223 | unsigned int power:1; | ||
224 | unsigned int ctrl_sync:1; | ||
225 | |||
226 | u8 resolution; | ||
227 | u8 mode; | ||
228 | |||
229 | int (*set_power)(struct device *dev, int on); | ||
230 | }; | ||
231 | |||
232 | #define is_available_af(__info) (__info->ver.af) | ||
233 | #define is_code(__code, __type) (__code == m5mols_default_ffmt[__type].code) | ||
234 | #define is_manufacturer(__info, __manufacturer) \ | ||
235 | (__info->ver.str[0] == __manufacturer[0] && \ | ||
236 | __info->ver.str[1] == __manufacturer[1]) | ||
237 | /* | ||
238 | * I2C operation of the M-5MOLS | ||
239 | * | ||
240 | * The I2C read operation of the M-5MOLS requires 2 messages. The first | ||
241 | * message sends the information about the command, command category, and total | ||
242 | * message size. The second message is used to retrieve the data specifed in | ||
243 | * the first message | ||
244 | * | ||
245 | * 1st message 2nd message | ||
246 | * +-------+---+----------+-----+-------+ +------+------+------+------+ | ||
247 | * | size1 | R | category | cmd | size2 | | d[0] | d[1] | d[2] | d[3] | | ||
248 | * +-------+---+----------+-----+-------+ +------+------+------+------+ | ||
249 | * - size1: message data size(5 in this case) | ||
250 | * - size2: desired buffer size of the 2nd message | ||
251 | * - d[0..3]: according to size2 | ||
252 | * | ||
253 | * The I2C write operation needs just one message. The message includes | ||
254 | * category, command, total size, and desired data. | ||
255 | * | ||
256 | * 1st message | ||
257 | * +-------+---+----------+-----+------+------+------+------+ | ||
258 | * | size1 | W | category | cmd | d[0] | d[1] | d[2] | d[3] | | ||
259 | * +-------+---+----------+-----+------+------+------+------+ | ||
260 | * - d[0..3]: according to size1 | ||
261 | */ | ||
262 | int m5mols_read_u8(struct v4l2_subdev *sd, u32 reg_comb, u8 *val); | ||
263 | int m5mols_read_u16(struct v4l2_subdev *sd, u32 reg_comb, u16 *val); | ||
264 | int m5mols_read_u32(struct v4l2_subdev *sd, u32 reg_comb, u32 *val); | ||
265 | int m5mols_write(struct v4l2_subdev *sd, u32 reg_comb, u32 val); | ||
266 | |||
267 | int m5mols_busy_wait(struct v4l2_subdev *sd, u32 reg, u32 value, u32 mask, | ||
268 | int timeout); | ||
269 | |||
270 | /* Mask value for busy waiting until M-5MOLS I2C interface is initialized */ | ||
271 | #define M5MOLS_I2C_RDY_WAIT_FL (1 << 16) | ||
272 | /* ISP state transition timeout, in ms */ | ||
273 | #define M5MOLS_MODE_CHANGE_TIMEOUT 200 | ||
274 | #define M5MOLS_BUSY_WAIT_DEF_TIMEOUT 250 | ||
275 | |||
276 | /* | ||
277 | * Mode operation of the M-5MOLS | ||
278 | * | ||
279 | * Changing the mode of the M-5MOLS is needed right executing order. | ||
280 | * There are three modes(PARAMETER, MONITOR, CAPTURE) which can be changed | ||
281 | * by user. There are various categories associated with each mode. | ||
282 | * | ||
283 | * +============================================================+ | ||
284 | * | mode | category | | ||
285 | * +============================================================+ | ||
286 | * | FLASH | FLASH(only after Stand-by or Power-on) | | ||
287 | * | SYSTEM | SYSTEM(only after sensor arm-booting) | | ||
288 | * | PARAMETER | PARAMETER | | ||
289 | * | MONITOR | MONITOR(preview), Auto Focus, Face Detection | | ||
290 | * | CAPTURE | Single CAPTURE, Preview(recording) | | ||
291 | * +============================================================+ | ||
292 | * | ||
293 | * The available executing order between each modes are as follows: | ||
294 | * PARAMETER <---> MONITOR <---> CAPTURE | ||
295 | */ | ||
296 | int m5mols_set_mode(struct m5mols_info *info, u8 mode); | ||
297 | |||
298 | int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg); | ||
299 | int m5mols_wait_interrupt(struct v4l2_subdev *sd, u8 condition, u32 timeout); | ||
300 | int m5mols_restore_controls(struct m5mols_info *info); | ||
301 | int m5mols_start_capture(struct m5mols_info *info); | ||
302 | int m5mols_do_scenemode(struct m5mols_info *info, u8 mode); | ||
303 | int m5mols_lock_3a(struct m5mols_info *info, bool lock); | ||
304 | int m5mols_set_ctrl(struct v4l2_ctrl *ctrl); | ||
305 | int m5mols_init_controls(struct v4l2_subdev *sd); | ||
306 | |||
307 | /* The firmware function */ | ||
308 | int m5mols_update_fw(struct v4l2_subdev *sd, | ||
309 | int (*set_power)(struct m5mols_info *, bool)); | ||
310 | |||
311 | static inline struct m5mols_info *to_m5mols(struct v4l2_subdev *subdev) | ||
312 | { | ||
313 | return container_of(subdev, struct m5mols_info, sd); | ||
314 | } | ||
315 | |||
316 | static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) | ||
317 | { | ||
318 | struct m5mols_info *info = container_of(ctrl->handler, | ||
319 | struct m5mols_info, handle); | ||
320 | return &info->sd; | ||
321 | } | ||
322 | |||
323 | static inline void m5mols_set_ctrl_mode(struct v4l2_ctrl *ctrl, | ||
324 | unsigned int mode) | ||
325 | { | ||
326 | ctrl->priv = (void *)mode; | ||
327 | } | ||
328 | |||
329 | static inline unsigned int m5mols_get_ctrl_mode(struct v4l2_ctrl *ctrl) | ||
330 | { | ||
331 | return (unsigned int)ctrl->priv; | ||
332 | } | ||
333 | |||
334 | #endif /* M5MOLS_H */ | ||
diff --git a/drivers/media/i2c/m5mols/m5mols_capture.c b/drivers/media/i2c/m5mols/m5mols_capture.c new file mode 100644 index 000000000000..cb243bd278ce --- /dev/null +++ b/drivers/media/i2c/m5mols/m5mols_capture.c | |||
@@ -0,0 +1,155 @@ | |||
1 | |||
2 | /* | ||
3 | * The Capture code for Fujitsu M-5MOLS ISP | ||
4 | * | ||
5 | * Copyright (C) 2011 Samsung Electronics Co., Ltd. | ||
6 | * Author: HeungJun Kim <riverful.kim@samsung.com> | ||
7 | * | ||
8 | * Copyright (C) 2009 Samsung Electronics Co., Ltd. | ||
9 | * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | */ | ||
16 | |||
17 | #include <linux/i2c.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/irq.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/gpio.h> | ||
23 | #include <linux/regulator/consumer.h> | ||
24 | #include <linux/videodev2.h> | ||
25 | #include <media/v4l2-ctrls.h> | ||
26 | #include <media/v4l2-device.h> | ||
27 | #include <media/v4l2-subdev.h> | ||
28 | #include <media/m5mols.h> | ||
29 | #include <media/s5p_fimc.h> | ||
30 | |||
31 | #include "m5mols.h" | ||
32 | #include "m5mols_reg.h" | ||
33 | |||
34 | /** | ||
35 | * m5mols_read_rational - I2C read of a rational number | ||
36 | * | ||
37 | * Read numerator and denominator from registers @addr_num and @addr_den | ||
38 | * respectively and return the division result in @val. | ||
39 | */ | ||
40 | static int m5mols_read_rational(struct v4l2_subdev *sd, u32 addr_num, | ||
41 | u32 addr_den, u32 *val) | ||
42 | { | ||
43 | u32 num, den; | ||
44 | |||
45 | int ret = m5mols_read_u32(sd, addr_num, &num); | ||
46 | if (!ret) | ||
47 | ret = m5mols_read_u32(sd, addr_den, &den); | ||
48 | if (ret) | ||
49 | return ret; | ||
50 | *val = den == 0 ? 0 : num / den; | ||
51 | return ret; | ||
52 | } | ||
53 | |||
54 | /** | ||
55 | * m5mols_capture_info - Gather captured image information | ||
56 | * | ||
57 | * For now it gathers only EXIF information and file size. | ||
58 | */ | ||
59 | static int m5mols_capture_info(struct m5mols_info *info) | ||
60 | { | ||
61 | struct m5mols_exif *exif = &info->cap.exif; | ||
62 | struct v4l2_subdev *sd = &info->sd; | ||
63 | int ret; | ||
64 | |||
65 | ret = m5mols_read_rational(sd, EXIF_INFO_EXPTIME_NU, | ||
66 | EXIF_INFO_EXPTIME_DE, &exif->exposure_time); | ||
67 | if (ret) | ||
68 | return ret; | ||
69 | ret = m5mols_read_rational(sd, EXIF_INFO_TV_NU, EXIF_INFO_TV_DE, | ||
70 | &exif->shutter_speed); | ||
71 | if (ret) | ||
72 | return ret; | ||
73 | ret = m5mols_read_rational(sd, EXIF_INFO_AV_NU, EXIF_INFO_AV_DE, | ||
74 | &exif->aperture); | ||
75 | if (ret) | ||
76 | return ret; | ||
77 | ret = m5mols_read_rational(sd, EXIF_INFO_BV_NU, EXIF_INFO_BV_DE, | ||
78 | &exif->brightness); | ||
79 | if (ret) | ||
80 | return ret; | ||
81 | ret = m5mols_read_rational(sd, EXIF_INFO_EBV_NU, EXIF_INFO_EBV_DE, | ||
82 | &exif->exposure_bias); | ||
83 | if (ret) | ||
84 | return ret; | ||
85 | |||
86 | ret = m5mols_read_u16(sd, EXIF_INFO_ISO, &exif->iso_speed); | ||
87 | if (!ret) | ||
88 | ret = m5mols_read_u16(sd, EXIF_INFO_FLASH, &exif->flash); | ||
89 | if (!ret) | ||
90 | ret = m5mols_read_u16(sd, EXIF_INFO_SDR, &exif->sdr); | ||
91 | if (!ret) | ||
92 | ret = m5mols_read_u16(sd, EXIF_INFO_QVAL, &exif->qval); | ||
93 | if (ret) | ||
94 | return ret; | ||
95 | |||
96 | if (!ret) | ||
97 | ret = m5mols_read_u32(sd, CAPC_IMAGE_SIZE, &info->cap.main); | ||
98 | if (!ret) | ||
99 | ret = m5mols_read_u32(sd, CAPC_THUMB_SIZE, &info->cap.thumb); | ||
100 | if (!ret) | ||
101 | info->cap.total = info->cap.main + info->cap.thumb; | ||
102 | |||
103 | return ret; | ||
104 | } | ||
105 | |||
106 | int m5mols_start_capture(struct m5mols_info *info) | ||
107 | { | ||
108 | struct v4l2_subdev *sd = &info->sd; | ||
109 | int ret; | ||
110 | |||
111 | /* | ||
112 | * Synchronize the controls, set the capture frame resolution and color | ||
113 | * format. The frame capture is initiated during switching from Monitor | ||
114 | * to Capture mode. | ||
115 | */ | ||
116 | ret = m5mols_set_mode(info, REG_MONITOR); | ||
117 | if (!ret) | ||
118 | ret = m5mols_restore_controls(info); | ||
119 | if (!ret) | ||
120 | ret = m5mols_write(sd, CAPP_YUVOUT_MAIN, REG_JPEG); | ||
121 | if (!ret) | ||
122 | ret = m5mols_write(sd, CAPP_MAIN_IMAGE_SIZE, info->resolution); | ||
123 | if (!ret) | ||
124 | ret = m5mols_set_mode(info, REG_CAPTURE); | ||
125 | if (!ret) | ||
126 | /* Wait until a frame is captured to ISP internal memory */ | ||
127 | ret = m5mols_wait_interrupt(sd, REG_INT_CAPTURE, 2000); | ||
128 | if (ret) | ||
129 | return ret; | ||
130 | |||
131 | /* | ||
132 | * Initiate the captured data transfer to a MIPI-CSI receiver. | ||
133 | */ | ||
134 | ret = m5mols_write(sd, CAPC_SEL_FRAME, 1); | ||
135 | if (!ret) | ||
136 | ret = m5mols_write(sd, CAPC_START, REG_CAP_START_MAIN); | ||
137 | if (!ret) { | ||
138 | bool captured = false; | ||
139 | unsigned int size; | ||
140 | |||
141 | /* Wait for the capture completion interrupt */ | ||
142 | ret = m5mols_wait_interrupt(sd, REG_INT_CAPTURE, 2000); | ||
143 | if (!ret) { | ||
144 | captured = true; | ||
145 | ret = m5mols_capture_info(info); | ||
146 | } | ||
147 | size = captured ? info->cap.main : 0; | ||
148 | v4l2_dbg(1, m5mols_debug, sd, "%s: size: %d, thumb.: %d B\n", | ||
149 | __func__, size, info->cap.thumb); | ||
150 | |||
151 | v4l2_subdev_notify(sd, S5P_FIMC_TX_END_NOTIFY, &size); | ||
152 | } | ||
153 | |||
154 | return ret; | ||
155 | } | ||
diff --git a/drivers/media/i2c/m5mols/m5mols_controls.c b/drivers/media/i2c/m5mols/m5mols_controls.c new file mode 100644 index 000000000000..fdbc205a2969 --- /dev/null +++ b/drivers/media/i2c/m5mols/m5mols_controls.c | |||
@@ -0,0 +1,628 @@ | |||
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 | */ | ||
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 = v4l2_ctrl_s_ctrl(info->lock_3a, 0); | ||
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_set_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_set_mode(info, REG_MONITOR); | ||
185 | |||
186 | return ret; | ||
187 | } | ||
188 | |||
189 | static int m5mols_3a_lock(struct m5mols_info *info, struct v4l2_ctrl *ctrl) | ||
190 | { | ||
191 | bool af_lock = ctrl->val & V4L2_LOCK_FOCUS; | ||
192 | int ret = 0; | ||
193 | |||
194 | if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_EXPOSURE) { | ||
195 | bool ae_lock = ctrl->val & V4L2_LOCK_EXPOSURE; | ||
196 | |||
197 | ret = m5mols_write(&info->sd, AE_LOCK, ae_lock ? | ||
198 | REG_AE_LOCK : REG_AE_UNLOCK); | ||
199 | if (ret) | ||
200 | return ret; | ||
201 | } | ||
202 | |||
203 | if (((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_WHITE_BALANCE) | ||
204 | && info->auto_wb->val) { | ||
205 | bool awb_lock = ctrl->val & V4L2_LOCK_WHITE_BALANCE; | ||
206 | |||
207 | ret = m5mols_write(&info->sd, AWB_LOCK, awb_lock ? | ||
208 | REG_AWB_LOCK : REG_AWB_UNLOCK); | ||
209 | if (ret) | ||
210 | return ret; | ||
211 | } | ||
212 | |||
213 | if (!info->ver.af || !af_lock) | ||
214 | return ret; | ||
215 | |||
216 | if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_FOCUS) | ||
217 | ret = m5mols_write(&info->sd, AF_EXECUTE, REG_AF_STOP); | ||
218 | |||
219 | return ret; | ||
220 | } | ||
221 | |||
222 | static int m5mols_set_metering_mode(struct m5mols_info *info, int mode) | ||
223 | { | ||
224 | unsigned int metering; | ||
225 | |||
226 | switch (mode) { | ||
227 | case V4L2_EXPOSURE_METERING_CENTER_WEIGHTED: | ||
228 | metering = REG_AE_CENTER; | ||
229 | break; | ||
230 | case V4L2_EXPOSURE_METERING_SPOT: | ||
231 | metering = REG_AE_SPOT; | ||
232 | break; | ||
233 | default: | ||
234 | metering = REG_AE_ALL; | ||
235 | break; | ||
236 | } | ||
237 | |||
238 | return m5mols_write(&info->sd, AE_MODE, metering); | ||
239 | } | ||
240 | |||
241 | static int m5mols_set_exposure(struct m5mols_info *info, int exposure) | ||
242 | { | ||
243 | struct v4l2_subdev *sd = &info->sd; | ||
244 | int ret = 0; | ||
245 | |||
246 | if (exposure == V4L2_EXPOSURE_AUTO) { | ||
247 | /* Unlock auto exposure */ | ||
248 | info->lock_3a->val &= ~V4L2_LOCK_EXPOSURE; | ||
249 | m5mols_3a_lock(info, info->lock_3a); | ||
250 | |||
251 | ret = m5mols_set_metering_mode(info, info->metering->val); | ||
252 | if (ret < 0) | ||
253 | return ret; | ||
254 | |||
255 | v4l2_dbg(1, m5mols_debug, sd, | ||
256 | "%s: exposure bias: %#x, metering: %#x\n", | ||
257 | __func__, info->exposure_bias->val, | ||
258 | info->metering->val); | ||
259 | |||
260 | return m5mols_write(sd, AE_INDEX, info->exposure_bias->val); | ||
261 | } | ||
262 | |||
263 | if (exposure == V4L2_EXPOSURE_MANUAL) { | ||
264 | ret = m5mols_write(sd, AE_MODE, REG_AE_OFF); | ||
265 | if (ret == 0) | ||
266 | ret = m5mols_write(sd, AE_MAN_GAIN_MON, | ||
267 | info->exposure->val); | ||
268 | if (ret == 0) | ||
269 | ret = m5mols_write(sd, AE_MAN_GAIN_CAP, | ||
270 | info->exposure->val); | ||
271 | |||
272 | v4l2_dbg(1, m5mols_debug, sd, "%s: exposure: %#x\n", | ||
273 | __func__, info->exposure->val); | ||
274 | } | ||
275 | |||
276 | return ret; | ||
277 | } | ||
278 | |||
279 | static int m5mols_set_white_balance(struct m5mols_info *info, int val) | ||
280 | { | ||
281 | static const unsigned short wb[][2] = { | ||
282 | { V4L2_WHITE_BALANCE_INCANDESCENT, REG_AWB_INCANDESCENT }, | ||
283 | { V4L2_WHITE_BALANCE_FLUORESCENT, REG_AWB_FLUORESCENT_1 }, | ||
284 | { V4L2_WHITE_BALANCE_FLUORESCENT_H, REG_AWB_FLUORESCENT_2 }, | ||
285 | { V4L2_WHITE_BALANCE_HORIZON, REG_AWB_HORIZON }, | ||
286 | { V4L2_WHITE_BALANCE_DAYLIGHT, REG_AWB_DAYLIGHT }, | ||
287 | { V4L2_WHITE_BALANCE_FLASH, REG_AWB_LEDLIGHT }, | ||
288 | { V4L2_WHITE_BALANCE_CLOUDY, REG_AWB_CLOUDY }, | ||
289 | { V4L2_WHITE_BALANCE_SHADE, REG_AWB_SHADE }, | ||
290 | { V4L2_WHITE_BALANCE_AUTO, REG_AWB_AUTO }, | ||
291 | }; | ||
292 | int i; | ||
293 | struct v4l2_subdev *sd = &info->sd; | ||
294 | int ret = -EINVAL; | ||
295 | |||
296 | for (i = 0; i < ARRAY_SIZE(wb); i++) { | ||
297 | int awb; | ||
298 | if (wb[i][0] != val) | ||
299 | continue; | ||
300 | |||
301 | v4l2_dbg(1, m5mols_debug, sd, | ||
302 | "Setting white balance to: %#x\n", wb[i][0]); | ||
303 | |||
304 | awb = wb[i][0] == V4L2_WHITE_BALANCE_AUTO; | ||
305 | ret = m5mols_write(sd, AWB_MODE, awb ? REG_AWB_AUTO : | ||
306 | REG_AWB_PRESET); | ||
307 | if (ret < 0) | ||
308 | return ret; | ||
309 | |||
310 | if (!awb) | ||
311 | ret = m5mols_write(sd, AWB_MANUAL, wb[i][1]); | ||
312 | } | ||
313 | |||
314 | return ret; | ||
315 | } | ||
316 | |||
317 | static int m5mols_set_saturation(struct m5mols_info *info, int val) | ||
318 | { | ||
319 | int ret = m5mols_write(&info->sd, MON_CHROMA_LVL, val); | ||
320 | if (ret < 0) | ||
321 | return ret; | ||
322 | |||
323 | return m5mols_write(&info->sd, MON_CHROMA_EN, REG_CHROMA_ON); | ||
324 | } | ||
325 | |||
326 | static int m5mols_set_color_effect(struct m5mols_info *info, int val) | ||
327 | { | ||
328 | unsigned int m_effect = REG_COLOR_EFFECT_OFF; | ||
329 | unsigned int p_effect = REG_EFFECT_OFF; | ||
330 | unsigned int cfix_r = 0, cfix_b = 0; | ||
331 | struct v4l2_subdev *sd = &info->sd; | ||
332 | int ret = 0; | ||
333 | |||
334 | switch (val) { | ||
335 | case V4L2_COLORFX_BW: | ||
336 | m_effect = REG_COLOR_EFFECT_ON; | ||
337 | break; | ||
338 | case V4L2_COLORFX_NEGATIVE: | ||
339 | p_effect = REG_EFFECT_NEGA; | ||
340 | break; | ||
341 | case V4L2_COLORFX_EMBOSS: | ||
342 | p_effect = REG_EFFECT_EMBOSS; | ||
343 | break; | ||
344 | case V4L2_COLORFX_SEPIA: | ||
345 | m_effect = REG_COLOR_EFFECT_ON; | ||
346 | cfix_r = REG_CFIXR_SEPIA; | ||
347 | cfix_b = REG_CFIXB_SEPIA; | ||
348 | break; | ||
349 | } | ||
350 | |||
351 | ret = m5mols_write(sd, PARM_EFFECT, p_effect); | ||
352 | if (!ret) | ||
353 | ret = m5mols_write(sd, MON_EFFECT, m_effect); | ||
354 | |||
355 | if (ret == 0 && m_effect == REG_COLOR_EFFECT_ON) { | ||
356 | ret = m5mols_write(sd, MON_CFIXR, cfix_r); | ||
357 | if (!ret) | ||
358 | ret = m5mols_write(sd, MON_CFIXB, cfix_b); | ||
359 | } | ||
360 | |||
361 | v4l2_dbg(1, m5mols_debug, sd, | ||
362 | "p_effect: %#x, m_effect: %#x, r: %#x, b: %#x (%d)\n", | ||
363 | p_effect, m_effect, cfix_r, cfix_b, ret); | ||
364 | |||
365 | return ret; | ||
366 | } | ||
367 | |||
368 | static int m5mols_set_iso(struct m5mols_info *info, int auto_iso) | ||
369 | { | ||
370 | u32 iso = auto_iso ? 0 : info->iso->val + 1; | ||
371 | |||
372 | return m5mols_write(&info->sd, AE_ISO, iso); | ||
373 | } | ||
374 | |||
375 | static int m5mols_set_wdr(struct m5mols_info *info, int wdr) | ||
376 | { | ||
377 | int ret; | ||
378 | |||
379 | ret = m5mols_write(&info->sd, MON_TONE_CTL, wdr ? 9 : 5); | ||
380 | if (ret < 0) | ||
381 | return ret; | ||
382 | |||
383 | ret = m5mols_set_mode(info, REG_CAPTURE); | ||
384 | if (ret < 0) | ||
385 | return ret; | ||
386 | |||
387 | return m5mols_write(&info->sd, CAPP_WDR_EN, wdr); | ||
388 | } | ||
389 | |||
390 | static int m5mols_set_stabilization(struct m5mols_info *info, int val) | ||
391 | { | ||
392 | struct v4l2_subdev *sd = &info->sd; | ||
393 | unsigned int evp = val ? 0xe : 0x0; | ||
394 | int ret; | ||
395 | |||
396 | ret = m5mols_write(sd, AE_EV_PRESET_MONITOR, evp); | ||
397 | if (ret < 0) | ||
398 | return ret; | ||
399 | |||
400 | return m5mols_write(sd, AE_EV_PRESET_CAPTURE, evp); | ||
401 | } | ||
402 | |||
403 | static int m5mols_g_volatile_ctrl(struct v4l2_ctrl *ctrl) | ||
404 | { | ||
405 | struct v4l2_subdev *sd = to_sd(ctrl); | ||
406 | struct m5mols_info *info = to_m5mols(sd); | ||
407 | int ret = 0; | ||
408 | u8 status; | ||
409 | |||
410 | v4l2_dbg(1, m5mols_debug, sd, "%s: ctrl: %s (%d)\n", | ||
411 | __func__, ctrl->name, info->isp_ready); | ||
412 | |||
413 | if (!info->isp_ready) | ||
414 | return -EBUSY; | ||
415 | |||
416 | switch (ctrl->id) { | ||
417 | case V4L2_CID_ISO_SENSITIVITY_AUTO: | ||
418 | ret = m5mols_read_u8(sd, AE_ISO, &status); | ||
419 | if (ret == 0) | ||
420 | ctrl->val = !status; | ||
421 | if (status != REG_ISO_AUTO) | ||
422 | info->iso->val = status - 1; | ||
423 | break; | ||
424 | |||
425 | case V4L2_CID_3A_LOCK: | ||
426 | ctrl->val &= ~0x7; | ||
427 | |||
428 | ret = m5mols_read_u8(sd, AE_LOCK, &status); | ||
429 | if (ret) | ||
430 | return ret; | ||
431 | if (status) | ||
432 | info->lock_3a->val |= V4L2_LOCK_EXPOSURE; | ||
433 | |||
434 | ret = m5mols_read_u8(sd, AWB_LOCK, &status); | ||
435 | if (ret) | ||
436 | return ret; | ||
437 | if (status) | ||
438 | info->lock_3a->val |= V4L2_LOCK_EXPOSURE; | ||
439 | |||
440 | ret = m5mols_read_u8(sd, AF_EXECUTE, &status); | ||
441 | if (!status) | ||
442 | info->lock_3a->val |= V4L2_LOCK_EXPOSURE; | ||
443 | break; | ||
444 | } | ||
445 | |||
446 | return ret; | ||
447 | } | ||
448 | |||
449 | static int m5mols_s_ctrl(struct v4l2_ctrl *ctrl) | ||
450 | { | ||
451 | unsigned int ctrl_mode = m5mols_get_ctrl_mode(ctrl); | ||
452 | struct v4l2_subdev *sd = to_sd(ctrl); | ||
453 | struct m5mols_info *info = to_m5mols(sd); | ||
454 | int last_mode = info->mode; | ||
455 | int ret = 0; | ||
456 | |||
457 | /* | ||
458 | * If needed, defer restoring the controls until | ||
459 | * the device is fully initialized. | ||
460 | */ | ||
461 | if (!info->isp_ready) { | ||
462 | info->ctrl_sync = 0; | ||
463 | return 0; | ||
464 | } | ||
465 | |||
466 | v4l2_dbg(1, m5mols_debug, sd, "%s: %s, val: %d, priv: %#x\n", | ||
467 | __func__, ctrl->name, ctrl->val, (int)ctrl->priv); | ||
468 | |||
469 | if (ctrl_mode && ctrl_mode != info->mode) { | ||
470 | ret = m5mols_set_mode(info, ctrl_mode); | ||
471 | if (ret < 0) | ||
472 | return ret; | ||
473 | } | ||
474 | |||
475 | switch (ctrl->id) { | ||
476 | case V4L2_CID_3A_LOCK: | ||
477 | ret = m5mols_3a_lock(info, ctrl); | ||
478 | break; | ||
479 | |||
480 | case V4L2_CID_ZOOM_ABSOLUTE: | ||
481 | ret = m5mols_write(sd, MON_ZOOM, ctrl->val); | ||
482 | break; | ||
483 | |||
484 | case V4L2_CID_EXPOSURE_AUTO: | ||
485 | ret = m5mols_set_exposure(info, ctrl->val); | ||
486 | break; | ||
487 | |||
488 | case V4L2_CID_ISO_SENSITIVITY: | ||
489 | ret = m5mols_set_iso(info, ctrl->val); | ||
490 | break; | ||
491 | |||
492 | case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: | ||
493 | ret = m5mols_set_white_balance(info, ctrl->val); | ||
494 | break; | ||
495 | |||
496 | case V4L2_CID_SATURATION: | ||
497 | ret = m5mols_set_saturation(info, ctrl->val); | ||
498 | break; | ||
499 | |||
500 | case V4L2_CID_COLORFX: | ||
501 | ret = m5mols_set_color_effect(info, ctrl->val); | ||
502 | break; | ||
503 | |||
504 | case V4L2_CID_WIDE_DYNAMIC_RANGE: | ||
505 | ret = m5mols_set_wdr(info, ctrl->val); | ||
506 | break; | ||
507 | |||
508 | case V4L2_CID_IMAGE_STABILIZATION: | ||
509 | ret = m5mols_set_stabilization(info, ctrl->val); | ||
510 | break; | ||
511 | |||
512 | case V4L2_CID_JPEG_COMPRESSION_QUALITY: | ||
513 | ret = m5mols_write(sd, CAPP_JPEG_RATIO, ctrl->val); | ||
514 | break; | ||
515 | } | ||
516 | |||
517 | if (ret == 0 && info->mode != last_mode) | ||
518 | ret = m5mols_set_mode(info, last_mode); | ||
519 | |||
520 | return ret; | ||
521 | } | ||
522 | |||
523 | static const struct v4l2_ctrl_ops m5mols_ctrl_ops = { | ||
524 | .g_volatile_ctrl = m5mols_g_volatile_ctrl, | ||
525 | .s_ctrl = m5mols_s_ctrl, | ||
526 | }; | ||
527 | |||
528 | /* Supported manual ISO values */ | ||
529 | static const s64 iso_qmenu[] = { | ||
530 | /* AE_ISO: 0x01...0x07 (ISO: 50...3200) */ | ||
531 | 50000, 100000, 200000, 400000, 800000, 1600000, 3200000 | ||
532 | }; | ||
533 | |||
534 | /* Supported Exposure Bias values, -2.0EV...+2.0EV */ | ||
535 | static const s64 ev_bias_qmenu[] = { | ||
536 | /* AE_INDEX: 0x00...0x08 */ | ||
537 | -2000, -1500, -1000, -500, 0, 500, 1000, 1500, 2000 | ||
538 | }; | ||
539 | |||
540 | int m5mols_init_controls(struct v4l2_subdev *sd) | ||
541 | { | ||
542 | struct m5mols_info *info = to_m5mols(sd); | ||
543 | u16 exposure_max; | ||
544 | u16 zoom_step; | ||
545 | int ret; | ||
546 | |||
547 | /* Determine the firmware dependant control range and step values */ | ||
548 | ret = m5mols_read_u16(sd, AE_MAX_GAIN_MON, &exposure_max); | ||
549 | if (ret < 0) | ||
550 | return ret; | ||
551 | |||
552 | zoom_step = is_manufacturer(info, REG_SAMSUNG_OPTICS) ? 31 : 1; | ||
553 | v4l2_ctrl_handler_init(&info->handle, 20); | ||
554 | |||
555 | info->auto_wb = v4l2_ctrl_new_std_menu(&info->handle, | ||
556 | &m5mols_ctrl_ops, V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE, | ||
557 | 9, ~0x3fe, V4L2_WHITE_BALANCE_AUTO); | ||
558 | |||
559 | /* Exposure control cluster */ | ||
560 | info->auto_exposure = v4l2_ctrl_new_std_menu(&info->handle, | ||
561 | &m5mols_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, | ||
562 | 1, ~0x03, V4L2_EXPOSURE_AUTO); | ||
563 | |||
564 | info->exposure = v4l2_ctrl_new_std(&info->handle, | ||
565 | &m5mols_ctrl_ops, V4L2_CID_EXPOSURE, | ||
566 | 0, exposure_max, 1, exposure_max / 2); | ||
567 | |||
568 | info->exposure_bias = v4l2_ctrl_new_int_menu(&info->handle, | ||
569 | &m5mols_ctrl_ops, V4L2_CID_AUTO_EXPOSURE_BIAS, | ||
570 | ARRAY_SIZE(ev_bias_qmenu) - 1, | ||
571 | ARRAY_SIZE(ev_bias_qmenu)/2 - 1, | ||
572 | ev_bias_qmenu); | ||
573 | |||
574 | info->metering = v4l2_ctrl_new_std_menu(&info->handle, | ||
575 | &m5mols_ctrl_ops, V4L2_CID_EXPOSURE_METERING, | ||
576 | 2, ~0x7, V4L2_EXPOSURE_METERING_AVERAGE); | ||
577 | |||
578 | /* ISO control cluster */ | ||
579 | info->auto_iso = v4l2_ctrl_new_std_menu(&info->handle, &m5mols_ctrl_ops, | ||
580 | V4L2_CID_ISO_SENSITIVITY_AUTO, 1, ~0x03, 1); | ||
581 | |||
582 | info->iso = v4l2_ctrl_new_int_menu(&info->handle, &m5mols_ctrl_ops, | ||
583 | V4L2_CID_ISO_SENSITIVITY, ARRAY_SIZE(iso_qmenu) - 1, | ||
584 | ARRAY_SIZE(iso_qmenu)/2 - 1, iso_qmenu); | ||
585 | |||
586 | info->saturation = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops, | ||
587 | V4L2_CID_SATURATION, 1, 5, 1, 3); | ||
588 | |||
589 | info->zoom = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops, | ||
590 | V4L2_CID_ZOOM_ABSOLUTE, 1, 70, zoom_step, 1); | ||
591 | |||
592 | info->colorfx = v4l2_ctrl_new_std_menu(&info->handle, &m5mols_ctrl_ops, | ||
593 | V4L2_CID_COLORFX, 4, 0, V4L2_COLORFX_NONE); | ||
594 | |||
595 | info->wdr = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops, | ||
596 | V4L2_CID_WIDE_DYNAMIC_RANGE, 0, 1, 1, 0); | ||
597 | |||
598 | info->stabilization = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops, | ||
599 | V4L2_CID_IMAGE_STABILIZATION, 0, 1, 1, 0); | ||
600 | |||
601 | info->jpeg_quality = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops, | ||
602 | V4L2_CID_JPEG_COMPRESSION_QUALITY, 1, 100, 1, 80); | ||
603 | |||
604 | info->lock_3a = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops, | ||
605 | V4L2_CID_3A_LOCK, 0, 0x7, 0, 0); | ||
606 | |||
607 | if (info->handle.error) { | ||
608 | int ret = info->handle.error; | ||
609 | v4l2_err(sd, "Failed to initialize controls: %d\n", ret); | ||
610 | v4l2_ctrl_handler_free(&info->handle); | ||
611 | return ret; | ||
612 | } | ||
613 | |||
614 | v4l2_ctrl_auto_cluster(4, &info->auto_exposure, 1, false); | ||
615 | info->auto_iso->flags |= V4L2_CTRL_FLAG_VOLATILE | | ||
616 | V4L2_CTRL_FLAG_UPDATE; | ||
617 | v4l2_ctrl_auto_cluster(2, &info->auto_iso, 0, false); | ||
618 | |||
619 | info->lock_3a->flags |= V4L2_CTRL_FLAG_VOLATILE; | ||
620 | |||
621 | m5mols_set_ctrl_mode(info->auto_exposure, REG_PARAMETER); | ||
622 | m5mols_set_ctrl_mode(info->auto_wb, REG_PARAMETER); | ||
623 | m5mols_set_ctrl_mode(info->colorfx, REG_MONITOR); | ||
624 | |||
625 | sd->ctrl_handler = &info->handle; | ||
626 | |||
627 | return 0; | ||
628 | } | ||
diff --git a/drivers/media/i2c/m5mols/m5mols_core.c b/drivers/media/i2c/m5mols/m5mols_core.c new file mode 100644 index 000000000000..ac7d28b6ddf2 --- /dev/null +++ b/drivers/media/i2c/m5mols/m5mols_core.c | |||
@@ -0,0 +1,990 @@ | |||
1 | /* | ||
2 | * Driver 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/slab.h> | ||
18 | #include <linux/irq.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/gpio.h> | ||
22 | #include <linux/regulator/consumer.h> | ||
23 | #include <linux/videodev2.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <media/v4l2-ctrls.h> | ||
26 | #include <media/v4l2-device.h> | ||
27 | #include <media/v4l2-subdev.h> | ||
28 | #include <media/m5mols.h> | ||
29 | |||
30 | #include "m5mols.h" | ||
31 | #include "m5mols_reg.h" | ||
32 | |||
33 | int m5mols_debug; | ||
34 | module_param(m5mols_debug, int, 0644); | ||
35 | |||
36 | #define MODULE_NAME "M5MOLS" | ||
37 | #define M5MOLS_I2C_CHECK_RETRY 500 | ||
38 | |||
39 | /* The regulator consumer names for external voltage regulators */ | ||
40 | static struct regulator_bulk_data supplies[] = { | ||
41 | { | ||
42 | .supply = "core", /* ARM core power, 1.2V */ | ||
43 | }, { | ||
44 | .supply = "dig_18", /* digital power 1, 1.8V */ | ||
45 | }, { | ||
46 | .supply = "d_sensor", /* sensor power 1, 1.8V */ | ||
47 | }, { | ||
48 | .supply = "dig_28", /* digital power 2, 2.8V */ | ||
49 | }, { | ||
50 | .supply = "a_sensor", /* analog power */ | ||
51 | }, { | ||
52 | .supply = "dig_12", /* digital power 3, 1.2V */ | ||
53 | }, | ||
54 | }; | ||
55 | |||
56 | static struct v4l2_mbus_framefmt m5mols_default_ffmt[M5MOLS_RESTYPE_MAX] = { | ||
57 | [M5MOLS_RESTYPE_MONITOR] = { | ||
58 | .width = 1920, | ||
59 | .height = 1080, | ||
60 | .code = V4L2_MBUS_FMT_VYUY8_2X8, | ||
61 | .field = V4L2_FIELD_NONE, | ||
62 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
63 | }, | ||
64 | [M5MOLS_RESTYPE_CAPTURE] = { | ||
65 | .width = 1920, | ||
66 | .height = 1080, | ||
67 | .code = V4L2_MBUS_FMT_JPEG_1X8, | ||
68 | .field = V4L2_FIELD_NONE, | ||
69 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
70 | }, | ||
71 | }; | ||
72 | #define SIZE_DEFAULT_FFMT ARRAY_SIZE(m5mols_default_ffmt) | ||
73 | |||
74 | static const struct m5mols_resolution m5mols_reg_res[] = { | ||
75 | { 0x01, M5MOLS_RESTYPE_MONITOR, 128, 96 }, /* SUB-QCIF */ | ||
76 | { 0x03, M5MOLS_RESTYPE_MONITOR, 160, 120 }, /* QQVGA */ | ||
77 | { 0x05, M5MOLS_RESTYPE_MONITOR, 176, 144 }, /* QCIF */ | ||
78 | { 0x06, M5MOLS_RESTYPE_MONITOR, 176, 176 }, | ||
79 | { 0x08, M5MOLS_RESTYPE_MONITOR, 240, 320 }, /* QVGA */ | ||
80 | { 0x09, M5MOLS_RESTYPE_MONITOR, 320, 240 }, /* QVGA */ | ||
81 | { 0x0c, M5MOLS_RESTYPE_MONITOR, 240, 400 }, /* WQVGA */ | ||
82 | { 0x0d, M5MOLS_RESTYPE_MONITOR, 400, 240 }, /* WQVGA */ | ||
83 | { 0x0e, M5MOLS_RESTYPE_MONITOR, 352, 288 }, /* CIF */ | ||
84 | { 0x13, M5MOLS_RESTYPE_MONITOR, 480, 360 }, | ||
85 | { 0x15, M5MOLS_RESTYPE_MONITOR, 640, 360 }, /* qHD */ | ||
86 | { 0x17, M5MOLS_RESTYPE_MONITOR, 640, 480 }, /* VGA */ | ||
87 | { 0x18, M5MOLS_RESTYPE_MONITOR, 720, 480 }, | ||
88 | { 0x1a, M5MOLS_RESTYPE_MONITOR, 800, 480 }, /* WVGA */ | ||
89 | { 0x1f, M5MOLS_RESTYPE_MONITOR, 800, 600 }, /* SVGA */ | ||
90 | { 0x21, M5MOLS_RESTYPE_MONITOR, 1280, 720 }, /* HD */ | ||
91 | { 0x25, M5MOLS_RESTYPE_MONITOR, 1920, 1080 }, /* 1080p */ | ||
92 | { 0x29, M5MOLS_RESTYPE_MONITOR, 3264, 2448 }, /* 2.63fps 8M */ | ||
93 | { 0x39, M5MOLS_RESTYPE_MONITOR, 800, 602 }, /* AHS_MON debug */ | ||
94 | |||
95 | { 0x02, M5MOLS_RESTYPE_CAPTURE, 320, 240 }, /* QVGA */ | ||
96 | { 0x04, M5MOLS_RESTYPE_CAPTURE, 400, 240 }, /* WQVGA */ | ||
97 | { 0x07, M5MOLS_RESTYPE_CAPTURE, 480, 360 }, | ||
98 | { 0x08, M5MOLS_RESTYPE_CAPTURE, 640, 360 }, /* qHD */ | ||
99 | { 0x09, M5MOLS_RESTYPE_CAPTURE, 640, 480 }, /* VGA */ | ||
100 | { 0x0a, M5MOLS_RESTYPE_CAPTURE, 800, 480 }, /* WVGA */ | ||
101 | { 0x10, M5MOLS_RESTYPE_CAPTURE, 1280, 720 }, /* HD */ | ||
102 | { 0x14, M5MOLS_RESTYPE_CAPTURE, 1280, 960 }, /* 1M */ | ||
103 | { 0x17, M5MOLS_RESTYPE_CAPTURE, 1600, 1200 }, /* 2M */ | ||
104 | { 0x19, M5MOLS_RESTYPE_CAPTURE, 1920, 1080 }, /* Full-HD */ | ||
105 | { 0x1a, M5MOLS_RESTYPE_CAPTURE, 2048, 1152 }, /* 3Mega */ | ||
106 | { 0x1b, M5MOLS_RESTYPE_CAPTURE, 2048, 1536 }, | ||
107 | { 0x1c, M5MOLS_RESTYPE_CAPTURE, 2560, 1440 }, /* 4Mega */ | ||
108 | { 0x1d, M5MOLS_RESTYPE_CAPTURE, 2560, 1536 }, | ||
109 | { 0x1f, M5MOLS_RESTYPE_CAPTURE, 2560, 1920 }, /* 5Mega */ | ||
110 | { 0x21, M5MOLS_RESTYPE_CAPTURE, 3264, 1836 }, /* 6Mega */ | ||
111 | { 0x22, M5MOLS_RESTYPE_CAPTURE, 3264, 1960 }, | ||
112 | { 0x25, M5MOLS_RESTYPE_CAPTURE, 3264, 2448 }, /* 8Mega */ | ||
113 | }; | ||
114 | |||
115 | /** | ||
116 | * m5mols_swap_byte - an byte array to integer conversion function | ||
117 | * @size: size in bytes of I2C packet defined in the M-5MOLS datasheet | ||
118 | * | ||
119 | * Convert I2C data byte array with performing any required byte | ||
120 | * reordering to assure proper values for each data type, regardless | ||
121 | * of the architecture endianness. | ||
122 | */ | ||
123 | static u32 m5mols_swap_byte(u8 *data, u8 length) | ||
124 | { | ||
125 | if (length == 1) | ||
126 | return *data; | ||
127 | else if (length == 2) | ||
128 | return be16_to_cpu(*((u16 *)data)); | ||
129 | else | ||
130 | return be32_to_cpu(*((u32 *)data)); | ||
131 | } | ||
132 | |||
133 | /** | ||
134 | * m5mols_read - I2C read function | ||
135 | * @reg: combination of size, category and command for the I2C packet | ||
136 | * @size: desired size of I2C packet | ||
137 | * @val: read value | ||
138 | * | ||
139 | * Returns 0 on success, or else negative errno. | ||
140 | */ | ||
141 | static int m5mols_read(struct v4l2_subdev *sd, u32 size, u32 reg, u32 *val) | ||
142 | { | ||
143 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
144 | struct m5mols_info *info = to_m5mols(sd); | ||
145 | u8 rbuf[M5MOLS_I2C_MAX_SIZE + 1]; | ||
146 | u8 category = I2C_CATEGORY(reg); | ||
147 | u8 cmd = I2C_COMMAND(reg); | ||
148 | struct i2c_msg msg[2]; | ||
149 | u8 wbuf[5]; | ||
150 | int ret; | ||
151 | |||
152 | if (!client->adapter) | ||
153 | return -ENODEV; | ||
154 | |||
155 | msg[0].addr = client->addr; | ||
156 | msg[0].flags = 0; | ||
157 | msg[0].len = 5; | ||
158 | msg[0].buf = wbuf; | ||
159 | wbuf[0] = 5; | ||
160 | wbuf[1] = M5MOLS_BYTE_READ; | ||
161 | wbuf[2] = category; | ||
162 | wbuf[3] = cmd; | ||
163 | wbuf[4] = size; | ||
164 | |||
165 | msg[1].addr = client->addr; | ||
166 | msg[1].flags = I2C_M_RD; | ||
167 | msg[1].len = size + 1; | ||
168 | msg[1].buf = rbuf; | ||
169 | |||
170 | /* minimum stabilization time */ | ||
171 | usleep_range(200, 200); | ||
172 | |||
173 | ret = i2c_transfer(client->adapter, msg, 2); | ||
174 | |||
175 | if (ret == 2) { | ||
176 | *val = m5mols_swap_byte(&rbuf[1], size); | ||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | if (info->isp_ready) | ||
181 | v4l2_err(sd, "read failed: size:%d cat:%02x cmd:%02x. %d\n", | ||
182 | size, category, cmd, ret); | ||
183 | |||
184 | return ret < 0 ? ret : -EIO; | ||
185 | } | ||
186 | |||
187 | int m5mols_read_u8(struct v4l2_subdev *sd, u32 reg, u8 *val) | ||
188 | { | ||
189 | u32 val_32; | ||
190 | int ret; | ||
191 | |||
192 | if (I2C_SIZE(reg) != 1) { | ||
193 | v4l2_err(sd, "Wrong data size\n"); | ||
194 | return -EINVAL; | ||
195 | } | ||
196 | |||
197 | ret = m5mols_read(sd, I2C_SIZE(reg), reg, &val_32); | ||
198 | if (ret) | ||
199 | return ret; | ||
200 | |||
201 | *val = (u8)val_32; | ||
202 | return ret; | ||
203 | } | ||
204 | |||
205 | int m5mols_read_u16(struct v4l2_subdev *sd, u32 reg, u16 *val) | ||
206 | { | ||
207 | u32 val_32; | ||
208 | int ret; | ||
209 | |||
210 | if (I2C_SIZE(reg) != 2) { | ||
211 | v4l2_err(sd, "Wrong data size\n"); | ||
212 | return -EINVAL; | ||
213 | } | ||
214 | |||
215 | ret = m5mols_read(sd, I2C_SIZE(reg), reg, &val_32); | ||
216 | if (ret) | ||
217 | return ret; | ||
218 | |||
219 | *val = (u16)val_32; | ||
220 | return ret; | ||
221 | } | ||
222 | |||
223 | int m5mols_read_u32(struct v4l2_subdev *sd, u32 reg, u32 *val) | ||
224 | { | ||
225 | if (I2C_SIZE(reg) != 4) { | ||
226 | v4l2_err(sd, "Wrong data size\n"); | ||
227 | return -EINVAL; | ||
228 | } | ||
229 | |||
230 | return m5mols_read(sd, I2C_SIZE(reg), reg, val); | ||
231 | } | ||
232 | |||
233 | /** | ||
234 | * m5mols_write - I2C command write function | ||
235 | * @reg: combination of size, category and command for the I2C packet | ||
236 | * @val: value to write | ||
237 | * | ||
238 | * Returns 0 on success, or else negative errno. | ||
239 | */ | ||
240 | int m5mols_write(struct v4l2_subdev *sd, u32 reg, u32 val) | ||
241 | { | ||
242 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
243 | struct m5mols_info *info = to_m5mols(sd); | ||
244 | u8 wbuf[M5MOLS_I2C_MAX_SIZE + 4]; | ||
245 | u8 category = I2C_CATEGORY(reg); | ||
246 | u8 cmd = I2C_COMMAND(reg); | ||
247 | u8 size = I2C_SIZE(reg); | ||
248 | u32 *buf = (u32 *)&wbuf[4]; | ||
249 | struct i2c_msg msg[1]; | ||
250 | int ret; | ||
251 | |||
252 | if (!client->adapter) | ||
253 | return -ENODEV; | ||
254 | |||
255 | if (size != 1 && size != 2 && size != 4) { | ||
256 | v4l2_err(sd, "Wrong data size\n"); | ||
257 | return -EINVAL; | ||
258 | } | ||
259 | |||
260 | msg->addr = client->addr; | ||
261 | msg->flags = 0; | ||
262 | msg->len = (u16)size + 4; | ||
263 | msg->buf = wbuf; | ||
264 | wbuf[0] = size + 4; | ||
265 | wbuf[1] = M5MOLS_BYTE_WRITE; | ||
266 | wbuf[2] = category; | ||
267 | wbuf[3] = cmd; | ||
268 | |||
269 | *buf = m5mols_swap_byte((u8 *)&val, size); | ||
270 | |||
271 | usleep_range(200, 200); | ||
272 | |||
273 | ret = i2c_transfer(client->adapter, msg, 1); | ||
274 | if (ret == 1) | ||
275 | return 0; | ||
276 | |||
277 | if (info->isp_ready) | ||
278 | v4l2_err(sd, "write failed: cat:%02x cmd:%02x ret:%d\n", | ||
279 | category, cmd, ret); | ||
280 | |||
281 | return ret < 0 ? ret : -EIO; | ||
282 | } | ||
283 | |||
284 | /** | ||
285 | * m5mols_busy_wait - Busy waiting with I2C register polling | ||
286 | * @reg: the I2C_REG() address of an 8-bit status register to check | ||
287 | * @value: expected status register value | ||
288 | * @mask: bit mask for the read status register value | ||
289 | * @timeout: timeout in miliseconds, or -1 for default timeout | ||
290 | * | ||
291 | * The @reg register value is ORed with @mask before comparing with @value. | ||
292 | * | ||
293 | * Return: 0 if the requested condition became true within less than | ||
294 | * @timeout ms, or else negative errno. | ||
295 | */ | ||
296 | int m5mols_busy_wait(struct v4l2_subdev *sd, u32 reg, u32 value, u32 mask, | ||
297 | int timeout) | ||
298 | { | ||
299 | int ms = timeout < 0 ? M5MOLS_BUSY_WAIT_DEF_TIMEOUT : timeout; | ||
300 | unsigned long end = jiffies + msecs_to_jiffies(ms); | ||
301 | u8 status; | ||
302 | |||
303 | do { | ||
304 | int ret = m5mols_read_u8(sd, reg, &status); | ||
305 | |||
306 | if (ret < 0 && !(mask & M5MOLS_I2C_RDY_WAIT_FL)) | ||
307 | return ret; | ||
308 | if (!ret && (status & mask & 0xff) == (value & 0xff)) | ||
309 | return 0; | ||
310 | usleep_range(100, 250); | ||
311 | } while (ms > 0 && time_is_after_jiffies(end)); | ||
312 | |||
313 | return -EBUSY; | ||
314 | } | ||
315 | |||
316 | /** | ||
317 | * m5mols_enable_interrupt - Clear interrupt pending bits and unmask interrupts | ||
318 | * | ||
319 | * Before writing desired interrupt value the INT_FACTOR register should | ||
320 | * be read to clear pending interrupts. | ||
321 | */ | ||
322 | int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg) | ||
323 | { | ||
324 | struct m5mols_info *info = to_m5mols(sd); | ||
325 | u8 mask = is_available_af(info) ? REG_INT_AF : 0; | ||
326 | u8 dummy; | ||
327 | int ret; | ||
328 | |||
329 | ret = m5mols_read_u8(sd, SYSTEM_INT_FACTOR, &dummy); | ||
330 | if (!ret) | ||
331 | ret = m5mols_write(sd, SYSTEM_INT_ENABLE, reg & ~mask); | ||
332 | return ret; | ||
333 | } | ||
334 | |||
335 | int m5mols_wait_interrupt(struct v4l2_subdev *sd, u8 irq_mask, u32 timeout) | ||
336 | { | ||
337 | struct m5mols_info *info = to_m5mols(sd); | ||
338 | |||
339 | int ret = wait_event_interruptible_timeout(info->irq_waitq, | ||
340 | atomic_add_unless(&info->irq_done, -1, 0), | ||
341 | msecs_to_jiffies(timeout)); | ||
342 | if (ret <= 0) | ||
343 | return ret ? ret : -ETIMEDOUT; | ||
344 | |||
345 | return m5mols_busy_wait(sd, SYSTEM_INT_FACTOR, irq_mask, | ||
346 | M5MOLS_I2C_RDY_WAIT_FL | irq_mask, -1); | ||
347 | } | ||
348 | |||
349 | /** | ||
350 | * m5mols_reg_mode - Write the mode and check busy status | ||
351 | * | ||
352 | * It always accompanies a little delay changing the M-5MOLS mode, so it is | ||
353 | * needed checking current busy status to guarantee right mode. | ||
354 | */ | ||
355 | static int m5mols_reg_mode(struct v4l2_subdev *sd, u8 mode) | ||
356 | { | ||
357 | int ret = m5mols_write(sd, SYSTEM_SYSMODE, mode); | ||
358 | if (ret < 0) | ||
359 | return ret; | ||
360 | return m5mols_busy_wait(sd, SYSTEM_SYSMODE, mode, 0xff, | ||
361 | M5MOLS_MODE_CHANGE_TIMEOUT); | ||
362 | } | ||
363 | |||
364 | /** | ||
365 | * m5mols_set_mode - set the M-5MOLS controller mode | ||
366 | * @mode: the required operation mode | ||
367 | * | ||
368 | * The commands of M-5MOLS are grouped into specific modes. Each functionality | ||
369 | * can be guaranteed only when the sensor is operating in mode which a command | ||
370 | * belongs to. | ||
371 | */ | ||
372 | int m5mols_set_mode(struct m5mols_info *info, u8 mode) | ||
373 | { | ||
374 | struct v4l2_subdev *sd = &info->sd; | ||
375 | int ret = -EINVAL; | ||
376 | u8 reg; | ||
377 | |||
378 | if (mode < REG_PARAMETER || mode > REG_CAPTURE) | ||
379 | return ret; | ||
380 | |||
381 | ret = m5mols_read_u8(sd, SYSTEM_SYSMODE, ®); | ||
382 | if (ret || reg == mode) | ||
383 | return ret; | ||
384 | |||
385 | switch (reg) { | ||
386 | case REG_PARAMETER: | ||
387 | ret = m5mols_reg_mode(sd, REG_MONITOR); | ||
388 | if (mode == REG_MONITOR) | ||
389 | break; | ||
390 | if (!ret) | ||
391 | ret = m5mols_reg_mode(sd, REG_CAPTURE); | ||
392 | break; | ||
393 | |||
394 | case REG_MONITOR: | ||
395 | if (mode == REG_PARAMETER) { | ||
396 | ret = m5mols_reg_mode(sd, REG_PARAMETER); | ||
397 | break; | ||
398 | } | ||
399 | |||
400 | ret = m5mols_reg_mode(sd, REG_CAPTURE); | ||
401 | break; | ||
402 | |||
403 | case REG_CAPTURE: | ||
404 | ret = m5mols_reg_mode(sd, REG_MONITOR); | ||
405 | if (mode == REG_MONITOR) | ||
406 | break; | ||
407 | if (!ret) | ||
408 | ret = m5mols_reg_mode(sd, REG_PARAMETER); | ||
409 | break; | ||
410 | |||
411 | default: | ||
412 | v4l2_warn(sd, "Wrong mode: %d\n", mode); | ||
413 | } | ||
414 | |||
415 | if (!ret) | ||
416 | info->mode = mode; | ||
417 | |||
418 | return ret; | ||
419 | } | ||
420 | |||
421 | /** | ||
422 | * m5mols_get_version - retrieve full revisions information of M-5MOLS | ||
423 | * | ||
424 | * The version information includes revisions of hardware and firmware, | ||
425 | * AutoFocus alghorithm version and the version string. | ||
426 | */ | ||
427 | static int m5mols_get_version(struct v4l2_subdev *sd) | ||
428 | { | ||
429 | struct m5mols_info *info = to_m5mols(sd); | ||
430 | struct m5mols_version *ver = &info->ver; | ||
431 | u8 *str = ver->str; | ||
432 | int i; | ||
433 | int ret; | ||
434 | |||
435 | ret = m5mols_read_u8(sd, SYSTEM_VER_CUSTOMER, &ver->customer); | ||
436 | if (!ret) | ||
437 | ret = m5mols_read_u8(sd, SYSTEM_VER_PROJECT, &ver->project); | ||
438 | if (!ret) | ||
439 | ret = m5mols_read_u16(sd, SYSTEM_VER_FIRMWARE, &ver->fw); | ||
440 | if (!ret) | ||
441 | ret = m5mols_read_u16(sd, SYSTEM_VER_HARDWARE, &ver->hw); | ||
442 | if (!ret) | ||
443 | ret = m5mols_read_u16(sd, SYSTEM_VER_PARAMETER, &ver->param); | ||
444 | if (!ret) | ||
445 | ret = m5mols_read_u16(sd, SYSTEM_VER_AWB, &ver->awb); | ||
446 | if (!ret) | ||
447 | ret = m5mols_read_u8(sd, AF_VERSION, &ver->af); | ||
448 | if (ret) | ||
449 | return ret; | ||
450 | |||
451 | for (i = 0; i < VERSION_STRING_SIZE; i++) { | ||
452 | ret = m5mols_read_u8(sd, SYSTEM_VER_STRING, &str[i]); | ||
453 | if (ret) | ||
454 | return ret; | ||
455 | } | ||
456 | |||
457 | ver->fw = be16_to_cpu(ver->fw); | ||
458 | ver->hw = be16_to_cpu(ver->hw); | ||
459 | ver->param = be16_to_cpu(ver->param); | ||
460 | ver->awb = be16_to_cpu(ver->awb); | ||
461 | |||
462 | v4l2_info(sd, "Manufacturer\t[%s]\n", | ||
463 | is_manufacturer(info, REG_SAMSUNG_ELECTRO) ? | ||
464 | "Samsung Electro-Machanics" : | ||
465 | is_manufacturer(info, REG_SAMSUNG_OPTICS) ? | ||
466 | "Samsung Fiber-Optics" : | ||
467 | is_manufacturer(info, REG_SAMSUNG_TECHWIN) ? | ||
468 | "Samsung Techwin" : "None"); | ||
469 | v4l2_info(sd, "Customer/Project\t[0x%02x/0x%02x]\n", | ||
470 | info->ver.customer, info->ver.project); | ||
471 | |||
472 | if (!is_available_af(info)) | ||
473 | v4l2_info(sd, "No support Auto Focus on this firmware\n"); | ||
474 | |||
475 | return ret; | ||
476 | } | ||
477 | |||
478 | /** | ||
479 | * __find_restype - Lookup M-5MOLS resolution type according to pixel code | ||
480 | * @code: pixel code | ||
481 | */ | ||
482 | static enum m5mols_restype __find_restype(enum v4l2_mbus_pixelcode code) | ||
483 | { | ||
484 | enum m5mols_restype type = M5MOLS_RESTYPE_MONITOR; | ||
485 | |||
486 | do { | ||
487 | if (code == m5mols_default_ffmt[type].code) | ||
488 | return type; | ||
489 | } while (type++ != SIZE_DEFAULT_FFMT); | ||
490 | |||
491 | return 0; | ||
492 | } | ||
493 | |||
494 | /** | ||
495 | * __find_resolution - Lookup preset and type of M-5MOLS's resolution | ||
496 | * @mf: pixel format to find/negotiate the resolution preset for | ||
497 | * @type: M-5MOLS resolution type | ||
498 | * @resolution: M-5MOLS resolution preset register value | ||
499 | * | ||
500 | * Find nearest resolution matching resolution preset and adjust mf | ||
501 | * to supported values. | ||
502 | */ | ||
503 | static int __find_resolution(struct v4l2_subdev *sd, | ||
504 | struct v4l2_mbus_framefmt *mf, | ||
505 | enum m5mols_restype *type, | ||
506 | u32 *resolution) | ||
507 | { | ||
508 | const struct m5mols_resolution *fsize = &m5mols_reg_res[0]; | ||
509 | const struct m5mols_resolution *match = NULL; | ||
510 | enum m5mols_restype stype = __find_restype(mf->code); | ||
511 | int i = ARRAY_SIZE(m5mols_reg_res); | ||
512 | unsigned int min_err = ~0; | ||
513 | |||
514 | while (i--) { | ||
515 | int err; | ||
516 | if (stype == fsize->type) { | ||
517 | err = abs(fsize->width - mf->width) | ||
518 | + abs(fsize->height - mf->height); | ||
519 | |||
520 | if (err < min_err) { | ||
521 | min_err = err; | ||
522 | match = fsize; | ||
523 | } | ||
524 | } | ||
525 | fsize++; | ||
526 | } | ||
527 | if (match) { | ||
528 | mf->width = match->width; | ||
529 | mf->height = match->height; | ||
530 | *resolution = match->reg; | ||
531 | *type = stype; | ||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | return -EINVAL; | ||
536 | } | ||
537 | |||
538 | static struct v4l2_mbus_framefmt *__find_format(struct m5mols_info *info, | ||
539 | struct v4l2_subdev_fh *fh, | ||
540 | enum v4l2_subdev_format_whence which, | ||
541 | enum m5mols_restype type) | ||
542 | { | ||
543 | if (which == V4L2_SUBDEV_FORMAT_TRY) | ||
544 | return fh ? v4l2_subdev_get_try_format(fh, 0) : NULL; | ||
545 | |||
546 | return &info->ffmt[type]; | ||
547 | } | ||
548 | |||
549 | static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | ||
550 | struct v4l2_subdev_format *fmt) | ||
551 | { | ||
552 | struct m5mols_info *info = to_m5mols(sd); | ||
553 | struct v4l2_mbus_framefmt *format; | ||
554 | |||
555 | format = __find_format(info, fh, fmt->which, info->res_type); | ||
556 | if (!format) | ||
557 | return -EINVAL; | ||
558 | |||
559 | fmt->format = *format; | ||
560 | return 0; | ||
561 | } | ||
562 | |||
563 | static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | ||
564 | struct v4l2_subdev_format *fmt) | ||
565 | { | ||
566 | struct m5mols_info *info = to_m5mols(sd); | ||
567 | struct v4l2_mbus_framefmt *format = &fmt->format; | ||
568 | struct v4l2_mbus_framefmt *sfmt; | ||
569 | enum m5mols_restype type; | ||
570 | u32 resolution = 0; | ||
571 | int ret; | ||
572 | |||
573 | ret = __find_resolution(sd, format, &type, &resolution); | ||
574 | if (ret < 0) | ||
575 | return ret; | ||
576 | |||
577 | sfmt = __find_format(info, fh, fmt->which, type); | ||
578 | if (!sfmt) | ||
579 | return 0; | ||
580 | |||
581 | |||
582 | format->code = m5mols_default_ffmt[type].code; | ||
583 | format->colorspace = V4L2_COLORSPACE_JPEG; | ||
584 | format->field = V4L2_FIELD_NONE; | ||
585 | |||
586 | if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { | ||
587 | *sfmt = *format; | ||
588 | info->resolution = resolution; | ||
589 | info->res_type = type; | ||
590 | } | ||
591 | |||
592 | return 0; | ||
593 | } | ||
594 | |||
595 | static int m5mols_enum_mbus_code(struct v4l2_subdev *sd, | ||
596 | struct v4l2_subdev_fh *fh, | ||
597 | struct v4l2_subdev_mbus_code_enum *code) | ||
598 | { | ||
599 | if (!code || code->index >= SIZE_DEFAULT_FFMT) | ||
600 | return -EINVAL; | ||
601 | |||
602 | code->code = m5mols_default_ffmt[code->index].code; | ||
603 | |||
604 | return 0; | ||
605 | } | ||
606 | |||
607 | static struct v4l2_subdev_pad_ops m5mols_pad_ops = { | ||
608 | .enum_mbus_code = m5mols_enum_mbus_code, | ||
609 | .get_fmt = m5mols_get_fmt, | ||
610 | .set_fmt = m5mols_set_fmt, | ||
611 | }; | ||
612 | |||
613 | /** | ||
614 | * m5mols_restore_controls - Apply current control values to the registers | ||
615 | * | ||
616 | * m5mols_do_scenemode() handles all parameters for which there is yet no | ||
617 | * individual control. It should be replaced at some point by setting each | ||
618 | * control individually, in required register set up order. | ||
619 | */ | ||
620 | int m5mols_restore_controls(struct m5mols_info *info) | ||
621 | { | ||
622 | int ret; | ||
623 | |||
624 | if (info->ctrl_sync) | ||
625 | return 0; | ||
626 | |||
627 | ret = m5mols_do_scenemode(info, REG_SCENE_NORMAL); | ||
628 | if (ret) | ||
629 | return ret; | ||
630 | |||
631 | ret = v4l2_ctrl_handler_setup(&info->handle); | ||
632 | info->ctrl_sync = !ret; | ||
633 | |||
634 | return ret; | ||
635 | } | ||
636 | |||
637 | /** | ||
638 | * m5mols_start_monitor - Start the monitor mode | ||
639 | * | ||
640 | * Before applying the controls setup the resolution and frame rate | ||
641 | * in PARAMETER mode, and then switch over to MONITOR mode. | ||
642 | */ | ||
643 | static int m5mols_start_monitor(struct m5mols_info *info) | ||
644 | { | ||
645 | struct v4l2_subdev *sd = &info->sd; | ||
646 | int ret; | ||
647 | |||
648 | ret = m5mols_set_mode(info, REG_PARAMETER); | ||
649 | if (!ret) | ||
650 | ret = m5mols_write(sd, PARM_MON_SIZE, info->resolution); | ||
651 | if (!ret) | ||
652 | ret = m5mols_write(sd, PARM_MON_FPS, REG_FPS_30); | ||
653 | if (!ret) | ||
654 | ret = m5mols_set_mode(info, REG_MONITOR); | ||
655 | if (!ret) | ||
656 | ret = m5mols_restore_controls(info); | ||
657 | |||
658 | return ret; | ||
659 | } | ||
660 | |||
661 | static int m5mols_s_stream(struct v4l2_subdev *sd, int enable) | ||
662 | { | ||
663 | struct m5mols_info *info = to_m5mols(sd); | ||
664 | u32 code = info->ffmt[info->res_type].code; | ||
665 | |||
666 | if (enable) { | ||
667 | int ret = -EINVAL; | ||
668 | |||
669 | if (is_code(code, M5MOLS_RESTYPE_MONITOR)) | ||
670 | ret = m5mols_start_monitor(info); | ||
671 | if (is_code(code, M5MOLS_RESTYPE_CAPTURE)) | ||
672 | ret = m5mols_start_capture(info); | ||
673 | |||
674 | return ret; | ||
675 | } | ||
676 | |||
677 | return m5mols_set_mode(info, REG_PARAMETER); | ||
678 | } | ||
679 | |||
680 | static const struct v4l2_subdev_video_ops m5mols_video_ops = { | ||
681 | .s_stream = m5mols_s_stream, | ||
682 | }; | ||
683 | |||
684 | static int m5mols_sensor_power(struct m5mols_info *info, bool enable) | ||
685 | { | ||
686 | struct v4l2_subdev *sd = &info->sd; | ||
687 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
688 | const struct m5mols_platform_data *pdata = info->pdata; | ||
689 | int ret; | ||
690 | |||
691 | if (info->power == enable) | ||
692 | return 0; | ||
693 | |||
694 | if (enable) { | ||
695 | if (info->set_power) { | ||
696 | ret = info->set_power(&client->dev, 1); | ||
697 | if (ret) | ||
698 | return ret; | ||
699 | } | ||
700 | |||
701 | ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies); | ||
702 | if (ret) { | ||
703 | info->set_power(&client->dev, 0); | ||
704 | return ret; | ||
705 | } | ||
706 | |||
707 | gpio_set_value(pdata->gpio_reset, !pdata->reset_polarity); | ||
708 | info->power = 1; | ||
709 | |||
710 | return ret; | ||
711 | } | ||
712 | |||
713 | ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies); | ||
714 | if (ret) | ||
715 | return ret; | ||
716 | |||
717 | if (info->set_power) | ||
718 | info->set_power(&client->dev, 0); | ||
719 | |||
720 | gpio_set_value(pdata->gpio_reset, pdata->reset_polarity); | ||
721 | |||
722 | info->isp_ready = 0; | ||
723 | info->power = 0; | ||
724 | |||
725 | return ret; | ||
726 | } | ||
727 | |||
728 | /* m5mols_update_fw - optional firmware update routine */ | ||
729 | int __attribute__ ((weak)) m5mols_update_fw(struct v4l2_subdev *sd, | ||
730 | int (*set_power)(struct m5mols_info *, bool)) | ||
731 | { | ||
732 | return 0; | ||
733 | } | ||
734 | |||
735 | /** | ||
736 | * m5mols_fw_start - M-5MOLS internal ARM controller initialization | ||
737 | * | ||
738 | * Execute the M-5MOLS internal ARM controller initialization sequence. | ||
739 | * This function should be called after the supply voltage has been | ||
740 | * applied and before any requests to the device are made. | ||
741 | */ | ||
742 | static int m5mols_fw_start(struct v4l2_subdev *sd) | ||
743 | { | ||
744 | struct m5mols_info *info = to_m5mols(sd); | ||
745 | int ret; | ||
746 | |||
747 | atomic_set(&info->irq_done, 0); | ||
748 | /* Wait until I2C slave is initialized in Flash Writer mode */ | ||
749 | ret = m5mols_busy_wait(sd, FLASH_CAM_START, REG_IN_FLASH_MODE, | ||
750 | M5MOLS_I2C_RDY_WAIT_FL | 0xff, -1); | ||
751 | if (!ret) | ||
752 | ret = m5mols_write(sd, FLASH_CAM_START, REG_START_ARM_BOOT); | ||
753 | if (!ret) | ||
754 | ret = m5mols_wait_interrupt(sd, REG_INT_MODE, 2000); | ||
755 | if (ret < 0) | ||
756 | return ret; | ||
757 | |||
758 | info->isp_ready = 1; | ||
759 | |||
760 | ret = m5mols_get_version(sd); | ||
761 | if (!ret) | ||
762 | ret = m5mols_update_fw(sd, m5mols_sensor_power); | ||
763 | if (ret) | ||
764 | return ret; | ||
765 | |||
766 | v4l2_dbg(1, m5mols_debug, sd, "Success ARM Booting\n"); | ||
767 | |||
768 | ret = m5mols_write(sd, PARM_INTERFACE, REG_INTERFACE_MIPI); | ||
769 | if (!ret) | ||
770 | ret = m5mols_enable_interrupt(sd, | ||
771 | REG_INT_AF | REG_INT_CAPTURE); | ||
772 | |||
773 | return ret; | ||
774 | } | ||
775 | |||
776 | /** | ||
777 | * m5mols_s_power - Main sensor power control function | ||
778 | * | ||
779 | * To prevent breaking the lens when the sensor is powered off the Soft-Landing | ||
780 | * algorithm is called where available. The Soft-Landing algorithm availability | ||
781 | * dependends on the firmware provider. | ||
782 | */ | ||
783 | static int m5mols_s_power(struct v4l2_subdev *sd, int on) | ||
784 | { | ||
785 | struct m5mols_info *info = to_m5mols(sd); | ||
786 | int ret; | ||
787 | |||
788 | if (on) { | ||
789 | ret = m5mols_sensor_power(info, true); | ||
790 | if (!ret) | ||
791 | ret = m5mols_fw_start(sd); | ||
792 | return ret; | ||
793 | } | ||
794 | |||
795 | if (is_manufacturer(info, REG_SAMSUNG_TECHWIN)) { | ||
796 | ret = m5mols_set_mode(info, REG_MONITOR); | ||
797 | if (!ret) | ||
798 | ret = m5mols_write(sd, AF_EXECUTE, REG_AF_STOP); | ||
799 | if (!ret) | ||
800 | ret = m5mols_write(sd, AF_MODE, REG_AF_POWEROFF); | ||
801 | if (!ret) | ||
802 | ret = m5mols_busy_wait(sd, SYSTEM_STATUS, REG_AF_IDLE, | ||
803 | 0xff, -1); | ||
804 | if (ret < 0) | ||
805 | v4l2_warn(sd, "Soft landing lens failed\n"); | ||
806 | } | ||
807 | |||
808 | ret = m5mols_sensor_power(info, false); | ||
809 | info->ctrl_sync = 0; | ||
810 | |||
811 | return ret; | ||
812 | } | ||
813 | |||
814 | static int m5mols_log_status(struct v4l2_subdev *sd) | ||
815 | { | ||
816 | struct m5mols_info *info = to_m5mols(sd); | ||
817 | |||
818 | v4l2_ctrl_handler_log_status(&info->handle, sd->name); | ||
819 | |||
820 | return 0; | ||
821 | } | ||
822 | |||
823 | static const struct v4l2_subdev_core_ops m5mols_core_ops = { | ||
824 | .s_power = m5mols_s_power, | ||
825 | .g_ctrl = v4l2_subdev_g_ctrl, | ||
826 | .s_ctrl = v4l2_subdev_s_ctrl, | ||
827 | .queryctrl = v4l2_subdev_queryctrl, | ||
828 | .querymenu = v4l2_subdev_querymenu, | ||
829 | .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, | ||
830 | .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, | ||
831 | .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, | ||
832 | .log_status = m5mols_log_status, | ||
833 | }; | ||
834 | |||
835 | /* | ||
836 | * V4L2 subdev internal operations | ||
837 | */ | ||
838 | static int m5mols_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | ||
839 | { | ||
840 | struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0); | ||
841 | |||
842 | *format = m5mols_default_ffmt[0]; | ||
843 | return 0; | ||
844 | } | ||
845 | |||
846 | static const struct v4l2_subdev_internal_ops m5mols_subdev_internal_ops = { | ||
847 | .open = m5mols_open, | ||
848 | }; | ||
849 | |||
850 | static const struct v4l2_subdev_ops m5mols_ops = { | ||
851 | .core = &m5mols_core_ops, | ||
852 | .pad = &m5mols_pad_ops, | ||
853 | .video = &m5mols_video_ops, | ||
854 | }; | ||
855 | |||
856 | static irqreturn_t m5mols_irq_handler(int irq, void *data) | ||
857 | { | ||
858 | struct m5mols_info *info = to_m5mols(data); | ||
859 | |||
860 | atomic_set(&info->irq_done, 1); | ||
861 | wake_up_interruptible(&info->irq_waitq); | ||
862 | |||
863 | return IRQ_HANDLED; | ||
864 | } | ||
865 | |||
866 | static int __devinit m5mols_probe(struct i2c_client *client, | ||
867 | const struct i2c_device_id *id) | ||
868 | { | ||
869 | const struct m5mols_platform_data *pdata = client->dev.platform_data; | ||
870 | struct m5mols_info *info; | ||
871 | struct v4l2_subdev *sd; | ||
872 | int ret; | ||
873 | |||
874 | if (pdata == NULL) { | ||
875 | dev_err(&client->dev, "No platform data\n"); | ||
876 | return -EINVAL; | ||
877 | } | ||
878 | |||
879 | if (!gpio_is_valid(pdata->gpio_reset)) { | ||
880 | dev_err(&client->dev, "No valid RESET GPIO specified\n"); | ||
881 | return -EINVAL; | ||
882 | } | ||
883 | |||
884 | if (!client->irq) { | ||
885 | dev_err(&client->dev, "Interrupt not assigned\n"); | ||
886 | return -EINVAL; | ||
887 | } | ||
888 | |||
889 | info = kzalloc(sizeof(struct m5mols_info), GFP_KERNEL); | ||
890 | if (!info) | ||
891 | return -ENOMEM; | ||
892 | |||
893 | info->pdata = pdata; | ||
894 | info->set_power = pdata->set_power; | ||
895 | |||
896 | ret = gpio_request(pdata->gpio_reset, "M5MOLS_NRST"); | ||
897 | if (ret) { | ||
898 | dev_err(&client->dev, "Failed to request gpio: %d\n", ret); | ||
899 | goto out_free; | ||
900 | } | ||
901 | gpio_direction_output(pdata->gpio_reset, pdata->reset_polarity); | ||
902 | |||
903 | ret = regulator_bulk_get(&client->dev, ARRAY_SIZE(supplies), supplies); | ||
904 | if (ret) { | ||
905 | dev_err(&client->dev, "Failed to get regulators: %d\n", ret); | ||
906 | goto out_gpio; | ||
907 | } | ||
908 | |||
909 | sd = &info->sd; | ||
910 | v4l2_i2c_subdev_init(sd, client, &m5mols_ops); | ||
911 | strlcpy(sd->name, MODULE_NAME, sizeof(sd->name)); | ||
912 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
913 | |||
914 | sd->internal_ops = &m5mols_subdev_internal_ops; | ||
915 | info->pad.flags = MEDIA_PAD_FL_SOURCE; | ||
916 | ret = media_entity_init(&sd->entity, 1, &info->pad, 0); | ||
917 | if (ret < 0) | ||
918 | goto out_reg; | ||
919 | sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; | ||
920 | |||
921 | init_waitqueue_head(&info->irq_waitq); | ||
922 | ret = request_irq(client->irq, m5mols_irq_handler, | ||
923 | IRQF_TRIGGER_RISING, MODULE_NAME, sd); | ||
924 | if (ret) { | ||
925 | dev_err(&client->dev, "Interrupt request failed: %d\n", ret); | ||
926 | goto out_me; | ||
927 | } | ||
928 | info->res_type = M5MOLS_RESTYPE_MONITOR; | ||
929 | info->ffmt[0] = m5mols_default_ffmt[0]; | ||
930 | info->ffmt[1] = m5mols_default_ffmt[1]; | ||
931 | |||
932 | ret = m5mols_sensor_power(info, true); | ||
933 | if (ret) | ||
934 | goto out_me; | ||
935 | |||
936 | ret = m5mols_fw_start(sd); | ||
937 | if (!ret) | ||
938 | ret = m5mols_init_controls(sd); | ||
939 | |||
940 | m5mols_sensor_power(info, false); | ||
941 | if (!ret) | ||
942 | return 0; | ||
943 | out_me: | ||
944 | media_entity_cleanup(&sd->entity); | ||
945 | out_reg: | ||
946 | regulator_bulk_free(ARRAY_SIZE(supplies), supplies); | ||
947 | out_gpio: | ||
948 | gpio_free(pdata->gpio_reset); | ||
949 | out_free: | ||
950 | kfree(info); | ||
951 | return ret; | ||
952 | } | ||
953 | |||
954 | static int __devexit m5mols_remove(struct i2c_client *client) | ||
955 | { | ||
956 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | ||
957 | struct m5mols_info *info = to_m5mols(sd); | ||
958 | |||
959 | v4l2_device_unregister_subdev(sd); | ||
960 | v4l2_ctrl_handler_free(sd->ctrl_handler); | ||
961 | free_irq(client->irq, sd); | ||
962 | |||
963 | regulator_bulk_free(ARRAY_SIZE(supplies), supplies); | ||
964 | gpio_free(info->pdata->gpio_reset); | ||
965 | media_entity_cleanup(&sd->entity); | ||
966 | kfree(info); | ||
967 | return 0; | ||
968 | } | ||
969 | |||
970 | static const struct i2c_device_id m5mols_id[] = { | ||
971 | { MODULE_NAME, 0 }, | ||
972 | { }, | ||
973 | }; | ||
974 | MODULE_DEVICE_TABLE(i2c, m5mols_id); | ||
975 | |||
976 | static struct i2c_driver m5mols_i2c_driver = { | ||
977 | .driver = { | ||
978 | .name = MODULE_NAME, | ||
979 | }, | ||
980 | .probe = m5mols_probe, | ||
981 | .remove = __devexit_p(m5mols_remove), | ||
982 | .id_table = m5mols_id, | ||
983 | }; | ||
984 | |||
985 | module_i2c_driver(m5mols_i2c_driver); | ||
986 | |||
987 | MODULE_AUTHOR("HeungJun Kim <riverful.kim@samsung.com>"); | ||
988 | MODULE_AUTHOR("Dongsoo Kim <dongsoo45.kim@samsung.com>"); | ||
989 | MODULE_DESCRIPTION("Fujitsu M-5MOLS 8M Pixel camera driver"); | ||
990 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/i2c/m5mols/m5mols_reg.h b/drivers/media/i2c/m5mols/m5mols_reg.h new file mode 100644 index 000000000000..14d4be72aeff --- /dev/null +++ b/drivers/media/i2c/m5mols/m5mols_reg.h | |||
@@ -0,0 +1,362 @@ | |||
1 | /* | ||
2 | * Register map 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 | #ifndef M5MOLS_REG_H | ||
17 | #define M5MOLS_REG_H | ||
18 | |||
19 | #define M5MOLS_I2C_MAX_SIZE 4 | ||
20 | #define M5MOLS_BYTE_READ 0x01 | ||
21 | #define M5MOLS_BYTE_WRITE 0x02 | ||
22 | |||
23 | #define I2C_CATEGORY(__cat) ((__cat >> 16) & 0xff) | ||
24 | #define I2C_COMMAND(__comm) ((__comm >> 8) & 0xff) | ||
25 | #define I2C_SIZE(__reg_s) ((__reg_s) & 0xff) | ||
26 | #define I2C_REG(__cat, __cmd, __reg_s) ((__cat << 16) | (__cmd << 8) | __reg_s) | ||
27 | |||
28 | /* | ||
29 | * Category section register | ||
30 | * | ||
31 | * The category means set including relevant command of M-5MOLS. | ||
32 | */ | ||
33 | #define CAT_SYSTEM 0x00 | ||
34 | #define CAT_PARAM 0x01 | ||
35 | #define CAT_MONITOR 0x02 | ||
36 | #define CAT_AE 0x03 | ||
37 | #define CAT_WB 0x06 | ||
38 | #define CAT_EXIF 0x07 | ||
39 | #define CAT_FD 0x09 | ||
40 | #define CAT_LENS 0x0a | ||
41 | #define CAT_CAPT_PARM 0x0b | ||
42 | #define CAT_CAPT_CTRL 0x0c | ||
43 | #define CAT_FLASH 0x0f /* related to FW, revisions, booting */ | ||
44 | |||
45 | /* | ||
46 | * Category 0 - SYSTEM mode | ||
47 | * | ||
48 | * The SYSTEM mode in the M-5MOLS means area available to handle with the whole | ||
49 | * & all-round system of sensor. It deals with version/interrupt/setting mode & | ||
50 | * even sensor's status. Especially, the M-5MOLS sensor with ISP varies by | ||
51 | * packaging & manufacturer, even the customer and project code. And the | ||
52 | * function details may vary among them. The version information helps to | ||
53 | * determine what methods shall be used in the driver. | ||
54 | * | ||
55 | * There is many registers between customer version address and awb one. For | ||
56 | * more specific contents, see definition if file m5mols.h. | ||
57 | */ | ||
58 | #define SYSTEM_VER_CUSTOMER I2C_REG(CAT_SYSTEM, 0x00, 1) | ||
59 | #define SYSTEM_VER_PROJECT I2C_REG(CAT_SYSTEM, 0x01, 1) | ||
60 | #define SYSTEM_VER_FIRMWARE I2C_REG(CAT_SYSTEM, 0x02, 2) | ||
61 | #define SYSTEM_VER_HARDWARE I2C_REG(CAT_SYSTEM, 0x04, 2) | ||
62 | #define SYSTEM_VER_PARAMETER I2C_REG(CAT_SYSTEM, 0x06, 2) | ||
63 | #define SYSTEM_VER_AWB I2C_REG(CAT_SYSTEM, 0x08, 2) | ||
64 | |||
65 | #define SYSTEM_SYSMODE I2C_REG(CAT_SYSTEM, 0x0b, 1) | ||
66 | #define REG_SYSINIT 0x00 /* SYSTEM mode */ | ||
67 | #define REG_PARAMETER 0x01 /* PARAMETER mode */ | ||
68 | #define REG_MONITOR 0x02 /* MONITOR mode */ | ||
69 | #define REG_CAPTURE 0x03 /* CAPTURE mode */ | ||
70 | |||
71 | #define SYSTEM_CMD(__cmd) I2C_REG(CAT_SYSTEM, cmd, 1) | ||
72 | #define SYSTEM_VER_STRING I2C_REG(CAT_SYSTEM, 0x0a, 1) | ||
73 | #define REG_SAMSUNG_ELECTRO "SE" /* Samsung Electro-Mechanics */ | ||
74 | #define REG_SAMSUNG_OPTICS "OP" /* Samsung Fiber-Optics */ | ||
75 | #define REG_SAMSUNG_TECHWIN "TB" /* Samsung Techwin */ | ||
76 | /* SYSTEM mode status */ | ||
77 | #define SYSTEM_STATUS I2C_REG(CAT_SYSTEM, 0x0c, 1) | ||
78 | |||
79 | /* Interrupt pending register */ | ||
80 | #define SYSTEM_INT_FACTOR I2C_REG(CAT_SYSTEM, 0x10, 1) | ||
81 | /* interrupt enable register */ | ||
82 | #define SYSTEM_INT_ENABLE I2C_REG(CAT_SYSTEM, 0x11, 1) | ||
83 | #define REG_INT_MODE (1 << 0) | ||
84 | #define REG_INT_AF (1 << 1) | ||
85 | #define REG_INT_ZOOM (1 << 2) | ||
86 | #define REG_INT_CAPTURE (1 << 3) | ||
87 | #define REG_INT_FRAMESYNC (1 << 4) | ||
88 | #define REG_INT_FD (1 << 5) | ||
89 | #define REG_INT_LENS_INIT (1 << 6) | ||
90 | #define REG_INT_SOUND (1 << 7) | ||
91 | #define REG_INT_MASK 0x0f | ||
92 | |||
93 | /* | ||
94 | * category 1 - PARAMETER mode | ||
95 | * | ||
96 | * This category supports function of camera features of M-5MOLS. It means we | ||
97 | * can handle with preview(MONITOR) resolution size/frame per second/interface | ||
98 | * between the sensor and the Application Processor/even the image effect. | ||
99 | */ | ||
100 | |||
101 | /* Resolution in the MONITOR mode */ | ||
102 | #define PARM_MON_SIZE I2C_REG(CAT_PARAM, 0x01, 1) | ||
103 | |||
104 | /* Frame rate */ | ||
105 | #define PARM_MON_FPS I2C_REG(CAT_PARAM, 0x02, 1) | ||
106 | #define REG_FPS_30 0x02 | ||
107 | |||
108 | /* Video bus between the sensor and a host processor */ | ||
109 | #define PARM_INTERFACE I2C_REG(CAT_PARAM, 0x00, 1) | ||
110 | #define REG_INTERFACE_MIPI 0x02 | ||
111 | |||
112 | /* Image effects */ | ||
113 | #define PARM_EFFECT I2C_REG(CAT_PARAM, 0x0b, 1) | ||
114 | #define REG_EFFECT_OFF 0x00 | ||
115 | #define REG_EFFECT_NEGA 0x01 | ||
116 | #define REG_EFFECT_EMBOSS 0x06 | ||
117 | #define REG_EFFECT_OUTLINE 0x07 | ||
118 | #define REG_EFFECT_WATERCOLOR 0x08 | ||
119 | |||
120 | /* | ||
121 | * Category 2 - MONITOR mode | ||
122 | * | ||
123 | * The MONITOR mode is same as preview mode as we said. The M-5MOLS has another | ||
124 | * mode named "Preview", but this preview mode is used at the case specific | ||
125 | * vider-recording mode. This mmode supports only YUYV format. On the other | ||
126 | * hand, the JPEG & RAW formats is supports by CAPTURE mode. And, there are | ||
127 | * another options like zoom/color effect(different with effect in PARAMETER | ||
128 | * mode)/anti hand shaking algorithm. | ||
129 | */ | ||
130 | |||
131 | /* Target digital zoom position */ | ||
132 | #define MON_ZOOM I2C_REG(CAT_MONITOR, 0x01, 1) | ||
133 | |||
134 | /* CR value for color effect */ | ||
135 | #define MON_CFIXR I2C_REG(CAT_MONITOR, 0x0a, 1) | ||
136 | /* CB value for color effect */ | ||
137 | #define MON_CFIXB I2C_REG(CAT_MONITOR, 0x09, 1) | ||
138 | #define REG_CFIXB_SEPIA 0xd8 | ||
139 | #define REG_CFIXR_SEPIA 0x18 | ||
140 | |||
141 | #define MON_EFFECT I2C_REG(CAT_MONITOR, 0x0b, 1) | ||
142 | #define REG_COLOR_EFFECT_OFF 0x00 | ||
143 | #define REG_COLOR_EFFECT_ON 0x01 | ||
144 | |||
145 | /* Chroma enable */ | ||
146 | #define MON_CHROMA_EN I2C_REG(CAT_MONITOR, 0x10, 1) | ||
147 | /* Chroma level */ | ||
148 | #define MON_CHROMA_LVL I2C_REG(CAT_MONITOR, 0x0f, 1) | ||
149 | #define REG_CHROMA_OFF 0x00 | ||
150 | #define REG_CHROMA_ON 0x01 | ||
151 | |||
152 | /* Sharpness on/off */ | ||
153 | #define MON_EDGE_EN I2C_REG(CAT_MONITOR, 0x12, 1) | ||
154 | /* Sharpness level */ | ||
155 | #define MON_EDGE_LVL I2C_REG(CAT_MONITOR, 0x11, 1) | ||
156 | #define REG_EDGE_OFF 0x00 | ||
157 | #define REG_EDGE_ON 0x01 | ||
158 | |||
159 | /* Set color tone (contrast) */ | ||
160 | #define MON_TONE_CTL I2C_REG(CAT_MONITOR, 0x25, 1) | ||
161 | |||
162 | /* | ||
163 | * Category 3 - Auto Exposure | ||
164 | * | ||
165 | * The M-5MOLS exposure capbility is detailed as which is similar to digital | ||
166 | * camera. This category supports AE locking/various AE mode(range of exposure) | ||
167 | * /ISO/flickering/EV bias/shutter/meteoring, and anything else. And the | ||
168 | * maximum/minimum exposure gain value depending on M-5MOLS firmware, may be | ||
169 | * different. So, this category also provide getting the max/min values. And, | ||
170 | * each MONITOR and CAPTURE mode has each gain/shutter/max exposure values. | ||
171 | */ | ||
172 | |||
173 | /* Auto Exposure locking */ | ||
174 | #define AE_LOCK I2C_REG(CAT_AE, 0x00, 1) | ||
175 | #define REG_AE_UNLOCK 0x00 | ||
176 | #define REG_AE_LOCK 0x01 | ||
177 | |||
178 | /* Auto Exposure algorithm mode */ | ||
179 | #define AE_MODE I2C_REG(CAT_AE, 0x01, 1) | ||
180 | #define REG_AE_OFF 0x00 /* AE off */ | ||
181 | #define REG_AE_ALL 0x01 /* calc AE in all block integral */ | ||
182 | #define REG_AE_CENTER 0x03 /* calc AE in center weighted */ | ||
183 | #define REG_AE_SPOT 0x06 /* calc AE in specific spot */ | ||
184 | |||
185 | #define AE_ISO I2C_REG(CAT_AE, 0x05, 1) | ||
186 | #define REG_ISO_AUTO 0x00 | ||
187 | #define REG_ISO_50 0x01 | ||
188 | #define REG_ISO_100 0x02 | ||
189 | #define REG_ISO_200 0x03 | ||
190 | #define REG_ISO_400 0x04 | ||
191 | #define REG_ISO_800 0x05 | ||
192 | |||
193 | /* EV (scenemode) preset for MONITOR */ | ||
194 | #define AE_EV_PRESET_MONITOR I2C_REG(CAT_AE, 0x0a, 1) | ||
195 | /* EV (scenemode) preset for CAPTURE */ | ||
196 | #define AE_EV_PRESET_CAPTURE I2C_REG(CAT_AE, 0x0b, 1) | ||
197 | #define REG_SCENE_NORMAL 0x00 | ||
198 | #define REG_SCENE_PORTRAIT 0x01 | ||
199 | #define REG_SCENE_LANDSCAPE 0x02 | ||
200 | #define REG_SCENE_SPORTS 0x03 | ||
201 | #define REG_SCENE_PARTY_INDOOR 0x04 | ||
202 | #define REG_SCENE_BEACH_SNOW 0x05 | ||
203 | #define REG_SCENE_SUNSET 0x06 | ||
204 | #define REG_SCENE_DAWN_DUSK 0x07 | ||
205 | #define REG_SCENE_FALL 0x08 | ||
206 | #define REG_SCENE_NIGHT 0x09 | ||
207 | #define REG_SCENE_AGAINST_LIGHT 0x0a | ||
208 | #define REG_SCENE_FIRE 0x0b | ||
209 | #define REG_SCENE_TEXT 0x0c | ||
210 | #define REG_SCENE_CANDLE 0x0d | ||
211 | |||
212 | /* Manual gain in MONITOR mode */ | ||
213 | #define AE_MAN_GAIN_MON I2C_REG(CAT_AE, 0x12, 2) | ||
214 | /* Maximum gain in MONITOR mode */ | ||
215 | #define AE_MAX_GAIN_MON I2C_REG(CAT_AE, 0x1a, 2) | ||
216 | /* Manual gain in CAPTURE mode */ | ||
217 | #define AE_MAN_GAIN_CAP I2C_REG(CAT_AE, 0x26, 2) | ||
218 | |||
219 | #define AE_INDEX I2C_REG(CAT_AE, 0x38, 1) | ||
220 | #define REG_AE_INDEX_20_NEG 0x00 | ||
221 | #define REG_AE_INDEX_15_NEG 0x01 | ||
222 | #define REG_AE_INDEX_10_NEG 0x02 | ||
223 | #define REG_AE_INDEX_05_NEG 0x03 | ||
224 | #define REG_AE_INDEX_00 0x04 | ||
225 | #define REG_AE_INDEX_05_POS 0x05 | ||
226 | #define REG_AE_INDEX_10_POS 0x06 | ||
227 | #define REG_AE_INDEX_15_POS 0x07 | ||
228 | #define REG_AE_INDEX_20_POS 0x08 | ||
229 | |||
230 | /* | ||
231 | * Category 6 - White Balance | ||
232 | */ | ||
233 | |||
234 | /* Auto Whitebalance locking */ | ||
235 | #define AWB_LOCK I2C_REG(CAT_WB, 0x00, 1) | ||
236 | #define REG_AWB_UNLOCK 0x00 | ||
237 | #define REG_AWB_LOCK 0x01 | ||
238 | |||
239 | #define AWB_MODE I2C_REG(CAT_WB, 0x02, 1) | ||
240 | #define REG_AWB_AUTO 0x01 /* AWB off */ | ||
241 | #define REG_AWB_PRESET 0x02 /* AWB preset */ | ||
242 | |||
243 | /* Manual WB (preset) */ | ||
244 | #define AWB_MANUAL I2C_REG(CAT_WB, 0x03, 1) | ||
245 | #define REG_AWB_INCANDESCENT 0x01 | ||
246 | #define REG_AWB_FLUORESCENT_1 0x02 | ||
247 | #define REG_AWB_FLUORESCENT_2 0x03 | ||
248 | #define REG_AWB_DAYLIGHT 0x04 | ||
249 | #define REG_AWB_CLOUDY 0x05 | ||
250 | #define REG_AWB_SHADE 0x06 | ||
251 | #define REG_AWB_HORIZON 0x07 | ||
252 | #define REG_AWB_LEDLIGHT 0x09 | ||
253 | |||
254 | /* | ||
255 | * Category 7 - EXIF information | ||
256 | */ | ||
257 | #define EXIF_INFO_EXPTIME_NU I2C_REG(CAT_EXIF, 0x00, 4) | ||
258 | #define EXIF_INFO_EXPTIME_DE I2C_REG(CAT_EXIF, 0x04, 4) | ||
259 | #define EXIF_INFO_TV_NU I2C_REG(CAT_EXIF, 0x08, 4) | ||
260 | #define EXIF_INFO_TV_DE I2C_REG(CAT_EXIF, 0x0c, 4) | ||
261 | #define EXIF_INFO_AV_NU I2C_REG(CAT_EXIF, 0x10, 4) | ||
262 | #define EXIF_INFO_AV_DE I2C_REG(CAT_EXIF, 0x14, 4) | ||
263 | #define EXIF_INFO_BV_NU I2C_REG(CAT_EXIF, 0x18, 4) | ||
264 | #define EXIF_INFO_BV_DE I2C_REG(CAT_EXIF, 0x1c, 4) | ||
265 | #define EXIF_INFO_EBV_NU I2C_REG(CAT_EXIF, 0x20, 4) | ||
266 | #define EXIF_INFO_EBV_DE I2C_REG(CAT_EXIF, 0x24, 4) | ||
267 | #define EXIF_INFO_ISO I2C_REG(CAT_EXIF, 0x28, 2) | ||
268 | #define EXIF_INFO_FLASH I2C_REG(CAT_EXIF, 0x2a, 2) | ||
269 | #define EXIF_INFO_SDR I2C_REG(CAT_EXIF, 0x2c, 2) | ||
270 | #define EXIF_INFO_QVAL I2C_REG(CAT_EXIF, 0x2e, 2) | ||
271 | |||
272 | /* | ||
273 | * Category 9 - Face Detection | ||
274 | */ | ||
275 | #define FD_CTL I2C_REG(CAT_FD, 0x00, 1) | ||
276 | #define BIT_FD_EN 0 | ||
277 | #define BIT_FD_DRAW_FACE_FRAME 4 | ||
278 | #define BIT_FD_DRAW_SMILE_LVL 6 | ||
279 | #define REG_FD(shift) (1 << shift) | ||
280 | #define REG_FD_OFF 0x0 | ||
281 | |||
282 | /* | ||
283 | * Category A - Lens Parameter | ||
284 | */ | ||
285 | #define AF_MODE I2C_REG(CAT_LENS, 0x01, 1) | ||
286 | #define REG_AF_NORMAL 0x00 /* Normal AF, one time */ | ||
287 | #define REG_AF_MACRO 0x01 /* Macro AF, one time */ | ||
288 | #define REG_AF_POWEROFF 0x07 | ||
289 | |||
290 | #define AF_EXECUTE I2C_REG(CAT_LENS, 0x02, 1) | ||
291 | #define REG_AF_STOP 0x00 | ||
292 | #define REG_AF_EXE_AUTO 0x01 | ||
293 | #define REG_AF_EXE_CAF 0x02 | ||
294 | |||
295 | #define AF_STATUS I2C_REG(CAT_LENS, 0x03, 1) | ||
296 | #define REG_AF_FAIL 0x00 | ||
297 | #define REG_AF_SUCCESS 0x02 | ||
298 | #define REG_AF_IDLE 0x04 | ||
299 | #define REG_AF_BUSY 0x05 | ||
300 | |||
301 | #define AF_VERSION I2C_REG(CAT_LENS, 0x0a, 1) | ||
302 | |||
303 | /* | ||
304 | * Category B - CAPTURE Parameter | ||
305 | */ | ||
306 | #define CAPP_YUVOUT_MAIN I2C_REG(CAT_CAPT_PARM, 0x00, 1) | ||
307 | #define REG_YUV422 0x00 | ||
308 | #define REG_BAYER10 0x05 | ||
309 | #define REG_BAYER8 0x06 | ||
310 | #define REG_JPEG 0x10 | ||
311 | |||
312 | #define CAPP_MAIN_IMAGE_SIZE I2C_REG(CAT_CAPT_PARM, 0x01, 1) | ||
313 | #define CAPP_JPEG_RATIO I2C_REG(CAT_CAPT_PARM, 0x17, 1) | ||
314 | |||
315 | #define CAPP_MCC_MODE I2C_REG(CAT_CAPT_PARM, 0x1d, 1) | ||
316 | #define REG_MCC_OFF 0x00 | ||
317 | #define REG_MCC_NORMAL 0x01 | ||
318 | |||
319 | #define CAPP_WDR_EN I2C_REG(CAT_CAPT_PARM, 0x2c, 1) | ||
320 | #define REG_WDR_OFF 0x00 | ||
321 | #define REG_WDR_ON 0x01 | ||
322 | #define REG_WDR_AUTO 0x02 | ||
323 | |||
324 | #define CAPP_LIGHT_CTRL I2C_REG(CAT_CAPT_PARM, 0x40, 1) | ||
325 | #define REG_LIGHT_OFF 0x00 | ||
326 | #define REG_LIGHT_ON 0x01 | ||
327 | #define REG_LIGHT_AUTO 0x02 | ||
328 | |||
329 | #define CAPP_FLASH_CTRL I2C_REG(CAT_CAPT_PARM, 0x41, 1) | ||
330 | #define REG_FLASH_OFF 0x00 | ||
331 | #define REG_FLASH_ON 0x01 | ||
332 | #define REG_FLASH_AUTO 0x02 | ||
333 | |||
334 | /* | ||
335 | * Category C - CAPTURE Control | ||
336 | */ | ||
337 | #define CAPC_MODE I2C_REG(CAT_CAPT_CTRL, 0x00, 1) | ||
338 | #define REG_CAP_NONE 0x00 | ||
339 | #define REG_CAP_ANTI_SHAKE 0x02 | ||
340 | |||
341 | /* Select single- or multi-shot capture */ | ||
342 | #define CAPC_SEL_FRAME I2C_REG(CAT_CAPT_CTRL, 0x06, 1) | ||
343 | |||
344 | #define CAPC_START I2C_REG(CAT_CAPT_CTRL, 0x09, 1) | ||
345 | #define REG_CAP_START_MAIN 0x01 | ||
346 | #define REG_CAP_START_THUMB 0x03 | ||
347 | |||
348 | #define CAPC_IMAGE_SIZE I2C_REG(CAT_CAPT_CTRL, 0x0d, 4) | ||
349 | #define CAPC_THUMB_SIZE I2C_REG(CAT_CAPT_CTRL, 0x11, 4) | ||
350 | |||
351 | /* | ||
352 | * Category F - Flash | ||
353 | * | ||
354 | * This mode provides functions about internal flash stuff and system startup. | ||
355 | */ | ||
356 | |||
357 | /* Starts internal ARM core booting after power-up */ | ||
358 | #define FLASH_CAM_START I2C_REG(CAT_FLASH, 0x12, 1) | ||
359 | #define REG_START_ARM_BOOT 0x01 /* write value */ | ||
360 | #define REG_IN_FLASH_MODE 0x00 /* read value */ | ||
361 | |||
362 | #endif /* M5MOLS_REG_H */ | ||