diff options
Diffstat (limited to 'drivers/media/video/m5mols')
-rw-r--r-- | drivers/media/video/m5mols/Kconfig | 5 | ||||
-rw-r--r-- | drivers/media/video/m5mols/Makefile | 3 | ||||
-rw-r--r-- | drivers/media/video/m5mols/m5mols.h | 297 | ||||
-rw-r--r-- | drivers/media/video/m5mols/m5mols_capture.c | 189 | ||||
-rw-r--r-- | drivers/media/video/m5mols/m5mols_controls.c | 299 | ||||
-rw-r--r-- | drivers/media/video/m5mols/m5mols_core.c | 1041 | ||||
-rw-r--r-- | drivers/media/video/m5mols/m5mols_reg.h | 410 |
7 files changed, 2244 insertions, 0 deletions
diff --git a/drivers/media/video/m5mols/Kconfig b/drivers/media/video/m5mols/Kconfig new file mode 100644 index 00000000000..302dc3d7019 --- /dev/null +++ b/drivers/media/video/m5mols/Kconfig | |||
@@ -0,0 +1,5 @@ | |||
1 | config VIDEO_M5MOLS | ||
2 | tristate "Fujitsu M-5MOLS 8MP sensor support" | ||
3 | depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API | ||
4 | ---help--- | ||
5 | This driver supports Fujitsu M-5MOLS camera sensor with ISP | ||
diff --git a/drivers/media/video/m5mols/Makefile b/drivers/media/video/m5mols/Makefile new file mode 100644 index 00000000000..0a44e028edc --- /dev/null +++ b/drivers/media/video/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/video/m5mols/m5mols.h b/drivers/media/video/m5mols/m5mols.h new file mode 100644 index 00000000000..89d09a8914f --- /dev/null +++ b/drivers/media/video/m5mols/m5mols.h | |||
@@ -0,0 +1,297 @@ | |||
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 | #define to_m5mols(__sd) container_of(__sd, struct m5mols_info, sd) | ||
25 | |||
26 | #define to_sd(__ctrl) \ | ||
27 | (&container_of(__ctrl->handler, struct m5mols_info, handle)->sd) | ||
28 | |||
29 | enum m5mols_restype { | ||
30 | M5MOLS_RESTYPE_MONITOR, | ||
31 | M5MOLS_RESTYPE_CAPTURE, | ||
32 | M5MOLS_RESTYPE_MAX, | ||
33 | }; | ||
34 | |||
35 | /** | ||
36 | * struct m5mols_resolution - structure for the resolution | ||
37 | * @type: resolution type according to the pixel code | ||
38 | * @width: width of the resolution | ||
39 | * @height: height of the resolution | ||
40 | * @reg: resolution preset register value | ||
41 | */ | ||
42 | struct m5mols_resolution { | ||
43 | u8 reg; | ||
44 | enum m5mols_restype type; | ||
45 | u16 width; | ||
46 | u16 height; | ||
47 | }; | ||
48 | |||
49 | /** | ||
50 | * struct m5mols_exif - structure for the EXIF information of M-5MOLS | ||
51 | * @exposure_time: exposure time register value | ||
52 | * @shutter_speed: speed of the shutter register value | ||
53 | * @aperture: aperture register value | ||
54 | * @exposure_bias: it calls also EV bias | ||
55 | * @iso_speed: ISO register value | ||
56 | * @flash: status register value of the flash | ||
57 | * @sdr: status register value of the Subject Distance Range | ||
58 | * @qval: not written exact meaning in document | ||
59 | */ | ||
60 | struct m5mols_exif { | ||
61 | u32 exposure_time; | ||
62 | u32 shutter_speed; | ||
63 | u32 aperture; | ||
64 | u32 brightness; | ||
65 | u32 exposure_bias; | ||
66 | u16 iso_speed; | ||
67 | u16 flash; | ||
68 | u16 sdr; | ||
69 | u16 qval; | ||
70 | }; | ||
71 | |||
72 | /** | ||
73 | * struct m5mols_capture - Structure for the capture capability | ||
74 | * @exif: EXIF information | ||
75 | * @main: size in bytes of the main image | ||
76 | * @thumb: size in bytes of the thumb image, if it was accompanied | ||
77 | * @total: total size in bytes of the produced image | ||
78 | */ | ||
79 | struct m5mols_capture { | ||
80 | struct m5mols_exif exif; | ||
81 | u32 main; | ||
82 | u32 thumb; | ||
83 | u32 total; | ||
84 | }; | ||
85 | |||
86 | /** | ||
87 | * struct m5mols_scenemode - structure for the scenemode capability | ||
88 | * @metering: metering light register value | ||
89 | * @ev_bias: EV bias register value | ||
90 | * @wb_mode: mode which means the WhiteBalance is Auto or Manual | ||
91 | * @wb_preset: whitebalance preset register value in the Manual mode | ||
92 | * @chroma_en: register value whether the Chroma capability is enabled or not | ||
93 | * @chroma_lvl: chroma's level register value | ||
94 | * @edge_en: register value Whether the Edge capability is enabled or not | ||
95 | * @edge_lvl: edge's level register value | ||
96 | * @af_range: Auto Focus's range | ||
97 | * @fd_mode: Face Detection mode | ||
98 | * @mcc: Multi-axis Color Conversion which means emotion color | ||
99 | * @light: status of the Light | ||
100 | * @flash: status of the Flash | ||
101 | * @tone: Tone color which means Contrast | ||
102 | * @iso: ISO register value | ||
103 | * @capt_mode: Mode of the Image Stabilization while the camera capturing | ||
104 | * @wdr: Wide Dynamic Range register value | ||
105 | * | ||
106 | * The each value according to each scenemode is recommended in the documents. | ||
107 | */ | ||
108 | struct m5mols_scenemode { | ||
109 | u8 metering; | ||
110 | u8 ev_bias; | ||
111 | u8 wb_mode; | ||
112 | u8 wb_preset; | ||
113 | u8 chroma_en; | ||
114 | u8 chroma_lvl; | ||
115 | u8 edge_en; | ||
116 | u8 edge_lvl; | ||
117 | u8 af_range; | ||
118 | u8 fd_mode; | ||
119 | u8 mcc; | ||
120 | u8 light; | ||
121 | u8 flash; | ||
122 | u8 tone; | ||
123 | u8 iso; | ||
124 | u8 capt_mode; | ||
125 | u8 wdr; | ||
126 | }; | ||
127 | |||
128 | /** | ||
129 | * struct m5mols_version - firmware version information | ||
130 | * @customer: customer information | ||
131 | * @project: version of project information according to customer | ||
132 | * @fw: firmware revision | ||
133 | * @hw: hardware revision | ||
134 | * @param: version of the parameter | ||
135 | * @awb: Auto WhiteBalance algorithm version | ||
136 | * @str: information about manufacturer and packaging vendor | ||
137 | * @af: Auto Focus version | ||
138 | * | ||
139 | * The register offset starts the customer version at 0x0, and it ends | ||
140 | * the awb version at 0x09. The customer, project information occupies 1 bytes | ||
141 | * each. And also the fw, hw, param, awb each requires 2 bytes. The str is | ||
142 | * unique string associated with firmware's version. It includes information | ||
143 | * about manufacturer and the vendor of the sensor's packaging. The least | ||
144 | * significant 2 bytes of the string indicate packaging manufacturer. | ||
145 | */ | ||
146 | #define VERSION_STRING_SIZE 22 | ||
147 | struct m5mols_version { | ||
148 | u8 customer; | ||
149 | u8 project; | ||
150 | u16 fw; | ||
151 | u16 hw; | ||
152 | u16 param; | ||
153 | u16 awb; | ||
154 | u8 str[VERSION_STRING_SIZE]; | ||
155 | u8 af; | ||
156 | }; | ||
157 | |||
158 | /** | ||
159 | * struct m5mols_info - M-5MOLS driver data structure | ||
160 | * @pdata: platform data | ||
161 | * @sd: v4l-subdev instance | ||
162 | * @pad: media pad | ||
163 | * @ffmt: current fmt according to resolution type | ||
164 | * @res_type: current resolution type | ||
165 | * @code: current code | ||
166 | * @irq_waitq: waitqueue for the capture | ||
167 | * @work_irq: workqueue for the IRQ | ||
168 | * @flags: state variable for the interrupt handler | ||
169 | * @handle: control handler | ||
170 | * @autoexposure: Auto Exposure control | ||
171 | * @exposure: Exposure control | ||
172 | * @autowb: Auto White Balance control | ||
173 | * @colorfx: Color effect control | ||
174 | * @saturation: Saturation control | ||
175 | * @zoom: Zoom control | ||
176 | * @ver: information of the version | ||
177 | * @cap: the capture mode attributes | ||
178 | * @power: current sensor's power status | ||
179 | * @ctrl_sync: true means all controls of the sensor are initialized | ||
180 | * @int_capture: true means the capture interrupt is issued once | ||
181 | * @lock_ae: true means the Auto Exposure is locked | ||
182 | * @lock_awb: true means the Aut WhiteBalance is locked | ||
183 | * @resolution: register value for current resolution | ||
184 | * @interrupt: register value for current interrupt status | ||
185 | * @mode: register value for current operation mode | ||
186 | * @mode_save: register value for current operation mode for saving | ||
187 | * @set_power: optional power callback to the board code | ||
188 | */ | ||
189 | struct m5mols_info { | ||
190 | const struct m5mols_platform_data *pdata; | ||
191 | struct v4l2_subdev sd; | ||
192 | struct media_pad pad; | ||
193 | struct v4l2_mbus_framefmt ffmt[M5MOLS_RESTYPE_MAX]; | ||
194 | int res_type; | ||
195 | enum v4l2_mbus_pixelcode code; | ||
196 | wait_queue_head_t irq_waitq; | ||
197 | struct work_struct work_irq; | ||
198 | unsigned long flags; | ||
199 | |||
200 | struct v4l2_ctrl_handler handle; | ||
201 | /* Autoexposure/exposure control cluster */ | ||
202 | struct { | ||
203 | struct v4l2_ctrl *autoexposure; | ||
204 | struct v4l2_ctrl *exposure; | ||
205 | }; | ||
206 | struct v4l2_ctrl *autowb; | ||
207 | struct v4l2_ctrl *colorfx; | ||
208 | struct v4l2_ctrl *saturation; | ||
209 | struct v4l2_ctrl *zoom; | ||
210 | |||
211 | struct m5mols_version ver; | ||
212 | struct m5mols_capture cap; | ||
213 | bool power; | ||
214 | bool ctrl_sync; | ||
215 | bool lock_ae; | ||
216 | bool lock_awb; | ||
217 | u8 resolution; | ||
218 | u8 interrupt; | ||
219 | u8 mode; | ||
220 | u8 mode_save; | ||
221 | int (*set_power)(struct device *dev, int on); | ||
222 | }; | ||
223 | |||
224 | #define ST_CAPT_IRQ 0 | ||
225 | |||
226 | #define is_powered(__info) (__info->power) | ||
227 | #define is_ctrl_synced(__info) (__info->ctrl_sync) | ||
228 | #define is_available_af(__info) (__info->ver.af) | ||
229 | #define is_code(__code, __type) (__code == m5mols_default_ffmt[__type].code) | ||
230 | #define is_manufacturer(__info, __manufacturer) \ | ||
231 | (__info->ver.str[0] == __manufacturer[0] && \ | ||
232 | __info->ver.str[1] == __manufacturer[1]) | ||
233 | /* | ||
234 | * I2C operation of the M-5MOLS | ||
235 | * | ||
236 | * The I2C read operation of the M-5MOLS requires 2 messages. The first | ||
237 | * message sends the information about the command, command category, and total | ||
238 | * message size. The second message is used to retrieve the data specifed in | ||
239 | * the first message | ||
240 | * | ||
241 | * 1st message 2nd message | ||
242 | * +-------+---+----------+-----+-------+ +------+------+------+------+ | ||
243 | * | size1 | R | category | cmd | size2 | | d[0] | d[1] | d[2] | d[3] | | ||
244 | * +-------+---+----------+-----+-------+ +------+------+------+------+ | ||
245 | * - size1: message data size(5 in this case) | ||
246 | * - size2: desired buffer size of the 2nd message | ||
247 | * - d[0..3]: according to size2 | ||
248 | * | ||
249 | * The I2C write operation needs just one message. The message includes | ||
250 | * category, command, total size, and desired data. | ||
251 | * | ||
252 | * 1st message | ||
253 | * +-------+---+----------+-----+------+------+------+------+ | ||
254 | * | size1 | W | category | cmd | d[0] | d[1] | d[2] | d[3] | | ||
255 | * +-------+---+----------+-----+------+------+------+------+ | ||
256 | * - d[0..3]: according to size1 | ||
257 | */ | ||
258 | int m5mols_read_u8(struct v4l2_subdev *sd, u32 reg_comb, u8 *val); | ||
259 | int m5mols_read_u16(struct v4l2_subdev *sd, u32 reg_comb, u16 *val); | ||
260 | int m5mols_read_u32(struct v4l2_subdev *sd, u32 reg_comb, u32 *val); | ||
261 | int m5mols_write(struct v4l2_subdev *sd, u32 reg_comb, u32 val); | ||
262 | int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u8 value); | ||
263 | |||
264 | /* | ||
265 | * Mode operation of the M-5MOLS | ||
266 | * | ||
267 | * Changing the mode of the M-5MOLS is needed right executing order. | ||
268 | * There are three modes(PARAMETER, MONITOR, CAPTURE) which can be changed | ||
269 | * by user. There are various categories associated with each mode. | ||
270 | * | ||
271 | * +============================================================+ | ||
272 | * | mode | category | | ||
273 | * +============================================================+ | ||
274 | * | FLASH | FLASH(only after Stand-by or Power-on) | | ||
275 | * | SYSTEM | SYSTEM(only after sensor arm-booting) | | ||
276 | * | PARAMETER | PARAMETER | | ||
277 | * | MONITOR | MONITOR(preview), Auto Focus, Face Detection | | ||
278 | * | CAPTURE | Single CAPTURE, Preview(recording) | | ||
279 | * +============================================================+ | ||
280 | * | ||
281 | * The available executing order between each modes are as follows: | ||
282 | * PARAMETER <---> MONITOR <---> CAPTURE | ||
283 | */ | ||
284 | int m5mols_mode(struct m5mols_info *info, u8 mode); | ||
285 | |||
286 | int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg); | ||
287 | int m5mols_sync_controls(struct m5mols_info *info); | ||
288 | int m5mols_start_capture(struct m5mols_info *info); | ||
289 | int m5mols_do_scenemode(struct m5mols_info *info, u8 mode); | ||
290 | int m5mols_lock_3a(struct m5mols_info *info, bool lock); | ||
291 | int m5mols_set_ctrl(struct v4l2_ctrl *ctrl); | ||
292 | |||
293 | /* The firmware function */ | ||
294 | int m5mols_update_fw(struct v4l2_subdev *sd, | ||
295 | int (*set_power)(struct m5mols_info *, bool)); | ||
296 | |||
297 | #endif /* M5MOLS_H */ | ||
diff --git a/drivers/media/video/m5mols/m5mols_capture.c b/drivers/media/video/m5mols/m5mols_capture.c new file mode 100644 index 00000000000..3248ac80571 --- /dev/null +++ b/drivers/media/video/m5mols/m5mols_capture.c | |||
@@ -0,0 +1,189 @@ | |||
1 | /* | ||
2 | * The Capture code for Fujitsu M-5MOLS 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 <media/v4l2-ctrls.h> | ||
25 | #include <media/v4l2-device.h> | ||
26 | #include <media/v4l2-subdev.h> | ||
27 | #include <media/m5mols.h> | ||
28 | |||
29 | #include "m5mols.h" | ||
30 | #include "m5mols_reg.h" | ||
31 | |||
32 | static int m5mols_capture_error_handler(struct m5mols_info *info, | ||
33 | int timeout) | ||
34 | { | ||
35 | int ret; | ||
36 | |||
37 | /* Disable all interrupts and clear relevant interrupt staus bits */ | ||
38 | ret = m5mols_write(&info->sd, SYSTEM_INT_ENABLE, | ||
39 | info->interrupt & ~(REG_INT_CAPTURE)); | ||
40 | if (ret) | ||
41 | return ret; | ||
42 | |||
43 | if (timeout == 0) | ||
44 | return -ETIMEDOUT; | ||
45 | |||
46 | return 0; | ||
47 | } | ||
48 | /** | ||
49 | * m5mols_read_rational - I2C read of a rational number | ||
50 | * | ||
51 | * Read numerator and denominator from registers @addr_num and @addr_den | ||
52 | * respectively and return the division result in @val. | ||
53 | */ | ||
54 | static int m5mols_read_rational(struct v4l2_subdev *sd, u32 addr_num, | ||
55 | u32 addr_den, u32 *val) | ||
56 | { | ||
57 | u32 num, den; | ||
58 | |||
59 | int ret = m5mols_read_u32(sd, addr_num, &num); | ||
60 | if (!ret) | ||
61 | ret = m5mols_read_u32(sd, addr_den, &den); | ||
62 | if (ret) | ||
63 | return ret; | ||
64 | *val = den == 0 ? 0 : num / den; | ||
65 | return ret; | ||
66 | } | ||
67 | |||
68 | /** | ||
69 | * m5mols_capture_info - Gather captured image information | ||
70 | * | ||
71 | * For now it gathers only EXIF information and file size. | ||
72 | */ | ||
73 | static int m5mols_capture_info(struct m5mols_info *info) | ||
74 | { | ||
75 | struct m5mols_exif *exif = &info->cap.exif; | ||
76 | struct v4l2_subdev *sd = &info->sd; | ||
77 | int ret; | ||
78 | |||
79 | ret = m5mols_read_rational(sd, EXIF_INFO_EXPTIME_NU, | ||
80 | EXIF_INFO_EXPTIME_DE, &exif->exposure_time); | ||
81 | if (ret) | ||
82 | return ret; | ||
83 | ret = m5mols_read_rational(sd, EXIF_INFO_TV_NU, EXIF_INFO_TV_DE, | ||
84 | &exif->shutter_speed); | ||
85 | if (ret) | ||
86 | return ret; | ||
87 | ret = m5mols_read_rational(sd, EXIF_INFO_AV_NU, EXIF_INFO_AV_DE, | ||
88 | &exif->aperture); | ||
89 | if (ret) | ||
90 | return ret; | ||
91 | ret = m5mols_read_rational(sd, EXIF_INFO_BV_NU, EXIF_INFO_BV_DE, | ||
92 | &exif->brightness); | ||
93 | if (ret) | ||
94 | return ret; | ||
95 | ret = m5mols_read_rational(sd, EXIF_INFO_EBV_NU, EXIF_INFO_EBV_DE, | ||
96 | &exif->exposure_bias); | ||
97 | if (ret) | ||
98 | return ret; | ||
99 | |||
100 | ret = m5mols_read_u16(sd, EXIF_INFO_ISO, &exif->iso_speed); | ||
101 | if (!ret) | ||
102 | ret = m5mols_read_u16(sd, EXIF_INFO_FLASH, &exif->flash); | ||
103 | if (!ret) | ||
104 | ret = m5mols_read_u16(sd, EXIF_INFO_SDR, &exif->sdr); | ||
105 | if (!ret) | ||
106 | ret = m5mols_read_u16(sd, EXIF_INFO_QVAL, &exif->qval); | ||
107 | if (ret) | ||
108 | return ret; | ||
109 | |||
110 | if (!ret) | ||
111 | ret = m5mols_read_u32(sd, CAPC_IMAGE_SIZE, &info->cap.main); | ||
112 | if (!ret) | ||
113 | ret = m5mols_read_u32(sd, CAPC_THUMB_SIZE, &info->cap.thumb); | ||
114 | if (!ret) | ||
115 | info->cap.total = info->cap.main + info->cap.thumb; | ||
116 | |||
117 | return ret; | ||
118 | } | ||
119 | |||
120 | int m5mols_start_capture(struct m5mols_info *info) | ||
121 | { | ||
122 | struct v4l2_subdev *sd = &info->sd; | ||
123 | u8 resolution = info->resolution; | ||
124 | int timeout; | ||
125 | int ret; | ||
126 | |||
127 | /* | ||
128 | * Preparing capture. Setting control & interrupt before entering | ||
129 | * capture mode | ||
130 | * | ||
131 | * 1) change to MONITOR mode for operating control & interrupt | ||
132 | * 2) set controls (considering v4l2_control value & lock 3A) | ||
133 | * 3) set interrupt | ||
134 | * 4) change to CAPTURE mode | ||
135 | */ | ||
136 | ret = m5mols_mode(info, REG_MONITOR); | ||
137 | if (!ret) | ||
138 | ret = m5mols_sync_controls(info); | ||
139 | if (!ret) | ||
140 | ret = m5mols_lock_3a(info, true); | ||
141 | if (!ret) | ||
142 | ret = m5mols_enable_interrupt(sd, REG_INT_CAPTURE); | ||
143 | if (!ret) | ||
144 | ret = m5mols_mode(info, REG_CAPTURE); | ||
145 | if (!ret) { | ||
146 | /* Wait for capture interrupt, after changing capture mode */ | ||
147 | timeout = wait_event_interruptible_timeout(info->irq_waitq, | ||
148 | test_bit(ST_CAPT_IRQ, &info->flags), | ||
149 | msecs_to_jiffies(2000)); | ||
150 | if (test_and_clear_bit(ST_CAPT_IRQ, &info->flags)) | ||
151 | ret = m5mols_capture_error_handler(info, timeout); | ||
152 | } | ||
153 | if (!ret) | ||
154 | ret = m5mols_lock_3a(info, false); | ||
155 | if (ret) | ||
156 | return ret; | ||
157 | /* | ||
158 | * Starting capture. Setting capture frame count and resolution and | ||
159 | * the format(available format: JPEG, Bayer RAW, YUV). | ||
160 | * | ||
161 | * 1) select single or multi(enable to 25), format, size | ||
162 | * 2) set interrupt | ||
163 | * 3) start capture(for main image, now) | ||
164 | * 4) get information | ||
165 | * 5) notify file size to v4l2 device(e.g, to s5p-fimc v4l2 device) | ||
166 | */ | ||
167 | ret = m5mols_write(sd, CAPC_SEL_FRAME, 1); | ||
168 | if (!ret) | ||
169 | ret = m5mols_write(sd, CAPP_YUVOUT_MAIN, REG_JPEG); | ||
170 | if (!ret) | ||
171 | ret = m5mols_write(sd, CAPP_MAIN_IMAGE_SIZE, resolution); | ||
172 | if (!ret) | ||
173 | ret = m5mols_enable_interrupt(sd, REG_INT_CAPTURE); | ||
174 | if (!ret) | ||
175 | ret = m5mols_write(sd, CAPC_START, REG_CAP_START_MAIN); | ||
176 | if (!ret) { | ||
177 | /* Wait for the capture completion interrupt */ | ||
178 | timeout = wait_event_interruptible_timeout(info->irq_waitq, | ||
179 | test_bit(ST_CAPT_IRQ, &info->flags), | ||
180 | msecs_to_jiffies(2000)); | ||
181 | if (test_and_clear_bit(ST_CAPT_IRQ, &info->flags)) { | ||
182 | ret = m5mols_capture_info(info); | ||
183 | if (!ret) | ||
184 | v4l2_subdev_notify(sd, 0, &info->cap.total); | ||
185 | } | ||
186 | } | ||
187 | |||
188 | return m5mols_capture_error_handler(info, timeout); | ||
189 | } | ||
diff --git a/drivers/media/video/m5mols/m5mols_controls.c b/drivers/media/video/m5mols/m5mols_controls.c new file mode 100644 index 00000000000..d135d20d09c --- /dev/null +++ b/drivers/media/video/m5mols/m5mols_controls.c | |||
@@ -0,0 +1,299 @@ | |||
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 = m5mols_lock_3a(info, false); | ||
143 | if (!ret) | ||
144 | ret = m5mols_write(sd, AE_EV_PRESET_MONITOR, mode); | ||
145 | if (!ret) | ||
146 | ret = m5mols_write(sd, AE_EV_PRESET_CAPTURE, mode); | ||
147 | if (!ret) | ||
148 | ret = m5mols_write(sd, AE_MODE, scenemode.metering); | ||
149 | if (!ret) | ||
150 | ret = m5mols_write(sd, AE_INDEX, scenemode.ev_bias); | ||
151 | if (!ret) | ||
152 | ret = m5mols_write(sd, AWB_MODE, scenemode.wb_mode); | ||
153 | if (!ret) | ||
154 | ret = m5mols_write(sd, AWB_MANUAL, scenemode.wb_preset); | ||
155 | if (!ret) | ||
156 | ret = m5mols_write(sd, MON_CHROMA_EN, scenemode.chroma_en); | ||
157 | if (!ret) | ||
158 | ret = m5mols_write(sd, MON_CHROMA_LVL, scenemode.chroma_lvl); | ||
159 | if (!ret) | ||
160 | ret = m5mols_write(sd, MON_EDGE_EN, scenemode.edge_en); | ||
161 | if (!ret) | ||
162 | ret = m5mols_write(sd, MON_EDGE_LVL, scenemode.edge_lvl); | ||
163 | if (!ret && is_available_af(info)) | ||
164 | ret = m5mols_write(sd, AF_MODE, scenemode.af_range); | ||
165 | if (!ret && is_available_af(info)) | ||
166 | ret = m5mols_write(sd, FD_CTL, scenemode.fd_mode); | ||
167 | if (!ret) | ||
168 | ret = m5mols_write(sd, MON_TONE_CTL, scenemode.tone); | ||
169 | if (!ret) | ||
170 | ret = m5mols_write(sd, AE_ISO, scenemode.iso); | ||
171 | if (!ret) | ||
172 | ret = m5mols_mode(info, REG_CAPTURE); | ||
173 | if (!ret) | ||
174 | ret = m5mols_write(sd, CAPP_WDR_EN, scenemode.wdr); | ||
175 | if (!ret) | ||
176 | ret = m5mols_write(sd, CAPP_MCC_MODE, scenemode.mcc); | ||
177 | if (!ret) | ||
178 | ret = m5mols_write(sd, CAPP_LIGHT_CTRL, scenemode.light); | ||
179 | if (!ret) | ||
180 | ret = m5mols_write(sd, CAPP_FLASH_CTRL, scenemode.flash); | ||
181 | if (!ret) | ||
182 | ret = m5mols_write(sd, CAPC_MODE, scenemode.capt_mode); | ||
183 | if (!ret) | ||
184 | ret = m5mols_mode(info, REG_MONITOR); | ||
185 | |||
186 | return ret; | ||
187 | } | ||
188 | |||
189 | static int m5mols_lock_ae(struct m5mols_info *info, bool lock) | ||
190 | { | ||
191 | int ret = 0; | ||
192 | |||
193 | if (info->lock_ae != lock) | ||
194 | ret = m5mols_write(&info->sd, AE_LOCK, | ||
195 | lock ? REG_AE_LOCK : REG_AE_UNLOCK); | ||
196 | if (!ret) | ||
197 | info->lock_ae = lock; | ||
198 | |||
199 | return ret; | ||
200 | } | ||
201 | |||
202 | static int m5mols_lock_awb(struct m5mols_info *info, bool lock) | ||
203 | { | ||
204 | int ret = 0; | ||
205 | |||
206 | if (info->lock_awb != lock) | ||
207 | ret = m5mols_write(&info->sd, AWB_LOCK, | ||
208 | lock ? REG_AWB_LOCK : REG_AWB_UNLOCK); | ||
209 | if (!ret) | ||
210 | info->lock_awb = lock; | ||
211 | |||
212 | return ret; | ||
213 | } | ||
214 | |||
215 | /* m5mols_lock_3a() - Lock 3A(Auto Exposure, Auto Whitebalance, Auto Focus) */ | ||
216 | int m5mols_lock_3a(struct m5mols_info *info, bool lock) | ||
217 | { | ||
218 | int ret; | ||
219 | |||
220 | ret = m5mols_lock_ae(info, lock); | ||
221 | if (!ret) | ||
222 | ret = m5mols_lock_awb(info, lock); | ||
223 | /* Don't need to handle unlocking AF */ | ||
224 | if (!ret && is_available_af(info) && lock) | ||
225 | ret = m5mols_write(&info->sd, AF_EXECUTE, REG_AF_STOP); | ||
226 | |||
227 | return ret; | ||
228 | } | ||
229 | |||
230 | /* m5mols_set_ctrl() - The main s_ctrl function called by m5mols_set_ctrl() */ | ||
231 | int m5mols_set_ctrl(struct v4l2_ctrl *ctrl) | ||
232 | { | ||
233 | struct v4l2_subdev *sd = to_sd(ctrl); | ||
234 | struct m5mols_info *info = to_m5mols(sd); | ||
235 | int ret; | ||
236 | |||
237 | switch (ctrl->id) { | ||
238 | case V4L2_CID_ZOOM_ABSOLUTE: | ||
239 | return m5mols_write(sd, MON_ZOOM, ctrl->val); | ||
240 | |||
241 | case V4L2_CID_EXPOSURE_AUTO: | ||
242 | ret = m5mols_lock_ae(info, | ||
243 | ctrl->val == V4L2_EXPOSURE_AUTO ? false : true); | ||
244 | if (!ret && ctrl->val == V4L2_EXPOSURE_AUTO) | ||
245 | ret = m5mols_write(sd, AE_MODE, REG_AE_ALL); | ||
246 | if (!ret && ctrl->val == V4L2_EXPOSURE_MANUAL) { | ||
247 | int val = info->exposure->val; | ||
248 | ret = m5mols_write(sd, AE_MODE, REG_AE_OFF); | ||
249 | if (!ret) | ||
250 | ret = m5mols_write(sd, AE_MAN_GAIN_MON, val); | ||
251 | if (!ret) | ||
252 | ret = m5mols_write(sd, AE_MAN_GAIN_CAP, val); | ||
253 | } | ||
254 | return ret; | ||
255 | |||
256 | case V4L2_CID_AUTO_WHITE_BALANCE: | ||
257 | ret = m5mols_lock_awb(info, ctrl->val ? false : true); | ||
258 | if (!ret) | ||
259 | ret = m5mols_write(sd, AWB_MODE, ctrl->val ? | ||
260 | REG_AWB_AUTO : REG_AWB_PRESET); | ||
261 | return ret; | ||
262 | |||
263 | case V4L2_CID_SATURATION: | ||
264 | ret = m5mols_write(sd, MON_CHROMA_LVL, ctrl->val); | ||
265 | if (!ret) | ||
266 | ret = m5mols_write(sd, MON_CHROMA_EN, REG_CHROMA_ON); | ||
267 | return ret; | ||
268 | |||
269 | case V4L2_CID_COLORFX: | ||
270 | /* | ||
271 | * This control uses two kinds of registers: normal & color. | ||
272 | * The normal effect belongs to category 1, while the color | ||
273 | * one belongs to category 2. | ||
274 | * | ||
275 | * The normal effect uses one register: CAT1_EFFECT. | ||
276 | * The color effect uses three registers: | ||
277 | * CAT2_COLOR_EFFECT, CAT2_CFIXR, CAT2_CFIXB. | ||
278 | */ | ||
279 | ret = m5mols_write(sd, PARM_EFFECT, | ||
280 | ctrl->val == V4L2_COLORFX_NEGATIVE ? REG_EFFECT_NEGA : | ||
281 | ctrl->val == V4L2_COLORFX_EMBOSS ? REG_EFFECT_EMBOSS : | ||
282 | REG_EFFECT_OFF); | ||
283 | if (!ret) | ||
284 | ret = m5mols_write(sd, MON_EFFECT, | ||
285 | ctrl->val == V4L2_COLORFX_SEPIA ? | ||
286 | REG_COLOR_EFFECT_ON : REG_COLOR_EFFECT_OFF); | ||
287 | if (!ret) | ||
288 | ret = m5mols_write(sd, MON_CFIXR, | ||
289 | ctrl->val == V4L2_COLORFX_SEPIA ? | ||
290 | REG_CFIXR_SEPIA : 0); | ||
291 | if (!ret) | ||
292 | ret = m5mols_write(sd, MON_CFIXB, | ||
293 | ctrl->val == V4L2_COLORFX_SEPIA ? | ||
294 | REG_CFIXB_SEPIA : 0); | ||
295 | return ret; | ||
296 | } | ||
297 | |||
298 | return -EINVAL; | ||
299 | } | ||
diff --git a/drivers/media/video/m5mols/m5mols_core.c b/drivers/media/video/m5mols/m5mols_core.c new file mode 100644 index 00000000000..fb8e4a7a9dd --- /dev/null +++ b/drivers/media/video/m5mols/m5mols_core.c | |||
@@ -0,0 +1,1041 @@ | |||
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 <media/v4l2-ctrls.h> | ||
25 | #include <media/v4l2-device.h> | ||
26 | #include <media/v4l2-subdev.h> | ||
27 | #include <media/m5mols.h> | ||
28 | |||
29 | #include "m5mols.h" | ||
30 | #include "m5mols_reg.h" | ||
31 | |||
32 | int m5mols_debug; | ||
33 | module_param(m5mols_debug, int, 0644); | ||
34 | |||
35 | #define MODULE_NAME "M5MOLS" | ||
36 | #define M5MOLS_I2C_CHECK_RETRY 500 | ||
37 | |||
38 | /* The regulator consumer names for external voltage regulators */ | ||
39 | static struct regulator_bulk_data supplies[] = { | ||
40 | { | ||
41 | .supply = "core", /* ARM core power, 1.2V */ | ||
42 | }, { | ||
43 | .supply = "dig_18", /* digital power 1, 1.8V */ | ||
44 | }, { | ||
45 | .supply = "d_sensor", /* sensor power 1, 1.8V */ | ||
46 | }, { | ||
47 | .supply = "dig_28", /* digital power 2, 2.8V */ | ||
48 | }, { | ||
49 | .supply = "a_sensor", /* analog power */ | ||
50 | }, { | ||
51 | .supply = "dig_12", /* digital power 3, 1.2V */ | ||
52 | }, | ||
53 | }; | ||
54 | |||
55 | static struct v4l2_mbus_framefmt m5mols_default_ffmt[M5MOLS_RESTYPE_MAX] = { | ||
56 | [M5MOLS_RESTYPE_MONITOR] = { | ||
57 | .width = 1920, | ||
58 | .height = 1080, | ||
59 | .code = V4L2_MBUS_FMT_VYUY8_2X8, | ||
60 | .field = V4L2_FIELD_NONE, | ||
61 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
62 | }, | ||
63 | [M5MOLS_RESTYPE_CAPTURE] = { | ||
64 | .width = 1920, | ||
65 | .height = 1080, | ||
66 | .code = V4L2_MBUS_FMT_JPEG_1X8, | ||
67 | .field = V4L2_FIELD_NONE, | ||
68 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
69 | }, | ||
70 | }; | ||
71 | #define SIZE_DEFAULT_FFMT ARRAY_SIZE(m5mols_default_ffmt) | ||
72 | |||
73 | static const struct m5mols_resolution m5mols_reg_res[] = { | ||
74 | { 0x01, M5MOLS_RESTYPE_MONITOR, 128, 96 }, /* SUB-QCIF */ | ||
75 | { 0x03, M5MOLS_RESTYPE_MONITOR, 160, 120 }, /* QQVGA */ | ||
76 | { 0x05, M5MOLS_RESTYPE_MONITOR, 176, 144 }, /* QCIF */ | ||
77 | { 0x06, M5MOLS_RESTYPE_MONITOR, 176, 176 }, | ||
78 | { 0x08, M5MOLS_RESTYPE_MONITOR, 240, 320 }, /* QVGA */ | ||
79 | { 0x09, M5MOLS_RESTYPE_MONITOR, 320, 240 }, /* QVGA */ | ||
80 | { 0x0c, M5MOLS_RESTYPE_MONITOR, 240, 400 }, /* WQVGA */ | ||
81 | { 0x0d, M5MOLS_RESTYPE_MONITOR, 400, 240 }, /* WQVGA */ | ||
82 | { 0x0e, M5MOLS_RESTYPE_MONITOR, 352, 288 }, /* CIF */ | ||
83 | { 0x13, M5MOLS_RESTYPE_MONITOR, 480, 360 }, | ||
84 | { 0x15, M5MOLS_RESTYPE_MONITOR, 640, 360 }, /* qHD */ | ||
85 | { 0x17, M5MOLS_RESTYPE_MONITOR, 640, 480 }, /* VGA */ | ||
86 | { 0x18, M5MOLS_RESTYPE_MONITOR, 720, 480 }, | ||
87 | { 0x1a, M5MOLS_RESTYPE_MONITOR, 800, 480 }, /* WVGA */ | ||
88 | { 0x1f, M5MOLS_RESTYPE_MONITOR, 800, 600 }, /* SVGA */ | ||
89 | { 0x21, M5MOLS_RESTYPE_MONITOR, 1280, 720 }, /* HD */ | ||
90 | { 0x25, M5MOLS_RESTYPE_MONITOR, 1920, 1080 }, /* 1080p */ | ||
91 | { 0x29, M5MOLS_RESTYPE_MONITOR, 3264, 2448 }, /* 2.63fps 8M */ | ||
92 | { 0x39, M5MOLS_RESTYPE_MONITOR, 800, 602 }, /* AHS_MON debug */ | ||
93 | |||
94 | { 0x02, M5MOLS_RESTYPE_CAPTURE, 320, 240 }, /* QVGA */ | ||
95 | { 0x04, M5MOLS_RESTYPE_CAPTURE, 400, 240 }, /* WQVGA */ | ||
96 | { 0x07, M5MOLS_RESTYPE_CAPTURE, 480, 360 }, | ||
97 | { 0x08, M5MOLS_RESTYPE_CAPTURE, 640, 360 }, /* qHD */ | ||
98 | { 0x09, M5MOLS_RESTYPE_CAPTURE, 640, 480 }, /* VGA */ | ||
99 | { 0x0a, M5MOLS_RESTYPE_CAPTURE, 800, 480 }, /* WVGA */ | ||
100 | { 0x10, M5MOLS_RESTYPE_CAPTURE, 1280, 720 }, /* HD */ | ||
101 | { 0x14, M5MOLS_RESTYPE_CAPTURE, 1280, 960 }, /* 1M */ | ||
102 | { 0x17, M5MOLS_RESTYPE_CAPTURE, 1600, 1200 }, /* 2M */ | ||
103 | { 0x19, M5MOLS_RESTYPE_CAPTURE, 1920, 1080 }, /* Full-HD */ | ||
104 | { 0x1a, M5MOLS_RESTYPE_CAPTURE, 2048, 1152 }, /* 3Mega */ | ||
105 | { 0x1b, M5MOLS_RESTYPE_CAPTURE, 2048, 1536 }, | ||
106 | { 0x1c, M5MOLS_RESTYPE_CAPTURE, 2560, 1440 }, /* 4Mega */ | ||
107 | { 0x1d, M5MOLS_RESTYPE_CAPTURE, 2560, 1536 }, | ||
108 | { 0x1f, M5MOLS_RESTYPE_CAPTURE, 2560, 1920 }, /* 5Mega */ | ||
109 | { 0x21, M5MOLS_RESTYPE_CAPTURE, 3264, 1836 }, /* 6Mega */ | ||
110 | { 0x22, M5MOLS_RESTYPE_CAPTURE, 3264, 1960 }, | ||
111 | { 0x25, M5MOLS_RESTYPE_CAPTURE, 3264, 2448 }, /* 8Mega */ | ||
112 | }; | ||
113 | |||
114 | /** | ||
115 | * m5mols_swap_byte - an byte array to integer conversion function | ||
116 | * @size: size in bytes of I2C packet defined in the M-5MOLS datasheet | ||
117 | * | ||
118 | * Convert I2C data byte array with performing any required byte | ||
119 | * reordering to assure proper values for each data type, regardless | ||
120 | * of the architecture endianness. | ||
121 | */ | ||
122 | static u32 m5mols_swap_byte(u8 *data, u8 length) | ||
123 | { | ||
124 | if (length == 1) | ||
125 | return *data; | ||
126 | else if (length == 2) | ||
127 | return be16_to_cpu(*((u16 *)data)); | ||
128 | else | ||
129 | return be32_to_cpu(*((u32 *)data)); | ||
130 | } | ||
131 | |||
132 | /** | ||
133 | * m5mols_read - I2C read function | ||
134 | * @reg: combination of size, category and command for the I2C packet | ||
135 | * @size: desired size of I2C packet | ||
136 | * @val: read value | ||
137 | */ | ||
138 | static int m5mols_read(struct v4l2_subdev *sd, u32 size, u32 reg, u32 *val) | ||
139 | { | ||
140 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
141 | u8 rbuf[M5MOLS_I2C_MAX_SIZE + 1]; | ||
142 | u8 category = I2C_CATEGORY(reg); | ||
143 | u8 cmd = I2C_COMMAND(reg); | ||
144 | struct i2c_msg msg[2]; | ||
145 | u8 wbuf[5]; | ||
146 | int ret; | ||
147 | |||
148 | if (!client->adapter) | ||
149 | return -ENODEV; | ||
150 | |||
151 | msg[0].addr = client->addr; | ||
152 | msg[0].flags = 0; | ||
153 | msg[0].len = 5; | ||
154 | msg[0].buf = wbuf; | ||
155 | wbuf[0] = 5; | ||
156 | wbuf[1] = M5MOLS_BYTE_READ; | ||
157 | wbuf[2] = category; | ||
158 | wbuf[3] = cmd; | ||
159 | wbuf[4] = size; | ||
160 | |||
161 | msg[1].addr = client->addr; | ||
162 | msg[1].flags = I2C_M_RD; | ||
163 | msg[1].len = size + 1; | ||
164 | msg[1].buf = rbuf; | ||
165 | |||
166 | /* minimum stabilization time */ | ||
167 | usleep_range(200, 200); | ||
168 | |||
169 | ret = i2c_transfer(client->adapter, msg, 2); | ||
170 | if (ret < 0) { | ||
171 | v4l2_err(sd, "read failed: size:%d cat:%02x cmd:%02x. %d\n", | ||
172 | size, category, cmd, ret); | ||
173 | return ret; | ||
174 | } | ||
175 | |||
176 | *val = m5mols_swap_byte(&rbuf[1], size); | ||
177 | |||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | int m5mols_read_u8(struct v4l2_subdev *sd, u32 reg, u8 *val) | ||
182 | { | ||
183 | u32 val_32; | ||
184 | int ret; | ||
185 | |||
186 | if (I2C_SIZE(reg) != 1) { | ||
187 | v4l2_err(sd, "Wrong data size\n"); | ||
188 | return -EINVAL; | ||
189 | } | ||
190 | |||
191 | ret = m5mols_read(sd, I2C_SIZE(reg), reg, &val_32); | ||
192 | if (ret) | ||
193 | return ret; | ||
194 | |||
195 | *val = (u8)val_32; | ||
196 | return ret; | ||
197 | } | ||
198 | |||
199 | int m5mols_read_u16(struct v4l2_subdev *sd, u32 reg, u16 *val) | ||
200 | { | ||
201 | u32 val_32; | ||
202 | int ret; | ||
203 | |||
204 | if (I2C_SIZE(reg) != 2) { | ||
205 | v4l2_err(sd, "Wrong data size\n"); | ||
206 | return -EINVAL; | ||
207 | } | ||
208 | |||
209 | ret = m5mols_read(sd, I2C_SIZE(reg), reg, &val_32); | ||
210 | if (ret) | ||
211 | return ret; | ||
212 | |||
213 | *val = (u16)val_32; | ||
214 | return ret; | ||
215 | } | ||
216 | |||
217 | int m5mols_read_u32(struct v4l2_subdev *sd, u32 reg, u32 *val) | ||
218 | { | ||
219 | if (I2C_SIZE(reg) != 4) { | ||
220 | v4l2_err(sd, "Wrong data size\n"); | ||
221 | return -EINVAL; | ||
222 | } | ||
223 | |||
224 | return m5mols_read(sd, I2C_SIZE(reg), reg, val); | ||
225 | } | ||
226 | |||
227 | /** | ||
228 | * m5mols_write - I2C command write function | ||
229 | * @reg: combination of size, category and command for the I2C packet | ||
230 | * @val: value to write | ||
231 | */ | ||
232 | int m5mols_write(struct v4l2_subdev *sd, u32 reg, u32 val) | ||
233 | { | ||
234 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
235 | u8 wbuf[M5MOLS_I2C_MAX_SIZE + 4]; | ||
236 | u8 category = I2C_CATEGORY(reg); | ||
237 | u8 cmd = I2C_COMMAND(reg); | ||
238 | u8 size = I2C_SIZE(reg); | ||
239 | u32 *buf = (u32 *)&wbuf[4]; | ||
240 | struct i2c_msg msg[1]; | ||
241 | int ret; | ||
242 | |||
243 | if (!client->adapter) | ||
244 | return -ENODEV; | ||
245 | |||
246 | if (size != 1 && size != 2 && size != 4) { | ||
247 | v4l2_err(sd, "Wrong data size\n"); | ||
248 | return -EINVAL; | ||
249 | } | ||
250 | |||
251 | msg->addr = client->addr; | ||
252 | msg->flags = 0; | ||
253 | msg->len = (u16)size + 4; | ||
254 | msg->buf = wbuf; | ||
255 | wbuf[0] = size + 4; | ||
256 | wbuf[1] = M5MOLS_BYTE_WRITE; | ||
257 | wbuf[2] = category; | ||
258 | wbuf[3] = cmd; | ||
259 | |||
260 | *buf = m5mols_swap_byte((u8 *)&val, size); | ||
261 | |||
262 | usleep_range(200, 200); | ||
263 | |||
264 | ret = i2c_transfer(client->adapter, msg, 1); | ||
265 | if (ret < 0) { | ||
266 | v4l2_err(sd, "write failed: size:%d cat:%02x cmd:%02x. %d\n", | ||
267 | size, category, cmd, ret); | ||
268 | return ret; | ||
269 | } | ||
270 | |||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u8 mask) | ||
275 | { | ||
276 | u8 busy; | ||
277 | int i; | ||
278 | int ret; | ||
279 | |||
280 | for (i = 0; i < M5MOLS_I2C_CHECK_RETRY; i++) { | ||
281 | ret = m5mols_read_u8(sd, I2C_REG(category, cmd, 1), &busy); | ||
282 | if (ret < 0) | ||
283 | return ret; | ||
284 | if ((busy & mask) == mask) | ||
285 | return 0; | ||
286 | } | ||
287 | return -EBUSY; | ||
288 | } | ||
289 | |||
290 | /** | ||
291 | * m5mols_enable_interrupt - Clear interrupt pending bits and unmask interrupts | ||
292 | * | ||
293 | * Before writing desired interrupt value the INT_FACTOR register should | ||
294 | * be read to clear pending interrupts. | ||
295 | */ | ||
296 | int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg) | ||
297 | { | ||
298 | struct m5mols_info *info = to_m5mols(sd); | ||
299 | u8 mask = is_available_af(info) ? REG_INT_AF : 0; | ||
300 | u8 dummy; | ||
301 | int ret; | ||
302 | |||
303 | ret = m5mols_read_u8(sd, SYSTEM_INT_FACTOR, &dummy); | ||
304 | if (!ret) | ||
305 | ret = m5mols_write(sd, SYSTEM_INT_ENABLE, reg & ~mask); | ||
306 | return ret; | ||
307 | } | ||
308 | |||
309 | /** | ||
310 | * m5mols_reg_mode - Write the mode and check busy status | ||
311 | * | ||
312 | * It always accompanies a little delay changing the M-5MOLS mode, so it is | ||
313 | * needed checking current busy status to guarantee right mode. | ||
314 | */ | ||
315 | static int m5mols_reg_mode(struct v4l2_subdev *sd, u8 mode) | ||
316 | { | ||
317 | int ret = m5mols_write(sd, SYSTEM_SYSMODE, mode); | ||
318 | |||
319 | return ret ? ret : m5mols_busy(sd, CAT_SYSTEM, CAT0_SYSMODE, mode); | ||
320 | } | ||
321 | |||
322 | /** | ||
323 | * m5mols_mode - manage the M-5MOLS's mode | ||
324 | * @mode: the required operation mode | ||
325 | * | ||
326 | * The commands of M-5MOLS are grouped into specific modes. Each functionality | ||
327 | * can be guaranteed only when the sensor is operating in mode which which | ||
328 | * a command belongs to. | ||
329 | */ | ||
330 | int m5mols_mode(struct m5mols_info *info, u8 mode) | ||
331 | { | ||
332 | struct v4l2_subdev *sd = &info->sd; | ||
333 | int ret = -EINVAL; | ||
334 | u8 reg; | ||
335 | |||
336 | if (mode < REG_PARAMETER && mode > REG_CAPTURE) | ||
337 | return ret; | ||
338 | |||
339 | ret = m5mols_read_u8(sd, SYSTEM_SYSMODE, ®); | ||
340 | if ((!ret && reg == mode) || ret) | ||
341 | return ret; | ||
342 | |||
343 | switch (reg) { | ||
344 | case REG_PARAMETER: | ||
345 | ret = m5mols_reg_mode(sd, REG_MONITOR); | ||
346 | if (!ret && mode == REG_MONITOR) | ||
347 | break; | ||
348 | if (!ret) | ||
349 | ret = m5mols_reg_mode(sd, REG_CAPTURE); | ||
350 | break; | ||
351 | |||
352 | case REG_MONITOR: | ||
353 | if (mode == REG_PARAMETER) { | ||
354 | ret = m5mols_reg_mode(sd, REG_PARAMETER); | ||
355 | break; | ||
356 | } | ||
357 | |||
358 | ret = m5mols_reg_mode(sd, REG_CAPTURE); | ||
359 | break; | ||
360 | |||
361 | case REG_CAPTURE: | ||
362 | ret = m5mols_reg_mode(sd, REG_MONITOR); | ||
363 | if (!ret && mode == REG_MONITOR) | ||
364 | break; | ||
365 | if (!ret) | ||
366 | ret = m5mols_reg_mode(sd, REG_PARAMETER); | ||
367 | break; | ||
368 | |||
369 | default: | ||
370 | v4l2_warn(sd, "Wrong mode: %d\n", mode); | ||
371 | } | ||
372 | |||
373 | if (!ret) | ||
374 | info->mode = mode; | ||
375 | |||
376 | return ret; | ||
377 | } | ||
378 | |||
379 | /** | ||
380 | * m5mols_get_version - retrieve full revisions information of M-5MOLS | ||
381 | * | ||
382 | * The version information includes revisions of hardware and firmware, | ||
383 | * AutoFocus alghorithm version and the version string. | ||
384 | */ | ||
385 | static int m5mols_get_version(struct v4l2_subdev *sd) | ||
386 | { | ||
387 | struct m5mols_info *info = to_m5mols(sd); | ||
388 | struct m5mols_version *ver = &info->ver; | ||
389 | u8 *str = ver->str; | ||
390 | int i; | ||
391 | int ret; | ||
392 | |||
393 | ret = m5mols_read_u8(sd, SYSTEM_VER_CUSTOMER, &ver->customer); | ||
394 | if (!ret) | ||
395 | ret = m5mols_read_u8(sd, SYSTEM_VER_PROJECT, &ver->project); | ||
396 | if (!ret) | ||
397 | ret = m5mols_read_u16(sd, SYSTEM_VER_FIRMWARE, &ver->fw); | ||
398 | if (!ret) | ||
399 | ret = m5mols_read_u16(sd, SYSTEM_VER_HARDWARE, &ver->hw); | ||
400 | if (!ret) | ||
401 | ret = m5mols_read_u16(sd, SYSTEM_VER_PARAMETER, &ver->param); | ||
402 | if (!ret) | ||
403 | ret = m5mols_read_u16(sd, SYSTEM_VER_AWB, &ver->awb); | ||
404 | if (!ret) | ||
405 | ret = m5mols_read_u8(sd, AF_VERSION, &ver->af); | ||
406 | if (ret) | ||
407 | return ret; | ||
408 | |||
409 | for (i = 0; i < VERSION_STRING_SIZE; i++) { | ||
410 | ret = m5mols_read_u8(sd, SYSTEM_VER_STRING, &str[i]); | ||
411 | if (ret) | ||
412 | return ret; | ||
413 | } | ||
414 | |||
415 | ver->fw = be16_to_cpu(ver->fw); | ||
416 | ver->hw = be16_to_cpu(ver->hw); | ||
417 | ver->param = be16_to_cpu(ver->param); | ||
418 | ver->awb = be16_to_cpu(ver->awb); | ||
419 | |||
420 | v4l2_info(sd, "Manufacturer\t[%s]\n", | ||
421 | is_manufacturer(info, REG_SAMSUNG_ELECTRO) ? | ||
422 | "Samsung Electro-Machanics" : | ||
423 | is_manufacturer(info, REG_SAMSUNG_OPTICS) ? | ||
424 | "Samsung Fiber-Optics" : | ||
425 | is_manufacturer(info, REG_SAMSUNG_TECHWIN) ? | ||
426 | "Samsung Techwin" : "None"); | ||
427 | v4l2_info(sd, "Customer/Project\t[0x%02x/0x%02x]\n", | ||
428 | info->ver.customer, info->ver.project); | ||
429 | |||
430 | if (!is_available_af(info)) | ||
431 | v4l2_info(sd, "No support Auto Focus on this firmware\n"); | ||
432 | |||
433 | return ret; | ||
434 | } | ||
435 | |||
436 | /** | ||
437 | * __find_restype - Lookup M-5MOLS resolution type according to pixel code | ||
438 | * @code: pixel code | ||
439 | */ | ||
440 | static enum m5mols_restype __find_restype(enum v4l2_mbus_pixelcode code) | ||
441 | { | ||
442 | enum m5mols_restype type = M5MOLS_RESTYPE_MONITOR; | ||
443 | |||
444 | do { | ||
445 | if (code == m5mols_default_ffmt[type].code) | ||
446 | return type; | ||
447 | } while (type++ != SIZE_DEFAULT_FFMT); | ||
448 | |||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | /** | ||
453 | * __find_resolution - Lookup preset and type of M-5MOLS's resolution | ||
454 | * @mf: pixel format to find/negotiate the resolution preset for | ||
455 | * @type: M-5MOLS resolution type | ||
456 | * @resolution: M-5MOLS resolution preset register value | ||
457 | * | ||
458 | * Find nearest resolution matching resolution preset and adjust mf | ||
459 | * to supported values. | ||
460 | */ | ||
461 | static int __find_resolution(struct v4l2_subdev *sd, | ||
462 | struct v4l2_mbus_framefmt *mf, | ||
463 | enum m5mols_restype *type, | ||
464 | u32 *resolution) | ||
465 | { | ||
466 | const struct m5mols_resolution *fsize = &m5mols_reg_res[0]; | ||
467 | const struct m5mols_resolution *match = NULL; | ||
468 | enum m5mols_restype stype = __find_restype(mf->code); | ||
469 | int i = ARRAY_SIZE(m5mols_reg_res); | ||
470 | unsigned int min_err = ~0; | ||
471 | |||
472 | while (i--) { | ||
473 | int err; | ||
474 | if (stype == fsize->type) { | ||
475 | err = abs(fsize->width - mf->width) | ||
476 | + abs(fsize->height - mf->height); | ||
477 | |||
478 | if (err < min_err) { | ||
479 | min_err = err; | ||
480 | match = fsize; | ||
481 | } | ||
482 | } | ||
483 | fsize++; | ||
484 | } | ||
485 | if (match) { | ||
486 | mf->width = match->width; | ||
487 | mf->height = match->height; | ||
488 | *resolution = match->reg; | ||
489 | *type = stype; | ||
490 | return 0; | ||
491 | } | ||
492 | |||
493 | return -EINVAL; | ||
494 | } | ||
495 | |||
496 | static struct v4l2_mbus_framefmt *__find_format(struct m5mols_info *info, | ||
497 | struct v4l2_subdev_fh *fh, | ||
498 | enum v4l2_subdev_format_whence which, | ||
499 | enum m5mols_restype type) | ||
500 | { | ||
501 | if (which == V4L2_SUBDEV_FORMAT_TRY) | ||
502 | return fh ? v4l2_subdev_get_try_format(fh, 0) : NULL; | ||
503 | |||
504 | return &info->ffmt[type]; | ||
505 | } | ||
506 | |||
507 | static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | ||
508 | struct v4l2_subdev_format *fmt) | ||
509 | { | ||
510 | struct m5mols_info *info = to_m5mols(sd); | ||
511 | struct v4l2_mbus_framefmt *format; | ||
512 | |||
513 | if (fmt->pad != 0) | ||
514 | return -EINVAL; | ||
515 | |||
516 | format = __find_format(info, fh, fmt->which, info->res_type); | ||
517 | if (!format) | ||
518 | return -EINVAL; | ||
519 | |||
520 | fmt->format = *format; | ||
521 | return 0; | ||
522 | } | ||
523 | |||
524 | static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | ||
525 | struct v4l2_subdev_format *fmt) | ||
526 | { | ||
527 | struct m5mols_info *info = to_m5mols(sd); | ||
528 | struct v4l2_mbus_framefmt *format = &fmt->format; | ||
529 | struct v4l2_mbus_framefmt *sfmt; | ||
530 | enum m5mols_restype type; | ||
531 | u32 resolution = 0; | ||
532 | int ret; | ||
533 | |||
534 | if (fmt->pad != 0) | ||
535 | return -EINVAL; | ||
536 | |||
537 | ret = __find_resolution(sd, format, &type, &resolution); | ||
538 | if (ret < 0) | ||
539 | return ret; | ||
540 | |||
541 | sfmt = __find_format(info, fh, fmt->which, type); | ||
542 | if (!sfmt) | ||
543 | return 0; | ||
544 | |||
545 | *sfmt = m5mols_default_ffmt[type]; | ||
546 | sfmt->width = format->width; | ||
547 | sfmt->height = format->height; | ||
548 | |||
549 | if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { | ||
550 | info->resolution = resolution; | ||
551 | info->code = format->code; | ||
552 | info->res_type = type; | ||
553 | } | ||
554 | |||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | static int m5mols_enum_mbus_code(struct v4l2_subdev *sd, | ||
559 | struct v4l2_subdev_fh *fh, | ||
560 | struct v4l2_subdev_mbus_code_enum *code) | ||
561 | { | ||
562 | if (!code || code->index >= SIZE_DEFAULT_FFMT) | ||
563 | return -EINVAL; | ||
564 | |||
565 | code->code = m5mols_default_ffmt[code->index].code; | ||
566 | |||
567 | return 0; | ||
568 | } | ||
569 | |||
570 | static struct v4l2_subdev_pad_ops m5mols_pad_ops = { | ||
571 | .enum_mbus_code = m5mols_enum_mbus_code, | ||
572 | .get_fmt = m5mols_get_fmt, | ||
573 | .set_fmt = m5mols_set_fmt, | ||
574 | }; | ||
575 | |||
576 | /** | ||
577 | * m5mols_sync_controls - Apply default scene mode and the current controls | ||
578 | * | ||
579 | * This is used only streaming for syncing between v4l2_ctrl framework and | ||
580 | * m5mols's controls. First, do the scenemode to the sensor, then call | ||
581 | * v4l2_ctrl_handler_setup. It can be same between some commands and | ||
582 | * the scenemode's in the default v4l2_ctrls. But, such commands of control | ||
583 | * should be prior to the scenemode's one. | ||
584 | */ | ||
585 | int m5mols_sync_controls(struct m5mols_info *info) | ||
586 | { | ||
587 | int ret = -EINVAL; | ||
588 | |||
589 | if (!is_ctrl_synced(info)) { | ||
590 | ret = m5mols_do_scenemode(info, REG_SCENE_NORMAL); | ||
591 | if (ret) | ||
592 | return ret; | ||
593 | |||
594 | v4l2_ctrl_handler_setup(&info->handle); | ||
595 | info->ctrl_sync = true; | ||
596 | } | ||
597 | |||
598 | return ret; | ||
599 | } | ||
600 | |||
601 | /** | ||
602 | * m5mols_start_monitor - Start the monitor mode | ||
603 | * | ||
604 | * Before applying the controls setup the resolution and frame rate | ||
605 | * in PARAMETER mode, and then switch over to MONITOR mode. | ||
606 | */ | ||
607 | static int m5mols_start_monitor(struct m5mols_info *info) | ||
608 | { | ||
609 | struct v4l2_subdev *sd = &info->sd; | ||
610 | int ret; | ||
611 | |||
612 | ret = m5mols_mode(info, REG_PARAMETER); | ||
613 | if (!ret) | ||
614 | ret = m5mols_write(sd, PARM_MON_SIZE, info->resolution); | ||
615 | if (!ret) | ||
616 | ret = m5mols_write(sd, PARM_MON_FPS, REG_FPS_30); | ||
617 | if (!ret) | ||
618 | ret = m5mols_mode(info, REG_MONITOR); | ||
619 | if (!ret) | ||
620 | ret = m5mols_sync_controls(info); | ||
621 | |||
622 | return ret; | ||
623 | } | ||
624 | |||
625 | static int m5mols_s_stream(struct v4l2_subdev *sd, int enable) | ||
626 | { | ||
627 | struct m5mols_info *info = to_m5mols(sd); | ||
628 | |||
629 | if (enable) { | ||
630 | int ret = -EINVAL; | ||
631 | |||
632 | if (is_code(info->code, M5MOLS_RESTYPE_MONITOR)) | ||
633 | ret = m5mols_start_monitor(info); | ||
634 | if (is_code(info->code, M5MOLS_RESTYPE_CAPTURE)) | ||
635 | ret = m5mols_start_capture(info); | ||
636 | |||
637 | return ret; | ||
638 | } | ||
639 | |||
640 | return m5mols_mode(info, REG_PARAMETER); | ||
641 | } | ||
642 | |||
643 | static const struct v4l2_subdev_video_ops m5mols_video_ops = { | ||
644 | .s_stream = m5mols_s_stream, | ||
645 | }; | ||
646 | |||
647 | static int m5mols_s_ctrl(struct v4l2_ctrl *ctrl) | ||
648 | { | ||
649 | struct v4l2_subdev *sd = to_sd(ctrl); | ||
650 | struct m5mols_info *info = to_m5mols(sd); | ||
651 | int ret; | ||
652 | |||
653 | info->mode_save = info->mode; | ||
654 | |||
655 | ret = m5mols_mode(info, REG_PARAMETER); | ||
656 | if (!ret) | ||
657 | ret = m5mols_set_ctrl(ctrl); | ||
658 | if (!ret) | ||
659 | ret = m5mols_mode(info, info->mode_save); | ||
660 | |||
661 | return ret; | ||
662 | } | ||
663 | |||
664 | static const struct v4l2_ctrl_ops m5mols_ctrl_ops = { | ||
665 | .s_ctrl = m5mols_s_ctrl, | ||
666 | }; | ||
667 | |||
668 | static int m5mols_sensor_power(struct m5mols_info *info, bool enable) | ||
669 | { | ||
670 | struct v4l2_subdev *sd = &info->sd; | ||
671 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
672 | const struct m5mols_platform_data *pdata = info->pdata; | ||
673 | int ret; | ||
674 | |||
675 | if (enable) { | ||
676 | if (is_powered(info)) | ||
677 | return 0; | ||
678 | |||
679 | if (info->set_power) { | ||
680 | ret = info->set_power(&client->dev, 1); | ||
681 | if (ret) | ||
682 | return ret; | ||
683 | } | ||
684 | |||
685 | ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies); | ||
686 | if (ret) { | ||
687 | info->set_power(&client->dev, 0); | ||
688 | return ret; | ||
689 | } | ||
690 | |||
691 | gpio_set_value(pdata->gpio_reset, !pdata->reset_polarity); | ||
692 | usleep_range(1000, 1000); | ||
693 | info->power = true; | ||
694 | |||
695 | return ret; | ||
696 | } | ||
697 | |||
698 | if (!is_powered(info)) | ||
699 | return 0; | ||
700 | |||
701 | ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies); | ||
702 | if (ret) | ||
703 | return ret; | ||
704 | |||
705 | if (info->set_power) | ||
706 | info->set_power(&client->dev, 0); | ||
707 | |||
708 | gpio_set_value(pdata->gpio_reset, pdata->reset_polarity); | ||
709 | usleep_range(1000, 1000); | ||
710 | info->power = false; | ||
711 | |||
712 | return ret; | ||
713 | } | ||
714 | |||
715 | /* m5mols_update_fw - optional firmware update routine */ | ||
716 | int __attribute__ ((weak)) m5mols_update_fw(struct v4l2_subdev *sd, | ||
717 | int (*set_power)(struct m5mols_info *, bool)) | ||
718 | { | ||
719 | return 0; | ||
720 | } | ||
721 | |||
722 | /** | ||
723 | * m5mols_sensor_armboot - Booting M-5MOLS internal ARM core. | ||
724 | * | ||
725 | * Booting internal ARM core makes the M-5MOLS is ready for getting commands | ||
726 | * with I2C. It's the first thing to be done after it powered up. It must wait | ||
727 | * at least 520ms recommended by M-5MOLS datasheet, after executing arm booting. | ||
728 | */ | ||
729 | static int m5mols_sensor_armboot(struct v4l2_subdev *sd) | ||
730 | { | ||
731 | int ret; | ||
732 | |||
733 | ret = m5mols_write(sd, FLASH_CAM_START, REG_START_ARM_BOOT); | ||
734 | if (ret < 0) | ||
735 | return ret; | ||
736 | |||
737 | msleep(520); | ||
738 | |||
739 | ret = m5mols_get_version(sd); | ||
740 | if (!ret) | ||
741 | ret = m5mols_update_fw(sd, m5mols_sensor_power); | ||
742 | if (ret) | ||
743 | return ret; | ||
744 | |||
745 | v4l2_dbg(1, m5mols_debug, sd, "Success ARM Booting\n"); | ||
746 | |||
747 | ret = m5mols_write(sd, PARM_INTERFACE, REG_INTERFACE_MIPI); | ||
748 | if (!ret) | ||
749 | ret = m5mols_enable_interrupt(sd, REG_INT_AF); | ||
750 | |||
751 | return ret; | ||
752 | } | ||
753 | |||
754 | static int m5mols_init_controls(struct m5mols_info *info) | ||
755 | { | ||
756 | struct v4l2_subdev *sd = &info->sd; | ||
757 | u16 max_exposure; | ||
758 | u16 step_zoom; | ||
759 | int ret; | ||
760 | |||
761 | /* Determine value's range & step of controls for various FW version */ | ||
762 | ret = m5mols_read_u16(sd, AE_MAX_GAIN_MON, &max_exposure); | ||
763 | if (!ret) | ||
764 | step_zoom = is_manufacturer(info, REG_SAMSUNG_OPTICS) ? 31 : 1; | ||
765 | if (ret) | ||
766 | return ret; | ||
767 | |||
768 | v4l2_ctrl_handler_init(&info->handle, 6); | ||
769 | info->autowb = v4l2_ctrl_new_std(&info->handle, | ||
770 | &m5mols_ctrl_ops, V4L2_CID_AUTO_WHITE_BALANCE, | ||
771 | 0, 1, 1, 0); | ||
772 | info->saturation = v4l2_ctrl_new_std(&info->handle, | ||
773 | &m5mols_ctrl_ops, V4L2_CID_SATURATION, | ||
774 | 1, 5, 1, 3); | ||
775 | info->zoom = v4l2_ctrl_new_std(&info->handle, | ||
776 | &m5mols_ctrl_ops, V4L2_CID_ZOOM_ABSOLUTE, | ||
777 | 1, 70, step_zoom, 1); | ||
778 | info->exposure = v4l2_ctrl_new_std(&info->handle, | ||
779 | &m5mols_ctrl_ops, V4L2_CID_EXPOSURE, | ||
780 | 0, max_exposure, 1, (int)max_exposure/2); | ||
781 | info->colorfx = v4l2_ctrl_new_std_menu(&info->handle, | ||
782 | &m5mols_ctrl_ops, V4L2_CID_COLORFX, | ||
783 | 4, (1 << V4L2_COLORFX_BW), V4L2_COLORFX_NONE); | ||
784 | info->autoexposure = v4l2_ctrl_new_std_menu(&info->handle, | ||
785 | &m5mols_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, | ||
786 | 1, 0, V4L2_EXPOSURE_MANUAL); | ||
787 | |||
788 | sd->ctrl_handler = &info->handle; | ||
789 | if (info->handle.error) { | ||
790 | v4l2_err(sd, "Failed to initialize controls: %d\n", ret); | ||
791 | v4l2_ctrl_handler_free(&info->handle); | ||
792 | return info->handle.error; | ||
793 | } | ||
794 | |||
795 | v4l2_ctrl_cluster(2, &info->autoexposure); | ||
796 | |||
797 | return 0; | ||
798 | } | ||
799 | |||
800 | /** | ||
801 | * m5mols_s_power - Main sensor power control function | ||
802 | * | ||
803 | * To prevent breaking the lens when the sensor is powered off the Soft-Landing | ||
804 | * algorithm is called where available. The Soft-Landing algorithm availability | ||
805 | * dependends on the firmware provider. | ||
806 | */ | ||
807 | static int m5mols_s_power(struct v4l2_subdev *sd, int on) | ||
808 | { | ||
809 | struct m5mols_info *info = to_m5mols(sd); | ||
810 | int ret; | ||
811 | |||
812 | if (on) { | ||
813 | ret = m5mols_sensor_power(info, true); | ||
814 | if (!ret) | ||
815 | ret = m5mols_sensor_armboot(sd); | ||
816 | if (!ret) | ||
817 | ret = m5mols_init_controls(info); | ||
818 | if (ret) | ||
819 | return ret; | ||
820 | |||
821 | info->ffmt[M5MOLS_RESTYPE_MONITOR] = | ||
822 | m5mols_default_ffmt[M5MOLS_RESTYPE_MONITOR]; | ||
823 | info->ffmt[M5MOLS_RESTYPE_CAPTURE] = | ||
824 | m5mols_default_ffmt[M5MOLS_RESTYPE_CAPTURE]; | ||
825 | return ret; | ||
826 | } | ||
827 | |||
828 | if (is_manufacturer(info, REG_SAMSUNG_TECHWIN)) { | ||
829 | ret = m5mols_mode(info, REG_MONITOR); | ||
830 | if (!ret) | ||
831 | ret = m5mols_write(sd, AF_EXECUTE, REG_AF_STOP); | ||
832 | if (!ret) | ||
833 | ret = m5mols_write(sd, AF_MODE, REG_AF_POWEROFF); | ||
834 | if (!ret) | ||
835 | ret = m5mols_busy(sd, CAT_SYSTEM, CAT0_STATUS, | ||
836 | REG_AF_IDLE); | ||
837 | if (!ret) | ||
838 | v4l2_info(sd, "Success soft-landing lens\n"); | ||
839 | } | ||
840 | |||
841 | ret = m5mols_sensor_power(info, false); | ||
842 | if (!ret) { | ||
843 | v4l2_ctrl_handler_free(&info->handle); | ||
844 | info->ctrl_sync = false; | ||
845 | } | ||
846 | |||
847 | return ret; | ||
848 | } | ||
849 | |||
850 | static int m5mols_log_status(struct v4l2_subdev *sd) | ||
851 | { | ||
852 | struct m5mols_info *info = to_m5mols(sd); | ||
853 | |||
854 | v4l2_ctrl_handler_log_status(&info->handle, sd->name); | ||
855 | |||
856 | return 0; | ||
857 | } | ||
858 | |||
859 | static const struct v4l2_subdev_core_ops m5mols_core_ops = { | ||
860 | .s_power = m5mols_s_power, | ||
861 | .g_ctrl = v4l2_subdev_g_ctrl, | ||
862 | .s_ctrl = v4l2_subdev_s_ctrl, | ||
863 | .queryctrl = v4l2_subdev_queryctrl, | ||
864 | .querymenu = v4l2_subdev_querymenu, | ||
865 | .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, | ||
866 | .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, | ||
867 | .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, | ||
868 | .log_status = m5mols_log_status, | ||
869 | }; | ||
870 | |||
871 | static const struct v4l2_subdev_ops m5mols_ops = { | ||
872 | .core = &m5mols_core_ops, | ||
873 | .pad = &m5mols_pad_ops, | ||
874 | .video = &m5mols_video_ops, | ||
875 | }; | ||
876 | |||
877 | static void m5mols_irq_work(struct work_struct *work) | ||
878 | { | ||
879 | struct m5mols_info *info = | ||
880 | container_of(work, struct m5mols_info, work_irq); | ||
881 | struct v4l2_subdev *sd = &info->sd; | ||
882 | u8 reg; | ||
883 | int ret; | ||
884 | |||
885 | if (!is_powered(info) || | ||
886 | m5mols_read_u8(sd, SYSTEM_INT_FACTOR, &info->interrupt)) | ||
887 | return; | ||
888 | |||
889 | switch (info->interrupt & REG_INT_MASK) { | ||
890 | case REG_INT_AF: | ||
891 | if (!is_available_af(info)) | ||
892 | break; | ||
893 | ret = m5mols_read_u8(sd, AF_STATUS, ®); | ||
894 | v4l2_dbg(2, m5mols_debug, sd, "AF %s\n", | ||
895 | reg == REG_AF_FAIL ? "Failed" : | ||
896 | reg == REG_AF_SUCCESS ? "Success" : | ||
897 | reg == REG_AF_IDLE ? "Idle" : "Busy"); | ||
898 | break; | ||
899 | case REG_INT_CAPTURE: | ||
900 | if (!test_and_set_bit(ST_CAPT_IRQ, &info->flags)) | ||
901 | wake_up_interruptible(&info->irq_waitq); | ||
902 | |||
903 | v4l2_dbg(2, m5mols_debug, sd, "CAPTURE\n"); | ||
904 | break; | ||
905 | default: | ||
906 | v4l2_dbg(2, m5mols_debug, sd, "Undefined: %02x\n", reg); | ||
907 | break; | ||
908 | }; | ||
909 | } | ||
910 | |||
911 | static irqreturn_t m5mols_irq_handler(int irq, void *data) | ||
912 | { | ||
913 | struct v4l2_subdev *sd = data; | ||
914 | struct m5mols_info *info = to_m5mols(sd); | ||
915 | |||
916 | schedule_work(&info->work_irq); | ||
917 | |||
918 | return IRQ_HANDLED; | ||
919 | } | ||
920 | |||
921 | static int __devinit m5mols_probe(struct i2c_client *client, | ||
922 | const struct i2c_device_id *id) | ||
923 | { | ||
924 | const struct m5mols_platform_data *pdata = client->dev.platform_data; | ||
925 | struct m5mols_info *info; | ||
926 | struct v4l2_subdev *sd; | ||
927 | int ret; | ||
928 | |||
929 | if (pdata == NULL) { | ||
930 | dev_err(&client->dev, "No platform data\n"); | ||
931 | return -EINVAL; | ||
932 | } | ||
933 | |||
934 | if (!gpio_is_valid(pdata->gpio_reset)) { | ||
935 | dev_err(&client->dev, "No valid RESET GPIO specified\n"); | ||
936 | return -EINVAL; | ||
937 | } | ||
938 | |||
939 | if (!pdata->irq) { | ||
940 | dev_err(&client->dev, "Interrupt not assigned\n"); | ||
941 | return -EINVAL; | ||
942 | } | ||
943 | |||
944 | info = kzalloc(sizeof(struct m5mols_info), GFP_KERNEL); | ||
945 | if (!info) | ||
946 | return -ENOMEM; | ||
947 | |||
948 | info->pdata = pdata; | ||
949 | info->set_power = pdata->set_power; | ||
950 | |||
951 | ret = gpio_request(pdata->gpio_reset, "M5MOLS_NRST"); | ||
952 | if (ret) { | ||
953 | dev_err(&client->dev, "Failed to request gpio: %d\n", ret); | ||
954 | goto out_free; | ||
955 | } | ||
956 | gpio_direction_output(pdata->gpio_reset, pdata->reset_polarity); | ||
957 | |||
958 | ret = regulator_bulk_get(&client->dev, ARRAY_SIZE(supplies), supplies); | ||
959 | if (ret) { | ||
960 | dev_err(&client->dev, "Failed to get regulators: %d\n", ret); | ||
961 | goto out_gpio; | ||
962 | } | ||
963 | |||
964 | sd = &info->sd; | ||
965 | strlcpy(sd->name, MODULE_NAME, sizeof(sd->name)); | ||
966 | v4l2_i2c_subdev_init(sd, client, &m5mols_ops); | ||
967 | |||
968 | info->pad.flags = MEDIA_PAD_FL_SOURCE; | ||
969 | ret = media_entity_init(&sd->entity, 1, &info->pad, 0); | ||
970 | if (ret < 0) | ||
971 | goto out_reg; | ||
972 | sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; | ||
973 | |||
974 | init_waitqueue_head(&info->irq_waitq); | ||
975 | INIT_WORK(&info->work_irq, m5mols_irq_work); | ||
976 | ret = request_irq(pdata->irq, m5mols_irq_handler, | ||
977 | IRQF_TRIGGER_RISING, MODULE_NAME, sd); | ||
978 | if (ret) { | ||
979 | dev_err(&client->dev, "Interrupt request failed: %d\n", ret); | ||
980 | goto out_me; | ||
981 | } | ||
982 | info->res_type = M5MOLS_RESTYPE_MONITOR; | ||
983 | return 0; | ||
984 | out_me: | ||
985 | media_entity_cleanup(&sd->entity); | ||
986 | out_reg: | ||
987 | regulator_bulk_free(ARRAY_SIZE(supplies), supplies); | ||
988 | out_gpio: | ||
989 | gpio_free(pdata->gpio_reset); | ||
990 | out_free: | ||
991 | kfree(info); | ||
992 | return ret; | ||
993 | } | ||
994 | |||
995 | static int __devexit m5mols_remove(struct i2c_client *client) | ||
996 | { | ||
997 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | ||
998 | struct m5mols_info *info = to_m5mols(sd); | ||
999 | |||
1000 | v4l2_device_unregister_subdev(sd); | ||
1001 | free_irq(info->pdata->irq, sd); | ||
1002 | |||
1003 | regulator_bulk_free(ARRAY_SIZE(supplies), supplies); | ||
1004 | gpio_free(info->pdata->gpio_reset); | ||
1005 | media_entity_cleanup(&sd->entity); | ||
1006 | kfree(info); | ||
1007 | return 0; | ||
1008 | } | ||
1009 | |||
1010 | static const struct i2c_device_id m5mols_id[] = { | ||
1011 | { MODULE_NAME, 0 }, | ||
1012 | { }, | ||
1013 | }; | ||
1014 | MODULE_DEVICE_TABLE(i2c, m5mols_id); | ||
1015 | |||
1016 | static struct i2c_driver m5mols_i2c_driver = { | ||
1017 | .driver = { | ||
1018 | .name = MODULE_NAME, | ||
1019 | }, | ||
1020 | .probe = m5mols_probe, | ||
1021 | .remove = __devexit_p(m5mols_remove), | ||
1022 | .id_table = m5mols_id, | ||
1023 | }; | ||
1024 | |||
1025 | static int __init m5mols_mod_init(void) | ||
1026 | { | ||
1027 | return i2c_add_driver(&m5mols_i2c_driver); | ||
1028 | } | ||
1029 | |||
1030 | static void __exit m5mols_mod_exit(void) | ||
1031 | { | ||
1032 | i2c_del_driver(&m5mols_i2c_driver); | ||
1033 | } | ||
1034 | |||
1035 | module_init(m5mols_mod_init); | ||
1036 | module_exit(m5mols_mod_exit); | ||
1037 | |||
1038 | MODULE_AUTHOR("HeungJun Kim <riverful.kim@samsung.com>"); | ||
1039 | MODULE_AUTHOR("Dongsoo Kim <dongsoo45.kim@samsung.com>"); | ||
1040 | MODULE_DESCRIPTION("Fujitsu M-5MOLS 8M Pixel camera driver"); | ||
1041 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/video/m5mols/m5mols_reg.h b/drivers/media/video/m5mols/m5mols_reg.h new file mode 100644 index 00000000000..c755bd6edfe --- /dev/null +++ b/drivers/media/video/m5mols/m5mols_reg.h | |||
@@ -0,0 +1,410 @@ | |||
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 CAT0_VER_CUSTOMER 0x00 /* customer version */ | ||
59 | #define CAT0_VER_PROJECT 0x01 /* project version */ | ||
60 | #define CAT0_VER_FIRMWARE 0x02 /* Firmware version */ | ||
61 | #define CAT0_VER_HARDWARE 0x04 /* Hardware version */ | ||
62 | #define CAT0_VER_PARAMETER 0x06 /* Parameter version */ | ||
63 | #define CAT0_VER_AWB 0x08 /* Auto WB version */ | ||
64 | #define CAT0_VER_STRING 0x0a /* string including M-5MOLS */ | ||
65 | #define CAT0_SYSMODE 0x0b /* SYSTEM mode register */ | ||
66 | #define CAT0_STATUS 0x0c /* SYSTEM mode status register */ | ||
67 | #define CAT0_INT_FACTOR 0x10 /* interrupt pending register */ | ||
68 | #define CAT0_INT_ENABLE 0x11 /* interrupt enable register */ | ||
69 | |||
70 | #define SYSTEM_VER_CUSTOMER I2C_REG(CAT_SYSTEM, CAT0_VER_CUSTOMER, 1) | ||
71 | #define SYSTEM_VER_PROJECT I2C_REG(CAT_SYSTEM, CAT0_VER_PROJECT, 1) | ||
72 | #define SYSTEM_VER_FIRMWARE I2C_REG(CAT_SYSTEM, CAT0_VER_FIRMWARE, 2) | ||
73 | #define SYSTEM_VER_HARDWARE I2C_REG(CAT_SYSTEM, CAT0_VER_HARDWARE, 2) | ||
74 | #define SYSTEM_VER_PARAMETER I2C_REG(CAT_SYSTEM, CAT0_VER_PARAMETER, 2) | ||
75 | #define SYSTEM_VER_AWB I2C_REG(CAT_SYSTEM, CAT0_VER_AWB, 2) | ||
76 | |||
77 | #define SYSTEM_SYSMODE I2C_REG(CAT_SYSTEM, CAT0_SYSMODE, 1) | ||
78 | #define REG_SYSINIT 0x00 /* SYSTEM mode */ | ||
79 | #define REG_PARAMETER 0x01 /* PARAMETER mode */ | ||
80 | #define REG_MONITOR 0x02 /* MONITOR mode */ | ||
81 | #define REG_CAPTURE 0x03 /* CAPTURE mode */ | ||
82 | |||
83 | #define SYSTEM_CMD(__cmd) I2C_REG(CAT_SYSTEM, cmd, 1) | ||
84 | #define SYSTEM_VER_STRING I2C_REG(CAT_SYSTEM, CAT0_VER_STRING, 1) | ||
85 | #define REG_SAMSUNG_ELECTRO "SE" /* Samsung Electro-Mechanics */ | ||
86 | #define REG_SAMSUNG_OPTICS "OP" /* Samsung Fiber-Optics */ | ||
87 | #define REG_SAMSUNG_TECHWIN "TB" /* Samsung Techwin */ | ||
88 | |||
89 | #define SYSTEM_INT_FACTOR I2C_REG(CAT_SYSTEM, CAT0_INT_FACTOR, 1) | ||
90 | #define SYSTEM_INT_ENABLE I2C_REG(CAT_SYSTEM, CAT0_INT_ENABLE, 1) | ||
91 | #define REG_INT_MODE (1 << 0) | ||
92 | #define REG_INT_AF (1 << 1) | ||
93 | #define REG_INT_ZOOM (1 << 2) | ||
94 | #define REG_INT_CAPTURE (1 << 3) | ||
95 | #define REG_INT_FRAMESYNC (1 << 4) | ||
96 | #define REG_INT_FD (1 << 5) | ||
97 | #define REG_INT_LENS_INIT (1 << 6) | ||
98 | #define REG_INT_SOUND (1 << 7) | ||
99 | #define REG_INT_MASK 0x0f | ||
100 | |||
101 | /* | ||
102 | * category 1 - PARAMETER mode | ||
103 | * | ||
104 | * This category supports function of camera features of M-5MOLS. It means we | ||
105 | * can handle with preview(MONITOR) resolution size/frame per second/interface | ||
106 | * between the sensor and the Application Processor/even the image effect. | ||
107 | */ | ||
108 | #define CAT1_DATA_INTERFACE 0x00 /* interface between sensor and AP */ | ||
109 | #define CAT1_MONITOR_SIZE 0x01 /* resolution at the MONITOR mode */ | ||
110 | #define CAT1_MONITOR_FPS 0x02 /* frame per second at this mode */ | ||
111 | #define CAT1_EFFECT 0x0b /* image effects */ | ||
112 | |||
113 | #define PARM_MON_SIZE I2C_REG(CAT_PARAM, CAT1_MONITOR_SIZE, 1) | ||
114 | |||
115 | #define PARM_MON_FPS I2C_REG(CAT_PARAM, CAT1_MONITOR_FPS, 1) | ||
116 | #define REG_FPS_30 0x02 | ||
117 | |||
118 | #define PARM_INTERFACE I2C_REG(CAT_PARAM, CAT1_DATA_INTERFACE, 1) | ||
119 | #define REG_INTERFACE_MIPI 0x02 | ||
120 | |||
121 | #define PARM_EFFECT I2C_REG(CAT_PARAM, CAT1_EFFECT, 1) | ||
122 | #define REG_EFFECT_OFF 0x00 | ||
123 | #define REG_EFFECT_NEGA 0x01 | ||
124 | #define REG_EFFECT_EMBOSS 0x06 | ||
125 | #define REG_EFFECT_OUTLINE 0x07 | ||
126 | #define REG_EFFECT_WATERCOLOR 0x08 | ||
127 | |||
128 | /* | ||
129 | * Category 2 - MONITOR mode | ||
130 | * | ||
131 | * The MONITOR mode is same as preview mode as we said. The M-5MOLS has another | ||
132 | * mode named "Preview", but this preview mode is used at the case specific | ||
133 | * vider-recording mode. This mmode supports only YUYV format. On the other | ||
134 | * hand, the JPEG & RAW formats is supports by CAPTURE mode. And, there are | ||
135 | * another options like zoom/color effect(different with effect in PARAMETER | ||
136 | * mode)/anti hand shaking algorithm. | ||
137 | */ | ||
138 | #define CAT2_ZOOM 0x01 /* set the zoom position & execute */ | ||
139 | #define CAT2_ZOOM_STEP 0x03 /* set the zoom step */ | ||
140 | #define CAT2_CFIXB 0x09 /* CB value for color effect */ | ||
141 | #define CAT2_CFIXR 0x0a /* CR value for color effect */ | ||
142 | #define CAT2_COLOR_EFFECT 0x0b /* set on/off of color effect */ | ||
143 | #define CAT2_CHROMA_LVL 0x0f /* set chroma level */ | ||
144 | #define CAT2_CHROMA_EN 0x10 /* set on/off of choroma */ | ||
145 | #define CAT2_EDGE_LVL 0x11 /* set sharpness level */ | ||
146 | #define CAT2_EDGE_EN 0x12 /* set on/off sharpness */ | ||
147 | #define CAT2_TONE_CTL 0x25 /* set tone color(contrast) */ | ||
148 | |||
149 | #define MON_ZOOM I2C_REG(CAT_MONITOR, CAT2_ZOOM, 1) | ||
150 | |||
151 | #define MON_CFIXR I2C_REG(CAT_MONITOR, CAT2_CFIXR, 1) | ||
152 | #define MON_CFIXB I2C_REG(CAT_MONITOR, CAT2_CFIXB, 1) | ||
153 | #define REG_CFIXB_SEPIA 0xd8 | ||
154 | #define REG_CFIXR_SEPIA 0x18 | ||
155 | |||
156 | #define MON_EFFECT I2C_REG(CAT_MONITOR, CAT2_COLOR_EFFECT, 1) | ||
157 | #define REG_COLOR_EFFECT_OFF 0x00 | ||
158 | #define REG_COLOR_EFFECT_ON 0x01 | ||
159 | |||
160 | #define MON_CHROMA_EN I2C_REG(CAT_MONITOR, CAT2_CHROMA_EN, 1) | ||
161 | #define MON_CHROMA_LVL I2C_REG(CAT_MONITOR, CAT2_CHROMA_LVL, 1) | ||
162 | #define REG_CHROMA_OFF 0x00 | ||
163 | #define REG_CHROMA_ON 0x01 | ||
164 | |||
165 | #define MON_EDGE_EN I2C_REG(CAT_MONITOR, CAT2_EDGE_EN, 1) | ||
166 | #define MON_EDGE_LVL I2C_REG(CAT_MONITOR, CAT2_EDGE_LVL, 1) | ||
167 | #define REG_EDGE_OFF 0x00 | ||
168 | #define REG_EDGE_ON 0x01 | ||
169 | |||
170 | #define MON_TONE_CTL I2C_REG(CAT_MONITOR, CAT2_TONE_CTL, 1) | ||
171 | |||
172 | /* | ||
173 | * Category 3 - Auto Exposure | ||
174 | * | ||
175 | * The M-5MOLS exposure capbility is detailed as which is similar to digital | ||
176 | * camera. This category supports AE locking/various AE mode(range of exposure) | ||
177 | * /ISO/flickering/EV bias/shutter/meteoring, and anything else. And the | ||
178 | * maximum/minimum exposure gain value depending on M-5MOLS firmware, may be | ||
179 | * different. So, this category also provide getting the max/min values. And, | ||
180 | * each MONITOR and CAPTURE mode has each gain/shutter/max exposure values. | ||
181 | */ | ||
182 | #define CAT3_AE_LOCK 0x00 /* locking Auto exposure */ | ||
183 | #define CAT3_AE_MODE 0x01 /* set AE mode, mode means range */ | ||
184 | #define CAT3_ISO 0x05 /* set ISO */ | ||
185 | #define CAT3_EV_PRESET_MONITOR 0x0a /* EV(scenemode) preset for MONITOR */ | ||
186 | #define CAT3_EV_PRESET_CAPTURE 0x0b /* EV(scenemode) preset for CAPTURE */ | ||
187 | #define CAT3_MANUAL_GAIN_MON 0x12 /* meteoring value for the MONITOR */ | ||
188 | #define CAT3_MAX_GAIN_MON 0x1a /* max gain value for the MONITOR */ | ||
189 | #define CAT3_MANUAL_GAIN_CAP 0x26 /* meteoring value for the CAPTURE */ | ||
190 | #define CAT3_AE_INDEX 0x38 /* AE index */ | ||
191 | |||
192 | #define AE_LOCK I2C_REG(CAT_AE, CAT3_AE_LOCK, 1) | ||
193 | #define REG_AE_UNLOCK 0x00 | ||
194 | #define REG_AE_LOCK 0x01 | ||
195 | |||
196 | #define AE_MODE I2C_REG(CAT_AE, CAT3_AE_MODE, 1) | ||
197 | #define REG_AE_OFF 0x00 /* AE off */ | ||
198 | #define REG_AE_ALL 0x01 /* calc AE in all block integral */ | ||
199 | #define REG_AE_CENTER 0x03 /* calc AE in center weighted */ | ||
200 | #define REG_AE_SPOT 0x06 /* calc AE in specific spot */ | ||
201 | |||
202 | #define AE_ISO I2C_REG(CAT_AE, CAT3_ISO, 1) | ||
203 | #define REG_ISO_AUTO 0x00 | ||
204 | #define REG_ISO_50 0x01 | ||
205 | #define REG_ISO_100 0x02 | ||
206 | #define REG_ISO_200 0x03 | ||
207 | #define REG_ISO_400 0x04 | ||
208 | #define REG_ISO_800 0x05 | ||
209 | |||
210 | #define AE_EV_PRESET_MONITOR I2C_REG(CAT_AE, CAT3_EV_PRESET_MONITOR, 1) | ||
211 | #define AE_EV_PRESET_CAPTURE I2C_REG(CAT_AE, CAT3_EV_PRESET_CAPTURE, 1) | ||
212 | #define REG_SCENE_NORMAL 0x00 | ||
213 | #define REG_SCENE_PORTRAIT 0x01 | ||
214 | #define REG_SCENE_LANDSCAPE 0x02 | ||
215 | #define REG_SCENE_SPORTS 0x03 | ||
216 | #define REG_SCENE_PARTY_INDOOR 0x04 | ||
217 | #define REG_SCENE_BEACH_SNOW 0x05 | ||
218 | #define REG_SCENE_SUNSET 0x06 | ||
219 | #define REG_SCENE_DAWN_DUSK 0x07 | ||
220 | #define REG_SCENE_FALL 0x08 | ||
221 | #define REG_SCENE_NIGHT 0x09 | ||
222 | #define REG_SCENE_AGAINST_LIGHT 0x0a | ||
223 | #define REG_SCENE_FIRE 0x0b | ||
224 | #define REG_SCENE_TEXT 0x0c | ||
225 | #define REG_SCENE_CANDLE 0x0d | ||
226 | |||
227 | #define AE_MAN_GAIN_MON I2C_REG(CAT_AE, CAT3_MANUAL_GAIN_MON, 2) | ||
228 | #define AE_MAX_GAIN_MON I2C_REG(CAT_AE, CAT3_MAX_GAIN_MON, 2) | ||
229 | #define AE_MAN_GAIN_CAP I2C_REG(CAT_AE, CAT3_MANUAL_GAIN_CAP, 2) | ||
230 | |||
231 | #define AE_INDEX I2C_REG(CAT_AE, CAT3_AE_INDEX, 1) | ||
232 | #define REG_AE_INDEX_20_NEG 0x00 | ||
233 | #define REG_AE_INDEX_15_NEG 0x01 | ||
234 | #define REG_AE_INDEX_10_NEG 0x02 | ||
235 | #define REG_AE_INDEX_05_NEG 0x03 | ||
236 | #define REG_AE_INDEX_00 0x04 | ||
237 | #define REG_AE_INDEX_05_POS 0x05 | ||
238 | #define REG_AE_INDEX_10_POS 0x06 | ||
239 | #define REG_AE_INDEX_15_POS 0x07 | ||
240 | #define REG_AE_INDEX_20_POS 0x08 | ||
241 | |||
242 | /* | ||
243 | * Category 6 - White Balance | ||
244 | * | ||
245 | * This category provide AWB locking/mode/preset/speed/gain bias, etc. | ||
246 | */ | ||
247 | #define CAT6_AWB_LOCK 0x00 /* locking Auto Whitebalance */ | ||
248 | #define CAT6_AWB_MODE 0x02 /* set Auto or Manual */ | ||
249 | #define CAT6_AWB_MANUAL 0x03 /* set Manual(preset) value */ | ||
250 | |||
251 | #define AWB_LOCK I2C_REG(CAT_WB, CAT6_AWB_LOCK, 1) | ||
252 | #define REG_AWB_UNLOCK 0x00 | ||
253 | #define REG_AWB_LOCK 0x01 | ||
254 | |||
255 | #define AWB_MODE I2C_REG(CAT_WB, CAT6_AWB_MODE, 1) | ||
256 | #define REG_AWB_AUTO 0x01 /* AWB off */ | ||
257 | #define REG_AWB_PRESET 0x02 /* AWB preset */ | ||
258 | |||
259 | #define AWB_MANUAL I2C_REG(CAT_WB, CAT6_AWB_MANUAL, 1) | ||
260 | #define REG_AWB_INCANDESCENT 0x01 | ||
261 | #define REG_AWB_FLUORESCENT_1 0x02 | ||
262 | #define REG_AWB_FLUORESCENT_2 0x03 | ||
263 | #define REG_AWB_DAYLIGHT 0x04 | ||
264 | #define REG_AWB_CLOUDY 0x05 | ||
265 | #define REG_AWB_SHADE 0x06 | ||
266 | #define REG_AWB_HORIZON 0x07 | ||
267 | #define REG_AWB_LEDLIGHT 0x09 | ||
268 | |||
269 | /* | ||
270 | * Category 7 - EXIF information | ||
271 | */ | ||
272 | #define CAT7_INFO_EXPTIME_NU 0x00 | ||
273 | #define CAT7_INFO_EXPTIME_DE 0x04 | ||
274 | #define CAT7_INFO_TV_NU 0x08 | ||
275 | #define CAT7_INFO_TV_DE 0x0c | ||
276 | #define CAT7_INFO_AV_NU 0x10 | ||
277 | #define CAT7_INFO_AV_DE 0x14 | ||
278 | #define CAT7_INFO_BV_NU 0x18 | ||
279 | #define CAT7_INFO_BV_DE 0x1c | ||
280 | #define CAT7_INFO_EBV_NU 0x20 | ||
281 | #define CAT7_INFO_EBV_DE 0x24 | ||
282 | #define CAT7_INFO_ISO 0x28 | ||
283 | #define CAT7_INFO_FLASH 0x2a | ||
284 | #define CAT7_INFO_SDR 0x2c | ||
285 | #define CAT7_INFO_QVAL 0x2e | ||
286 | |||
287 | #define EXIF_INFO_EXPTIME_NU I2C_REG(CAT_EXIF, CAT7_INFO_EXPTIME_NU, 4) | ||
288 | #define EXIF_INFO_EXPTIME_DE I2C_REG(CAT_EXIF, CAT7_INFO_EXPTIME_DE, 4) | ||
289 | #define EXIF_INFO_TV_NU I2C_REG(CAT_EXIF, CAT7_INFO_TV_NU, 4) | ||
290 | #define EXIF_INFO_TV_DE I2C_REG(CAT_EXIF, CAT7_INFO_TV_DE, 4) | ||
291 | #define EXIF_INFO_AV_NU I2C_REG(CAT_EXIF, CAT7_INFO_AV_NU, 4) | ||
292 | #define EXIF_INFO_AV_DE I2C_REG(CAT_EXIF, CAT7_INFO_AV_DE, 4) | ||
293 | #define EXIF_INFO_BV_NU I2C_REG(CAT_EXIF, CAT7_INFO_BV_NU, 4) | ||
294 | #define EXIF_INFO_BV_DE I2C_REG(CAT_EXIF, CAT7_INFO_BV_DE, 4) | ||
295 | #define EXIF_INFO_EBV_NU I2C_REG(CAT_EXIF, CAT7_INFO_EBV_NU, 4) | ||
296 | #define EXIF_INFO_EBV_DE I2C_REG(CAT_EXIF, CAT7_INFO_EBV_DE, 4) | ||
297 | #define EXIF_INFO_ISO I2C_REG(CAT_EXIF, CAT7_INFO_ISO, 2) | ||
298 | #define EXIF_INFO_FLASH I2C_REG(CAT_EXIF, CAT7_INFO_FLASH, 2) | ||
299 | #define EXIF_INFO_SDR I2C_REG(CAT_EXIF, CAT7_INFO_SDR, 2) | ||
300 | #define EXIF_INFO_QVAL I2C_REG(CAT_EXIF, CAT7_INFO_QVAL, 2) | ||
301 | |||
302 | /* | ||
303 | * Category 9 - Face Detection | ||
304 | */ | ||
305 | #define CAT9_FD_CTL 0x00 | ||
306 | |||
307 | #define FD_CTL I2C_REG(CAT_FD, CAT9_FD_CTL, 1) | ||
308 | #define BIT_FD_EN 0 | ||
309 | #define BIT_FD_DRAW_FACE_FRAME 4 | ||
310 | #define BIT_FD_DRAW_SMILE_LVL 6 | ||
311 | #define REG_FD(shift) (1 << shift) | ||
312 | #define REG_FD_OFF 0x0 | ||
313 | |||
314 | /* | ||
315 | * Category A - Lens Parameter | ||
316 | */ | ||
317 | #define CATA_AF_MODE 0x01 | ||
318 | #define CATA_AF_EXECUTE 0x02 | ||
319 | #define CATA_AF_STATUS 0x03 | ||
320 | #define CATA_AF_VERSION 0x0a | ||
321 | |||
322 | #define AF_MODE I2C_REG(CAT_LENS, CATA_AF_MODE, 1) | ||
323 | #define REG_AF_NORMAL 0x00 /* Normal AF, one time */ | ||
324 | #define REG_AF_MACRO 0x01 /* Macro AF, one time */ | ||
325 | #define REG_AF_POWEROFF 0x07 | ||
326 | |||
327 | #define AF_EXECUTE I2C_REG(CAT_LENS, CATA_AF_EXECUTE, 1) | ||
328 | #define REG_AF_STOP 0x00 | ||
329 | #define REG_AF_EXE_AUTO 0x01 | ||
330 | #define REG_AF_EXE_CAF 0x02 | ||
331 | |||
332 | #define AF_STATUS I2C_REG(CAT_LENS, CATA_AF_STATUS, 1) | ||
333 | #define REG_AF_FAIL 0x00 | ||
334 | #define REG_AF_SUCCESS 0x02 | ||
335 | #define REG_AF_IDLE 0x04 | ||
336 | #define REG_AF_BUSY 0x05 | ||
337 | |||
338 | #define AF_VERSION I2C_REG(CAT_LENS, CATA_AF_VERSION, 1) | ||
339 | |||
340 | /* | ||
341 | * Category B - CAPTURE Parameter | ||
342 | */ | ||
343 | #define CATB_YUVOUT_MAIN 0x00 | ||
344 | #define CATB_MAIN_IMAGE_SIZE 0x01 | ||
345 | #define CATB_MCC_MODE 0x1d | ||
346 | #define CATB_WDR_EN 0x2c | ||
347 | #define CATB_LIGHT_CTRL 0x40 | ||
348 | #define CATB_FLASH_CTRL 0x41 | ||
349 | |||
350 | #define CAPP_YUVOUT_MAIN I2C_REG(CAT_CAPT_PARM, CATB_YUVOUT_MAIN, 1) | ||
351 | #define REG_YUV422 0x00 | ||
352 | #define REG_BAYER10 0x05 | ||
353 | #define REG_BAYER8 0x06 | ||
354 | #define REG_JPEG 0x10 | ||
355 | |||
356 | #define CAPP_MAIN_IMAGE_SIZE I2C_REG(CAT_CAPT_PARM, CATB_MAIN_IMAGE_SIZE, 1) | ||
357 | |||
358 | #define CAPP_MCC_MODE I2C_REG(CAT_CAPT_PARM, CATB_MCC_MODE, 1) | ||
359 | #define REG_MCC_OFF 0x00 | ||
360 | #define REG_MCC_NORMAL 0x01 | ||
361 | |||
362 | #define CAPP_WDR_EN I2C_REG(CAT_CAPT_PARM, CATB_WDR_EN, 1) | ||
363 | #define REG_WDR_OFF 0x00 | ||
364 | #define REG_WDR_ON 0x01 | ||
365 | #define REG_WDR_AUTO 0x02 | ||
366 | |||
367 | #define CAPP_LIGHT_CTRL I2C_REG(CAT_CAPT_PARM, CATB_LIGHT_CTRL, 1) | ||
368 | #define REG_LIGHT_OFF 0x00 | ||
369 | #define REG_LIGHT_ON 0x01 | ||
370 | #define REG_LIGHT_AUTO 0x02 | ||
371 | |||
372 | #define CAPP_FLASH_CTRL I2C_REG(CAT_CAPT_PARM, CATB_FLASH_CTRL, 1) | ||
373 | #define REG_FLASH_OFF 0x00 | ||
374 | #define REG_FLASH_ON 0x01 | ||
375 | #define REG_FLASH_AUTO 0x02 | ||
376 | |||
377 | /* | ||
378 | * Category C - CAPTURE Control | ||
379 | */ | ||
380 | #define CATC_CAP_MODE 0x00 | ||
381 | #define CATC_CAP_SEL_FRAME 0x06 /* It determines Single or Multi */ | ||
382 | #define CATC_CAP_START 0x09 | ||
383 | #define CATC_CAP_IMAGE_SIZE 0x0d | ||
384 | #define CATC_CAP_THUMB_SIZE 0x11 | ||
385 | |||
386 | #define CAPC_MODE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_MODE, 1) | ||
387 | #define REG_CAP_NONE 0x00 | ||
388 | #define REG_CAP_ANTI_SHAKE 0x02 | ||
389 | |||
390 | #define CAPC_SEL_FRAME I2C_REG(CAT_CAPT_CTRL, CATC_CAP_SEL_FRAME, 1) | ||
391 | |||
392 | #define CAPC_START I2C_REG(CAT_CAPT_CTRL, CATC_CAP_START, 1) | ||
393 | #define REG_CAP_START_MAIN 0x01 | ||
394 | #define REG_CAP_START_THUMB 0x03 | ||
395 | |||
396 | #define CAPC_IMAGE_SIZE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_IMAGE_SIZE, 4) | ||
397 | #define CAPC_THUMB_SIZE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_THUMB_SIZE, 4) | ||
398 | |||
399 | /* | ||
400 | * Category F - Flash | ||
401 | * | ||
402 | * This mode provides functions about internal flash stuff and system startup. | ||
403 | */ | ||
404 | #define CATF_CAM_START 0x12 /* It starts internal ARM core booting | ||
405 | * after power-up */ | ||
406 | |||
407 | #define FLASH_CAM_START I2C_REG(CAT_FLASH, CATF_CAM_START, 1) | ||
408 | #define REG_START_ARM_BOOT 0x01 | ||
409 | |||
410 | #endif /* M5MOLS_REG_H */ | ||