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>
23 #include <media/mt9v032.h>
24 #include <media/v4l2-ctrls.h>
25 #include <media/v4l2-device.h>
26 #include <media/v4l2-subdev.h>
28 #define MT9V032_PIXEL_ARRAY_HEIGHT 492
29 #define MT9V032_PIXEL_ARRAY_WIDTH 782
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
118 struct v4l2_subdev subdev
;
119 struct media_pad pad
;
121 struct v4l2_mbus_framefmt format
;
122 struct v4l2_rect crop
;
124 struct v4l2_ctrl_handler ctrls
;
126 struct mutex power_lock
;
129 struct mt9v032_platform_data
*pdata
;
134 static struct mt9v032
*to_mt9v032(struct v4l2_subdev
*sd
)
136 return container_of(sd
, struct mt9v032
, subdev
);
139 static int mt9v032_read(struct i2c_client
*client
, const u8 reg
)
141 s32 data
= i2c_smbus_read_word_data(client
, reg
);
142 dev_dbg(&client
->dev
, "%s: read 0x%04x from 0x%02x\n", __func__
,
144 return data
< 0 ? data
: swab16(data
);
147 static int mt9v032_write(struct i2c_client
*client
, const u8 reg
,
150 dev_dbg(&client
->dev
, "%s: writing 0x%04x to 0x%02x\n", __func__
,
152 return i2c_smbus_write_word_data(client
, reg
, swab16(data
));
155 static int mt9v032_set_chip_control(struct mt9v032
*mt9v032
, u16 clear
, u16 set
)
157 struct i2c_client
*client
= v4l2_get_subdevdata(&mt9v032
->subdev
);
158 u16 value
= (mt9v032
->chip_control
& ~clear
) | set
;
161 ret
= mt9v032_write(client
, MT9V032_CHIP_CONTROL
, value
);
165 mt9v032
->chip_control
= value
;
170 mt9v032_update_aec_agc(struct mt9v032
*mt9v032
, u16 which
, int enable
)
172 struct i2c_client
*client
= v4l2_get_subdevdata(&mt9v032
->subdev
);
173 u16 value
= mt9v032
->aec_agc
;
181 ret
= mt9v032_write(client
, MT9V032_AEC_AGC_ENABLE
, value
);
185 mt9v032
->aec_agc
= value
;
189 static int mt9v032_power_on(struct mt9v032
*mt9v032
)
191 struct i2c_client
*client
= v4l2_get_subdevdata(&mt9v032
->subdev
);
194 if (mt9v032
->pdata
->set_clock
) {
195 mt9v032
->pdata
->set_clock(&mt9v032
->subdev
, 25000000);
199 /* Reset the chip and stop data read out */
200 ret
= mt9v032_write(client
, MT9V032_RESET
, 1);
204 ret
= mt9v032_write(client
, MT9V032_RESET
, 0);
208 return mt9v032_write(client
, MT9V032_CHIP_CONTROL
, 0);
211 static void mt9v032_power_off(struct mt9v032
*mt9v032
)
213 if (mt9v032
->pdata
->set_clock
)
214 mt9v032
->pdata
->set_clock(&mt9v032
->subdev
, 0);
217 static int __mt9v032_set_power(struct mt9v032
*mt9v032
, bool on
)
219 struct i2c_client
*client
= v4l2_get_subdevdata(&mt9v032
->subdev
);
223 mt9v032_power_off(mt9v032
);
227 ret
= mt9v032_power_on(mt9v032
);
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
);
239 /* Disable the noise correction algorithm and restore the controls. */
240 ret
= mt9v032_write(client
, MT9V032_ROW_NOISE_CORR_CONTROL
, 0);
244 return v4l2_ctrl_handler_setup(&mt9v032
->ctrls
);
247 /* -----------------------------------------------------------------------------
248 * V4L2 subdev video operations
251 static 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
)
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
;
265 static 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
)
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
;
279 static int mt9v032_s_stream(struct v4l2_subdev
*subdev
, int enable
)
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
;
293 return mt9v032_set_chip_control(mt9v032
, mode
, 0);
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
);
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
);
305 ret
= mt9v032_write(client
, MT9V032_COLUMN_START
, crop
->left
);
309 ret
= mt9v032_write(client
, MT9V032_ROW_START
, crop
->top
);
313 ret
= mt9v032_write(client
, MT9V032_WINDOW_WIDTH
, crop
->width
);
317 ret
= mt9v032_write(client
, MT9V032_WINDOW_HEIGHT
, crop
->height
);
321 ret
= mt9v032_write(client
, MT9V032_HORIZONTAL_BLANKING
,
322 max(43, 660 - crop
->width
));
326 /* Switch to master "normal" mode */
327 return mt9v032_set_chip_control(mt9v032
, 0, mode
);
330 static int mt9v032_enum_mbus_code(struct v4l2_subdev
*subdev
,
331 struct v4l2_subdev_fh
*fh
,
332 struct v4l2_subdev_mbus_code_enum
*code
)
337 code
->code
= V4L2_MBUS_FMT_SGRBG10_1X10
;
341 static int mt9v032_enum_frame_size(struct v4l2_subdev
*subdev
,
342 struct v4l2_subdev_fh
*fh
,
343 struct v4l2_subdev_frame_size_enum
*fse
)
345 if (fse
->index
>= 8 || fse
->code
!= V4L2_MBUS_FMT_SGRBG10_1X10
)
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
;
356 static int mt9v032_get_format(struct v4l2_subdev
*subdev
,
357 struct v4l2_subdev_fh
*fh
,
358 struct v4l2_subdev_format
*format
)
360 struct mt9v032
*mt9v032
= to_mt9v032(subdev
);
362 format
->format
= *__mt9v032_get_pad_format(mt9v032
, fh
, format
->pad
,
367 static int mt9v032_set_format(struct v4l2_subdev
*subdev
,
368 struct v4l2_subdev_fh
*fh
,
369 struct v4l2_subdev_format
*format
)
371 struct mt9v032
*mt9v032
= to_mt9v032(subdev
);
372 struct v4l2_mbus_framefmt
*__format
;
373 struct v4l2_rect
*__crop
;
379 __crop
= __mt9v032_get_pad_crop(mt9v032
, fh
, format
->pad
,
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
),
386 height
= clamp_t(unsigned int, ALIGN(format
->format
.height
, 2),
387 max(__crop
->height
/ 8, MT9V032_WINDOW_HEIGHT_MIN
),
390 hratio
= DIV_ROUND_CLOSEST(__crop
->width
, width
);
391 vratio
= DIV_ROUND_CLOSEST(__crop
->height
, height
);
393 __format
= __mt9v032_get_pad_format(mt9v032
, fh
, format
->pad
,
395 __format
->width
= __crop
->width
/ hratio
;
396 __format
->height
= __crop
->height
/ vratio
;
398 format
->format
= *__format
;
403 static int mt9v032_get_crop(struct v4l2_subdev
*subdev
,
404 struct v4l2_subdev_fh
*fh
,
405 struct v4l2_subdev_crop
*crop
)
407 struct mt9v032
*mt9v032
= to_mt9v032(subdev
);
409 crop
->rect
= *__mt9v032_get_pad_crop(mt9v032
, fh
, crop
->pad
,
414 static int mt9v032_set_crop(struct v4l2_subdev
*subdev
,
415 struct v4l2_subdev_fh
*fh
,
416 struct v4l2_subdev_crop
*crop
)
418 struct mt9v032
*mt9v032
= to_mt9v032(subdev
);
419 struct v4l2_mbus_framefmt
*__format
;
420 struct v4l2_rect
*__crop
;
421 struct v4l2_rect rect
;
423 /* Clamp the crop rectangle boundaries and align them to a multiple of 2
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
);
439 rect
.width
= min(rect
.width
, MT9V032_PIXEL_ARRAY_WIDTH
- rect
.left
);
440 rect
.height
= min(rect
.height
, MT9V032_PIXEL_ARRAY_HEIGHT
- rect
.top
);
442 __crop
= __mt9v032_get_pad_crop(mt9v032
, fh
, crop
->pad
, crop
->which
);
444 if (rect
.width
!= __crop
->width
|| rect
.height
!= __crop
->height
) {
445 /* Reset the output image size if the crop rectangle size has
448 __format
= __mt9v032_get_pad_format(mt9v032
, fh
, crop
->pad
,
450 __format
->width
= rect
.width
;
451 __format
->height
= rect
.height
;
460 /* -----------------------------------------------------------------------------
461 * V4L2 subdev control operations
464 #define V4L2_CID_TEST_PATTERN (V4L2_CID_USER_BASE | 0x1001)
466 static int mt9v032_s_ctrl(struct v4l2_ctrl
*ctrl
)
468 struct mt9v032
*mt9v032
=
469 container_of(ctrl
->handler
, struct mt9v032
, ctrls
);
470 struct i2c_client
*client
= v4l2_get_subdevdata(&mt9v032
->subdev
);
474 case V4L2_CID_AUTOGAIN
:
475 return mt9v032_update_aec_agc(mt9v032
, MT9V032_AGC_ENABLE
,
479 return mt9v032_write(client
, MT9V032_ANALOG_GAIN
, ctrl
->val
);
481 case V4L2_CID_EXPOSURE_AUTO
:
482 return mt9v032_update_aec_agc(mt9v032
, MT9V032_AEC_ENABLE
,
485 case V4L2_CID_EXPOSURE
:
486 return mt9v032_write(client
, MT9V032_TOTAL_SHUTTER_WIDTH
,
489 case V4L2_CID_TEST_PATTERN
:
495 data
= MT9V032_TEST_PATTERN_GRAY_VERTICAL
496 | MT9V032_TEST_PATTERN_ENABLE
;
499 data
= MT9V032_TEST_PATTERN_GRAY_HORIZONTAL
500 | MT9V032_TEST_PATTERN_ENABLE
;
503 data
= MT9V032_TEST_PATTERN_GRAY_DIAGONAL
504 | MT9V032_TEST_PATTERN_ENABLE
;
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
;
514 return mt9v032_write(client
, MT9V032_TEST_PATTERN
, data
);
520 static struct v4l2_ctrl_ops mt9v032_ctrl_ops
= {
521 .s_ctrl
= mt9v032_s_ctrl
,
524 static const struct v4l2_ctrl_config mt9v032_ctrls
[] = {
526 .ops
= &mt9v032_ctrl_ops
,
527 .id
= V4L2_CID_TEST_PATTERN
,
528 .type
= V4L2_CTRL_TYPE_INTEGER
,
529 .name
= "Test pattern",
538 /* -----------------------------------------------------------------------------
539 * V4L2 subdev core operations
542 static int mt9v032_set_power(struct v4l2_subdev
*subdev
, int on
)
544 struct mt9v032
*mt9v032
= to_mt9v032(subdev
);
547 mutex_lock(&mt9v032
->power_lock
);
549 /* If the power count is modified from 0 to != 0 or from != 0 to 0,
550 * update the power state.
552 if (mt9v032
->power_count
== !on
) {
553 ret
= __mt9v032_set_power(mt9v032
, !!on
);
558 /* Update the power count. */
559 mt9v032
->power_count
+= on
? 1 : -1;
560 WARN_ON(mt9v032
->power_count
< 0);
563 mutex_unlock(&mt9v032
->power_lock
);
567 /* -----------------------------------------------------------------------------
568 * V4L2 subdev internal operations
571 static int mt9v032_registered(struct v4l2_subdev
*subdev
)
573 struct i2c_client
*client
= v4l2_get_subdevdata(subdev
);
574 struct mt9v032
*mt9v032
= to_mt9v032(subdev
);
578 dev_info(&client
->dev
, "Probing MT9V032 at address 0x%02x\n",
581 ret
= mt9v032_power_on(mt9v032
);
583 dev_err(&client
->dev
, "MT9V032 power up failed\n");
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 "
595 mt9v032_power_off(mt9v032
);
597 dev_info(&client
->dev
, "MT9V032 detected at address 0x%02x\n",
603 static int mt9v032_open(struct v4l2_subdev
*subdev
, struct v4l2_subdev_fh
*fh
)
605 struct v4l2_mbus_framefmt
*format
;
606 struct v4l2_rect
*crop
;
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
;
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
;
621 return mt9v032_set_power(subdev
, 1);
624 static int mt9v032_close(struct v4l2_subdev
*subdev
, struct v4l2_subdev_fh
*fh
)
626 return mt9v032_set_power(subdev
, 0);
629 static struct v4l2_subdev_core_ops mt9v032_subdev_core_ops
= {
630 .s_power
= mt9v032_set_power
,
633 static struct v4l2_subdev_video_ops mt9v032_subdev_video_ops
= {
634 .s_stream
= mt9v032_s_stream
,
637 static 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
,
646 static 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
,
652 static const struct v4l2_subdev_internal_ops mt9v032_subdev_internal_ops
= {
653 .registered
= mt9v032_registered
,
654 .open
= mt9v032_open
,
655 .close
= mt9v032_close
,
658 /* -----------------------------------------------------------------------------
659 * Driver initialization and probing
662 static int mt9v032_probe(struct i2c_client
*client
,
663 const struct i2c_device_id
*did
)
665 struct mt9v032
*mt9v032
;
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");
676 mt9v032
= kzalloc(sizeof(*mt9v032
), GFP_KERNEL
);
680 mutex_init(&mt9v032
->power_lock
);
681 mt9v032
->pdata
= client
->dev
.platform_data
;
683 v4l2_ctrl_handler_init(&mt9v032
->ctrls
, ARRAY_SIZE(mt9v032_ctrls
) + 4);
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,
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
);
698 for (i
= 0; i
< ARRAY_SIZE(mt9v032_ctrls
); ++i
)
699 v4l2_ctrl_new_custom(&mt9v032
->ctrls
, &mt9v032_ctrls
[i
], NULL
);
701 mt9v032
->subdev
.ctrl_handler
= &mt9v032
->ctrls
;
703 if (mt9v032
->ctrls
.error
)
704 printk(KERN_INFO
"%s: control initialization error %d\n",
705 __func__
, mt9v032
->ctrls
.error
);
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
;
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
;
718 mt9v032
->aec_agc
= MT9V032_AEC_ENABLE
| MT9V032_AGC_ENABLE
;
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
;
724 mt9v032
->pad
.flags
= MEDIA_PAD_FL_SOURCE
;
725 ret
= media_entity_init(&mt9v032
->subdev
.entity
, 1, &mt9v032
->pad
, 0);
732 static int mt9v032_remove(struct i2c_client
*client
)
734 struct v4l2_subdev
*subdev
= i2c_get_clientdata(client
);
735 struct mt9v032
*mt9v032
= to_mt9v032(subdev
);
737 v4l2_device_unregister_subdev(subdev
);
738 media_entity_cleanup(&subdev
->entity
);
743 static const struct i2c_device_id mt9v032_id
[] = {
747 MODULE_DEVICE_TABLE(i2c
, mt9v032_id
);
749 static struct i2c_driver mt9v032_driver
= {
753 .probe
= mt9v032_probe
,
754 .remove
= mt9v032_remove
,
755 .id_table
= mt9v032_id
,
758 static int __init
mt9v032_init(void)
760 return i2c_add_driver(&mt9v032_driver
);
763 static void __exit
mt9v032_exit(void)
765 i2c_del_driver(&mt9v032_driver
);
768 module_init(mt9v032_init
);
769 module_exit(mt9v032_exit
);
771 MODULE_DESCRIPTION("Aptina MT9V032 Camera driver");
772 MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
773 MODULE_LICENSE("GPL");