diff options
Diffstat (limited to 'drivers/media/video/mt9m111.c')
-rw-r--r-- | drivers/media/video/mt9m111.c | 973 |
1 files changed, 973 insertions, 0 deletions
diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c new file mode 100644 index 000000000000..da0b2d553fd0 --- /dev/null +++ b/drivers/media/video/mt9m111.c | |||
@@ -0,0 +1,973 @@ | |||
1 | /* | ||
2 | * Driver for MT9M111 CMOS Image Sensor from Micron | ||
3 | * | ||
4 | * Copyright (C) 2008, Robert Jarzmik <robert.jarzmik@free.fr> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | #include <linux/videodev2.h> | ||
11 | #include <linux/slab.h> | ||
12 | #include <linux/i2c.h> | ||
13 | #include <linux/log2.h> | ||
14 | #include <linux/gpio.h> | ||
15 | #include <linux/delay.h> | ||
16 | |||
17 | #include <media/v4l2-common.h> | ||
18 | #include <media/v4l2-chip-ident.h> | ||
19 | #include <media/soc_camera.h> | ||
20 | |||
21 | /* | ||
22 | * mt9m111 i2c address is 0x5d or 0x48 (depending on SAddr pin) | ||
23 | * The platform has to define i2c_board_info and call i2c_register_board_info() | ||
24 | */ | ||
25 | |||
26 | /* mt9m111: Sensor register addresses */ | ||
27 | #define MT9M111_CHIP_VERSION 0x000 | ||
28 | #define MT9M111_ROW_START 0x001 | ||
29 | #define MT9M111_COLUMN_START 0x002 | ||
30 | #define MT9M111_WINDOW_HEIGHT 0x003 | ||
31 | #define MT9M111_WINDOW_WIDTH 0x004 | ||
32 | #define MT9M111_HORIZONTAL_BLANKING_B 0x005 | ||
33 | #define MT9M111_VERTICAL_BLANKING_B 0x006 | ||
34 | #define MT9M111_HORIZONTAL_BLANKING_A 0x007 | ||
35 | #define MT9M111_VERTICAL_BLANKING_A 0x008 | ||
36 | #define MT9M111_SHUTTER_WIDTH 0x009 | ||
37 | #define MT9M111_ROW_SPEED 0x00a | ||
38 | #define MT9M111_EXTRA_DELAY 0x00b | ||
39 | #define MT9M111_SHUTTER_DELAY 0x00c | ||
40 | #define MT9M111_RESET 0x00d | ||
41 | #define MT9M111_READ_MODE_B 0x020 | ||
42 | #define MT9M111_READ_MODE_A 0x021 | ||
43 | #define MT9M111_FLASH_CONTROL 0x023 | ||
44 | #define MT9M111_GREEN1_GAIN 0x02b | ||
45 | #define MT9M111_BLUE_GAIN 0x02c | ||
46 | #define MT9M111_RED_GAIN 0x02d | ||
47 | #define MT9M111_GREEN2_GAIN 0x02e | ||
48 | #define MT9M111_GLOBAL_GAIN 0x02f | ||
49 | #define MT9M111_CONTEXT_CONTROL 0x0c8 | ||
50 | #define MT9M111_PAGE_MAP 0x0f0 | ||
51 | #define MT9M111_BYTE_WISE_ADDR 0x0f1 | ||
52 | |||
53 | #define MT9M111_RESET_SYNC_CHANGES (1 << 15) | ||
54 | #define MT9M111_RESET_RESTART_BAD_FRAME (1 << 9) | ||
55 | #define MT9M111_RESET_SHOW_BAD_FRAMES (1 << 8) | ||
56 | #define MT9M111_RESET_RESET_SOC (1 << 5) | ||
57 | #define MT9M111_RESET_OUTPUT_DISABLE (1 << 4) | ||
58 | #define MT9M111_RESET_CHIP_ENABLE (1 << 3) | ||
59 | #define MT9M111_RESET_ANALOG_STANDBY (1 << 2) | ||
60 | #define MT9M111_RESET_RESTART_FRAME (1 << 1) | ||
61 | #define MT9M111_RESET_RESET_MODE (1 << 0) | ||
62 | |||
63 | #define MT9M111_RMB_MIRROR_COLS (1 << 1) | ||
64 | #define MT9M111_RMB_MIRROR_ROWS (1 << 0) | ||
65 | #define MT9M111_CTXT_CTRL_RESTART (1 << 15) | ||
66 | #define MT9M111_CTXT_CTRL_DEFECTCOR_B (1 << 12) | ||
67 | #define MT9M111_CTXT_CTRL_RESIZE_B (1 << 10) | ||
68 | #define MT9M111_CTXT_CTRL_CTRL2_B (1 << 9) | ||
69 | #define MT9M111_CTXT_CTRL_GAMMA_B (1 << 8) | ||
70 | #define MT9M111_CTXT_CTRL_XENON_EN (1 << 7) | ||
71 | #define MT9M111_CTXT_CTRL_READ_MODE_B (1 << 3) | ||
72 | #define MT9M111_CTXT_CTRL_LED_FLASH_EN (1 << 2) | ||
73 | #define MT9M111_CTXT_CTRL_VBLANK_SEL_B (1 << 1) | ||
74 | #define MT9M111_CTXT_CTRL_HBLANK_SEL_B (1 << 0) | ||
75 | /* | ||
76 | * mt9m111: Colorpipe register addresses (0x100..0x1ff) | ||
77 | */ | ||
78 | #define MT9M111_OPER_MODE_CTRL 0x106 | ||
79 | #define MT9M111_OUTPUT_FORMAT_CTRL 0x108 | ||
80 | #define MT9M111_REDUCER_XZOOM_B 0x1a0 | ||
81 | #define MT9M111_REDUCER_XSIZE_B 0x1a1 | ||
82 | #define MT9M111_REDUCER_YZOOM_B 0x1a3 | ||
83 | #define MT9M111_REDUCER_YSIZE_B 0x1a4 | ||
84 | #define MT9M111_REDUCER_XZOOM_A 0x1a6 | ||
85 | #define MT9M111_REDUCER_XSIZE_A 0x1a7 | ||
86 | #define MT9M111_REDUCER_YZOOM_A 0x1a9 | ||
87 | #define MT9M111_REDUCER_YSIZE_A 0x1aa | ||
88 | |||
89 | #define MT9M111_OUTPUT_FORMAT_CTRL2_A 0x13a | ||
90 | #define MT9M111_OUTPUT_FORMAT_CTRL2_B 0x19b | ||
91 | |||
92 | #define MT9M111_OPMODE_AUTOEXPO_EN (1 << 14) | ||
93 | |||
94 | |||
95 | #define MT9M111_OUTFMT_PROCESSED_BAYER (1 << 14) | ||
96 | #define MT9M111_OUTFMT_BYPASS_IFP (1 << 10) | ||
97 | #define MT9M111_OUTFMT_INV_PIX_CLOCK (1 << 9) | ||
98 | #define MT9M111_OUTFMT_RGB (1 << 8) | ||
99 | #define MT9M111_OUTFMT_RGB565 (0x0 << 6) | ||
100 | #define MT9M111_OUTFMT_RGB555 (0x1 << 6) | ||
101 | #define MT9M111_OUTFMT_RGB444x (0x2 << 6) | ||
102 | #define MT9M111_OUTFMT_RGBx444 (0x3 << 6) | ||
103 | #define MT9M111_OUTFMT_TST_RAMP_OFF (0x0 << 4) | ||
104 | #define MT9M111_OUTFMT_TST_RAMP_COL (0x1 << 4) | ||
105 | #define MT9M111_OUTFMT_TST_RAMP_ROW (0x2 << 4) | ||
106 | #define MT9M111_OUTFMT_TST_RAMP_FRAME (0x3 << 4) | ||
107 | #define MT9M111_OUTFMT_SHIFT_3_UP (1 << 3) | ||
108 | #define MT9M111_OUTFMT_AVG_CHROMA (1 << 2) | ||
109 | #define MT9M111_OUTFMT_SWAP_YCbCr_C_Y (1 << 1) | ||
110 | #define MT9M111_OUTFMT_SWAP_RGB_EVEN (1 << 1) | ||
111 | #define MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr (1 << 0) | ||
112 | /* | ||
113 | * mt9m111: Camera control register addresses (0x200..0x2ff not implemented) | ||
114 | */ | ||
115 | |||
116 | #define reg_read(reg) mt9m111_reg_read(icd, MT9M111_##reg) | ||
117 | #define reg_write(reg, val) mt9m111_reg_write(icd, MT9M111_##reg, (val)) | ||
118 | #define reg_set(reg, val) mt9m111_reg_set(icd, MT9M111_##reg, (val)) | ||
119 | #define reg_clear(reg, val) mt9m111_reg_clear(icd, MT9M111_##reg, (val)) | ||
120 | |||
121 | #define MT9M111_MIN_DARK_ROWS 8 | ||
122 | #define MT9M111_MIN_DARK_COLS 24 | ||
123 | #define MT9M111_MAX_HEIGHT 1024 | ||
124 | #define MT9M111_MAX_WIDTH 1280 | ||
125 | |||
126 | #define COL_FMT(_name, _depth, _fourcc, _colorspace) \ | ||
127 | { .name = _name, .depth = _depth, .fourcc = _fourcc, \ | ||
128 | .colorspace = _colorspace } | ||
129 | #define RGB_FMT(_name, _depth, _fourcc) \ | ||
130 | COL_FMT(_name, _depth, _fourcc, V4L2_COLORSPACE_SRGB) | ||
131 | |||
132 | static const struct soc_camera_data_format mt9m111_colour_formats[] = { | ||
133 | COL_FMT("YCrYCb 8 bit", 8, V4L2_PIX_FMT_YUYV, V4L2_COLORSPACE_JPEG), | ||
134 | RGB_FMT("RGB 565", 16, V4L2_PIX_FMT_RGB565), | ||
135 | RGB_FMT("RGB 555", 16, V4L2_PIX_FMT_RGB555), | ||
136 | RGB_FMT("Bayer (sRGB) 10 bit", 10, V4L2_PIX_FMT_SBGGR16), | ||
137 | RGB_FMT("Bayer (sRGB) 8 bit", 8, V4L2_PIX_FMT_SBGGR8), | ||
138 | }; | ||
139 | |||
140 | enum mt9m111_context { | ||
141 | HIGHPOWER = 0, | ||
142 | LOWPOWER, | ||
143 | }; | ||
144 | |||
145 | struct mt9m111 { | ||
146 | struct i2c_client *client; | ||
147 | struct soc_camera_device icd; | ||
148 | int model; /* V4L2_IDENT_MT9M111* codes from v4l2-chip-ident.h */ | ||
149 | enum mt9m111_context context; | ||
150 | unsigned int left, top, width, height; | ||
151 | u32 pixfmt; | ||
152 | unsigned char autoexposure; | ||
153 | unsigned char datawidth; | ||
154 | unsigned int powered:1; | ||
155 | unsigned int hflip:1; | ||
156 | unsigned int vflip:1; | ||
157 | unsigned int swap_rgb_even_odd:1; | ||
158 | unsigned int swap_rgb_red_blue:1; | ||
159 | unsigned int swap_yuv_y_chromas:1; | ||
160 | unsigned int swap_yuv_cb_cr:1; | ||
161 | }; | ||
162 | |||
163 | static int reg_page_map_set(struct i2c_client *client, const u16 reg) | ||
164 | { | ||
165 | int ret; | ||
166 | u16 page; | ||
167 | static int lastpage = -1; /* PageMap cache value */ | ||
168 | |||
169 | page = (reg >> 8); | ||
170 | if (page == lastpage) | ||
171 | return 0; | ||
172 | if (page > 2) | ||
173 | return -EINVAL; | ||
174 | |||
175 | ret = i2c_smbus_write_word_data(client, MT9M111_PAGE_MAP, swab16(page)); | ||
176 | if (!ret) | ||
177 | lastpage = page; | ||
178 | return ret; | ||
179 | } | ||
180 | |||
181 | static int mt9m111_reg_read(struct soc_camera_device *icd, const u16 reg) | ||
182 | { | ||
183 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
184 | struct i2c_client *client = mt9m111->client; | ||
185 | int ret; | ||
186 | |||
187 | ret = reg_page_map_set(client, reg); | ||
188 | if (!ret) | ||
189 | ret = swab16(i2c_smbus_read_word_data(client, (reg & 0xff))); | ||
190 | |||
191 | dev_dbg(&icd->dev, "read reg.%03x -> %04x\n", reg, ret); | ||
192 | return ret; | ||
193 | } | ||
194 | |||
195 | static int mt9m111_reg_write(struct soc_camera_device *icd, const u16 reg, | ||
196 | const u16 data) | ||
197 | { | ||
198 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
199 | struct i2c_client *client = mt9m111->client; | ||
200 | int ret; | ||
201 | |||
202 | ret = reg_page_map_set(client, reg); | ||
203 | if (!ret) | ||
204 | ret = i2c_smbus_write_word_data(mt9m111->client, (reg & 0xff), | ||
205 | swab16(data)); | ||
206 | dev_dbg(&icd->dev, "write reg.%03x = %04x -> %d\n", reg, data, ret); | ||
207 | return ret; | ||
208 | } | ||
209 | |||
210 | static int mt9m111_reg_set(struct soc_camera_device *icd, const u16 reg, | ||
211 | const u16 data) | ||
212 | { | ||
213 | int ret; | ||
214 | |||
215 | ret = mt9m111_reg_read(icd, reg); | ||
216 | if (ret >= 0) | ||
217 | ret = mt9m111_reg_write(icd, reg, ret | data); | ||
218 | return ret; | ||
219 | } | ||
220 | |||
221 | static int mt9m111_reg_clear(struct soc_camera_device *icd, const u16 reg, | ||
222 | const u16 data) | ||
223 | { | ||
224 | int ret; | ||
225 | |||
226 | ret = mt9m111_reg_read(icd, reg); | ||
227 | return mt9m111_reg_write(icd, reg, ret & ~data); | ||
228 | } | ||
229 | |||
230 | static int mt9m111_set_context(struct soc_camera_device *icd, | ||
231 | enum mt9m111_context ctxt) | ||
232 | { | ||
233 | int valB = MT9M111_CTXT_CTRL_RESTART | MT9M111_CTXT_CTRL_DEFECTCOR_B | ||
234 | | MT9M111_CTXT_CTRL_RESIZE_B | MT9M111_CTXT_CTRL_CTRL2_B | ||
235 | | MT9M111_CTXT_CTRL_GAMMA_B | MT9M111_CTXT_CTRL_READ_MODE_B | ||
236 | | MT9M111_CTXT_CTRL_VBLANK_SEL_B | ||
237 | | MT9M111_CTXT_CTRL_HBLANK_SEL_B; | ||
238 | int valA = MT9M111_CTXT_CTRL_RESTART; | ||
239 | |||
240 | if (ctxt == HIGHPOWER) | ||
241 | return reg_write(CONTEXT_CONTROL, valB); | ||
242 | else | ||
243 | return reg_write(CONTEXT_CONTROL, valA); | ||
244 | } | ||
245 | |||
246 | static int mt9m111_setup_rect(struct soc_camera_device *icd) | ||
247 | { | ||
248 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
249 | int ret, is_raw_format; | ||
250 | int width = mt9m111->width; | ||
251 | int height = mt9m111->height; | ||
252 | |||
253 | if ((mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR8) | ||
254 | || (mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR16)) | ||
255 | is_raw_format = 1; | ||
256 | else | ||
257 | is_raw_format = 0; | ||
258 | |||
259 | ret = reg_write(COLUMN_START, mt9m111->left); | ||
260 | if (!ret) | ||
261 | ret = reg_write(ROW_START, mt9m111->top); | ||
262 | |||
263 | if (is_raw_format) { | ||
264 | if (!ret) | ||
265 | ret = reg_write(WINDOW_WIDTH, width); | ||
266 | if (!ret) | ||
267 | ret = reg_write(WINDOW_HEIGHT, height); | ||
268 | } else { | ||
269 | if (!ret) | ||
270 | ret = reg_write(REDUCER_XZOOM_B, MT9M111_MAX_WIDTH); | ||
271 | if (!ret) | ||
272 | ret = reg_write(REDUCER_YZOOM_B, MT9M111_MAX_HEIGHT); | ||
273 | if (!ret) | ||
274 | ret = reg_write(REDUCER_XSIZE_B, width); | ||
275 | if (!ret) | ||
276 | ret = reg_write(REDUCER_YSIZE_B, height); | ||
277 | if (!ret) | ||
278 | ret = reg_write(REDUCER_XZOOM_A, MT9M111_MAX_WIDTH); | ||
279 | if (!ret) | ||
280 | ret = reg_write(REDUCER_YZOOM_A, MT9M111_MAX_HEIGHT); | ||
281 | if (!ret) | ||
282 | ret = reg_write(REDUCER_XSIZE_A, width); | ||
283 | if (!ret) | ||
284 | ret = reg_write(REDUCER_YSIZE_A, height); | ||
285 | } | ||
286 | |||
287 | return ret; | ||
288 | } | ||
289 | |||
290 | static int mt9m111_setup_pixfmt(struct soc_camera_device *icd, u16 outfmt) | ||
291 | { | ||
292 | int ret; | ||
293 | |||
294 | ret = reg_write(OUTPUT_FORMAT_CTRL2_A, outfmt); | ||
295 | if (!ret) | ||
296 | ret = reg_write(OUTPUT_FORMAT_CTRL2_B, outfmt); | ||
297 | return ret; | ||
298 | } | ||
299 | |||
300 | static int mt9m111_setfmt_bayer8(struct soc_camera_device *icd) | ||
301 | { | ||
302 | return mt9m111_setup_pixfmt(icd, MT9M111_OUTFMT_PROCESSED_BAYER); | ||
303 | } | ||
304 | |||
305 | static int mt9m111_setfmt_bayer10(struct soc_camera_device *icd) | ||
306 | { | ||
307 | return mt9m111_setup_pixfmt(icd, MT9M111_OUTFMT_BYPASS_IFP); | ||
308 | } | ||
309 | |||
310 | static int mt9m111_setfmt_rgb565(struct soc_camera_device *icd) | ||
311 | { | ||
312 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
313 | int val = 0; | ||
314 | |||
315 | if (mt9m111->swap_rgb_red_blue) | ||
316 | val |= MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr; | ||
317 | if (mt9m111->swap_rgb_even_odd) | ||
318 | val |= MT9M111_OUTFMT_SWAP_RGB_EVEN; | ||
319 | val |= MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565; | ||
320 | |||
321 | return mt9m111_setup_pixfmt(icd, val); | ||
322 | } | ||
323 | |||
324 | static int mt9m111_setfmt_rgb555(struct soc_camera_device *icd) | ||
325 | { | ||
326 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
327 | int val = 0; | ||
328 | |||
329 | if (mt9m111->swap_rgb_red_blue) | ||
330 | val |= MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr; | ||
331 | if (mt9m111->swap_rgb_even_odd) | ||
332 | val |= MT9M111_OUTFMT_SWAP_RGB_EVEN; | ||
333 | val |= MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555; | ||
334 | |||
335 | return mt9m111_setup_pixfmt(icd, val); | ||
336 | } | ||
337 | |||
338 | static int mt9m111_setfmt_yuv(struct soc_camera_device *icd) | ||
339 | { | ||
340 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
341 | int val = 0; | ||
342 | |||
343 | if (mt9m111->swap_yuv_cb_cr) | ||
344 | val |= MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr; | ||
345 | if (mt9m111->swap_yuv_y_chromas) | ||
346 | val |= MT9M111_OUTFMT_SWAP_YCbCr_C_Y; | ||
347 | |||
348 | return mt9m111_setup_pixfmt(icd, val); | ||
349 | } | ||
350 | |||
351 | static int mt9m111_enable(struct soc_camera_device *icd) | ||
352 | { | ||
353 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
354 | struct soc_camera_link *icl = mt9m111->client->dev.platform_data; | ||
355 | int ret; | ||
356 | |||
357 | if (icl->power) { | ||
358 | ret = icl->power(&mt9m111->client->dev, 1); | ||
359 | if (ret < 0) { | ||
360 | dev_err(icd->vdev->parent, | ||
361 | "Platform failed to power-on the camera.\n"); | ||
362 | return ret; | ||
363 | } | ||
364 | } | ||
365 | |||
366 | ret = reg_set(RESET, MT9M111_RESET_CHIP_ENABLE); | ||
367 | if (!ret) | ||
368 | mt9m111->powered = 1; | ||
369 | return ret; | ||
370 | } | ||
371 | |||
372 | static int mt9m111_disable(struct soc_camera_device *icd) | ||
373 | { | ||
374 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
375 | struct soc_camera_link *icl = mt9m111->client->dev.platform_data; | ||
376 | int ret; | ||
377 | |||
378 | ret = reg_clear(RESET, MT9M111_RESET_CHIP_ENABLE); | ||
379 | if (!ret) | ||
380 | mt9m111->powered = 0; | ||
381 | |||
382 | if (icl->power) | ||
383 | icl->power(&mt9m111->client->dev, 0); | ||
384 | |||
385 | return ret; | ||
386 | } | ||
387 | |||
388 | static int mt9m111_reset(struct soc_camera_device *icd) | ||
389 | { | ||
390 | int ret; | ||
391 | |||
392 | ret = reg_set(RESET, MT9M111_RESET_RESET_MODE); | ||
393 | if (!ret) | ||
394 | ret = reg_set(RESET, MT9M111_RESET_RESET_SOC); | ||
395 | if (!ret) | ||
396 | ret = reg_clear(RESET, MT9M111_RESET_RESET_MODE | ||
397 | | MT9M111_RESET_RESET_SOC); | ||
398 | return ret; | ||
399 | } | ||
400 | |||
401 | static int mt9m111_start_capture(struct soc_camera_device *icd) | ||
402 | { | ||
403 | return 0; | ||
404 | } | ||
405 | |||
406 | static int mt9m111_stop_capture(struct soc_camera_device *icd) | ||
407 | { | ||
408 | return 0; | ||
409 | } | ||
410 | |||
411 | static unsigned long mt9m111_query_bus_param(struct soc_camera_device *icd) | ||
412 | { | ||
413 | return SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING | | ||
414 | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | | ||
415 | SOCAM_DATAWIDTH_8; | ||
416 | } | ||
417 | |||
418 | static int mt9m111_set_bus_param(struct soc_camera_device *icd, unsigned long f) | ||
419 | { | ||
420 | return 0; | ||
421 | } | ||
422 | |||
423 | static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt) | ||
424 | { | ||
425 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
426 | int ret; | ||
427 | |||
428 | switch (pixfmt) { | ||
429 | case V4L2_PIX_FMT_SBGGR8: | ||
430 | ret = mt9m111_setfmt_bayer8(icd); | ||
431 | break; | ||
432 | case V4L2_PIX_FMT_SBGGR16: | ||
433 | ret = mt9m111_setfmt_bayer10(icd); | ||
434 | break; | ||
435 | case V4L2_PIX_FMT_RGB555: | ||
436 | ret = mt9m111_setfmt_rgb555(icd); | ||
437 | break; | ||
438 | case V4L2_PIX_FMT_RGB565: | ||
439 | ret = mt9m111_setfmt_rgb565(icd); | ||
440 | break; | ||
441 | case V4L2_PIX_FMT_YUYV: | ||
442 | ret = mt9m111_setfmt_yuv(icd); | ||
443 | break; | ||
444 | default: | ||
445 | dev_err(&icd->dev, "Pixel format not handled : %x\n", pixfmt); | ||
446 | ret = -EINVAL; | ||
447 | } | ||
448 | |||
449 | if (!ret) | ||
450 | mt9m111->pixfmt = pixfmt; | ||
451 | |||
452 | return ret; | ||
453 | } | ||
454 | |||
455 | static int mt9m111_set_fmt_cap(struct soc_camera_device *icd, | ||
456 | __u32 pixfmt, struct v4l2_rect *rect) | ||
457 | { | ||
458 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
459 | int ret; | ||
460 | |||
461 | mt9m111->left = rect->left; | ||
462 | mt9m111->top = rect->top; | ||
463 | mt9m111->width = rect->width; | ||
464 | mt9m111->height = rect->height; | ||
465 | |||
466 | dev_dbg(&icd->dev, "%s fmt=%x left=%d, top=%d, width=%d, height=%d\n", | ||
467 | __func__, pixfmt, mt9m111->left, mt9m111->top, mt9m111->width, | ||
468 | mt9m111->height); | ||
469 | |||
470 | ret = mt9m111_setup_rect(icd); | ||
471 | if (!ret) | ||
472 | ret = mt9m111_set_pixfmt(icd, pixfmt); | ||
473 | return ret; | ||
474 | } | ||
475 | |||
476 | static int mt9m111_try_fmt_cap(struct soc_camera_device *icd, | ||
477 | struct v4l2_format *f) | ||
478 | { | ||
479 | if (f->fmt.pix.height > MT9M111_MAX_HEIGHT) | ||
480 | f->fmt.pix.height = MT9M111_MAX_HEIGHT; | ||
481 | if (f->fmt.pix.width > MT9M111_MAX_WIDTH) | ||
482 | f->fmt.pix.width = MT9M111_MAX_WIDTH; | ||
483 | |||
484 | return 0; | ||
485 | } | ||
486 | |||
487 | static int mt9m111_get_chip_id(struct soc_camera_device *icd, | ||
488 | struct v4l2_chip_ident *id) | ||
489 | { | ||
490 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
491 | |||
492 | if (id->match_type != V4L2_CHIP_MATCH_I2C_ADDR) | ||
493 | return -EINVAL; | ||
494 | |||
495 | if (id->match_chip != mt9m111->client->addr) | ||
496 | return -ENODEV; | ||
497 | |||
498 | id->ident = mt9m111->model; | ||
499 | id->revision = 0; | ||
500 | |||
501 | return 0; | ||
502 | } | ||
503 | |||
504 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
505 | static int mt9m111_get_register(struct soc_camera_device *icd, | ||
506 | struct v4l2_register *reg) | ||
507 | { | ||
508 | int val; | ||
509 | |||
510 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
511 | |||
512 | if (reg->match_type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff) | ||
513 | return -EINVAL; | ||
514 | if (reg->match_chip != mt9m111->client->addr) | ||
515 | return -ENODEV; | ||
516 | |||
517 | val = mt9m111_reg_read(icd, reg->reg); | ||
518 | reg->val = (u64)val; | ||
519 | |||
520 | if (reg->val > 0xffff) | ||
521 | return -EIO; | ||
522 | |||
523 | return 0; | ||
524 | } | ||
525 | |||
526 | static int mt9m111_set_register(struct soc_camera_device *icd, | ||
527 | struct v4l2_register *reg) | ||
528 | { | ||
529 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
530 | |||
531 | if (reg->match_type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff) | ||
532 | return -EINVAL; | ||
533 | |||
534 | if (reg->match_chip != mt9m111->client->addr) | ||
535 | return -ENODEV; | ||
536 | |||
537 | if (mt9m111_reg_write(icd, reg->reg, reg->val) < 0) | ||
538 | return -EIO; | ||
539 | |||
540 | return 0; | ||
541 | } | ||
542 | #endif | ||
543 | |||
544 | static const struct v4l2_queryctrl mt9m111_controls[] = { | ||
545 | { | ||
546 | .id = V4L2_CID_VFLIP, | ||
547 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
548 | .name = "Flip Verticaly", | ||
549 | .minimum = 0, | ||
550 | .maximum = 1, | ||
551 | .step = 1, | ||
552 | .default_value = 0, | ||
553 | }, { | ||
554 | .id = V4L2_CID_HFLIP, | ||
555 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
556 | .name = "Flip Horizontaly", | ||
557 | .minimum = 0, | ||
558 | .maximum = 1, | ||
559 | .step = 1, | ||
560 | .default_value = 0, | ||
561 | }, { /* gain = 1/32*val (=>gain=1 if val==32) */ | ||
562 | .id = V4L2_CID_GAIN, | ||
563 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
564 | .name = "Gain", | ||
565 | .minimum = 0, | ||
566 | .maximum = 63 * 2 * 2, | ||
567 | .step = 1, | ||
568 | .default_value = 32, | ||
569 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
570 | }, { | ||
571 | .id = V4L2_CID_EXPOSURE_AUTO, | ||
572 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
573 | .name = "Auto Exposure", | ||
574 | .minimum = 0, | ||
575 | .maximum = 1, | ||
576 | .step = 1, | ||
577 | .default_value = 1, | ||
578 | } | ||
579 | }; | ||
580 | |||
581 | static int mt9m111_video_probe(struct soc_camera_device *); | ||
582 | static void mt9m111_video_remove(struct soc_camera_device *); | ||
583 | static int mt9m111_get_control(struct soc_camera_device *, | ||
584 | struct v4l2_control *); | ||
585 | static int mt9m111_set_control(struct soc_camera_device *, | ||
586 | struct v4l2_control *); | ||
587 | static int mt9m111_resume(struct soc_camera_device *icd); | ||
588 | static int mt9m111_init(struct soc_camera_device *icd); | ||
589 | static int mt9m111_release(struct soc_camera_device *icd); | ||
590 | |||
591 | static struct soc_camera_ops mt9m111_ops = { | ||
592 | .owner = THIS_MODULE, | ||
593 | .probe = mt9m111_video_probe, | ||
594 | .remove = mt9m111_video_remove, | ||
595 | .init = mt9m111_init, | ||
596 | .resume = mt9m111_resume, | ||
597 | .release = mt9m111_release, | ||
598 | .start_capture = mt9m111_start_capture, | ||
599 | .stop_capture = mt9m111_stop_capture, | ||
600 | .set_fmt_cap = mt9m111_set_fmt_cap, | ||
601 | .try_fmt_cap = mt9m111_try_fmt_cap, | ||
602 | .query_bus_param = mt9m111_query_bus_param, | ||
603 | .set_bus_param = mt9m111_set_bus_param, | ||
604 | .controls = mt9m111_controls, | ||
605 | .num_controls = ARRAY_SIZE(mt9m111_controls), | ||
606 | .get_control = mt9m111_get_control, | ||
607 | .set_control = mt9m111_set_control, | ||
608 | .get_chip_id = mt9m111_get_chip_id, | ||
609 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
610 | .get_register = mt9m111_get_register, | ||
611 | .set_register = mt9m111_set_register, | ||
612 | #endif | ||
613 | }; | ||
614 | |||
615 | static int mt9m111_set_flip(struct soc_camera_device *icd, int flip, int mask) | ||
616 | { | ||
617 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
618 | int ret; | ||
619 | |||
620 | if (mt9m111->context == HIGHPOWER) { | ||
621 | if (flip) | ||
622 | ret = reg_set(READ_MODE_B, mask); | ||
623 | else | ||
624 | ret = reg_clear(READ_MODE_B, mask); | ||
625 | } else { | ||
626 | if (flip) | ||
627 | ret = reg_set(READ_MODE_A, mask); | ||
628 | else | ||
629 | ret = reg_clear(READ_MODE_A, mask); | ||
630 | } | ||
631 | |||
632 | return ret; | ||
633 | } | ||
634 | |||
635 | static int mt9m111_get_global_gain(struct soc_camera_device *icd) | ||
636 | { | ||
637 | unsigned int data, gain; | ||
638 | |||
639 | data = reg_read(GLOBAL_GAIN); | ||
640 | if (data >= 0) | ||
641 | gain = ((data & (1 << 10)) * 2) | ||
642 | | ((data & (1 << 9)) * 2) | ||
643 | | (data & 0x2f); | ||
644 | else | ||
645 | gain = data; | ||
646 | |||
647 | return gain; | ||
648 | } | ||
649 | static int mt9m111_set_global_gain(struct soc_camera_device *icd, int gain) | ||
650 | { | ||
651 | u16 val; | ||
652 | |||
653 | if (gain > 63 * 2 * 2) | ||
654 | return -EINVAL; | ||
655 | |||
656 | icd->gain = gain; | ||
657 | if ((gain >= 64 * 2) && (gain < 63 * 2 * 2)) | ||
658 | val = (1 << 10) | (1 << 9) | (gain / 4); | ||
659 | else if ((gain >= 64) && (gain < 64 * 2)) | ||
660 | val = (1 << 9) | (gain / 2); | ||
661 | else | ||
662 | val = gain; | ||
663 | |||
664 | return reg_write(GLOBAL_GAIN, val); | ||
665 | } | ||
666 | |||
667 | static int mt9m111_set_autoexposure(struct soc_camera_device *icd, int on) | ||
668 | { | ||
669 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
670 | int ret; | ||
671 | |||
672 | if (on) | ||
673 | ret = reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN); | ||
674 | else | ||
675 | ret = reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN); | ||
676 | |||
677 | if (!ret) | ||
678 | mt9m111->autoexposure = on; | ||
679 | |||
680 | return ret; | ||
681 | } | ||
682 | static int mt9m111_get_control(struct soc_camera_device *icd, | ||
683 | struct v4l2_control *ctrl) | ||
684 | { | ||
685 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
686 | int data; | ||
687 | |||
688 | switch (ctrl->id) { | ||
689 | case V4L2_CID_VFLIP: | ||
690 | if (mt9m111->context == HIGHPOWER) | ||
691 | data = reg_read(READ_MODE_B); | ||
692 | else | ||
693 | data = reg_read(READ_MODE_A); | ||
694 | |||
695 | if (data < 0) | ||
696 | return -EIO; | ||
697 | ctrl->value = !!(data & MT9M111_RMB_MIRROR_ROWS); | ||
698 | break; | ||
699 | case V4L2_CID_HFLIP: | ||
700 | if (mt9m111->context == HIGHPOWER) | ||
701 | data = reg_read(READ_MODE_B); | ||
702 | else | ||
703 | data = reg_read(READ_MODE_A); | ||
704 | |||
705 | if (data < 0) | ||
706 | return -EIO; | ||
707 | ctrl->value = !!(data & MT9M111_RMB_MIRROR_COLS); | ||
708 | break; | ||
709 | case V4L2_CID_GAIN: | ||
710 | data = mt9m111_get_global_gain(icd); | ||
711 | if (data < 0) | ||
712 | return data; | ||
713 | ctrl->value = data; | ||
714 | break; | ||
715 | case V4L2_CID_EXPOSURE_AUTO: | ||
716 | ctrl->value = mt9m111->autoexposure; | ||
717 | break; | ||
718 | } | ||
719 | return 0; | ||
720 | } | ||
721 | |||
722 | static int mt9m111_set_control(struct soc_camera_device *icd, | ||
723 | struct v4l2_control *ctrl) | ||
724 | { | ||
725 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
726 | const struct v4l2_queryctrl *qctrl; | ||
727 | int ret; | ||
728 | |||
729 | qctrl = soc_camera_find_qctrl(&mt9m111_ops, ctrl->id); | ||
730 | |||
731 | if (!qctrl) | ||
732 | return -EINVAL; | ||
733 | |||
734 | switch (ctrl->id) { | ||
735 | case V4L2_CID_VFLIP: | ||
736 | mt9m111->vflip = ctrl->value; | ||
737 | ret = mt9m111_set_flip(icd, ctrl->value, | ||
738 | MT9M111_RMB_MIRROR_ROWS); | ||
739 | break; | ||
740 | case V4L2_CID_HFLIP: | ||
741 | mt9m111->hflip = ctrl->value; | ||
742 | ret = mt9m111_set_flip(icd, ctrl->value, | ||
743 | MT9M111_RMB_MIRROR_COLS); | ||
744 | break; | ||
745 | case V4L2_CID_GAIN: | ||
746 | ret = mt9m111_set_global_gain(icd, ctrl->value); | ||
747 | break; | ||
748 | case V4L2_CID_EXPOSURE_AUTO: | ||
749 | ret = mt9m111_set_autoexposure(icd, ctrl->value); | ||
750 | break; | ||
751 | default: | ||
752 | ret = -EINVAL; | ||
753 | } | ||
754 | |||
755 | return ret; | ||
756 | } | ||
757 | |||
758 | static int mt9m111_restore_state(struct soc_camera_device *icd) | ||
759 | { | ||
760 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
761 | |||
762 | mt9m111_set_context(icd, mt9m111->context); | ||
763 | mt9m111_set_pixfmt(icd, mt9m111->pixfmt); | ||
764 | mt9m111_setup_rect(icd); | ||
765 | mt9m111_set_flip(icd, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS); | ||
766 | mt9m111_set_flip(icd, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS); | ||
767 | mt9m111_set_global_gain(icd, icd->gain); | ||
768 | mt9m111_set_autoexposure(icd, mt9m111->autoexposure); | ||
769 | return 0; | ||
770 | } | ||
771 | |||
772 | static int mt9m111_resume(struct soc_camera_device *icd) | ||
773 | { | ||
774 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
775 | int ret = 0; | ||
776 | |||
777 | if (mt9m111->powered) { | ||
778 | ret = mt9m111_enable(icd); | ||
779 | if (!ret) | ||
780 | ret = mt9m111_reset(icd); | ||
781 | if (!ret) | ||
782 | ret = mt9m111_restore_state(icd); | ||
783 | } | ||
784 | return ret; | ||
785 | } | ||
786 | |||
787 | static int mt9m111_init(struct soc_camera_device *icd) | ||
788 | { | ||
789 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
790 | int ret; | ||
791 | |||
792 | mt9m111->context = HIGHPOWER; | ||
793 | ret = mt9m111_enable(icd); | ||
794 | if (!ret) | ||
795 | ret = mt9m111_reset(icd); | ||
796 | if (!ret) | ||
797 | ret = mt9m111_set_context(icd, mt9m111->context); | ||
798 | if (!ret) | ||
799 | ret = mt9m111_set_autoexposure(icd, mt9m111->autoexposure); | ||
800 | if (ret) | ||
801 | dev_err(&icd->dev, "mt9m111 init failed: %d\n", ret); | ||
802 | return ret; | ||
803 | } | ||
804 | |||
805 | static int mt9m111_release(struct soc_camera_device *icd) | ||
806 | { | ||
807 | int ret; | ||
808 | |||
809 | ret = mt9m111_disable(icd); | ||
810 | if (ret < 0) | ||
811 | dev_err(&icd->dev, "mt9m111 release failed: %d\n", ret); | ||
812 | |||
813 | return ret; | ||
814 | } | ||
815 | |||
816 | /* | ||
817 | * Interface active, can use i2c. If it fails, it can indeed mean, that | ||
818 | * this wasn't our capture interface, so, we wait for the right one | ||
819 | */ | ||
820 | static int mt9m111_video_probe(struct soc_camera_device *icd) | ||
821 | { | ||
822 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
823 | s32 data; | ||
824 | int ret; | ||
825 | |||
826 | /* | ||
827 | * We must have a parent by now. And it cannot be a wrong one. | ||
828 | * So this entire test is completely redundant. | ||
829 | */ | ||
830 | if (!icd->dev.parent || | ||
831 | to_soc_camera_host(icd->dev.parent)->nr != icd->iface) | ||
832 | return -ENODEV; | ||
833 | |||
834 | ret = mt9m111_enable(icd); | ||
835 | if (ret) | ||
836 | goto ei2c; | ||
837 | ret = mt9m111_reset(icd); | ||
838 | if (ret) | ||
839 | goto ei2c; | ||
840 | |||
841 | data = reg_read(CHIP_VERSION); | ||
842 | |||
843 | switch (data) { | ||
844 | case 0x143a: | ||
845 | mt9m111->model = V4L2_IDENT_MT9M111; | ||
846 | icd->formats = mt9m111_colour_formats; | ||
847 | icd->num_formats = ARRAY_SIZE(mt9m111_colour_formats); | ||
848 | break; | ||
849 | default: | ||
850 | ret = -ENODEV; | ||
851 | dev_err(&icd->dev, | ||
852 | "No MT9M111 chip detected, register read %x\n", data); | ||
853 | goto ei2c; | ||
854 | } | ||
855 | |||
856 | dev_info(&icd->dev, "Detected a MT9M111 chip ID 0x143a\n"); | ||
857 | |||
858 | ret = soc_camera_video_start(icd); | ||
859 | if (ret) | ||
860 | goto eisis; | ||
861 | |||
862 | mt9m111->autoexposure = 1; | ||
863 | |||
864 | mt9m111->swap_rgb_even_odd = 1; | ||
865 | mt9m111->swap_rgb_red_blue = 1; | ||
866 | |||
867 | return 0; | ||
868 | eisis: | ||
869 | ei2c: | ||
870 | return ret; | ||
871 | } | ||
872 | |||
873 | static void mt9m111_video_remove(struct soc_camera_device *icd) | ||
874 | { | ||
875 | struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); | ||
876 | |||
877 | dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9m111->client->addr, | ||
878 | mt9m111->icd.dev.parent, mt9m111->icd.vdev); | ||
879 | soc_camera_video_stop(&mt9m111->icd); | ||
880 | } | ||
881 | |||
882 | static int mt9m111_probe(struct i2c_client *client, | ||
883 | const struct i2c_device_id *did) | ||
884 | { | ||
885 | struct mt9m111 *mt9m111; | ||
886 | struct soc_camera_device *icd; | ||
887 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | ||
888 | struct soc_camera_link *icl = client->dev.platform_data; | ||
889 | int ret; | ||
890 | |||
891 | if (!icl) { | ||
892 | dev_err(&client->dev, "MT9M111 driver needs platform data\n"); | ||
893 | return -EINVAL; | ||
894 | } | ||
895 | |||
896 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { | ||
897 | dev_warn(&adapter->dev, | ||
898 | "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); | ||
899 | return -EIO; | ||
900 | } | ||
901 | |||
902 | mt9m111 = kzalloc(sizeof(struct mt9m111), GFP_KERNEL); | ||
903 | if (!mt9m111) | ||
904 | return -ENOMEM; | ||
905 | |||
906 | mt9m111->client = client; | ||
907 | i2c_set_clientdata(client, mt9m111); | ||
908 | |||
909 | /* Second stage probe - when a capture adapter is there */ | ||
910 | icd = &mt9m111->icd; | ||
911 | icd->ops = &mt9m111_ops; | ||
912 | icd->control = &client->dev; | ||
913 | icd->x_min = MT9M111_MIN_DARK_COLS; | ||
914 | icd->y_min = MT9M111_MIN_DARK_ROWS; | ||
915 | icd->x_current = icd->x_min; | ||
916 | icd->y_current = icd->y_min; | ||
917 | icd->width_min = MT9M111_MIN_DARK_ROWS; | ||
918 | icd->width_max = MT9M111_MAX_WIDTH; | ||
919 | icd->height_min = MT9M111_MIN_DARK_COLS; | ||
920 | icd->height_max = MT9M111_MAX_HEIGHT; | ||
921 | icd->y_skip_top = 0; | ||
922 | icd->iface = icl->bus_id; | ||
923 | |||
924 | ret = soc_camera_device_register(icd); | ||
925 | if (ret) | ||
926 | goto eisdr; | ||
927 | return 0; | ||
928 | |||
929 | eisdr: | ||
930 | kfree(mt9m111); | ||
931 | return ret; | ||
932 | } | ||
933 | |||
934 | static int mt9m111_remove(struct i2c_client *client) | ||
935 | { | ||
936 | struct mt9m111 *mt9m111 = i2c_get_clientdata(client); | ||
937 | soc_camera_device_unregister(&mt9m111->icd); | ||
938 | kfree(mt9m111); | ||
939 | |||
940 | return 0; | ||
941 | } | ||
942 | |||
943 | static const struct i2c_device_id mt9m111_id[] = { | ||
944 | { "mt9m111", 0 }, | ||
945 | { } | ||
946 | }; | ||
947 | MODULE_DEVICE_TABLE(i2c, mt9m111_id); | ||
948 | |||
949 | static struct i2c_driver mt9m111_i2c_driver = { | ||
950 | .driver = { | ||
951 | .name = "mt9m111", | ||
952 | }, | ||
953 | .probe = mt9m111_probe, | ||
954 | .remove = mt9m111_remove, | ||
955 | .id_table = mt9m111_id, | ||
956 | }; | ||
957 | |||
958 | static int __init mt9m111_mod_init(void) | ||
959 | { | ||
960 | return i2c_add_driver(&mt9m111_i2c_driver); | ||
961 | } | ||
962 | |||
963 | static void __exit mt9m111_mod_exit(void) | ||
964 | { | ||
965 | i2c_del_driver(&mt9m111_i2c_driver); | ||
966 | } | ||
967 | |||
968 | module_init(mt9m111_mod_init); | ||
969 | module_exit(mt9m111_mod_exit); | ||
970 | |||
971 | MODULE_DESCRIPTION("Micron MT9M111 Camera driver"); | ||
972 | MODULE_AUTHOR("Robert Jarzmik"); | ||
973 | MODULE_LICENSE("GPL"); | ||