xref: /openbmc/linux/drivers/media/i2c/mt9v032.c (revision b96fc2f3)
1 /*
2  * Driver for MT9V022, MT9V024, MT9V032, and MT9V034 CMOS Image Sensors
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/clk.h>
16 #include <linux/delay.h>
17 #include <linux/i2c.h>
18 #include <linux/log2.h>
19 #include <linux/mutex.h>
20 #include <linux/of.h>
21 #include <linux/of_gpio.h>
22 #include <linux/regmap.h>
23 #include <linux/slab.h>
24 #include <linux/videodev2.h>
25 #include <linux/v4l2-mediabus.h>
26 #include <linux/module.h>
27 
28 #include <media/mt9v032.h>
29 #include <media/v4l2-ctrls.h>
30 #include <media/v4l2-device.h>
31 #include <media/v4l2-of.h>
32 #include <media/v4l2-subdev.h>
33 
34 /* The first four rows are black rows. The active area spans 753x481 pixels. */
35 #define MT9V032_PIXEL_ARRAY_HEIGHT			485
36 #define MT9V032_PIXEL_ARRAY_WIDTH			753
37 
38 #define MT9V032_SYSCLK_FREQ_DEF				26600000
39 
40 #define MT9V032_CHIP_VERSION				0x00
41 #define		MT9V032_CHIP_ID_REV1			0x1311
42 #define		MT9V032_CHIP_ID_REV3			0x1313
43 #define		MT9V034_CHIP_ID_REV1			0X1324
44 #define MT9V032_COLUMN_START				0x01
45 #define		MT9V032_COLUMN_START_MIN		1
46 #define		MT9V032_COLUMN_START_DEF		1
47 #define		MT9V032_COLUMN_START_MAX		752
48 #define MT9V032_ROW_START				0x02
49 #define		MT9V032_ROW_START_MIN			4
50 #define		MT9V032_ROW_START_DEF			5
51 #define		MT9V032_ROW_START_MAX			482
52 #define MT9V032_WINDOW_HEIGHT				0x03
53 #define		MT9V032_WINDOW_HEIGHT_MIN		1
54 #define		MT9V032_WINDOW_HEIGHT_DEF		480
55 #define		MT9V032_WINDOW_HEIGHT_MAX		480
56 #define MT9V032_WINDOW_WIDTH				0x04
57 #define		MT9V032_WINDOW_WIDTH_MIN		1
58 #define		MT9V032_WINDOW_WIDTH_DEF		752
59 #define		MT9V032_WINDOW_WIDTH_MAX		752
60 #define MT9V032_HORIZONTAL_BLANKING			0x05
61 #define		MT9V032_HORIZONTAL_BLANKING_MIN		43
62 #define		MT9V034_HORIZONTAL_BLANKING_MIN		61
63 #define		MT9V032_HORIZONTAL_BLANKING_DEF		94
64 #define		MT9V032_HORIZONTAL_BLANKING_MAX		1023
65 #define MT9V032_VERTICAL_BLANKING			0x06
66 #define		MT9V032_VERTICAL_BLANKING_MIN		4
67 #define		MT9V034_VERTICAL_BLANKING_MIN		2
68 #define		MT9V032_VERTICAL_BLANKING_DEF		45
69 #define		MT9V032_VERTICAL_BLANKING_MAX		3000
70 #define		MT9V034_VERTICAL_BLANKING_MAX		32288
71 #define MT9V032_CHIP_CONTROL				0x07
72 #define		MT9V032_CHIP_CONTROL_MASTER_MODE	(1 << 3)
73 #define		MT9V032_CHIP_CONTROL_DOUT_ENABLE	(1 << 7)
74 #define		MT9V032_CHIP_CONTROL_SEQUENTIAL		(1 << 8)
75 #define MT9V032_SHUTTER_WIDTH1				0x08
76 #define MT9V032_SHUTTER_WIDTH2				0x09
77 #define MT9V032_SHUTTER_WIDTH_CONTROL			0x0a
78 #define MT9V032_TOTAL_SHUTTER_WIDTH			0x0b
79 #define		MT9V032_TOTAL_SHUTTER_WIDTH_MIN		1
80 #define		MT9V034_TOTAL_SHUTTER_WIDTH_MIN		0
81 #define		MT9V032_TOTAL_SHUTTER_WIDTH_DEF		480
82 #define		MT9V032_TOTAL_SHUTTER_WIDTH_MAX		32767
83 #define		MT9V034_TOTAL_SHUTTER_WIDTH_MAX		32765
84 #define MT9V032_RESET					0x0c
85 #define MT9V032_READ_MODE				0x0d
86 #define		MT9V032_READ_MODE_ROW_BIN_MASK		(3 << 0)
87 #define		MT9V032_READ_MODE_ROW_BIN_SHIFT		0
88 #define		MT9V032_READ_MODE_COLUMN_BIN_MASK	(3 << 2)
89 #define		MT9V032_READ_MODE_COLUMN_BIN_SHIFT	2
90 #define		MT9V032_READ_MODE_ROW_FLIP		(1 << 4)
91 #define		MT9V032_READ_MODE_COLUMN_FLIP		(1 << 5)
92 #define		MT9V032_READ_MODE_DARK_COLUMNS		(1 << 6)
93 #define		MT9V032_READ_MODE_DARK_ROWS		(1 << 7)
94 #define		MT9V032_READ_MODE_RESERVED		0x0300
95 #define MT9V032_PIXEL_OPERATION_MODE			0x0f
96 #define		MT9V034_PIXEL_OPERATION_MODE_HDR	(1 << 0)
97 #define		MT9V034_PIXEL_OPERATION_MODE_COLOR	(1 << 1)
98 #define		MT9V032_PIXEL_OPERATION_MODE_COLOR	(1 << 2)
99 #define		MT9V032_PIXEL_OPERATION_MODE_HDR	(1 << 6)
100 #define MT9V032_ANALOG_GAIN				0x35
101 #define		MT9V032_ANALOG_GAIN_MIN			16
102 #define		MT9V032_ANALOG_GAIN_DEF			16
103 #define		MT9V032_ANALOG_GAIN_MAX			64
104 #define MT9V032_MAX_ANALOG_GAIN				0x36
105 #define		MT9V032_MAX_ANALOG_GAIN_MAX		127
106 #define MT9V032_FRAME_DARK_AVERAGE			0x42
107 #define MT9V032_DARK_AVG_THRESH				0x46
108 #define		MT9V032_DARK_AVG_LOW_THRESH_MASK	(255 << 0)
109 #define		MT9V032_DARK_AVG_LOW_THRESH_SHIFT	0
110 #define		MT9V032_DARK_AVG_HIGH_THRESH_MASK	(255 << 8)
111 #define		MT9V032_DARK_AVG_HIGH_THRESH_SHIFT	8
112 #define MT9V032_ROW_NOISE_CORR_CONTROL			0x70
113 #define		MT9V034_ROW_NOISE_CORR_ENABLE		(1 << 0)
114 #define		MT9V034_ROW_NOISE_CORR_USE_BLK_AVG	(1 << 1)
115 #define		MT9V032_ROW_NOISE_CORR_ENABLE		(1 << 5)
116 #define		MT9V032_ROW_NOISE_CORR_USE_BLK_AVG	(1 << 7)
117 #define MT9V032_PIXEL_CLOCK				0x74
118 #define MT9V034_PIXEL_CLOCK				0x72
119 #define		MT9V032_PIXEL_CLOCK_INV_LINE		(1 << 0)
120 #define		MT9V032_PIXEL_CLOCK_INV_FRAME		(1 << 1)
121 #define		MT9V032_PIXEL_CLOCK_XOR_LINE		(1 << 2)
122 #define		MT9V032_PIXEL_CLOCK_CONT_LINE		(1 << 3)
123 #define		MT9V032_PIXEL_CLOCK_INV_PXL_CLK		(1 << 4)
124 #define MT9V032_TEST_PATTERN				0x7f
125 #define		MT9V032_TEST_PATTERN_DATA_MASK		(1023 << 0)
126 #define		MT9V032_TEST_PATTERN_DATA_SHIFT		0
127 #define		MT9V032_TEST_PATTERN_USE_DATA		(1 << 10)
128 #define		MT9V032_TEST_PATTERN_GRAY_MASK		(3 << 11)
129 #define		MT9V032_TEST_PATTERN_GRAY_NONE		(0 << 11)
130 #define		MT9V032_TEST_PATTERN_GRAY_VERTICAL	(1 << 11)
131 #define		MT9V032_TEST_PATTERN_GRAY_HORIZONTAL	(2 << 11)
132 #define		MT9V032_TEST_PATTERN_GRAY_DIAGONAL	(3 << 11)
133 #define		MT9V032_TEST_PATTERN_ENABLE		(1 << 13)
134 #define		MT9V032_TEST_PATTERN_FLIP		(1 << 14)
135 #define MT9V032_AEC_AGC_ENABLE				0xaf
136 #define		MT9V032_AEC_ENABLE			(1 << 0)
137 #define		MT9V032_AGC_ENABLE			(1 << 1)
138 #define MT9V032_THERMAL_INFO				0xc1
139 
140 enum mt9v032_model {
141 	MT9V032_MODEL_V022_COLOR,	/* MT9V022IX7ATC */
142 	MT9V032_MODEL_V022_MONO,	/* MT9V022IX7ATM */
143 	MT9V032_MODEL_V024_COLOR,	/* MT9V024IA7XTC */
144 	MT9V032_MODEL_V024_MONO,	/* MT9V024IA7XTM */
145 	MT9V032_MODEL_V032_COLOR,	/* MT9V032C12STM */
146 	MT9V032_MODEL_V032_MONO,	/* MT9V032C12STC */
147 	MT9V032_MODEL_V034_COLOR,
148 	MT9V032_MODEL_V034_MONO,
149 };
150 
151 struct mt9v032_model_version {
152 	unsigned int version;
153 	const char *name;
154 };
155 
156 struct mt9v032_model_data {
157 	unsigned int min_row_time;
158 	unsigned int min_hblank;
159 	unsigned int min_vblank;
160 	unsigned int max_vblank;
161 	unsigned int min_shutter;
162 	unsigned int max_shutter;
163 	unsigned int pclk_reg;
164 };
165 
166 struct mt9v032_model_info {
167 	const struct mt9v032_model_data *data;
168 	bool color;
169 };
170 
171 static const struct mt9v032_model_version mt9v032_versions[] = {
172 	{ MT9V032_CHIP_ID_REV1, "MT9V022/MT9V032 rev1/2" },
173 	{ MT9V032_CHIP_ID_REV3, "MT9V022/MT9V032 rev3" },
174 	{ MT9V034_CHIP_ID_REV1, "MT9V024/MT9V034 rev1" },
175 };
176 
177 static const struct mt9v032_model_data mt9v032_model_data[] = {
178 	{
179 		/* MT9V022, MT9V032 revisions 1/2/3 */
180 		.min_row_time = 660,
181 		.min_hblank = MT9V032_HORIZONTAL_BLANKING_MIN,
182 		.min_vblank = MT9V032_VERTICAL_BLANKING_MIN,
183 		.max_vblank = MT9V032_VERTICAL_BLANKING_MAX,
184 		.min_shutter = MT9V032_TOTAL_SHUTTER_WIDTH_MIN,
185 		.max_shutter = MT9V032_TOTAL_SHUTTER_WIDTH_MAX,
186 		.pclk_reg = MT9V032_PIXEL_CLOCK,
187 	}, {
188 		/* MT9V024, MT9V034 */
189 		.min_row_time = 690,
190 		.min_hblank = MT9V034_HORIZONTAL_BLANKING_MIN,
191 		.min_vblank = MT9V034_VERTICAL_BLANKING_MIN,
192 		.max_vblank = MT9V034_VERTICAL_BLANKING_MAX,
193 		.min_shutter = MT9V034_TOTAL_SHUTTER_WIDTH_MIN,
194 		.max_shutter = MT9V034_TOTAL_SHUTTER_WIDTH_MAX,
195 		.pclk_reg = MT9V034_PIXEL_CLOCK,
196 	},
197 };
198 
199 static const struct mt9v032_model_info mt9v032_models[] = {
200 	[MT9V032_MODEL_V022_COLOR] = {
201 		.data = &mt9v032_model_data[0],
202 		.color = true,
203 	},
204 	[MT9V032_MODEL_V022_MONO] = {
205 		.data = &mt9v032_model_data[0],
206 		.color = false,
207 	},
208 	[MT9V032_MODEL_V024_COLOR] = {
209 		.data = &mt9v032_model_data[1],
210 		.color = true,
211 	},
212 	[MT9V032_MODEL_V024_MONO] = {
213 		.data = &mt9v032_model_data[1],
214 		.color = false,
215 	},
216 	[MT9V032_MODEL_V032_COLOR] = {
217 		.data = &mt9v032_model_data[0],
218 		.color = true,
219 	},
220 	[MT9V032_MODEL_V032_MONO] = {
221 		.data = &mt9v032_model_data[0],
222 		.color = false,
223 	},
224 	[MT9V032_MODEL_V034_COLOR] = {
225 		.data = &mt9v032_model_data[1],
226 		.color = true,
227 	},
228 	[MT9V032_MODEL_V034_MONO] = {
229 		.data = &mt9v032_model_data[1],
230 		.color = false,
231 	},
232 };
233 
234 struct mt9v032 {
235 	struct v4l2_subdev subdev;
236 	struct media_pad pad;
237 
238 	struct v4l2_mbus_framefmt format;
239 	struct v4l2_rect crop;
240 	unsigned int hratio;
241 	unsigned int vratio;
242 
243 	struct v4l2_ctrl_handler ctrls;
244 	struct {
245 		struct v4l2_ctrl *link_freq;
246 		struct v4l2_ctrl *pixel_rate;
247 	};
248 
249 	struct mutex power_lock;
250 	int power_count;
251 
252 	struct regmap *regmap;
253 	struct clk *clk;
254 
255 	struct mt9v032_platform_data *pdata;
256 	const struct mt9v032_model_info *model;
257 	const struct mt9v032_model_version *version;
258 
259 	u32 sysclk;
260 	u16 aec_agc;
261 	u16 hblank;
262 	struct {
263 		struct v4l2_ctrl *test_pattern;
264 		struct v4l2_ctrl *test_pattern_color;
265 	};
266 };
267 
268 static struct mt9v032 *to_mt9v032(struct v4l2_subdev *sd)
269 {
270 	return container_of(sd, struct mt9v032, subdev);
271 }
272 
273 static int
274 mt9v032_update_aec_agc(struct mt9v032 *mt9v032, u16 which, int enable)
275 {
276 	struct regmap *map = mt9v032->regmap;
277 	u16 value = mt9v032->aec_agc;
278 	int ret;
279 
280 	if (enable)
281 		value |= which;
282 	else
283 		value &= ~which;
284 
285 	ret = regmap_write(map, MT9V032_AEC_AGC_ENABLE, value);
286 	if (ret < 0)
287 		return ret;
288 
289 	mt9v032->aec_agc = value;
290 	return 0;
291 }
292 
293 static int
294 mt9v032_update_hblank(struct mt9v032 *mt9v032)
295 {
296 	struct v4l2_rect *crop = &mt9v032->crop;
297 	unsigned int min_hblank = mt9v032->model->data->min_hblank;
298 	unsigned int hblank;
299 
300 	if (mt9v032->version->version == MT9V034_CHIP_ID_REV1)
301 		min_hblank += (mt9v032->hratio - 1) * 10;
302 	min_hblank = max_t(int, mt9v032->model->data->min_row_time - crop->width,
303 			   min_hblank);
304 	hblank = max_t(unsigned int, mt9v032->hblank, min_hblank);
305 
306 	return regmap_write(mt9v032->regmap, MT9V032_HORIZONTAL_BLANKING,
307 			    hblank);
308 }
309 
310 static int mt9v032_power_on(struct mt9v032 *mt9v032)
311 {
312 	struct regmap *map = mt9v032->regmap;
313 	int ret;
314 
315 	ret = clk_set_rate(mt9v032->clk, mt9v032->sysclk);
316 	if (ret < 0)
317 		return ret;
318 
319 	ret = clk_prepare_enable(mt9v032->clk);
320 	if (ret)
321 		return ret;
322 
323 	udelay(1);
324 
325 	/* Reset the chip and stop data read out */
326 	ret = regmap_write(map, MT9V032_RESET, 1);
327 	if (ret < 0)
328 		return ret;
329 
330 	ret = regmap_write(map, MT9V032_RESET, 0);
331 	if (ret < 0)
332 		return ret;
333 
334 	return regmap_write(map, MT9V032_CHIP_CONTROL, 0);
335 }
336 
337 static void mt9v032_power_off(struct mt9v032 *mt9v032)
338 {
339 	clk_disable_unprepare(mt9v032->clk);
340 }
341 
342 static int __mt9v032_set_power(struct mt9v032 *mt9v032, bool on)
343 {
344 	struct regmap *map = mt9v032->regmap;
345 	int ret;
346 
347 	if (!on) {
348 		mt9v032_power_off(mt9v032);
349 		return 0;
350 	}
351 
352 	ret = mt9v032_power_on(mt9v032);
353 	if (ret < 0)
354 		return ret;
355 
356 	/* Configure the pixel clock polarity */
357 	if (mt9v032->pdata && mt9v032->pdata->clk_pol) {
358 		ret = regmap_write(map, mt9v032->model->data->pclk_reg,
359 				MT9V032_PIXEL_CLOCK_INV_PXL_CLK);
360 		if (ret < 0)
361 			return ret;
362 	}
363 
364 	/* Disable the noise correction algorithm and restore the controls. */
365 	ret = regmap_write(map, MT9V032_ROW_NOISE_CORR_CONTROL, 0);
366 	if (ret < 0)
367 		return ret;
368 
369 	return v4l2_ctrl_handler_setup(&mt9v032->ctrls);
370 }
371 
372 /* -----------------------------------------------------------------------------
373  * V4L2 subdev video operations
374  */
375 
376 static struct v4l2_mbus_framefmt *
377 __mt9v032_get_pad_format(struct mt9v032 *mt9v032, struct v4l2_subdev_pad_config *cfg,
378 			 unsigned int pad, enum v4l2_subdev_format_whence which)
379 {
380 	switch (which) {
381 	case V4L2_SUBDEV_FORMAT_TRY:
382 		return v4l2_subdev_get_try_format(&mt9v032->subdev, cfg, pad);
383 	case V4L2_SUBDEV_FORMAT_ACTIVE:
384 		return &mt9v032->format;
385 	default:
386 		return NULL;
387 	}
388 }
389 
390 static struct v4l2_rect *
391 __mt9v032_get_pad_crop(struct mt9v032 *mt9v032, struct v4l2_subdev_pad_config *cfg,
392 		       unsigned int pad, enum v4l2_subdev_format_whence which)
393 {
394 	switch (which) {
395 	case V4L2_SUBDEV_FORMAT_TRY:
396 		return v4l2_subdev_get_try_crop(&mt9v032->subdev, cfg, pad);
397 	case V4L2_SUBDEV_FORMAT_ACTIVE:
398 		return &mt9v032->crop;
399 	default:
400 		return NULL;
401 	}
402 }
403 
404 static int mt9v032_s_stream(struct v4l2_subdev *subdev, int enable)
405 {
406 	const u16 mode = MT9V032_CHIP_CONTROL_MASTER_MODE
407 		       | MT9V032_CHIP_CONTROL_DOUT_ENABLE
408 		       | MT9V032_CHIP_CONTROL_SEQUENTIAL;
409 	struct mt9v032 *mt9v032 = to_mt9v032(subdev);
410 	struct v4l2_rect *crop = &mt9v032->crop;
411 	struct regmap *map = mt9v032->regmap;
412 	unsigned int hbin;
413 	unsigned int vbin;
414 	int ret;
415 
416 	if (!enable)
417 		return regmap_update_bits(map, MT9V032_CHIP_CONTROL, mode, 0);
418 
419 	/* Configure the window size and row/column bin */
420 	hbin = fls(mt9v032->hratio) - 1;
421 	vbin = fls(mt9v032->vratio) - 1;
422 	ret = regmap_update_bits(map, MT9V032_READ_MODE,
423 				 ~MT9V032_READ_MODE_RESERVED,
424 				 hbin << MT9V032_READ_MODE_COLUMN_BIN_SHIFT |
425 				 vbin << MT9V032_READ_MODE_ROW_BIN_SHIFT);
426 	if (ret < 0)
427 		return ret;
428 
429 	ret = regmap_write(map, MT9V032_COLUMN_START, crop->left);
430 	if (ret < 0)
431 		return ret;
432 
433 	ret = regmap_write(map, MT9V032_ROW_START, crop->top);
434 	if (ret < 0)
435 		return ret;
436 
437 	ret = regmap_write(map, MT9V032_WINDOW_WIDTH, crop->width);
438 	if (ret < 0)
439 		return ret;
440 
441 	ret = regmap_write(map, MT9V032_WINDOW_HEIGHT, crop->height);
442 	if (ret < 0)
443 		return ret;
444 
445 	ret = mt9v032_update_hblank(mt9v032);
446 	if (ret < 0)
447 		return ret;
448 
449 	/* Switch to master "normal" mode */
450 	return regmap_update_bits(map, MT9V032_CHIP_CONTROL, mode, mode);
451 }
452 
453 static int mt9v032_enum_mbus_code(struct v4l2_subdev *subdev,
454 				  struct v4l2_subdev_pad_config *cfg,
455 				  struct v4l2_subdev_mbus_code_enum *code)
456 {
457 	if (code->index > 0)
458 		return -EINVAL;
459 
460 	code->code = MEDIA_BUS_FMT_SGRBG10_1X10;
461 	return 0;
462 }
463 
464 static int mt9v032_enum_frame_size(struct v4l2_subdev *subdev,
465 				   struct v4l2_subdev_pad_config *cfg,
466 				   struct v4l2_subdev_frame_size_enum *fse)
467 {
468 	if (fse->index >= 3 || fse->code != MEDIA_BUS_FMT_SGRBG10_1X10)
469 		return -EINVAL;
470 
471 	fse->min_width = MT9V032_WINDOW_WIDTH_DEF / (1 << fse->index);
472 	fse->max_width = fse->min_width;
473 	fse->min_height = MT9V032_WINDOW_HEIGHT_DEF / (1 << fse->index);
474 	fse->max_height = fse->min_height;
475 
476 	return 0;
477 }
478 
479 static int mt9v032_get_format(struct v4l2_subdev *subdev,
480 			      struct v4l2_subdev_pad_config *cfg,
481 			      struct v4l2_subdev_format *format)
482 {
483 	struct mt9v032 *mt9v032 = to_mt9v032(subdev);
484 
485 	format->format = *__mt9v032_get_pad_format(mt9v032, cfg, format->pad,
486 						   format->which);
487 	return 0;
488 }
489 
490 static void mt9v032_configure_pixel_rate(struct mt9v032 *mt9v032)
491 {
492 	struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
493 	int ret;
494 
495 	ret = v4l2_ctrl_s_ctrl_int64(mt9v032->pixel_rate,
496 				     mt9v032->sysclk / mt9v032->hratio);
497 	if (ret < 0)
498 		dev_warn(&client->dev, "failed to set pixel rate (%d)\n", ret);
499 }
500 
501 static unsigned int mt9v032_calc_ratio(unsigned int input, unsigned int output)
502 {
503 	/* Compute the power-of-two binning factor closest to the input size to
504 	 * output size ratio. Given that the output size is bounded by input/4
505 	 * and input, a generic implementation would be an ineffective luxury.
506 	 */
507 	if (output * 3 > input * 2)
508 		return 1;
509 	if (output * 3 > input)
510 		return 2;
511 	return 4;
512 }
513 
514 static int mt9v032_set_format(struct v4l2_subdev *subdev,
515 			      struct v4l2_subdev_pad_config *cfg,
516 			      struct v4l2_subdev_format *format)
517 {
518 	struct mt9v032 *mt9v032 = to_mt9v032(subdev);
519 	struct v4l2_mbus_framefmt *__format;
520 	struct v4l2_rect *__crop;
521 	unsigned int width;
522 	unsigned int height;
523 	unsigned int hratio;
524 	unsigned int vratio;
525 
526 	__crop = __mt9v032_get_pad_crop(mt9v032, cfg, format->pad,
527 					format->which);
528 
529 	/* Clamp the width and height to avoid dividing by zero. */
530 	width = clamp(ALIGN(format->format.width, 2),
531 		      max_t(unsigned int, __crop->width / 4,
532 			    MT9V032_WINDOW_WIDTH_MIN),
533 		      __crop->width);
534 	height = clamp(ALIGN(format->format.height, 2),
535 		       max_t(unsigned int, __crop->height / 4,
536 			     MT9V032_WINDOW_HEIGHT_MIN),
537 		       __crop->height);
538 
539 	hratio = mt9v032_calc_ratio(__crop->width, width);
540 	vratio = mt9v032_calc_ratio(__crop->height, height);
541 
542 	__format = __mt9v032_get_pad_format(mt9v032, cfg, format->pad,
543 					    format->which);
544 	__format->width = __crop->width / hratio;
545 	__format->height = __crop->height / vratio;
546 
547 	if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
548 		mt9v032->hratio = hratio;
549 		mt9v032->vratio = vratio;
550 		mt9v032_configure_pixel_rate(mt9v032);
551 	}
552 
553 	format->format = *__format;
554 
555 	return 0;
556 }
557 
558 static int mt9v032_get_selection(struct v4l2_subdev *subdev,
559 				 struct v4l2_subdev_pad_config *cfg,
560 				 struct v4l2_subdev_selection *sel)
561 {
562 	struct mt9v032 *mt9v032 = to_mt9v032(subdev);
563 
564 	if (sel->target != V4L2_SEL_TGT_CROP)
565 		return -EINVAL;
566 
567 	sel->r = *__mt9v032_get_pad_crop(mt9v032, cfg, sel->pad, sel->which);
568 	return 0;
569 }
570 
571 static int mt9v032_set_selection(struct v4l2_subdev *subdev,
572 				 struct v4l2_subdev_pad_config *cfg,
573 				 struct v4l2_subdev_selection *sel)
574 {
575 	struct mt9v032 *mt9v032 = to_mt9v032(subdev);
576 	struct v4l2_mbus_framefmt *__format;
577 	struct v4l2_rect *__crop;
578 	struct v4l2_rect rect;
579 
580 	if (sel->target != V4L2_SEL_TGT_CROP)
581 		return -EINVAL;
582 
583 	/* Clamp the crop rectangle boundaries and align them to a non multiple
584 	 * of 2 pixels to ensure a GRBG Bayer pattern.
585 	 */
586 	rect.left = clamp(ALIGN(sel->r.left + 1, 2) - 1,
587 			  MT9V032_COLUMN_START_MIN,
588 			  MT9V032_COLUMN_START_MAX);
589 	rect.top = clamp(ALIGN(sel->r.top + 1, 2) - 1,
590 			 MT9V032_ROW_START_MIN,
591 			 MT9V032_ROW_START_MAX);
592 	rect.width = clamp_t(unsigned int, ALIGN(sel->r.width, 2),
593 			     MT9V032_WINDOW_WIDTH_MIN,
594 			     MT9V032_WINDOW_WIDTH_MAX);
595 	rect.height = clamp_t(unsigned int, ALIGN(sel->r.height, 2),
596 			      MT9V032_WINDOW_HEIGHT_MIN,
597 			      MT9V032_WINDOW_HEIGHT_MAX);
598 
599 	rect.width = min_t(unsigned int,
600 			   rect.width, MT9V032_PIXEL_ARRAY_WIDTH - rect.left);
601 	rect.height = min_t(unsigned int,
602 			    rect.height, MT9V032_PIXEL_ARRAY_HEIGHT - rect.top);
603 
604 	__crop = __mt9v032_get_pad_crop(mt9v032, cfg, sel->pad, sel->which);
605 
606 	if (rect.width != __crop->width || rect.height != __crop->height) {
607 		/* Reset the output image size if the crop rectangle size has
608 		 * been modified.
609 		 */
610 		__format = __mt9v032_get_pad_format(mt9v032, cfg, sel->pad,
611 						    sel->which);
612 		__format->width = rect.width;
613 		__format->height = rect.height;
614 		if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
615 			mt9v032->hratio = 1;
616 			mt9v032->vratio = 1;
617 			mt9v032_configure_pixel_rate(mt9v032);
618 		}
619 	}
620 
621 	*__crop = rect;
622 	sel->r = rect;
623 
624 	return 0;
625 }
626 
627 /* -----------------------------------------------------------------------------
628  * V4L2 subdev control operations
629  */
630 
631 #define V4L2_CID_TEST_PATTERN_COLOR	(V4L2_CID_USER_BASE | 0x1001)
632 
633 static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl)
634 {
635 	struct mt9v032 *mt9v032 =
636 			container_of(ctrl->handler, struct mt9v032, ctrls);
637 	struct regmap *map = mt9v032->regmap;
638 	u32 freq;
639 	u16 data;
640 
641 	switch (ctrl->id) {
642 	case V4L2_CID_AUTOGAIN:
643 		return mt9v032_update_aec_agc(mt9v032, MT9V032_AGC_ENABLE,
644 					      ctrl->val);
645 
646 	case V4L2_CID_GAIN:
647 		return regmap_write(map, MT9V032_ANALOG_GAIN, ctrl->val);
648 
649 	case V4L2_CID_EXPOSURE_AUTO:
650 		return mt9v032_update_aec_agc(mt9v032, MT9V032_AEC_ENABLE,
651 					      !ctrl->val);
652 
653 	case V4L2_CID_EXPOSURE:
654 		return regmap_write(map, MT9V032_TOTAL_SHUTTER_WIDTH,
655 				    ctrl->val);
656 
657 	case V4L2_CID_HBLANK:
658 		mt9v032->hblank = ctrl->val;
659 		return mt9v032_update_hblank(mt9v032);
660 
661 	case V4L2_CID_VBLANK:
662 		return regmap_write(map, MT9V032_VERTICAL_BLANKING,
663 				    ctrl->val);
664 
665 	case V4L2_CID_PIXEL_RATE:
666 	case V4L2_CID_LINK_FREQ:
667 		if (mt9v032->link_freq == NULL)
668 			break;
669 
670 		freq = mt9v032->pdata->link_freqs[mt9v032->link_freq->val];
671 		*mt9v032->pixel_rate->p_new.p_s64 = freq;
672 		mt9v032->sysclk = freq;
673 		break;
674 
675 	case V4L2_CID_TEST_PATTERN:
676 		switch (mt9v032->test_pattern->val) {
677 		case 0:
678 			data = 0;
679 			break;
680 		case 1:
681 			data = MT9V032_TEST_PATTERN_GRAY_VERTICAL
682 			     | MT9V032_TEST_PATTERN_ENABLE;
683 			break;
684 		case 2:
685 			data = MT9V032_TEST_PATTERN_GRAY_HORIZONTAL
686 			     | MT9V032_TEST_PATTERN_ENABLE;
687 			break;
688 		case 3:
689 			data = MT9V032_TEST_PATTERN_GRAY_DIAGONAL
690 			     | MT9V032_TEST_PATTERN_ENABLE;
691 			break;
692 		default:
693 			data = (mt9v032->test_pattern_color->val <<
694 				MT9V032_TEST_PATTERN_DATA_SHIFT)
695 			     | MT9V032_TEST_PATTERN_USE_DATA
696 			     | MT9V032_TEST_PATTERN_ENABLE
697 			     | MT9V032_TEST_PATTERN_FLIP;
698 			break;
699 		}
700 		return regmap_write(map, MT9V032_TEST_PATTERN, data);
701 	}
702 
703 	return 0;
704 }
705 
706 static struct v4l2_ctrl_ops mt9v032_ctrl_ops = {
707 	.s_ctrl = mt9v032_s_ctrl,
708 };
709 
710 static const char * const mt9v032_test_pattern_menu[] = {
711 	"Disabled",
712 	"Gray Vertical Shade",
713 	"Gray Horizontal Shade",
714 	"Gray Diagonal Shade",
715 	"Plain",
716 };
717 
718 static const struct v4l2_ctrl_config mt9v032_test_pattern_color = {
719 	.ops		= &mt9v032_ctrl_ops,
720 	.id		= V4L2_CID_TEST_PATTERN_COLOR,
721 	.type		= V4L2_CTRL_TYPE_INTEGER,
722 	.name		= "Test Pattern Color",
723 	.min		= 0,
724 	.max		= 1023,
725 	.step		= 1,
726 	.def		= 0,
727 	.flags		= 0,
728 };
729 
730 /* -----------------------------------------------------------------------------
731  * V4L2 subdev core operations
732  */
733 
734 static int mt9v032_set_power(struct v4l2_subdev *subdev, int on)
735 {
736 	struct mt9v032 *mt9v032 = to_mt9v032(subdev);
737 	int ret = 0;
738 
739 	mutex_lock(&mt9v032->power_lock);
740 
741 	/* If the power count is modified from 0 to != 0 or from != 0 to 0,
742 	 * update the power state.
743 	 */
744 	if (mt9v032->power_count == !on) {
745 		ret = __mt9v032_set_power(mt9v032, !!on);
746 		if (ret < 0)
747 			goto done;
748 	}
749 
750 	/* Update the power count. */
751 	mt9v032->power_count += on ? 1 : -1;
752 	WARN_ON(mt9v032->power_count < 0);
753 
754 done:
755 	mutex_unlock(&mt9v032->power_lock);
756 	return ret;
757 }
758 
759 /* -----------------------------------------------------------------------------
760  * V4L2 subdev internal operations
761  */
762 
763 static int mt9v032_registered(struct v4l2_subdev *subdev)
764 {
765 	struct i2c_client *client = v4l2_get_subdevdata(subdev);
766 	struct mt9v032 *mt9v032 = to_mt9v032(subdev);
767 	unsigned int i;
768 	u32 version;
769 	int ret;
770 
771 	dev_info(&client->dev, "Probing MT9V032 at address 0x%02x\n",
772 			client->addr);
773 
774 	ret = mt9v032_power_on(mt9v032);
775 	if (ret < 0) {
776 		dev_err(&client->dev, "MT9V032 power up failed\n");
777 		return ret;
778 	}
779 
780 	/* Read and check the sensor version */
781 	ret = regmap_read(mt9v032->regmap, MT9V032_CHIP_VERSION, &version);
782 	if (ret < 0) {
783 		dev_err(&client->dev, "Failed reading chip version\n");
784 		return ret;
785 	}
786 
787 	for (i = 0; i < ARRAY_SIZE(mt9v032_versions); ++i) {
788 		if (mt9v032_versions[i].version == version) {
789 			mt9v032->version = &mt9v032_versions[i];
790 			break;
791 		}
792 	}
793 
794 	if (mt9v032->version == NULL) {
795 		dev_err(&client->dev, "Unsupported chip version 0x%04x\n",
796 			version);
797 		return -ENODEV;
798 	}
799 
800 	mt9v032_power_off(mt9v032);
801 
802 	dev_info(&client->dev, "%s detected at address 0x%02x\n",
803 		 mt9v032->version->name, client->addr);
804 
805 	mt9v032_configure_pixel_rate(mt9v032);
806 
807 	return ret;
808 }
809 
810 static int mt9v032_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
811 {
812 	struct mt9v032 *mt9v032 = to_mt9v032(subdev);
813 	struct v4l2_mbus_framefmt *format;
814 	struct v4l2_rect *crop;
815 
816 	crop = v4l2_subdev_get_try_crop(subdev, fh->pad, 0);
817 	crop->left = MT9V032_COLUMN_START_DEF;
818 	crop->top = MT9V032_ROW_START_DEF;
819 	crop->width = MT9V032_WINDOW_WIDTH_DEF;
820 	crop->height = MT9V032_WINDOW_HEIGHT_DEF;
821 
822 	format = v4l2_subdev_get_try_format(subdev, fh->pad, 0);
823 
824 	if (mt9v032->model->color)
825 		format->code = MEDIA_BUS_FMT_SGRBG10_1X10;
826 	else
827 		format->code = MEDIA_BUS_FMT_Y10_1X10;
828 
829 	format->width = MT9V032_WINDOW_WIDTH_DEF;
830 	format->height = MT9V032_WINDOW_HEIGHT_DEF;
831 	format->field = V4L2_FIELD_NONE;
832 	format->colorspace = V4L2_COLORSPACE_SRGB;
833 
834 	return mt9v032_set_power(subdev, 1);
835 }
836 
837 static int mt9v032_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
838 {
839 	return mt9v032_set_power(subdev, 0);
840 }
841 
842 static struct v4l2_subdev_core_ops mt9v032_subdev_core_ops = {
843 	.s_power	= mt9v032_set_power,
844 };
845 
846 static struct v4l2_subdev_video_ops mt9v032_subdev_video_ops = {
847 	.s_stream	= mt9v032_s_stream,
848 };
849 
850 static struct v4l2_subdev_pad_ops mt9v032_subdev_pad_ops = {
851 	.enum_mbus_code = mt9v032_enum_mbus_code,
852 	.enum_frame_size = mt9v032_enum_frame_size,
853 	.get_fmt = mt9v032_get_format,
854 	.set_fmt = mt9v032_set_format,
855 	.get_selection = mt9v032_get_selection,
856 	.set_selection = mt9v032_set_selection,
857 };
858 
859 static struct v4l2_subdev_ops mt9v032_subdev_ops = {
860 	.core	= &mt9v032_subdev_core_ops,
861 	.video	= &mt9v032_subdev_video_ops,
862 	.pad	= &mt9v032_subdev_pad_ops,
863 };
864 
865 static const struct v4l2_subdev_internal_ops mt9v032_subdev_internal_ops = {
866 	.registered = mt9v032_registered,
867 	.open = mt9v032_open,
868 	.close = mt9v032_close,
869 };
870 
871 static const struct regmap_config mt9v032_regmap_config = {
872 	.reg_bits = 8,
873 	.val_bits = 16,
874 	.max_register = 0xff,
875 	.cache_type = REGCACHE_RBTREE,
876 };
877 
878 /* -----------------------------------------------------------------------------
879  * Driver initialization and probing
880  */
881 
882 static struct mt9v032_platform_data *
883 mt9v032_get_pdata(struct i2c_client *client)
884 {
885 	struct mt9v032_platform_data *pdata = NULL;
886 	struct v4l2_of_endpoint endpoint;
887 	struct device_node *np;
888 	struct property *prop;
889 
890 	if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
891 		return client->dev.platform_data;
892 
893 	np = of_graph_get_next_endpoint(client->dev.of_node, NULL);
894 	if (!np)
895 		return NULL;
896 
897 	if (v4l2_of_parse_endpoint(np, &endpoint) < 0)
898 		goto done;
899 
900 	pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
901 	if (!pdata)
902 		goto done;
903 
904 	prop = of_find_property(np, "link-frequencies", NULL);
905 	if (prop) {
906 		u64 *link_freqs;
907 		size_t size = prop->length / sizeof(*link_freqs);
908 
909 		link_freqs = devm_kcalloc(&client->dev, size,
910 					  sizeof(*link_freqs), GFP_KERNEL);
911 		if (!link_freqs)
912 			goto done;
913 
914 		if (of_property_read_u64_array(np, "link-frequencies",
915 					       link_freqs, size) < 0)
916 			goto done;
917 
918 		pdata->link_freqs = link_freqs;
919 		pdata->link_def_freq = link_freqs[0];
920 	}
921 
922 	pdata->clk_pol = !!(endpoint.bus.parallel.flags &
923 			    V4L2_MBUS_PCLK_SAMPLE_RISING);
924 
925 done:
926 	of_node_put(np);
927 	return pdata;
928 }
929 
930 static int mt9v032_probe(struct i2c_client *client,
931 		const struct i2c_device_id *did)
932 {
933 	struct mt9v032_platform_data *pdata = mt9v032_get_pdata(client);
934 	struct mt9v032 *mt9v032;
935 	unsigned int i;
936 	int ret;
937 
938 	if (!i2c_check_functionality(client->adapter,
939 				     I2C_FUNC_SMBUS_WORD_DATA)) {
940 		dev_warn(&client->adapter->dev,
941 			 "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
942 		return -EIO;
943 	}
944 
945 	mt9v032 = devm_kzalloc(&client->dev, sizeof(*mt9v032), GFP_KERNEL);
946 	if (!mt9v032)
947 		return -ENOMEM;
948 
949 	mt9v032->regmap = devm_regmap_init_i2c(client, &mt9v032_regmap_config);
950 	if (IS_ERR(mt9v032->regmap))
951 		return PTR_ERR(mt9v032->regmap);
952 
953 	mt9v032->clk = devm_clk_get(&client->dev, NULL);
954 	if (IS_ERR(mt9v032->clk))
955 		return PTR_ERR(mt9v032->clk);
956 
957 	mutex_init(&mt9v032->power_lock);
958 	mt9v032->pdata = pdata;
959 	mt9v032->model = (const void *)did->driver_data;
960 
961 	v4l2_ctrl_handler_init(&mt9v032->ctrls, 10);
962 
963 	v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
964 			  V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
965 	v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
966 			  V4L2_CID_GAIN, MT9V032_ANALOG_GAIN_MIN,
967 			  MT9V032_ANALOG_GAIN_MAX, 1, MT9V032_ANALOG_GAIN_DEF);
968 	v4l2_ctrl_new_std_menu(&mt9v032->ctrls, &mt9v032_ctrl_ops,
969 			       V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL, 0,
970 			       V4L2_EXPOSURE_AUTO);
971 	v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
972 			  V4L2_CID_EXPOSURE, mt9v032->model->data->min_shutter,
973 			  mt9v032->model->data->max_shutter, 1,
974 			  MT9V032_TOTAL_SHUTTER_WIDTH_DEF);
975 	v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
976 			  V4L2_CID_HBLANK, mt9v032->model->data->min_hblank,
977 			  MT9V032_HORIZONTAL_BLANKING_MAX, 1,
978 			  MT9V032_HORIZONTAL_BLANKING_DEF);
979 	v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
980 			  V4L2_CID_VBLANK, mt9v032->model->data->min_vblank,
981 			  mt9v032->model->data->max_vblank, 1,
982 			  MT9V032_VERTICAL_BLANKING_DEF);
983 	mt9v032->test_pattern = v4l2_ctrl_new_std_menu_items(&mt9v032->ctrls,
984 				&mt9v032_ctrl_ops, V4L2_CID_TEST_PATTERN,
985 				ARRAY_SIZE(mt9v032_test_pattern_menu) - 1, 0, 0,
986 				mt9v032_test_pattern_menu);
987 	mt9v032->test_pattern_color = v4l2_ctrl_new_custom(&mt9v032->ctrls,
988 				      &mt9v032_test_pattern_color, NULL);
989 
990 	v4l2_ctrl_cluster(2, &mt9v032->test_pattern);
991 
992 	mt9v032->pixel_rate =
993 		v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
994 				  V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, 1);
995 
996 	if (pdata && pdata->link_freqs) {
997 		unsigned int def = 0;
998 
999 		for (i = 0; pdata->link_freqs[i]; ++i) {
1000 			if (pdata->link_freqs[i] == pdata->link_def_freq)
1001 				def = i;
1002 		}
1003 
1004 		mt9v032->link_freq =
1005 			v4l2_ctrl_new_int_menu(&mt9v032->ctrls,
1006 					       &mt9v032_ctrl_ops,
1007 					       V4L2_CID_LINK_FREQ, i - 1, def,
1008 					       pdata->link_freqs);
1009 		v4l2_ctrl_cluster(2, &mt9v032->link_freq);
1010 	}
1011 
1012 
1013 	mt9v032->subdev.ctrl_handler = &mt9v032->ctrls;
1014 
1015 	if (mt9v032->ctrls.error) {
1016 		dev_err(&client->dev, "control initialization error %d\n",
1017 			mt9v032->ctrls.error);
1018 		ret = mt9v032->ctrls.error;
1019 		goto err;
1020 	}
1021 
1022 	mt9v032->crop.left = MT9V032_COLUMN_START_DEF;
1023 	mt9v032->crop.top = MT9V032_ROW_START_DEF;
1024 	mt9v032->crop.width = MT9V032_WINDOW_WIDTH_DEF;
1025 	mt9v032->crop.height = MT9V032_WINDOW_HEIGHT_DEF;
1026 
1027 	if (mt9v032->model->color)
1028 		mt9v032->format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
1029 	else
1030 		mt9v032->format.code = MEDIA_BUS_FMT_Y10_1X10;
1031 
1032 	mt9v032->format.width = MT9V032_WINDOW_WIDTH_DEF;
1033 	mt9v032->format.height = MT9V032_WINDOW_HEIGHT_DEF;
1034 	mt9v032->format.field = V4L2_FIELD_NONE;
1035 	mt9v032->format.colorspace = V4L2_COLORSPACE_SRGB;
1036 
1037 	mt9v032->hratio = 1;
1038 	mt9v032->vratio = 1;
1039 
1040 	mt9v032->aec_agc = MT9V032_AEC_ENABLE | MT9V032_AGC_ENABLE;
1041 	mt9v032->hblank = MT9V032_HORIZONTAL_BLANKING_DEF;
1042 	mt9v032->sysclk = MT9V032_SYSCLK_FREQ_DEF;
1043 
1044 	v4l2_i2c_subdev_init(&mt9v032->subdev, client, &mt9v032_subdev_ops);
1045 	mt9v032->subdev.internal_ops = &mt9v032_subdev_internal_ops;
1046 	mt9v032->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1047 
1048 	mt9v032->pad.flags = MEDIA_PAD_FL_SOURCE;
1049 	ret = media_entity_init(&mt9v032->subdev.entity, 1, &mt9v032->pad, 0);
1050 	if (ret < 0)
1051 		goto err;
1052 
1053 	mt9v032->subdev.dev = &client->dev;
1054 	ret = v4l2_async_register_subdev(&mt9v032->subdev);
1055 	if (ret < 0)
1056 		goto err;
1057 
1058 	return 0;
1059 
1060 err:
1061 	media_entity_cleanup(&mt9v032->subdev.entity);
1062 	v4l2_ctrl_handler_free(&mt9v032->ctrls);
1063 	return ret;
1064 }
1065 
1066 static int mt9v032_remove(struct i2c_client *client)
1067 {
1068 	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
1069 	struct mt9v032 *mt9v032 = to_mt9v032(subdev);
1070 
1071 	v4l2_async_unregister_subdev(subdev);
1072 	v4l2_ctrl_handler_free(&mt9v032->ctrls);
1073 	media_entity_cleanup(&subdev->entity);
1074 
1075 	return 0;
1076 }
1077 
1078 static const struct i2c_device_id mt9v032_id[] = {
1079 	{ "mt9v022", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V022_COLOR] },
1080 	{ "mt9v022m", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V022_MONO] },
1081 	{ "mt9v024", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V024_COLOR] },
1082 	{ "mt9v024m", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V024_MONO] },
1083 	{ "mt9v032", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V032_COLOR] },
1084 	{ "mt9v032m", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V032_MONO] },
1085 	{ "mt9v034", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V034_COLOR] },
1086 	{ "mt9v034m", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V034_MONO] },
1087 	{ }
1088 };
1089 MODULE_DEVICE_TABLE(i2c, mt9v032_id);
1090 
1091 #if IS_ENABLED(CONFIG_OF)
1092 static const struct of_device_id mt9v032_of_match[] = {
1093 	{ .compatible = "aptina,mt9v022" },
1094 	{ .compatible = "aptina,mt9v022m" },
1095 	{ .compatible = "aptina,mt9v024" },
1096 	{ .compatible = "aptina,mt9v024m" },
1097 	{ .compatible = "aptina,mt9v032" },
1098 	{ .compatible = "aptina,mt9v032m" },
1099 	{ .compatible = "aptina,mt9v034" },
1100 	{ .compatible = "aptina,mt9v034m" },
1101 	{ /* Sentinel */ }
1102 };
1103 MODULE_DEVICE_TABLE(of, mt9v032_of_match);
1104 #endif
1105 
1106 static struct i2c_driver mt9v032_driver = {
1107 	.driver = {
1108 		.name = "mt9v032",
1109 		.of_match_table = of_match_ptr(mt9v032_of_match),
1110 	},
1111 	.probe		= mt9v032_probe,
1112 	.remove		= mt9v032_remove,
1113 	.id_table	= mt9v032_id,
1114 };
1115 
1116 module_i2c_driver(mt9v032_driver);
1117 
1118 MODULE_DESCRIPTION("Aptina MT9V032 Camera driver");
1119 MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
1120 MODULE_LICENSE("GPL");
1121