2 * Driver for MT9V032 CMOS Image Sensor from Micron
4 * Copyright (C) 2010, Laurent Pinchart <laurent.pinchart@ideasonboard.com>
6 * Based on the MT9M001 driver,
8 * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
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.
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 #include <linux/module.h>
24 #include <media/mt9v032.h>
25 #include <media/v4l2-ctrls.h>
26 #include <media/v4l2-device.h>
27 #include <media/v4l2-subdev.h>
29 #define MT9V032_PIXEL_ARRAY_HEIGHT 492
30 #define MT9V032_PIXEL_ARRAY_WIDTH 782
32 #define MT9V032_CHIP_VERSION 0x00
33 #define MT9V032_CHIP_ID_REV1 0x1311
34 #define MT9V032_CHIP_ID_REV3 0x1313
35 #define MT9V032_COLUMN_START 0x01
36 #define MT9V032_COLUMN_START_MIN 1
37 #define MT9V032_COLUMN_START_DEF 1
38 #define MT9V032_COLUMN_START_MAX 752
39 #define MT9V032_ROW_START 0x02
40 #define MT9V032_ROW_START_MIN 4
41 #define MT9V032_ROW_START_DEF 5
42 #define MT9V032_ROW_START_MAX 482
43 #define MT9V032_WINDOW_HEIGHT 0x03
44 #define MT9V032_WINDOW_HEIGHT_MIN 1
45 #define MT9V032_WINDOW_HEIGHT_DEF 480
46 #define MT9V032_WINDOW_HEIGHT_MAX 480
47 #define MT9V032_WINDOW_WIDTH 0x04
48 #define MT9V032_WINDOW_WIDTH_MIN 1
49 #define MT9V032_WINDOW_WIDTH_DEF 752
50 #define MT9V032_WINDOW_WIDTH_MAX 752
51 #define MT9V032_HORIZONTAL_BLANKING 0x05
52 #define MT9V032_HORIZONTAL_BLANKING_MIN 43
53 #define MT9V032_HORIZONTAL_BLANKING_MAX 1023
54 #define MT9V032_VERTICAL_BLANKING 0x06
55 #define MT9V032_VERTICAL_BLANKING_MIN 4
56 #define MT9V032_VERTICAL_BLANKING_MAX 3000
57 #define MT9V032_CHIP_CONTROL 0x07
58 #define MT9V032_CHIP_CONTROL_MASTER_MODE (1 << 3)
59 #define MT9V032_CHIP_CONTROL_DOUT_ENABLE (1 << 7)
60 #define MT9V032_CHIP_CONTROL_SEQUENTIAL (1 << 8)
61 #define MT9V032_SHUTTER_WIDTH1 0x08
62 #define MT9V032_SHUTTER_WIDTH2 0x09
63 #define MT9V032_SHUTTER_WIDTH_CONTROL 0x0a
64 #define MT9V032_TOTAL_SHUTTER_WIDTH 0x0b
65 #define MT9V032_TOTAL_SHUTTER_WIDTH_MIN 1
66 #define MT9V032_TOTAL_SHUTTER_WIDTH_DEF 480
67 #define MT9V032_TOTAL_SHUTTER_WIDTH_MAX 32767
68 #define MT9V032_RESET 0x0c
69 #define MT9V032_READ_MODE 0x0d
70 #define MT9V032_READ_MODE_ROW_BIN_MASK (3 << 0)
71 #define MT9V032_READ_MODE_ROW_BIN_SHIFT 0
72 #define MT9V032_READ_MODE_COLUMN_BIN_MASK (3 << 2)
73 #define MT9V032_READ_MODE_COLUMN_BIN_SHIFT 2
74 #define MT9V032_READ_MODE_ROW_FLIP (1 << 4)
75 #define MT9V032_READ_MODE_COLUMN_FLIP (1 << 5)
76 #define MT9V032_READ_MODE_DARK_COLUMNS (1 << 6)
77 #define MT9V032_READ_MODE_DARK_ROWS (1 << 7)
78 #define MT9V032_PIXEL_OPERATION_MODE 0x0f
79 #define MT9V032_PIXEL_OPERATION_MODE_COLOR (1 << 2)
80 #define MT9V032_PIXEL_OPERATION_MODE_HDR (1 << 6)
81 #define MT9V032_ANALOG_GAIN 0x35
82 #define MT9V032_ANALOG_GAIN_MIN 16
83 #define MT9V032_ANALOG_GAIN_DEF 16
84 #define MT9V032_ANALOG_GAIN_MAX 64
85 #define MT9V032_MAX_ANALOG_GAIN 0x36
86 #define MT9V032_MAX_ANALOG_GAIN_MAX 127
87 #define MT9V032_FRAME_DARK_AVERAGE 0x42
88 #define MT9V032_DARK_AVG_THRESH 0x46
89 #define MT9V032_DARK_AVG_LOW_THRESH_MASK (255 << 0)
90 #define MT9V032_DARK_AVG_LOW_THRESH_SHIFT 0
91 #define MT9V032_DARK_AVG_HIGH_THRESH_MASK (255 << 8)
92 #define MT9V032_DARK_AVG_HIGH_THRESH_SHIFT 8
93 #define MT9V032_ROW_NOISE_CORR_CONTROL 0x70
94 #define MT9V032_ROW_NOISE_CORR_ENABLE (1 << 5)
95 #define MT9V032_ROW_NOISE_CORR_USE_BLK_AVG (1 << 7)
96 #define MT9V032_PIXEL_CLOCK 0x74
97 #define MT9V032_PIXEL_CLOCK_INV_LINE (1 << 0)
98 #define MT9V032_PIXEL_CLOCK_INV_FRAME (1 << 1)
99 #define MT9V032_PIXEL_CLOCK_XOR_LINE (1 << 2)
100 #define MT9V032_PIXEL_CLOCK_CONT_LINE (1 << 3)
101 #define MT9V032_PIXEL_CLOCK_INV_PXL_CLK (1 << 4)
102 #define MT9V032_TEST_PATTERN 0x7f
103 #define MT9V032_TEST_PATTERN_DATA_MASK (1023 << 0)
104 #define MT9V032_TEST_PATTERN_DATA_SHIFT 0
105 #define MT9V032_TEST_PATTERN_USE_DATA (1 << 10)
106 #define MT9V032_TEST_PATTERN_GRAY_MASK (3 << 11)
107 #define MT9V032_TEST_PATTERN_GRAY_NONE (0 << 11)
108 #define MT9V032_TEST_PATTERN_GRAY_VERTICAL (1 << 11)
109 #define MT9V032_TEST_PATTERN_GRAY_HORIZONTAL (2 << 11)
110 #define MT9V032_TEST_PATTERN_GRAY_DIAGONAL (3 << 11)
111 #define MT9V032_TEST_PATTERN_ENABLE (1 << 13)
112 #define MT9V032_TEST_PATTERN_FLIP (1 << 14)
113 #define MT9V032_AEC_AGC_ENABLE 0xaf
114 #define MT9V032_AEC_ENABLE (1 << 0)
115 #define MT9V032_AGC_ENABLE (1 << 1)
116 #define MT9V032_THERMAL_INFO 0xc1
119 struct v4l2_subdev subdev
;
120 struct media_pad pad
;
122 struct v4l2_mbus_framefmt format
;
123 struct v4l2_rect crop
;
125 struct v4l2_ctrl_handler ctrls
;
127 struct mutex power_lock
;
130 struct mt9v032_platform_data
*pdata
;
135 static struct mt9v032
*to_mt9v032(struct v4l2_subdev
*sd
)
137 return container_of(sd
, struct mt9v032
, subdev
);
140 static int mt9v032_read(struct i2c_client
*client
, const u8 reg
)
142 s32 data
= i2c_smbus_read_word_data(client
, reg
);
143 dev_dbg(&client
->dev
, "%s: read 0x%04x from 0x%02x\n", __func__
,
145 return data
< 0 ? data
: swab16(data
);
148 static int mt9v032_write(struct i2c_client
*client
, const u8 reg
,
151 dev_dbg(&client
->dev
, "%s: writing 0x%04x to 0x%02x\n", __func__
,
153 return i2c_smbus_write_word_data(client
, reg
, swab16(data
));
156 static int mt9v032_set_chip_control(struct mt9v032
*mt9v032
, u16 clear
, u16 set
)
158 struct i2c_client
*client
= v4l2_get_subdevdata(&mt9v032
->subdev
);
159 u16 value
= (mt9v032
->chip_control
& ~clear
) | set
;
162 ret
= mt9v032_write(client
, MT9V032_CHIP_CONTROL
, value
);
166 mt9v032
->chip_control
= value
;
171 mt9v032_update_aec_agc(struct mt9v032
*mt9v032
, u16 which
, int enable
)
173 struct i2c_client
*client
= v4l2_get_subdevdata(&mt9v032
->subdev
);
174 u16 value
= mt9v032
->aec_agc
;
182 ret
= mt9v032_write(client
, MT9V032_AEC_AGC_ENABLE
, value
);
186 mt9v032
->aec_agc
= value
;
190 static int mt9v032_power_on(struct mt9v032
*mt9v032
)
192 struct i2c_client
*client
= v4l2_get_subdevdata(&mt9v032
->subdev
);
195 if (mt9v032
->pdata
->set_clock
) {
196 mt9v032
->pdata
->set_clock(&mt9v032
->subdev
, 25000000);
200 /* Reset the chip and stop data read out */
201 ret
= mt9v032_write(client
, MT9V032_RESET
, 1);
205 ret
= mt9v032_write(client
, MT9V032_RESET
, 0);
209 return mt9v032_write(client
, MT9V032_CHIP_CONTROL
, 0);
212 static void mt9v032_power_off(struct mt9v032
*mt9v032
)
214 if (mt9v032
->pdata
->set_clock
)
215 mt9v032
->pdata
->set_clock(&mt9v032
->subdev
, 0);
218 static int __mt9v032_set_power(struct mt9v032
*mt9v032
, bool on
)
220 struct i2c_client
*client
= v4l2_get_subdevdata(&mt9v032
->subdev
);
224 mt9v032_power_off(mt9v032
);
228 ret
= mt9v032_power_on(mt9v032
);
232 /* Configure the pixel clock polarity */
233 if (mt9v032
->pdata
&& mt9v032
->pdata
->clk_pol
) {
234 ret
= mt9v032_write(client
, MT9V032_PIXEL_CLOCK
,
235 MT9V032_PIXEL_CLOCK_INV_PXL_CLK
);
240 /* Disable the noise correction algorithm and restore the controls. */
241 ret
= mt9v032_write(client
, MT9V032_ROW_NOISE_CORR_CONTROL
, 0);
245 return v4l2_ctrl_handler_setup(&mt9v032
->ctrls
);
248 /* -----------------------------------------------------------------------------
249 * V4L2 subdev video operations
252 static struct v4l2_mbus_framefmt
*
253 __mt9v032_get_pad_format(struct mt9v032
*mt9v032
, struct v4l2_subdev_fh
*fh
,
254 unsigned int pad
, enum v4l2_subdev_format_whence which
)
257 case V4L2_SUBDEV_FORMAT_TRY
:
258 return v4l2_subdev_get_try_format(fh
, pad
);
259 case V4L2_SUBDEV_FORMAT_ACTIVE
:
260 return &mt9v032
->format
;
266 static struct v4l2_rect
*
267 __mt9v032_get_pad_crop(struct mt9v032
*mt9v032
, struct v4l2_subdev_fh
*fh
,
268 unsigned int pad
, enum v4l2_subdev_format_whence which
)
271 case V4L2_SUBDEV_FORMAT_TRY
:
272 return v4l2_subdev_get_try_crop(fh
, pad
);
273 case V4L2_SUBDEV_FORMAT_ACTIVE
:
274 return &mt9v032
->crop
;
280 static int mt9v032_s_stream(struct v4l2_subdev
*subdev
, int enable
)
282 const u16 mode
= MT9V032_CHIP_CONTROL_MASTER_MODE
283 | MT9V032_CHIP_CONTROL_DOUT_ENABLE
284 | MT9V032_CHIP_CONTROL_SEQUENTIAL
;
285 struct i2c_client
*client
= v4l2_get_subdevdata(subdev
);
286 struct mt9v032
*mt9v032
= to_mt9v032(subdev
);
287 struct v4l2_mbus_framefmt
*format
= &mt9v032
->format
;
288 struct v4l2_rect
*crop
= &mt9v032
->crop
;
294 return mt9v032_set_chip_control(mt9v032
, mode
, 0);
296 /* Configure the window size and row/column bin */
297 hratio
= DIV_ROUND_CLOSEST(crop
->width
, format
->width
);
298 vratio
= DIV_ROUND_CLOSEST(crop
->height
, format
->height
);
300 ret
= mt9v032_write(client
, MT9V032_READ_MODE
,
301 (hratio
- 1) << MT9V032_READ_MODE_ROW_BIN_SHIFT
|
302 (vratio
- 1) << MT9V032_READ_MODE_COLUMN_BIN_SHIFT
);
306 ret
= mt9v032_write(client
, MT9V032_COLUMN_START
, crop
->left
);
310 ret
= mt9v032_write(client
, MT9V032_ROW_START
, crop
->top
);
314 ret
= mt9v032_write(client
, MT9V032_WINDOW_WIDTH
, crop
->width
);
318 ret
= mt9v032_write(client
, MT9V032_WINDOW_HEIGHT
, crop
->height
);
322 ret
= mt9v032_write(client
, MT9V032_HORIZONTAL_BLANKING
,
323 max(43, 660 - crop
->width
));
327 /* Switch to master "normal" mode */
328 return mt9v032_set_chip_control(mt9v032
, 0, mode
);
331 static int mt9v032_enum_mbus_code(struct v4l2_subdev
*subdev
,
332 struct v4l2_subdev_fh
*fh
,
333 struct v4l2_subdev_mbus_code_enum
*code
)
338 code
->code
= V4L2_MBUS_FMT_SGRBG10_1X10
;
342 static int mt9v032_enum_frame_size(struct v4l2_subdev
*subdev
,
343 struct v4l2_subdev_fh
*fh
,
344 struct v4l2_subdev_frame_size_enum
*fse
)
346 if (fse
->index
>= 8 || fse
->code
!= V4L2_MBUS_FMT_SGRBG10_1X10
)
349 fse
->min_width
= MT9V032_WINDOW_WIDTH_DEF
/ fse
->index
;
350 fse
->max_width
= fse
->min_width
;
351 fse
->min_height
= MT9V032_WINDOW_HEIGHT_DEF
/ fse
->index
;
352 fse
->max_height
= fse
->min_height
;
357 static int mt9v032_get_format(struct v4l2_subdev
*subdev
,
358 struct v4l2_subdev_fh
*fh
,
359 struct v4l2_subdev_format
*format
)
361 struct mt9v032
*mt9v032
= to_mt9v032(subdev
);
363 format
->format
= *__mt9v032_get_pad_format(mt9v032
, fh
, format
->pad
,
368 static int mt9v032_set_format(struct v4l2_subdev
*subdev
,
369 struct v4l2_subdev_fh
*fh
,
370 struct v4l2_subdev_format
*format
)
372 struct mt9v032
*mt9v032
= to_mt9v032(subdev
);
373 struct v4l2_mbus_framefmt
*__format
;
374 struct v4l2_rect
*__crop
;
380 __crop
= __mt9v032_get_pad_crop(mt9v032
, fh
, format
->pad
,
383 /* Clamp the width and height to avoid dividing by zero. */
384 width
= clamp_t(unsigned int, ALIGN(format
->format
.width
, 2),
385 max(__crop
->width
/ 8, MT9V032_WINDOW_WIDTH_MIN
),
387 height
= clamp_t(unsigned int, ALIGN(format
->format
.height
, 2),
388 max(__crop
->height
/ 8, MT9V032_WINDOW_HEIGHT_MIN
),
391 hratio
= DIV_ROUND_CLOSEST(__crop
->width
, width
);
392 vratio
= DIV_ROUND_CLOSEST(__crop
->height
, height
);
394 __format
= __mt9v032_get_pad_format(mt9v032
, fh
, format
->pad
,
396 __format
->width
= __crop
->width
/ hratio
;
397 __format
->height
= __crop
->height
/ vratio
;
399 format
->format
= *__format
;
404 static int mt9v032_get_crop(struct v4l2_subdev
*subdev
,
405 struct v4l2_subdev_fh
*fh
,
406 struct v4l2_subdev_crop
*crop
)
408 struct mt9v032
*mt9v032
= to_mt9v032(subdev
);
410 crop
->rect
= *__mt9v032_get_pad_crop(mt9v032
, fh
, crop
->pad
,
415 static int mt9v032_set_crop(struct v4l2_subdev
*subdev
,
416 struct v4l2_subdev_fh
*fh
,
417 struct v4l2_subdev_crop
*crop
)
419 struct mt9v032
*mt9v032
= to_mt9v032(subdev
);
420 struct v4l2_mbus_framefmt
*__format
;
421 struct v4l2_rect
*__crop
;
422 struct v4l2_rect rect
;
424 /* Clamp the crop rectangle boundaries and align them to a non multiple
425 * of 2 pixels to ensure a GRBG Bayer pattern.
427 rect
.left
= clamp(ALIGN(crop
->rect
.left
+ 1, 2) - 1,
428 MT9V032_COLUMN_START_MIN
,
429 MT9V032_COLUMN_START_MAX
);
430 rect
.top
= clamp(ALIGN(crop
->rect
.top
+ 1, 2) - 1,
431 MT9V032_ROW_START_MIN
,
432 MT9V032_ROW_START_MAX
);
433 rect
.width
= clamp(ALIGN(crop
->rect
.width
, 2),
434 MT9V032_WINDOW_WIDTH_MIN
,
435 MT9V032_WINDOW_WIDTH_MAX
);
436 rect
.height
= clamp(ALIGN(crop
->rect
.height
, 2),
437 MT9V032_WINDOW_HEIGHT_MIN
,
438 MT9V032_WINDOW_HEIGHT_MAX
);
440 rect
.width
= min(rect
.width
, MT9V032_PIXEL_ARRAY_WIDTH
- rect
.left
);
441 rect
.height
= min(rect
.height
, MT9V032_PIXEL_ARRAY_HEIGHT
- rect
.top
);
443 __crop
= __mt9v032_get_pad_crop(mt9v032
, fh
, crop
->pad
, crop
->which
);
445 if (rect
.width
!= __crop
->width
|| rect
.height
!= __crop
->height
) {
446 /* Reset the output image size if the crop rectangle size has
449 __format
= __mt9v032_get_pad_format(mt9v032
, fh
, crop
->pad
,
451 __format
->width
= rect
.width
;
452 __format
->height
= rect
.height
;
461 /* -----------------------------------------------------------------------------
462 * V4L2 subdev control operations
465 #define V4L2_CID_TEST_PATTERN (V4L2_CID_USER_BASE | 0x1001)
467 static int mt9v032_s_ctrl(struct v4l2_ctrl
*ctrl
)
469 struct mt9v032
*mt9v032
=
470 container_of(ctrl
->handler
, struct mt9v032
, ctrls
);
471 struct i2c_client
*client
= v4l2_get_subdevdata(&mt9v032
->subdev
);
475 case V4L2_CID_AUTOGAIN
:
476 return mt9v032_update_aec_agc(mt9v032
, MT9V032_AGC_ENABLE
,
480 return mt9v032_write(client
, MT9V032_ANALOG_GAIN
, ctrl
->val
);
482 case V4L2_CID_EXPOSURE_AUTO
:
483 return mt9v032_update_aec_agc(mt9v032
, MT9V032_AEC_ENABLE
,
486 case V4L2_CID_EXPOSURE
:
487 return mt9v032_write(client
, MT9V032_TOTAL_SHUTTER_WIDTH
,
490 case V4L2_CID_TEST_PATTERN
:
496 data
= MT9V032_TEST_PATTERN_GRAY_VERTICAL
497 | MT9V032_TEST_PATTERN_ENABLE
;
500 data
= MT9V032_TEST_PATTERN_GRAY_HORIZONTAL
501 | MT9V032_TEST_PATTERN_ENABLE
;
504 data
= MT9V032_TEST_PATTERN_GRAY_DIAGONAL
505 | MT9V032_TEST_PATTERN_ENABLE
;
508 data
= (ctrl
->val
<< MT9V032_TEST_PATTERN_DATA_SHIFT
)
509 | MT9V032_TEST_PATTERN_USE_DATA
510 | MT9V032_TEST_PATTERN_ENABLE
511 | MT9V032_TEST_PATTERN_FLIP
;
515 return mt9v032_write(client
, MT9V032_TEST_PATTERN
, data
);
521 static struct v4l2_ctrl_ops mt9v032_ctrl_ops
= {
522 .s_ctrl
= mt9v032_s_ctrl
,
525 static const struct v4l2_ctrl_config mt9v032_ctrls
[] = {
527 .ops
= &mt9v032_ctrl_ops
,
528 .id
= V4L2_CID_TEST_PATTERN
,
529 .type
= V4L2_CTRL_TYPE_INTEGER
,
530 .name
= "Test pattern",
539 /* -----------------------------------------------------------------------------
540 * V4L2 subdev core operations
543 static int mt9v032_set_power(struct v4l2_subdev
*subdev
, int on
)
545 struct mt9v032
*mt9v032
= to_mt9v032(subdev
);
548 mutex_lock(&mt9v032
->power_lock
);
550 /* If the power count is modified from 0 to != 0 or from != 0 to 0,
551 * update the power state.
553 if (mt9v032
->power_count
== !on
) {
554 ret
= __mt9v032_set_power(mt9v032
, !!on
);
559 /* Update the power count. */
560 mt9v032
->power_count
+= on
? 1 : -1;
561 WARN_ON(mt9v032
->power_count
< 0);
564 mutex_unlock(&mt9v032
->power_lock
);
568 /* -----------------------------------------------------------------------------
569 * V4L2 subdev internal operations
572 static int mt9v032_registered(struct v4l2_subdev
*subdev
)
574 struct i2c_client
*client
= v4l2_get_subdevdata(subdev
);
575 struct mt9v032
*mt9v032
= to_mt9v032(subdev
);
579 dev_info(&client
->dev
, "Probing MT9V032 at address 0x%02x\n",
582 ret
= mt9v032_power_on(mt9v032
);
584 dev_err(&client
->dev
, "MT9V032 power up failed\n");
588 /* Read and check the sensor version */
589 data
= mt9v032_read(client
, MT9V032_CHIP_VERSION
);
590 if (data
!= MT9V032_CHIP_ID_REV1
&& data
!= MT9V032_CHIP_ID_REV3
) {
591 dev_err(&client
->dev
, "MT9V032 not detected, wrong version "
596 mt9v032_power_off(mt9v032
);
598 dev_info(&client
->dev
, "MT9V032 detected at address 0x%02x\n",
604 static int mt9v032_open(struct v4l2_subdev
*subdev
, struct v4l2_subdev_fh
*fh
)
606 struct v4l2_mbus_framefmt
*format
;
607 struct v4l2_rect
*crop
;
609 crop
= v4l2_subdev_get_try_crop(fh
, 0);
610 crop
->left
= MT9V032_COLUMN_START_DEF
;
611 crop
->top
= MT9V032_ROW_START_DEF
;
612 crop
->width
= MT9V032_WINDOW_WIDTH_DEF
;
613 crop
->height
= MT9V032_WINDOW_HEIGHT_DEF
;
615 format
= v4l2_subdev_get_try_format(fh
, 0);
616 format
->code
= V4L2_MBUS_FMT_SGRBG10_1X10
;
617 format
->width
= MT9V032_WINDOW_WIDTH_DEF
;
618 format
->height
= MT9V032_WINDOW_HEIGHT_DEF
;
619 format
->field
= V4L2_FIELD_NONE
;
620 format
->colorspace
= V4L2_COLORSPACE_SRGB
;
622 return mt9v032_set_power(subdev
, 1);
625 static int mt9v032_close(struct v4l2_subdev
*subdev
, struct v4l2_subdev_fh
*fh
)
627 return mt9v032_set_power(subdev
, 0);
630 static struct v4l2_subdev_core_ops mt9v032_subdev_core_ops
= {
631 .s_power
= mt9v032_set_power
,
634 static struct v4l2_subdev_video_ops mt9v032_subdev_video_ops
= {
635 .s_stream
= mt9v032_s_stream
,
638 static struct v4l2_subdev_pad_ops mt9v032_subdev_pad_ops
= {
639 .enum_mbus_code
= mt9v032_enum_mbus_code
,
640 .enum_frame_size
= mt9v032_enum_frame_size
,
641 .get_fmt
= mt9v032_get_format
,
642 .set_fmt
= mt9v032_set_format
,
643 .get_crop
= mt9v032_get_crop
,
644 .set_crop
= mt9v032_set_crop
,
647 static struct v4l2_subdev_ops mt9v032_subdev_ops
= {
648 .core
= &mt9v032_subdev_core_ops
,
649 .video
= &mt9v032_subdev_video_ops
,
650 .pad
= &mt9v032_subdev_pad_ops
,
653 static const struct v4l2_subdev_internal_ops mt9v032_subdev_internal_ops
= {
654 .registered
= mt9v032_registered
,
655 .open
= mt9v032_open
,
656 .close
= mt9v032_close
,
659 /* -----------------------------------------------------------------------------
660 * Driver initialization and probing
663 static int mt9v032_probe(struct i2c_client
*client
,
664 const struct i2c_device_id
*did
)
666 struct mt9v032
*mt9v032
;
670 if (!i2c_check_functionality(client
->adapter
,
671 I2C_FUNC_SMBUS_WORD_DATA
)) {
672 dev_warn(&client
->adapter
->dev
,
673 "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
677 mt9v032
= kzalloc(sizeof(*mt9v032
), GFP_KERNEL
);
681 mutex_init(&mt9v032
->power_lock
);
682 mt9v032
->pdata
= client
->dev
.platform_data
;
684 v4l2_ctrl_handler_init(&mt9v032
->ctrls
, ARRAY_SIZE(mt9v032_ctrls
) + 4);
686 v4l2_ctrl_new_std(&mt9v032
->ctrls
, &mt9v032_ctrl_ops
,
687 V4L2_CID_AUTOGAIN
, 0, 1, 1, 1);
688 v4l2_ctrl_new_std(&mt9v032
->ctrls
, &mt9v032_ctrl_ops
,
689 V4L2_CID_GAIN
, MT9V032_ANALOG_GAIN_MIN
,
690 MT9V032_ANALOG_GAIN_MAX
, 1, MT9V032_ANALOG_GAIN_DEF
);
691 v4l2_ctrl_new_std_menu(&mt9v032
->ctrls
, &mt9v032_ctrl_ops
,
692 V4L2_CID_EXPOSURE_AUTO
, V4L2_EXPOSURE_MANUAL
, 0,
694 v4l2_ctrl_new_std(&mt9v032
->ctrls
, &mt9v032_ctrl_ops
,
695 V4L2_CID_EXPOSURE
, MT9V032_TOTAL_SHUTTER_WIDTH_MIN
,
696 MT9V032_TOTAL_SHUTTER_WIDTH_MAX
, 1,
697 MT9V032_TOTAL_SHUTTER_WIDTH_DEF
);
699 for (i
= 0; i
< ARRAY_SIZE(mt9v032_ctrls
); ++i
)
700 v4l2_ctrl_new_custom(&mt9v032
->ctrls
, &mt9v032_ctrls
[i
], NULL
);
702 mt9v032
->subdev
.ctrl_handler
= &mt9v032
->ctrls
;
704 if (mt9v032
->ctrls
.error
)
705 printk(KERN_INFO
"%s: control initialization error %d\n",
706 __func__
, mt9v032
->ctrls
.error
);
708 mt9v032
->crop
.left
= MT9V032_COLUMN_START_DEF
;
709 mt9v032
->crop
.top
= MT9V032_ROW_START_DEF
;
710 mt9v032
->crop
.width
= MT9V032_WINDOW_WIDTH_DEF
;
711 mt9v032
->crop
.height
= MT9V032_WINDOW_HEIGHT_DEF
;
713 mt9v032
->format
.code
= V4L2_MBUS_FMT_SGRBG10_1X10
;
714 mt9v032
->format
.width
= MT9V032_WINDOW_WIDTH_DEF
;
715 mt9v032
->format
.height
= MT9V032_WINDOW_HEIGHT_DEF
;
716 mt9v032
->format
.field
= V4L2_FIELD_NONE
;
717 mt9v032
->format
.colorspace
= V4L2_COLORSPACE_SRGB
;
719 mt9v032
->aec_agc
= MT9V032_AEC_ENABLE
| MT9V032_AGC_ENABLE
;
721 v4l2_i2c_subdev_init(&mt9v032
->subdev
, client
, &mt9v032_subdev_ops
);
722 mt9v032
->subdev
.internal_ops
= &mt9v032_subdev_internal_ops
;
723 mt9v032
->subdev
.flags
|= V4L2_SUBDEV_FL_HAS_DEVNODE
;
725 mt9v032
->pad
.flags
= MEDIA_PAD_FL_SOURCE
;
726 ret
= media_entity_init(&mt9v032
->subdev
.entity
, 1, &mt9v032
->pad
, 0);
733 static int mt9v032_remove(struct i2c_client
*client
)
735 struct v4l2_subdev
*subdev
= i2c_get_clientdata(client
);
736 struct mt9v032
*mt9v032
= to_mt9v032(subdev
);
738 v4l2_device_unregister_subdev(subdev
);
739 media_entity_cleanup(&subdev
->entity
);
744 static const struct i2c_device_id mt9v032_id
[] = {
748 MODULE_DEVICE_TABLE(i2c
, mt9v032_id
);
750 static struct i2c_driver mt9v032_driver
= {
754 .probe
= mt9v032_probe
,
755 .remove
= mt9v032_remove
,
756 .id_table
= mt9v032_id
,
759 static int __init
mt9v032_init(void)
761 return i2c_add_driver(&mt9v032_driver
);
764 static void __exit
mt9v032_exit(void)
766 i2c_del_driver(&mt9v032_driver
);
769 module_init(mt9v032_init
);
770 module_exit(mt9v032_exit
);
772 MODULE_DESCRIPTION("Aptina MT9V032 Camera driver");
773 MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
774 MODULE_LICENSE("GPL");