aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/media/video/Kconfig7
-rw-r--r--drivers/media/video/Makefile1
-rw-r--r--drivers/media/video/mt9v032.c773
-rw-r--r--include/media/mt9v032.h12
4 files changed, 793 insertions, 0 deletions
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 00f51dd121f3..3d259204616d 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -337,6 +337,13 @@ config VIDEO_MT9V011
337 mt0v011 1.3 Mpixel camera. It currently only works with the 337 mt0v011 1.3 Mpixel camera. It currently only works with the
338 em28xx driver. 338 em28xx driver.
339 339
340config VIDEO_MT9V032
341 tristate "Micron MT9V032 sensor support"
342 depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
343 ---help---
344 This is a Video4Linux2 sensor-level driver for the Micron
345 MT9V032 752x480 CMOS sensor.
346
340config VIDEO_TCM825X 347config VIDEO_TCM825X
341 tristate "TCM825x camera sensor support" 348 tristate "TCM825x camera sensor support"
342 depends on I2C && VIDEO_V4L2 349 depends on I2C && VIDEO_V4L2
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index ace5d8b57221..a10e4c3153fa 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -66,6 +66,7 @@ obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
66obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o 66obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
67obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o 67obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
68obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o 68obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o
69obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o
69obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o 70obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o
70obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o 71obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o
71 72
diff --git a/drivers/media/video/mt9v032.c b/drivers/media/video/mt9v032.c
new file mode 100644
index 000000000000..1319c2c48aff
--- /dev/null
+++ b/drivers/media/video/mt9v032.c
@@ -0,0 +1,773 @@
1/*
2 * Driver for MT9V032 CMOS Image Sensor from Micron
3 *
4 * Copyright (C) 2010, Laurent Pinchart <laurent.pinchart@ideasonboard.com>
5 *
6 * Based on the MT9M001 driver,
7 *
8 * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
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 version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#include <linux/delay.h>
16#include <linux/i2c.h>
17#include <linux/log2.h>
18#include <linux/mutex.h>
19#include <linux/slab.h>
20#include <linux/videodev2.h>
21#include <linux/v4l2-mediabus.h>
22
23#include <media/mt9v032.h>
24#include <media/v4l2-ctrls.h>
25#include <media/v4l2-device.h>
26#include <media/v4l2-subdev.h>
27
28#define MT9V032_PIXEL_ARRAY_HEIGHT 492
29#define MT9V032_PIXEL_ARRAY_WIDTH 782
30
31#define MT9V032_CHIP_VERSION 0x00
32#define MT9V032_CHIP_ID_REV1 0x1311
33#define MT9V032_CHIP_ID_REV3 0x1313
34#define MT9V032_ROW_START 0x01
35#define MT9V032_ROW_START_MIN 4
36#define MT9V032_ROW_START_DEF 10
37#define MT9V032_ROW_START_MAX 482
38#define MT9V032_COLUMN_START 0x02
39#define MT9V032_COLUMN_START_MIN 1
40#define MT9V032_COLUMN_START_DEF 2
41#define MT9V032_COLUMN_START_MAX 752
42#define MT9V032_WINDOW_HEIGHT 0x03
43#define MT9V032_WINDOW_HEIGHT_MIN 1
44#define MT9V032_WINDOW_HEIGHT_DEF 480
45#define MT9V032_WINDOW_HEIGHT_MAX 480
46#define MT9V032_WINDOW_WIDTH 0x04
47#define MT9V032_WINDOW_WIDTH_MIN 1
48#define MT9V032_WINDOW_WIDTH_DEF 752
49#define MT9V032_WINDOW_WIDTH_MAX 752
50#define MT9V032_HORIZONTAL_BLANKING 0x05
51#define MT9V032_HORIZONTAL_BLANKING_MIN 43
52#define MT9V032_HORIZONTAL_BLANKING_MAX 1023
53#define MT9V032_VERTICAL_BLANKING 0x06
54#define MT9V032_VERTICAL_BLANKING_MIN 4
55#define MT9V032_VERTICAL_BLANKING_MAX 3000
56#define MT9V032_CHIP_CONTROL 0x07
57#define MT9V032_CHIP_CONTROL_MASTER_MODE (1 << 3)
58#define MT9V032_CHIP_CONTROL_DOUT_ENABLE (1 << 7)
59#define MT9V032_CHIP_CONTROL_SEQUENTIAL (1 << 8)
60#define MT9V032_SHUTTER_WIDTH1 0x08
61#define MT9V032_SHUTTER_WIDTH2 0x09
62#define MT9V032_SHUTTER_WIDTH_CONTROL 0x0a
63#define MT9V032_TOTAL_SHUTTER_WIDTH 0x0b
64#define MT9V032_TOTAL_SHUTTER_WIDTH_MIN 1
65#define MT9V032_TOTAL_SHUTTER_WIDTH_DEF 480
66#define MT9V032_TOTAL_SHUTTER_WIDTH_MAX 32767
67#define MT9V032_RESET 0x0c
68#define MT9V032_READ_MODE 0x0d
69#define MT9V032_READ_MODE_ROW_BIN_MASK (3 << 0)
70#define MT9V032_READ_MODE_ROW_BIN_SHIFT 0
71#define MT9V032_READ_MODE_COLUMN_BIN_MASK (3 << 2)
72#define MT9V032_READ_MODE_COLUMN_BIN_SHIFT 2
73#define MT9V032_READ_MODE_ROW_FLIP (1 << 4)
74#define MT9V032_READ_MODE_COLUMN_FLIP (1 << 5)
75#define MT9V032_READ_MODE_DARK_COLUMNS (1 << 6)
76#define MT9V032_READ_MODE_DARK_ROWS (1 << 7)
77#define MT9V032_PIXEL_OPERATION_MODE 0x0f
78#define MT9V032_PIXEL_OPERATION_MODE_COLOR (1 << 2)
79#define MT9V032_PIXEL_OPERATION_MODE_HDR (1 << 6)
80#define MT9V032_ANALOG_GAIN 0x35
81#define MT9V032_ANALOG_GAIN_MIN 16
82#define MT9V032_ANALOG_GAIN_DEF 16
83#define MT9V032_ANALOG_GAIN_MAX 64
84#define MT9V032_MAX_ANALOG_GAIN 0x36
85#define MT9V032_MAX_ANALOG_GAIN_MAX 127
86#define MT9V032_FRAME_DARK_AVERAGE 0x42
87#define MT9V032_DARK_AVG_THRESH 0x46
88#define MT9V032_DARK_AVG_LOW_THRESH_MASK (255 << 0)
89#define MT9V032_DARK_AVG_LOW_THRESH_SHIFT 0
90#define MT9V032_DARK_AVG_HIGH_THRESH_MASK (255 << 8)
91#define MT9V032_DARK_AVG_HIGH_THRESH_SHIFT 8
92#define MT9V032_ROW_NOISE_CORR_CONTROL 0x70
93#define MT9V032_ROW_NOISE_CORR_ENABLE (1 << 5)
94#define MT9V032_ROW_NOISE_CORR_USE_BLK_AVG (1 << 7)
95#define MT9V032_PIXEL_CLOCK 0x74
96#define MT9V032_PIXEL_CLOCK_INV_LINE (1 << 0)
97#define MT9V032_PIXEL_CLOCK_INV_FRAME (1 << 1)
98#define MT9V032_PIXEL_CLOCK_XOR_LINE (1 << 2)
99#define MT9V032_PIXEL_CLOCK_CONT_LINE (1 << 3)
100#define MT9V032_PIXEL_CLOCK_INV_PXL_CLK (1 << 4)
101#define MT9V032_TEST_PATTERN 0x7f
102#define MT9V032_TEST_PATTERN_DATA_MASK (1023 << 0)
103#define MT9V032_TEST_PATTERN_DATA_SHIFT 0
104#define MT9V032_TEST_PATTERN_USE_DATA (1 << 10)
105#define MT9V032_TEST_PATTERN_GRAY_MASK (3 << 11)
106#define MT9V032_TEST_PATTERN_GRAY_NONE (0 << 11)
107#define MT9V032_TEST_PATTERN_GRAY_VERTICAL (1 << 11)
108#define MT9V032_TEST_PATTERN_GRAY_HORIZONTAL (2 << 11)
109#define MT9V032_TEST_PATTERN_GRAY_DIAGONAL (3 << 11)
110#define MT9V032_TEST_PATTERN_ENABLE (1 << 13)
111#define MT9V032_TEST_PATTERN_FLIP (1 << 14)
112#define MT9V032_AEC_AGC_ENABLE 0xaf
113#define MT9V032_AEC_ENABLE (1 << 0)
114#define MT9V032_AGC_ENABLE (1 << 1)
115#define MT9V032_THERMAL_INFO 0xc1
116
117struct mt9v032 {
118 struct v4l2_subdev subdev;
119 struct media_pad pad;
120
121 struct v4l2_mbus_framefmt format;
122 struct v4l2_rect crop;
123
124 struct v4l2_ctrl_handler ctrls;
125
126 struct mutex power_lock;
127 int power_count;
128
129 struct mt9v032_platform_data *pdata;
130 u16 chip_control;
131 u16 aec_agc;
132};
133
134static struct mt9v032 *to_mt9v032(struct v4l2_subdev *sd)
135{
136 return container_of(sd, struct mt9v032, subdev);
137}
138
139static int mt9v032_read(struct i2c_client *client, const u8 reg)
140{
141 s32 data = i2c_smbus_read_word_data(client, reg);
142 dev_dbg(&client->dev, "%s: read 0x%04x from 0x%02x\n", __func__,
143 swab16(data), reg);
144 return data < 0 ? data : swab16(data);
145}
146
147static int mt9v032_write(struct i2c_client *client, const u8 reg,
148 const u16 data)
149{
150 dev_dbg(&client->dev, "%s: writing 0x%04x to 0x%02x\n", __func__,
151 data, reg);
152 return i2c_smbus_write_word_data(client, reg, swab16(data));
153}
154
155static int mt9v032_set_chip_control(struct mt9v032 *mt9v032, u16 clear, u16 set)
156{
157 struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
158 u16 value = (mt9v032->chip_control & ~clear) | set;
159 int ret;
160
161 ret = mt9v032_write(client, MT9V032_CHIP_CONTROL, value);
162 if (ret < 0)
163 return ret;
164
165 mt9v032->chip_control = value;
166 return 0;
167}
168
169static int
170mt9v032_update_aec_agc(struct mt9v032 *mt9v032, u16 which, int enable)
171{
172 struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
173 u16 value = mt9v032->aec_agc;
174 int ret;
175
176 if (enable)
177 value |= which;
178 else
179 value &= ~which;
180
181 ret = mt9v032_write(client, MT9V032_AEC_AGC_ENABLE, value);
182 if (ret < 0)
183 return ret;
184
185 mt9v032->aec_agc = value;
186 return 0;
187}
188
189static int mt9v032_power_on(struct mt9v032 *mt9v032)
190{
191 struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
192 int ret;
193
194 if (mt9v032->pdata->set_clock) {
195 mt9v032->pdata->set_clock(&mt9v032->subdev, 25000000);
196 udelay(1);
197 }
198
199 /* Reset the chip and stop data read out */
200 ret = mt9v032_write(client, MT9V032_RESET, 1);
201 if (ret < 0)
202 return ret;
203
204 ret = mt9v032_write(client, MT9V032_RESET, 0);
205 if (ret < 0)
206 return ret;
207
208 return mt9v032_write(client, MT9V032_CHIP_CONTROL, 0);
209}
210
211static void mt9v032_power_off(struct mt9v032 *mt9v032)
212{
213 if (mt9v032->pdata->set_clock)
214 mt9v032->pdata->set_clock(&mt9v032->subdev, 0);
215}
216
217static int __mt9v032_set_power(struct mt9v032 *mt9v032, bool on)
218{
219 struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
220 int ret;
221
222 if (!on) {
223 mt9v032_power_off(mt9v032);
224 return 0;
225 }
226
227 ret = mt9v032_power_on(mt9v032);
228 if (ret < 0)
229 return ret;
230
231 /* Configure the pixel clock polarity */
232 if (mt9v032->pdata && mt9v032->pdata->clk_pol) {
233 ret = mt9v032_write(client, MT9V032_PIXEL_CLOCK,
234 MT9V032_PIXEL_CLOCK_INV_PXL_CLK);
235 if (ret < 0)
236 return ret;
237 }
238
239 /* Disable the noise correction algorithm and restore the controls. */
240 ret = mt9v032_write(client, MT9V032_ROW_NOISE_CORR_CONTROL, 0);
241 if (ret < 0)
242 return ret;
243
244 return v4l2_ctrl_handler_setup(&mt9v032->ctrls);
245}
246
247/* -----------------------------------------------------------------------------
248 * V4L2 subdev video operations
249 */
250
251static struct v4l2_mbus_framefmt *
252__mt9v032_get_pad_format(struct mt9v032 *mt9v032, struct v4l2_subdev_fh *fh,
253 unsigned int pad, enum v4l2_subdev_format_whence which)
254{
255 switch (which) {
256 case V4L2_SUBDEV_FORMAT_TRY:
257 return v4l2_subdev_get_try_format(fh, pad);
258 case V4L2_SUBDEV_FORMAT_ACTIVE:
259 return &mt9v032->format;
260 default:
261 return NULL;
262 }
263}
264
265static struct v4l2_rect *
266__mt9v032_get_pad_crop(struct mt9v032 *mt9v032, struct v4l2_subdev_fh *fh,
267 unsigned int pad, enum v4l2_subdev_format_whence which)
268{
269 switch (which) {
270 case V4L2_SUBDEV_FORMAT_TRY:
271 return v4l2_subdev_get_try_crop(fh, pad);
272 case V4L2_SUBDEV_FORMAT_ACTIVE:
273 return &mt9v032->crop;
274 default:
275 return NULL;
276 }
277}
278
279static int mt9v032_s_stream(struct v4l2_subdev *subdev, int enable)
280{
281 const u16 mode = MT9V032_CHIP_CONTROL_MASTER_MODE
282 | MT9V032_CHIP_CONTROL_DOUT_ENABLE
283 | MT9V032_CHIP_CONTROL_SEQUENTIAL;
284 struct i2c_client *client = v4l2_get_subdevdata(subdev);
285 struct mt9v032 *mt9v032 = to_mt9v032(subdev);
286 struct v4l2_mbus_framefmt *format = &mt9v032->format;
287 struct v4l2_rect *crop = &mt9v032->crop;
288 unsigned int hratio;
289 unsigned int vratio;
290 int ret;
291
292 if (!enable)
293 return mt9v032_set_chip_control(mt9v032, mode, 0);
294
295 /* Configure the window size and row/column bin */
296 hratio = DIV_ROUND_CLOSEST(crop->width, format->width);
297 vratio = DIV_ROUND_CLOSEST(crop->height, format->height);
298
299 ret = mt9v032_write(client, MT9V032_READ_MODE,
300 (hratio - 1) << MT9V032_READ_MODE_ROW_BIN_SHIFT |
301 (vratio - 1) << MT9V032_READ_MODE_COLUMN_BIN_SHIFT);
302 if (ret < 0)
303 return ret;
304
305 ret = mt9v032_write(client, MT9V032_COLUMN_START, crop->left);
306 if (ret < 0)
307 return ret;
308
309 ret = mt9v032_write(client, MT9V032_ROW_START, crop->top);
310 if (ret < 0)
311 return ret;
312
313 ret = mt9v032_write(client, MT9V032_WINDOW_WIDTH, crop->width);
314 if (ret < 0)
315 return ret;
316
317 ret = mt9v032_write(client, MT9V032_WINDOW_HEIGHT, crop->height);
318 if (ret < 0)
319 return ret;
320
321 ret = mt9v032_write(client, MT9V032_HORIZONTAL_BLANKING,
322 max(43, 660 - crop->width));
323 if (ret < 0)
324 return ret;
325
326 /* Switch to master "normal" mode */
327 return mt9v032_set_chip_control(mt9v032, 0, mode);
328}
329
330static int mt9v032_enum_mbus_code(struct v4l2_subdev *subdev,
331 struct v4l2_subdev_fh *fh,
332 struct v4l2_subdev_mbus_code_enum *code)
333{
334 if (code->index > 0)
335 return -EINVAL;
336
337 code->code = V4L2_MBUS_FMT_SGRBG10_1X10;
338 return 0;
339}
340
341static int mt9v032_enum_frame_size(struct v4l2_subdev *subdev,
342 struct v4l2_subdev_fh *fh,
343 struct v4l2_subdev_frame_size_enum *fse)
344{
345 if (fse->index >= 8 || fse->code != V4L2_MBUS_FMT_SGRBG10_1X10)
346 return -EINVAL;
347
348 fse->min_width = MT9V032_WINDOW_WIDTH_DEF / fse->index;
349 fse->max_width = fse->min_width;
350 fse->min_height = MT9V032_WINDOW_HEIGHT_DEF / fse->index;
351 fse->max_height = fse->min_height;
352
353 return 0;
354}
355
356static int mt9v032_get_format(struct v4l2_subdev *subdev,
357 struct v4l2_subdev_fh *fh,
358 struct v4l2_subdev_format *format)
359{
360 struct mt9v032 *mt9v032 = to_mt9v032(subdev);
361
362 format->format = *__mt9v032_get_pad_format(mt9v032, fh, format->pad,
363 format->which);
364 return 0;
365}
366
367static int mt9v032_set_format(struct v4l2_subdev *subdev,
368 struct v4l2_subdev_fh *fh,
369 struct v4l2_subdev_format *format)
370{
371 struct mt9v032 *mt9v032 = to_mt9v032(subdev);
372 struct v4l2_mbus_framefmt *__format;
373 struct v4l2_rect *__crop;
374 unsigned int width;
375 unsigned int height;
376 unsigned int hratio;
377 unsigned int vratio;
378
379 __crop = __mt9v032_get_pad_crop(mt9v032, fh, format->pad,
380 format->which);
381
382 /* Clamp the width and height to avoid dividing by zero. */
383 width = clamp_t(unsigned int, ALIGN(format->format.width, 2),
384 max(__crop->width / 8, MT9V032_WINDOW_WIDTH_MIN),
385 __crop->width);
386 height = clamp_t(unsigned int, ALIGN(format->format.height, 2),
387 max(__crop->height / 8, MT9V032_WINDOW_HEIGHT_MIN),
388 __crop->height);
389
390 hratio = DIV_ROUND_CLOSEST(__crop->width, width);
391 vratio = DIV_ROUND_CLOSEST(__crop->height, height);
392
393 __format = __mt9v032_get_pad_format(mt9v032, fh, format->pad,
394 format->which);
395 __format->width = __crop->width / hratio;
396 __format->height = __crop->height / vratio;
397
398 format->format = *__format;
399
400 return 0;
401}
402
403static int mt9v032_get_crop(struct v4l2_subdev *subdev,
404 struct v4l2_subdev_fh *fh,
405 struct v4l2_subdev_crop *crop)
406{
407 struct mt9v032 *mt9v032 = to_mt9v032(subdev);
408
409 crop->rect = *__mt9v032_get_pad_crop(mt9v032, fh, crop->pad,
410 crop->which);
411 return 0;
412}
413
414static int mt9v032_set_crop(struct v4l2_subdev *subdev,
415 struct v4l2_subdev_fh *fh,
416 struct v4l2_subdev_crop *crop)
417{
418 struct mt9v032 *mt9v032 = to_mt9v032(subdev);
419 struct v4l2_mbus_framefmt *__format;
420 struct v4l2_rect *__crop;
421 struct v4l2_rect rect;
422
423 /* Clamp the crop rectangle boundaries and align them to a multiple of 2
424 * pixels.
425 */
426 rect.left = clamp(ALIGN(crop->rect.left, 2),
427 MT9V032_COLUMN_START_MIN,
428 MT9V032_COLUMN_START_MAX);
429 rect.top = clamp(ALIGN(crop->rect.top, 2),
430 MT9V032_ROW_START_MIN,
431 MT9V032_ROW_START_MAX);
432 rect.width = clamp(ALIGN(crop->rect.width, 2),
433 MT9V032_WINDOW_WIDTH_MIN,
434 MT9V032_WINDOW_WIDTH_MAX);
435 rect.height = clamp(ALIGN(crop->rect.height, 2),
436 MT9V032_WINDOW_HEIGHT_MIN,
437 MT9V032_WINDOW_HEIGHT_MAX);
438
439 rect.width = min(rect.width, MT9V032_PIXEL_ARRAY_WIDTH - rect.left);
440 rect.height = min(rect.height, MT9V032_PIXEL_ARRAY_HEIGHT - rect.top);
441
442 __crop = __mt9v032_get_pad_crop(mt9v032, fh, crop->pad, crop->which);
443
444 if (rect.width != __crop->width || rect.height != __crop->height) {
445 /* Reset the output image size if the crop rectangle size has
446 * been modified.
447 */
448 __format = __mt9v032_get_pad_format(mt9v032, fh, crop->pad,
449 crop->which);
450 __format->width = rect.width;
451 __format->height = rect.height;
452 }
453
454 *__crop = rect;
455 crop->rect = rect;
456
457 return 0;
458}
459
460/* -----------------------------------------------------------------------------
461 * V4L2 subdev control operations
462 */
463
464#define V4L2_CID_TEST_PATTERN (V4L2_CID_USER_BASE | 0x1001)
465
466static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl)
467{
468 struct mt9v032 *mt9v032 =
469 container_of(ctrl->handler, struct mt9v032, ctrls);
470 struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
471 u16 data;
472
473 switch (ctrl->id) {
474 case V4L2_CID_AUTOGAIN:
475 return mt9v032_update_aec_agc(mt9v032, MT9V032_AGC_ENABLE,
476 ctrl->val);
477
478 case V4L2_CID_GAIN:
479 return mt9v032_write(client, MT9V032_ANALOG_GAIN, ctrl->val);
480
481 case V4L2_CID_EXPOSURE_AUTO:
482 return mt9v032_update_aec_agc(mt9v032, MT9V032_AEC_ENABLE,
483 ctrl->val);
484
485 case V4L2_CID_EXPOSURE:
486 return mt9v032_write(client, MT9V032_TOTAL_SHUTTER_WIDTH,
487 ctrl->val);
488
489 case V4L2_CID_TEST_PATTERN:
490 switch (ctrl->val) {
491 case 0:
492 data = 0;
493 break;
494 case 1:
495 data = MT9V032_TEST_PATTERN_GRAY_VERTICAL
496 | MT9V032_TEST_PATTERN_ENABLE;
497 break;
498 case 2:
499 data = MT9V032_TEST_PATTERN_GRAY_HORIZONTAL
500 | MT9V032_TEST_PATTERN_ENABLE;
501 break;
502 case 3:
503 data = MT9V032_TEST_PATTERN_GRAY_DIAGONAL
504 | MT9V032_TEST_PATTERN_ENABLE;
505 break;
506 default:
507 data = (ctrl->val << MT9V032_TEST_PATTERN_DATA_SHIFT)
508 | MT9V032_TEST_PATTERN_USE_DATA
509 | MT9V032_TEST_PATTERN_ENABLE
510 | MT9V032_TEST_PATTERN_FLIP;
511 break;
512 }
513
514 return mt9v032_write(client, MT9V032_TEST_PATTERN, data);
515 }
516
517 return 0;
518}
519
520static struct v4l2_ctrl_ops mt9v032_ctrl_ops = {
521 .s_ctrl = mt9v032_s_ctrl,
522};
523
524static const struct v4l2_ctrl_config mt9v032_ctrls[] = {
525 {
526 .ops = &mt9v032_ctrl_ops,
527 .id = V4L2_CID_TEST_PATTERN,
528 .type = V4L2_CTRL_TYPE_INTEGER,
529 .name = "Test pattern",
530 .min = 0,
531 .max = 1023,
532 .step = 1,
533 .def = 0,
534 .flags = 0,
535 }
536};
537
538/* -----------------------------------------------------------------------------
539 * V4L2 subdev core operations
540 */
541
542static int mt9v032_set_power(struct v4l2_subdev *subdev, int on)
543{
544 struct mt9v032 *mt9v032 = to_mt9v032(subdev);
545 int ret = 0;
546
547 mutex_lock(&mt9v032->power_lock);
548
549 /* If the power count is modified from 0 to != 0 or from != 0 to 0,
550 * update the power state.
551 */
552 if (mt9v032->power_count == !on) {
553 ret = __mt9v032_set_power(mt9v032, !!on);
554 if (ret < 0)
555 goto done;
556 }
557
558 /* Update the power count. */
559 mt9v032->power_count += on ? 1 : -1;
560 WARN_ON(mt9v032->power_count < 0);
561
562done:
563 mutex_unlock(&mt9v032->power_lock);
564 return ret;
565}
566
567/* -----------------------------------------------------------------------------
568 * V4L2 subdev internal operations
569 */
570
571static int mt9v032_registered(struct v4l2_subdev *subdev)
572{
573 struct i2c_client *client = v4l2_get_subdevdata(subdev);
574 struct mt9v032 *mt9v032 = to_mt9v032(subdev);
575 s32 data;
576 int ret;
577
578 dev_info(&client->dev, "Probing MT9V032 at address 0x%02x\n",
579 client->addr);
580
581 ret = mt9v032_power_on(mt9v032);
582 if (ret < 0) {
583 dev_err(&client->dev, "MT9V032 power up failed\n");
584 return ret;
585 }
586
587 /* Read and check the sensor version */
588 data = mt9v032_read(client, MT9V032_CHIP_VERSION);
589 if (data != MT9V032_CHIP_ID_REV1 && data != MT9V032_CHIP_ID_REV3) {
590 dev_err(&client->dev, "MT9V032 not detected, wrong version "
591 "0x%04x\n", data);
592 return -ENODEV;
593 }
594
595 mt9v032_power_off(mt9v032);
596
597 dev_info(&client->dev, "MT9V032 detected at address 0x%02x\n",
598 client->addr);
599
600 return ret;
601}
602
603static int mt9v032_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
604{
605 struct v4l2_mbus_framefmt *format;
606 struct v4l2_rect *crop;
607
608 crop = v4l2_subdev_get_try_crop(fh, 0);
609 crop->left = MT9V032_COLUMN_START_DEF;
610 crop->top = MT9V032_ROW_START_DEF;
611 crop->width = MT9V032_WINDOW_WIDTH_DEF;
612 crop->height = MT9V032_WINDOW_HEIGHT_DEF;
613
614 format = v4l2_subdev_get_try_format(fh, 0);
615 format->code = V4L2_MBUS_FMT_SGRBG10_1X10;
616 format->width = MT9V032_WINDOW_WIDTH_DEF;
617 format->height = MT9V032_WINDOW_HEIGHT_DEF;
618 format->field = V4L2_FIELD_NONE;
619 format->colorspace = V4L2_COLORSPACE_SRGB;
620
621 return mt9v032_set_power(subdev, 1);
622}
623
624static int mt9v032_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
625{
626 return mt9v032_set_power(subdev, 0);
627}
628
629static struct v4l2_subdev_core_ops mt9v032_subdev_core_ops = {
630 .s_power = mt9v032_set_power,
631};
632
633static struct v4l2_subdev_video_ops mt9v032_subdev_video_ops = {
634 .s_stream = mt9v032_s_stream,
635};
636
637static struct v4l2_subdev_pad_ops mt9v032_subdev_pad_ops = {
638 .enum_mbus_code = mt9v032_enum_mbus_code,
639 .enum_frame_size = mt9v032_enum_frame_size,
640 .get_fmt = mt9v032_get_format,
641 .set_fmt = mt9v032_set_format,
642 .get_crop = mt9v032_get_crop,
643 .set_crop = mt9v032_set_crop,
644};
645
646static struct v4l2_subdev_ops mt9v032_subdev_ops = {
647 .core = &mt9v032_subdev_core_ops,
648 .video = &mt9v032_subdev_video_ops,
649 .pad = &mt9v032_subdev_pad_ops,
650};
651
652static const struct v4l2_subdev_internal_ops mt9v032_subdev_internal_ops = {
653 .registered = mt9v032_registered,
654 .open = mt9v032_open,
655 .close = mt9v032_close,
656};
657
658/* -----------------------------------------------------------------------------
659 * Driver initialization and probing
660 */
661
662static int mt9v032_probe(struct i2c_client *client,
663 const struct i2c_device_id *did)
664{
665 struct mt9v032 *mt9v032;
666 unsigned int i;
667 int ret;
668
669 if (!i2c_check_functionality(client->adapter,
670 I2C_FUNC_SMBUS_WORD_DATA)) {
671 dev_warn(&client->adapter->dev,
672 "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
673 return -EIO;
674 }
675
676 mt9v032 = kzalloc(sizeof(*mt9v032), GFP_KERNEL);
677 if (!mt9v032)
678 return -ENOMEM;
679
680 mutex_init(&mt9v032->power_lock);
681 mt9v032->pdata = client->dev.platform_data;
682
683 v4l2_ctrl_handler_init(&mt9v032->ctrls, ARRAY_SIZE(mt9v032_ctrls) + 4);
684
685 v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
686 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
687 v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
688 V4L2_CID_GAIN, MT9V032_ANALOG_GAIN_MIN,
689 MT9V032_ANALOG_GAIN_MAX, 1, MT9V032_ANALOG_GAIN_DEF);
690 v4l2_ctrl_new_std_menu(&mt9v032->ctrls, &mt9v032_ctrl_ops,
691 V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL, 0,
692 V4L2_EXPOSURE_AUTO);
693 v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
694 V4L2_CID_EXPOSURE, MT9V032_TOTAL_SHUTTER_WIDTH_MIN,
695 MT9V032_TOTAL_SHUTTER_WIDTH_MAX, 1,
696 MT9V032_TOTAL_SHUTTER_WIDTH_DEF);
697
698 for (i = 0; i < ARRAY_SIZE(mt9v032_ctrls); ++i)
699 v4l2_ctrl_new_custom(&mt9v032->ctrls, &mt9v032_ctrls[i], NULL);
700
701 mt9v032->subdev.ctrl_handler = &mt9v032->ctrls;
702
703 if (mt9v032->ctrls.error)
704 printk(KERN_INFO "%s: control initialization error %d\n",
705 __func__, mt9v032->ctrls.error);
706
707 mt9v032->crop.left = MT9V032_COLUMN_START_DEF;
708 mt9v032->crop.top = MT9V032_ROW_START_DEF;
709 mt9v032->crop.width = MT9V032_WINDOW_WIDTH_DEF;
710 mt9v032->crop.height = MT9V032_WINDOW_HEIGHT_DEF;
711
712 mt9v032->format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
713 mt9v032->format.width = MT9V032_WINDOW_WIDTH_DEF;
714 mt9v032->format.height = MT9V032_WINDOW_HEIGHT_DEF;
715 mt9v032->format.field = V4L2_FIELD_NONE;
716 mt9v032->format.colorspace = V4L2_COLORSPACE_SRGB;
717
718 mt9v032->aec_agc = MT9V032_AEC_ENABLE | MT9V032_AGC_ENABLE;
719
720 v4l2_i2c_subdev_init(&mt9v032->subdev, client, &mt9v032_subdev_ops);
721 mt9v032->subdev.internal_ops = &mt9v032_subdev_internal_ops;
722 mt9v032->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
723
724 mt9v032->pad.flags = MEDIA_PAD_FL_SOURCE;
725 ret = media_entity_init(&mt9v032->subdev.entity, 1, &mt9v032->pad, 0);
726 if (ret < 0)
727 kfree(mt9v032);
728
729 return ret;
730}
731
732static int mt9v032_remove(struct i2c_client *client)
733{
734 struct v4l2_subdev *subdev = i2c_get_clientdata(client);
735 struct mt9v032 *mt9v032 = to_mt9v032(subdev);
736
737 v4l2_device_unregister_subdev(subdev);
738 media_entity_cleanup(&subdev->entity);
739 kfree(mt9v032);
740 return 0;
741}
742
743static const struct i2c_device_id mt9v032_id[] = {
744 { "mt9v032", 0 },
745 { }
746};
747MODULE_DEVICE_TABLE(i2c, mt9v032_id);
748
749static struct i2c_driver mt9v032_driver = {
750 .driver = {
751 .name = "mt9v032",
752 },
753 .probe = mt9v032_probe,
754 .remove = mt9v032_remove,
755 .id_table = mt9v032_id,
756};
757
758static int __init mt9v032_init(void)
759{
760 return i2c_add_driver(&mt9v032_driver);
761}
762
763static void __exit mt9v032_exit(void)
764{
765 i2c_del_driver(&mt9v032_driver);
766}
767
768module_init(mt9v032_init);
769module_exit(mt9v032_exit);
770
771MODULE_DESCRIPTION("Aptina MT9V032 Camera driver");
772MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
773MODULE_LICENSE("GPL");
diff --git a/include/media/mt9v032.h b/include/media/mt9v032.h
new file mode 100644
index 000000000000..5e27f9be6b95
--- /dev/null
+++ b/include/media/mt9v032.h
@@ -0,0 +1,12 @@
1#ifndef _MEDIA_MT9V032_H
2#define _MEDIA_MT9V032_H
3
4struct v4l2_subdev;
5
6struct mt9v032_platform_data {
7 unsigned int clk_pol:1;
8
9 void (*set_clock)(struct v4l2_subdev *subdev, unsigned int rate);
10};
11
12#endif