diff options
Diffstat (limited to 'drivers/media/i2c/mt9v032.c')
-rw-r--r-- | drivers/media/i2c/mt9v032.c | 264 |
1 files changed, 205 insertions, 59 deletions
diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c index 2c50effaa334..36c504b78f2c 100644 --- a/drivers/media/i2c/mt9v032.c +++ b/drivers/media/i2c/mt9v032.c | |||
@@ -27,14 +27,16 @@ | |||
27 | #include <media/v4l2-device.h> | 27 | #include <media/v4l2-device.h> |
28 | #include <media/v4l2-subdev.h> | 28 | #include <media/v4l2-subdev.h> |
29 | 29 | ||
30 | #define MT9V032_PIXEL_ARRAY_HEIGHT 492 | 30 | /* The first four rows are black rows. The active area spans 753x481 pixels. */ |
31 | #define MT9V032_PIXEL_ARRAY_WIDTH 782 | 31 | #define MT9V032_PIXEL_ARRAY_HEIGHT 485 |
32 | #define MT9V032_PIXEL_ARRAY_WIDTH 753 | ||
32 | 33 | ||
33 | #define MT9V032_SYSCLK_FREQ_DEF 26600000 | 34 | #define MT9V032_SYSCLK_FREQ_DEF 26600000 |
34 | 35 | ||
35 | #define MT9V032_CHIP_VERSION 0x00 | 36 | #define MT9V032_CHIP_VERSION 0x00 |
36 | #define MT9V032_CHIP_ID_REV1 0x1311 | 37 | #define MT9V032_CHIP_ID_REV1 0x1311 |
37 | #define MT9V032_CHIP_ID_REV3 0x1313 | 38 | #define MT9V032_CHIP_ID_REV3 0x1313 |
39 | #define MT9V034_CHIP_ID_REV1 0X1324 | ||
38 | #define MT9V032_COLUMN_START 0x01 | 40 | #define MT9V032_COLUMN_START 0x01 |
39 | #define MT9V032_COLUMN_START_MIN 1 | 41 | #define MT9V032_COLUMN_START_MIN 1 |
40 | #define MT9V032_COLUMN_START_DEF 1 | 42 | #define MT9V032_COLUMN_START_DEF 1 |
@@ -53,12 +55,15 @@ | |||
53 | #define MT9V032_WINDOW_WIDTH_MAX 752 | 55 | #define MT9V032_WINDOW_WIDTH_MAX 752 |
54 | #define MT9V032_HORIZONTAL_BLANKING 0x05 | 56 | #define MT9V032_HORIZONTAL_BLANKING 0x05 |
55 | #define MT9V032_HORIZONTAL_BLANKING_MIN 43 | 57 | #define MT9V032_HORIZONTAL_BLANKING_MIN 43 |
58 | #define MT9V034_HORIZONTAL_BLANKING_MIN 61 | ||
56 | #define MT9V032_HORIZONTAL_BLANKING_DEF 94 | 59 | #define MT9V032_HORIZONTAL_BLANKING_DEF 94 |
57 | #define MT9V032_HORIZONTAL_BLANKING_MAX 1023 | 60 | #define MT9V032_HORIZONTAL_BLANKING_MAX 1023 |
58 | #define MT9V032_VERTICAL_BLANKING 0x06 | 61 | #define MT9V032_VERTICAL_BLANKING 0x06 |
59 | #define MT9V032_VERTICAL_BLANKING_MIN 4 | 62 | #define MT9V032_VERTICAL_BLANKING_MIN 4 |
63 | #define MT9V034_VERTICAL_BLANKING_MIN 2 | ||
60 | #define MT9V032_VERTICAL_BLANKING_DEF 45 | 64 | #define MT9V032_VERTICAL_BLANKING_DEF 45 |
61 | #define MT9V032_VERTICAL_BLANKING_MAX 3000 | 65 | #define MT9V032_VERTICAL_BLANKING_MAX 3000 |
66 | #define MT9V034_VERTICAL_BLANKING_MAX 32288 | ||
62 | #define MT9V032_CHIP_CONTROL 0x07 | 67 | #define MT9V032_CHIP_CONTROL 0x07 |
63 | #define MT9V032_CHIP_CONTROL_MASTER_MODE (1 << 3) | 68 | #define MT9V032_CHIP_CONTROL_MASTER_MODE (1 << 3) |
64 | #define MT9V032_CHIP_CONTROL_DOUT_ENABLE (1 << 7) | 69 | #define MT9V032_CHIP_CONTROL_DOUT_ENABLE (1 << 7) |
@@ -68,8 +73,10 @@ | |||
68 | #define MT9V032_SHUTTER_WIDTH_CONTROL 0x0a | 73 | #define MT9V032_SHUTTER_WIDTH_CONTROL 0x0a |
69 | #define MT9V032_TOTAL_SHUTTER_WIDTH 0x0b | 74 | #define MT9V032_TOTAL_SHUTTER_WIDTH 0x0b |
70 | #define MT9V032_TOTAL_SHUTTER_WIDTH_MIN 1 | 75 | #define MT9V032_TOTAL_SHUTTER_WIDTH_MIN 1 |
76 | #define MT9V034_TOTAL_SHUTTER_WIDTH_MIN 0 | ||
71 | #define MT9V032_TOTAL_SHUTTER_WIDTH_DEF 480 | 77 | #define MT9V032_TOTAL_SHUTTER_WIDTH_DEF 480 |
72 | #define MT9V032_TOTAL_SHUTTER_WIDTH_MAX 32767 | 78 | #define MT9V032_TOTAL_SHUTTER_WIDTH_MAX 32767 |
79 | #define MT9V034_TOTAL_SHUTTER_WIDTH_MAX 32765 | ||
73 | #define MT9V032_RESET 0x0c | 80 | #define MT9V032_RESET 0x0c |
74 | #define MT9V032_READ_MODE 0x0d | 81 | #define MT9V032_READ_MODE 0x0d |
75 | #define MT9V032_READ_MODE_ROW_BIN_MASK (3 << 0) | 82 | #define MT9V032_READ_MODE_ROW_BIN_MASK (3 << 0) |
@@ -81,6 +88,8 @@ | |||
81 | #define MT9V032_READ_MODE_DARK_COLUMNS (1 << 6) | 88 | #define MT9V032_READ_MODE_DARK_COLUMNS (1 << 6) |
82 | #define MT9V032_READ_MODE_DARK_ROWS (1 << 7) | 89 | #define MT9V032_READ_MODE_DARK_ROWS (1 << 7) |
83 | #define MT9V032_PIXEL_OPERATION_MODE 0x0f | 90 | #define MT9V032_PIXEL_OPERATION_MODE 0x0f |
91 | #define MT9V034_PIXEL_OPERATION_MODE_HDR (1 << 0) | ||
92 | #define MT9V034_PIXEL_OPERATION_MODE_COLOR (1 << 1) | ||
84 | #define MT9V032_PIXEL_OPERATION_MODE_COLOR (1 << 2) | 93 | #define MT9V032_PIXEL_OPERATION_MODE_COLOR (1 << 2) |
85 | #define MT9V032_PIXEL_OPERATION_MODE_HDR (1 << 6) | 94 | #define MT9V032_PIXEL_OPERATION_MODE_HDR (1 << 6) |
86 | #define MT9V032_ANALOG_GAIN 0x35 | 95 | #define MT9V032_ANALOG_GAIN 0x35 |
@@ -96,9 +105,12 @@ | |||
96 | #define MT9V032_DARK_AVG_HIGH_THRESH_MASK (255 << 8) | 105 | #define MT9V032_DARK_AVG_HIGH_THRESH_MASK (255 << 8) |
97 | #define MT9V032_DARK_AVG_HIGH_THRESH_SHIFT 8 | 106 | #define MT9V032_DARK_AVG_HIGH_THRESH_SHIFT 8 |
98 | #define MT9V032_ROW_NOISE_CORR_CONTROL 0x70 | 107 | #define MT9V032_ROW_NOISE_CORR_CONTROL 0x70 |
108 | #define MT9V034_ROW_NOISE_CORR_ENABLE (1 << 0) | ||
109 | #define MT9V034_ROW_NOISE_CORR_USE_BLK_AVG (1 << 1) | ||
99 | #define MT9V032_ROW_NOISE_CORR_ENABLE (1 << 5) | 110 | #define MT9V032_ROW_NOISE_CORR_ENABLE (1 << 5) |
100 | #define MT9V032_ROW_NOISE_CORR_USE_BLK_AVG (1 << 7) | 111 | #define MT9V032_ROW_NOISE_CORR_USE_BLK_AVG (1 << 7) |
101 | #define MT9V032_PIXEL_CLOCK 0x74 | 112 | #define MT9V032_PIXEL_CLOCK 0x74 |
113 | #define MT9V034_PIXEL_CLOCK 0x72 | ||
102 | #define MT9V032_PIXEL_CLOCK_INV_LINE (1 << 0) | 114 | #define MT9V032_PIXEL_CLOCK_INV_LINE (1 << 0) |
103 | #define MT9V032_PIXEL_CLOCK_INV_FRAME (1 << 1) | 115 | #define MT9V032_PIXEL_CLOCK_INV_FRAME (1 << 1) |
104 | #define MT9V032_PIXEL_CLOCK_XOR_LINE (1 << 2) | 116 | #define MT9V032_PIXEL_CLOCK_XOR_LINE (1 << 2) |
@@ -120,12 +132,88 @@ | |||
120 | #define MT9V032_AGC_ENABLE (1 << 1) | 132 | #define MT9V032_AGC_ENABLE (1 << 1) |
121 | #define MT9V032_THERMAL_INFO 0xc1 | 133 | #define MT9V032_THERMAL_INFO 0xc1 |
122 | 134 | ||
135 | enum mt9v032_model { | ||
136 | MT9V032_MODEL_V032_COLOR, | ||
137 | MT9V032_MODEL_V032_MONO, | ||
138 | MT9V032_MODEL_V034_COLOR, | ||
139 | MT9V032_MODEL_V034_MONO, | ||
140 | }; | ||
141 | |||
142 | struct mt9v032_model_version { | ||
143 | unsigned int version; | ||
144 | const char *name; | ||
145 | }; | ||
146 | |||
147 | struct mt9v032_model_data { | ||
148 | unsigned int min_row_time; | ||
149 | unsigned int min_hblank; | ||
150 | unsigned int min_vblank; | ||
151 | unsigned int max_vblank; | ||
152 | unsigned int min_shutter; | ||
153 | unsigned int max_shutter; | ||
154 | unsigned int pclk_reg; | ||
155 | }; | ||
156 | |||
157 | struct mt9v032_model_info { | ||
158 | const struct mt9v032_model_data *data; | ||
159 | bool color; | ||
160 | }; | ||
161 | |||
162 | static const struct mt9v032_model_version mt9v032_versions[] = { | ||
163 | { MT9V032_CHIP_ID_REV1, "MT9V032 rev1/2" }, | ||
164 | { MT9V032_CHIP_ID_REV3, "MT9V032 rev3" }, | ||
165 | { MT9V034_CHIP_ID_REV1, "MT9V034 rev1" }, | ||
166 | }; | ||
167 | |||
168 | static const struct mt9v032_model_data mt9v032_model_data[] = { | ||
169 | { | ||
170 | /* MT9V032 revisions 1/2/3 */ | ||
171 | .min_row_time = 660, | ||
172 | .min_hblank = MT9V032_HORIZONTAL_BLANKING_MIN, | ||
173 | .min_vblank = MT9V032_VERTICAL_BLANKING_MIN, | ||
174 | .max_vblank = MT9V032_VERTICAL_BLANKING_MAX, | ||
175 | .min_shutter = MT9V032_TOTAL_SHUTTER_WIDTH_MIN, | ||
176 | .max_shutter = MT9V032_TOTAL_SHUTTER_WIDTH_MAX, | ||
177 | .pclk_reg = MT9V032_PIXEL_CLOCK, | ||
178 | }, { | ||
179 | /* MT9V034 */ | ||
180 | .min_row_time = 690, | ||
181 | .min_hblank = MT9V034_HORIZONTAL_BLANKING_MIN, | ||
182 | .min_vblank = MT9V034_VERTICAL_BLANKING_MIN, | ||
183 | .max_vblank = MT9V034_VERTICAL_BLANKING_MAX, | ||
184 | .min_shutter = MT9V034_TOTAL_SHUTTER_WIDTH_MIN, | ||
185 | .max_shutter = MT9V034_TOTAL_SHUTTER_WIDTH_MAX, | ||
186 | .pclk_reg = MT9V034_PIXEL_CLOCK, | ||
187 | }, | ||
188 | }; | ||
189 | |||
190 | static const struct mt9v032_model_info mt9v032_models[] = { | ||
191 | [MT9V032_MODEL_V032_COLOR] = { | ||
192 | .data = &mt9v032_model_data[0], | ||
193 | .color = true, | ||
194 | }, | ||
195 | [MT9V032_MODEL_V032_MONO] = { | ||
196 | .data = &mt9v032_model_data[0], | ||
197 | .color = false, | ||
198 | }, | ||
199 | [MT9V032_MODEL_V034_COLOR] = { | ||
200 | .data = &mt9v032_model_data[1], | ||
201 | .color = true, | ||
202 | }, | ||
203 | [MT9V032_MODEL_V034_MONO] = { | ||
204 | .data = &mt9v032_model_data[1], | ||
205 | .color = false, | ||
206 | }, | ||
207 | }; | ||
208 | |||
123 | struct mt9v032 { | 209 | struct mt9v032 { |
124 | struct v4l2_subdev subdev; | 210 | struct v4l2_subdev subdev; |
125 | struct media_pad pad; | 211 | struct media_pad pad; |
126 | 212 | ||
127 | struct v4l2_mbus_framefmt format; | 213 | struct v4l2_mbus_framefmt format; |
128 | struct v4l2_rect crop; | 214 | struct v4l2_rect crop; |
215 | unsigned int hratio; | ||
216 | unsigned int vratio; | ||
129 | 217 | ||
130 | struct v4l2_ctrl_handler ctrls; | 218 | struct v4l2_ctrl_handler ctrls; |
131 | struct { | 219 | struct { |
@@ -139,6 +227,8 @@ struct mt9v032 { | |||
139 | struct clk *clk; | 227 | struct clk *clk; |
140 | 228 | ||
141 | struct mt9v032_platform_data *pdata; | 229 | struct mt9v032_platform_data *pdata; |
230 | const struct mt9v032_model_info *model; | ||
231 | const struct mt9v032_model_version *version; | ||
142 | 232 | ||
143 | u32 sysclk; | 233 | u32 sysclk; |
144 | u16 chip_control; | 234 | u16 chip_control; |
@@ -210,12 +300,17 @@ mt9v032_update_hblank(struct mt9v032 *mt9v032) | |||
210 | { | 300 | { |
211 | struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev); | 301 | struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev); |
212 | struct v4l2_rect *crop = &mt9v032->crop; | 302 | struct v4l2_rect *crop = &mt9v032->crop; |
303 | unsigned int min_hblank = mt9v032->model->data->min_hblank; | ||
304 | unsigned int hblank; | ||
213 | 305 | ||
214 | return mt9v032_write(client, MT9V032_HORIZONTAL_BLANKING, | 306 | if (mt9v032->version->version == MT9V034_CHIP_ID_REV1) |
215 | max_t(s32, mt9v032->hblank, 660 - crop->width)); | 307 | min_hblank += (mt9v032->hratio - 1) * 10; |
216 | } | 308 | min_hblank = max_t(unsigned int, (int)mt9v032->model->data->min_row_time - crop->width, |
309 | (int)min_hblank); | ||
310 | hblank = max_t(unsigned int, mt9v032->hblank, min_hblank); | ||
217 | 311 | ||
218 | #define EXT_CLK 25000000 | 312 | return mt9v032_write(client, MT9V032_HORIZONTAL_BLANKING, hblank); |
313 | } | ||
219 | 314 | ||
220 | static int mt9v032_power_on(struct mt9v032 *mt9v032) | 315 | static int mt9v032_power_on(struct mt9v032 *mt9v032) |
221 | { | 316 | { |
@@ -259,7 +354,7 @@ static int __mt9v032_set_power(struct mt9v032 *mt9v032, bool on) | |||
259 | 354 | ||
260 | /* Configure the pixel clock polarity */ | 355 | /* Configure the pixel clock polarity */ |
261 | if (mt9v032->pdata && mt9v032->pdata->clk_pol) { | 356 | if (mt9v032->pdata && mt9v032->pdata->clk_pol) { |
262 | ret = mt9v032_write(client, MT9V032_PIXEL_CLOCK, | 357 | ret = mt9v032_write(client, mt9v032->model->data->pclk_reg, |
263 | MT9V032_PIXEL_CLOCK_INV_PXL_CLK); | 358 | MT9V032_PIXEL_CLOCK_INV_PXL_CLK); |
264 | if (ret < 0) | 359 | if (ret < 0) |
265 | return ret; | 360 | return ret; |
@@ -312,22 +407,20 @@ static int mt9v032_s_stream(struct v4l2_subdev *subdev, int enable) | |||
312 | | MT9V032_CHIP_CONTROL_SEQUENTIAL; | 407 | | MT9V032_CHIP_CONTROL_SEQUENTIAL; |
313 | struct i2c_client *client = v4l2_get_subdevdata(subdev); | 408 | struct i2c_client *client = v4l2_get_subdevdata(subdev); |
314 | struct mt9v032 *mt9v032 = to_mt9v032(subdev); | 409 | struct mt9v032 *mt9v032 = to_mt9v032(subdev); |
315 | struct v4l2_mbus_framefmt *format = &mt9v032->format; | ||
316 | struct v4l2_rect *crop = &mt9v032->crop; | 410 | struct v4l2_rect *crop = &mt9v032->crop; |
317 | unsigned int hratio; | 411 | unsigned int hbin; |
318 | unsigned int vratio; | 412 | unsigned int vbin; |
319 | int ret; | 413 | int ret; |
320 | 414 | ||
321 | if (!enable) | 415 | if (!enable) |
322 | return mt9v032_set_chip_control(mt9v032, mode, 0); | 416 | return mt9v032_set_chip_control(mt9v032, mode, 0); |
323 | 417 | ||
324 | /* Configure the window size and row/column bin */ | 418 | /* Configure the window size and row/column bin */ |
325 | hratio = DIV_ROUND_CLOSEST(crop->width, format->width); | 419 | hbin = fls(mt9v032->hratio) - 1; |
326 | vratio = DIV_ROUND_CLOSEST(crop->height, format->height); | 420 | vbin = fls(mt9v032->vratio) - 1; |
327 | |||
328 | ret = mt9v032_write(client, MT9V032_READ_MODE, | 421 | ret = mt9v032_write(client, MT9V032_READ_MODE, |
329 | (hratio - 1) << MT9V032_READ_MODE_ROW_BIN_SHIFT | | 422 | hbin << MT9V032_READ_MODE_COLUMN_BIN_SHIFT | |
330 | (vratio - 1) << MT9V032_READ_MODE_COLUMN_BIN_SHIFT); | 423 | vbin << MT9V032_READ_MODE_ROW_BIN_SHIFT); |
331 | if (ret < 0) | 424 | if (ret < 0) |
332 | return ret; | 425 | return ret; |
333 | 426 | ||
@@ -370,12 +463,12 @@ static int mt9v032_enum_frame_size(struct v4l2_subdev *subdev, | |||
370 | struct v4l2_subdev_fh *fh, | 463 | struct v4l2_subdev_fh *fh, |
371 | struct v4l2_subdev_frame_size_enum *fse) | 464 | struct v4l2_subdev_frame_size_enum *fse) |
372 | { | 465 | { |
373 | if (fse->index >= 8 || fse->code != V4L2_MBUS_FMT_SGRBG10_1X10) | 466 | if (fse->index >= 3 || fse->code != V4L2_MBUS_FMT_SGRBG10_1X10) |
374 | return -EINVAL; | 467 | return -EINVAL; |
375 | 468 | ||
376 | fse->min_width = MT9V032_WINDOW_WIDTH_DEF / fse->index; | 469 | fse->min_width = MT9V032_WINDOW_WIDTH_DEF / (1 << fse->index); |
377 | fse->max_width = fse->min_width; | 470 | fse->max_width = fse->min_width; |
378 | fse->min_height = MT9V032_WINDOW_HEIGHT_DEF / fse->index; | 471 | fse->min_height = MT9V032_WINDOW_HEIGHT_DEF / (1 << fse->index); |
379 | fse->max_height = fse->min_height; | 472 | fse->max_height = fse->min_height; |
380 | 473 | ||
381 | return 0; | 474 | return 0; |
@@ -392,18 +485,30 @@ static int mt9v032_get_format(struct v4l2_subdev *subdev, | |||
392 | return 0; | 485 | return 0; |
393 | } | 486 | } |
394 | 487 | ||
395 | static void mt9v032_configure_pixel_rate(struct mt9v032 *mt9v032, | 488 | static void mt9v032_configure_pixel_rate(struct mt9v032 *mt9v032) |
396 | unsigned int hratio) | ||
397 | { | 489 | { |
398 | struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev); | 490 | struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev); |
399 | int ret; | 491 | int ret; |
400 | 492 | ||
401 | ret = v4l2_ctrl_s_ctrl_int64(mt9v032->pixel_rate, | 493 | ret = v4l2_ctrl_s_ctrl_int64(mt9v032->pixel_rate, |
402 | mt9v032->sysclk / hratio); | 494 | mt9v032->sysclk / mt9v032->hratio); |
403 | if (ret < 0) | 495 | if (ret < 0) |
404 | dev_warn(&client->dev, "failed to set pixel rate (%d)\n", ret); | 496 | dev_warn(&client->dev, "failed to set pixel rate (%d)\n", ret); |
405 | } | 497 | } |
406 | 498 | ||
499 | static unsigned int mt9v032_calc_ratio(unsigned int input, unsigned int output) | ||
500 | { | ||
501 | /* Compute the power-of-two binning factor closest to the input size to | ||
502 | * output size ratio. Given that the output size is bounded by input/4 | ||
503 | * and input, a generic implementation would be an ineffective luxury. | ||
504 | */ | ||
505 | if (output * 3 > input * 2) | ||
506 | return 1; | ||
507 | if (output * 3 > input) | ||
508 | return 2; | ||
509 | return 4; | ||
510 | } | ||
511 | |||
407 | static int mt9v032_set_format(struct v4l2_subdev *subdev, | 512 | static int mt9v032_set_format(struct v4l2_subdev *subdev, |
408 | struct v4l2_subdev_fh *fh, | 513 | struct v4l2_subdev_fh *fh, |
409 | struct v4l2_subdev_format *format) | 514 | struct v4l2_subdev_format *format) |
@@ -420,22 +525,28 @@ static int mt9v032_set_format(struct v4l2_subdev *subdev, | |||
420 | format->which); | 525 | format->which); |
421 | 526 | ||
422 | /* Clamp the width and height to avoid dividing by zero. */ | 527 | /* Clamp the width and height to avoid dividing by zero. */ |
423 | width = clamp_t(unsigned int, ALIGN(format->format.width, 2), | 528 | width = clamp(ALIGN(format->format.width, 2), |
424 | max(__crop->width / 8, MT9V032_WINDOW_WIDTH_MIN), | 529 | max_t(unsigned int, __crop->width / 4, |
425 | __crop->width); | 530 | MT9V032_WINDOW_WIDTH_MIN), |
426 | height = clamp_t(unsigned int, ALIGN(format->format.height, 2), | 531 | __crop->width); |
427 | max(__crop->height / 8, MT9V032_WINDOW_HEIGHT_MIN), | 532 | height = clamp(ALIGN(format->format.height, 2), |
428 | __crop->height); | 533 | max_t(unsigned int, __crop->height / 4, |
429 | 534 | MT9V032_WINDOW_HEIGHT_MIN), | |
430 | hratio = DIV_ROUND_CLOSEST(__crop->width, width); | 535 | __crop->height); |
431 | vratio = DIV_ROUND_CLOSEST(__crop->height, height); | 536 | |
537 | hratio = mt9v032_calc_ratio(__crop->width, width); | ||
538 | vratio = mt9v032_calc_ratio(__crop->height, height); | ||
432 | 539 | ||
433 | __format = __mt9v032_get_pad_format(mt9v032, fh, format->pad, | 540 | __format = __mt9v032_get_pad_format(mt9v032, fh, format->pad, |
434 | format->which); | 541 | format->which); |
435 | __format->width = __crop->width / hratio; | 542 | __format->width = __crop->width / hratio; |
436 | __format->height = __crop->height / vratio; | 543 | __format->height = __crop->height / vratio; |
437 | if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) | 544 | |
438 | mt9v032_configure_pixel_rate(mt9v032, hratio); | 545 | if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) { |
546 | mt9v032->hratio = hratio; | ||
547 | mt9v032->vratio = vratio; | ||
548 | mt9v032_configure_pixel_rate(mt9v032); | ||
549 | } | ||
439 | 550 | ||
440 | format->format = *__format; | 551 | format->format = *__format; |
441 | 552 | ||
@@ -471,15 +582,17 @@ static int mt9v032_set_crop(struct v4l2_subdev *subdev, | |||
471 | rect.top = clamp(ALIGN(crop->rect.top + 1, 2) - 1, | 582 | rect.top = clamp(ALIGN(crop->rect.top + 1, 2) - 1, |
472 | MT9V032_ROW_START_MIN, | 583 | MT9V032_ROW_START_MIN, |
473 | MT9V032_ROW_START_MAX); | 584 | MT9V032_ROW_START_MAX); |
474 | rect.width = clamp(ALIGN(crop->rect.width, 2), | 585 | rect.width = clamp_t(unsigned int, ALIGN(crop->rect.width, 2), |
475 | MT9V032_WINDOW_WIDTH_MIN, | 586 | MT9V032_WINDOW_WIDTH_MIN, |
476 | MT9V032_WINDOW_WIDTH_MAX); | 587 | MT9V032_WINDOW_WIDTH_MAX); |
477 | rect.height = clamp(ALIGN(crop->rect.height, 2), | 588 | rect.height = clamp_t(unsigned int, ALIGN(crop->rect.height, 2), |
478 | MT9V032_WINDOW_HEIGHT_MIN, | 589 | MT9V032_WINDOW_HEIGHT_MIN, |
479 | MT9V032_WINDOW_HEIGHT_MAX); | 590 | MT9V032_WINDOW_HEIGHT_MAX); |
480 | 591 | ||
481 | rect.width = min(rect.width, MT9V032_PIXEL_ARRAY_WIDTH - rect.left); | 592 | rect.width = min_t(unsigned int, |
482 | rect.height = min(rect.height, MT9V032_PIXEL_ARRAY_HEIGHT - rect.top); | 593 | rect.width, MT9V032_PIXEL_ARRAY_WIDTH - rect.left); |
594 | rect.height = min_t(unsigned int, | ||
595 | rect.height, MT9V032_PIXEL_ARRAY_HEIGHT - rect.top); | ||
483 | 596 | ||
484 | __crop = __mt9v032_get_pad_crop(mt9v032, fh, crop->pad, crop->which); | 597 | __crop = __mt9v032_get_pad_crop(mt9v032, fh, crop->pad, crop->which); |
485 | 598 | ||
@@ -491,8 +604,11 @@ static int mt9v032_set_crop(struct v4l2_subdev *subdev, | |||
491 | crop->which); | 604 | crop->which); |
492 | __format->width = rect.width; | 605 | __format->width = rect.width; |
493 | __format->height = rect.height; | 606 | __format->height = rect.height; |
494 | if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) | 607 | if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) { |
495 | mt9v032_configure_pixel_rate(mt9v032, 1); | 608 | mt9v032->hratio = 1; |
609 | mt9v032->vratio = 1; | ||
610 | mt9v032_configure_pixel_rate(mt9v032); | ||
611 | } | ||
496 | } | 612 | } |
497 | 613 | ||
498 | *__crop = rect; | 614 | *__crop = rect; |
@@ -641,7 +757,8 @@ static int mt9v032_registered(struct v4l2_subdev *subdev) | |||
641 | { | 757 | { |
642 | struct i2c_client *client = v4l2_get_subdevdata(subdev); | 758 | struct i2c_client *client = v4l2_get_subdevdata(subdev); |
643 | struct mt9v032 *mt9v032 = to_mt9v032(subdev); | 759 | struct mt9v032 *mt9v032 = to_mt9v032(subdev); |
644 | s32 data; | 760 | unsigned int i; |
761 | s32 version; | ||
645 | int ret; | 762 | int ret; |
646 | 763 | ||
647 | dev_info(&client->dev, "Probing MT9V032 at address 0x%02x\n", | 764 | dev_info(&client->dev, "Probing MT9V032 at address 0x%02x\n", |
@@ -654,25 +771,38 @@ static int mt9v032_registered(struct v4l2_subdev *subdev) | |||
654 | } | 771 | } |
655 | 772 | ||
656 | /* Read and check the sensor version */ | 773 | /* Read and check the sensor version */ |
657 | data = mt9v032_read(client, MT9V032_CHIP_VERSION); | 774 | version = mt9v032_read(client, MT9V032_CHIP_VERSION); |
658 | if (data != MT9V032_CHIP_ID_REV1 && data != MT9V032_CHIP_ID_REV3) { | 775 | if (version < 0) { |
659 | dev_err(&client->dev, "MT9V032 not detected, wrong version " | 776 | dev_err(&client->dev, "Failed reading chip version\n"); |
660 | "0x%04x\n", data); | 777 | return version; |
778 | } | ||
779 | |||
780 | for (i = 0; i < ARRAY_SIZE(mt9v032_versions); ++i) { | ||
781 | if (mt9v032_versions[i].version == version) { | ||
782 | mt9v032->version = &mt9v032_versions[i]; | ||
783 | break; | ||
784 | } | ||
785 | } | ||
786 | |||
787 | if (mt9v032->version == NULL) { | ||
788 | dev_err(&client->dev, "Unsupported chip version 0x%04x\n", | ||
789 | version); | ||
661 | return -ENODEV; | 790 | return -ENODEV; |
662 | } | 791 | } |
663 | 792 | ||
664 | mt9v032_power_off(mt9v032); | 793 | mt9v032_power_off(mt9v032); |
665 | 794 | ||
666 | dev_info(&client->dev, "MT9V032 detected at address 0x%02x\n", | 795 | dev_info(&client->dev, "%s detected at address 0x%02x\n", |
667 | client->addr); | 796 | mt9v032->version->name, client->addr); |
668 | 797 | ||
669 | mt9v032_configure_pixel_rate(mt9v032, 1); | 798 | mt9v032_configure_pixel_rate(mt9v032); |
670 | 799 | ||
671 | return ret; | 800 | return ret; |
672 | } | 801 | } |
673 | 802 | ||
674 | static int mt9v032_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) | 803 | static int mt9v032_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) |
675 | { | 804 | { |
805 | struct mt9v032 *mt9v032 = to_mt9v032(subdev); | ||
676 | struct v4l2_mbus_framefmt *format; | 806 | struct v4l2_mbus_framefmt *format; |
677 | struct v4l2_rect *crop; | 807 | struct v4l2_rect *crop; |
678 | 808 | ||
@@ -683,7 +813,12 @@ static int mt9v032_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) | |||
683 | crop->height = MT9V032_WINDOW_HEIGHT_DEF; | 813 | crop->height = MT9V032_WINDOW_HEIGHT_DEF; |
684 | 814 | ||
685 | format = v4l2_subdev_get_try_format(fh, 0); | 815 | format = v4l2_subdev_get_try_format(fh, 0); |
686 | format->code = V4L2_MBUS_FMT_SGRBG10_1X10; | 816 | |
817 | if (mt9v032->model->color) | ||
818 | format->code = V4L2_MBUS_FMT_SGRBG10_1X10; | ||
819 | else | ||
820 | format->code = V4L2_MBUS_FMT_Y10_1X10; | ||
821 | |||
687 | format->width = MT9V032_WINDOW_WIDTH_DEF; | 822 | format->width = MT9V032_WINDOW_WIDTH_DEF; |
688 | format->height = MT9V032_WINDOW_HEIGHT_DEF; | 823 | format->height = MT9V032_WINDOW_HEIGHT_DEF; |
689 | format->field = V4L2_FIELD_NONE; | 824 | format->field = V4L2_FIELD_NONE; |
@@ -755,6 +890,7 @@ static int mt9v032_probe(struct i2c_client *client, | |||
755 | 890 | ||
756 | mutex_init(&mt9v032->power_lock); | 891 | mutex_init(&mt9v032->power_lock); |
757 | mt9v032->pdata = pdata; | 892 | mt9v032->pdata = pdata; |
893 | mt9v032->model = (const void *)did->driver_data; | ||
758 | 894 | ||
759 | v4l2_ctrl_handler_init(&mt9v032->ctrls, 10); | 895 | v4l2_ctrl_handler_init(&mt9v032->ctrls, 10); |
760 | 896 | ||
@@ -767,16 +903,16 @@ static int mt9v032_probe(struct i2c_client *client, | |||
767 | V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL, 0, | 903 | V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL, 0, |
768 | V4L2_EXPOSURE_AUTO); | 904 | V4L2_EXPOSURE_AUTO); |
769 | v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops, | 905 | v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops, |
770 | V4L2_CID_EXPOSURE, MT9V032_TOTAL_SHUTTER_WIDTH_MIN, | 906 | V4L2_CID_EXPOSURE, mt9v032->model->data->min_shutter, |
771 | MT9V032_TOTAL_SHUTTER_WIDTH_MAX, 1, | 907 | mt9v032->model->data->max_shutter, 1, |
772 | MT9V032_TOTAL_SHUTTER_WIDTH_DEF); | 908 | MT9V032_TOTAL_SHUTTER_WIDTH_DEF); |
773 | v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops, | 909 | v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops, |
774 | V4L2_CID_HBLANK, MT9V032_HORIZONTAL_BLANKING_MIN, | 910 | V4L2_CID_HBLANK, mt9v032->model->data->min_hblank, |
775 | MT9V032_HORIZONTAL_BLANKING_MAX, 1, | 911 | MT9V032_HORIZONTAL_BLANKING_MAX, 1, |
776 | MT9V032_HORIZONTAL_BLANKING_DEF); | 912 | MT9V032_HORIZONTAL_BLANKING_DEF); |
777 | v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops, | 913 | v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops, |
778 | V4L2_CID_VBLANK, MT9V032_VERTICAL_BLANKING_MIN, | 914 | V4L2_CID_VBLANK, mt9v032->model->data->min_vblank, |
779 | MT9V032_VERTICAL_BLANKING_MAX, 1, | 915 | mt9v032->model->data->max_vblank, 1, |
780 | MT9V032_VERTICAL_BLANKING_DEF); | 916 | MT9V032_VERTICAL_BLANKING_DEF); |
781 | mt9v032->test_pattern = v4l2_ctrl_new_std_menu_items(&mt9v032->ctrls, | 917 | mt9v032->test_pattern = v4l2_ctrl_new_std_menu_items(&mt9v032->ctrls, |
782 | &mt9v032_ctrl_ops, V4L2_CID_TEST_PATTERN, | 918 | &mt9v032_ctrl_ops, V4L2_CID_TEST_PATTERN, |
@@ -819,12 +955,19 @@ static int mt9v032_probe(struct i2c_client *client, | |||
819 | mt9v032->crop.width = MT9V032_WINDOW_WIDTH_DEF; | 955 | mt9v032->crop.width = MT9V032_WINDOW_WIDTH_DEF; |
820 | mt9v032->crop.height = MT9V032_WINDOW_HEIGHT_DEF; | 956 | mt9v032->crop.height = MT9V032_WINDOW_HEIGHT_DEF; |
821 | 957 | ||
822 | mt9v032->format.code = V4L2_MBUS_FMT_SGRBG10_1X10; | 958 | if (mt9v032->model->color) |
959 | mt9v032->format.code = V4L2_MBUS_FMT_SGRBG10_1X10; | ||
960 | else | ||
961 | mt9v032->format.code = V4L2_MBUS_FMT_Y10_1X10; | ||
962 | |||
823 | mt9v032->format.width = MT9V032_WINDOW_WIDTH_DEF; | 963 | mt9v032->format.width = MT9V032_WINDOW_WIDTH_DEF; |
824 | mt9v032->format.height = MT9V032_WINDOW_HEIGHT_DEF; | 964 | mt9v032->format.height = MT9V032_WINDOW_HEIGHT_DEF; |
825 | mt9v032->format.field = V4L2_FIELD_NONE; | 965 | mt9v032->format.field = V4L2_FIELD_NONE; |
826 | mt9v032->format.colorspace = V4L2_COLORSPACE_SRGB; | 966 | mt9v032->format.colorspace = V4L2_COLORSPACE_SRGB; |
827 | 967 | ||
968 | mt9v032->hratio = 1; | ||
969 | mt9v032->vratio = 1; | ||
970 | |||
828 | mt9v032->aec_agc = MT9V032_AEC_ENABLE | MT9V032_AGC_ENABLE; | 971 | mt9v032->aec_agc = MT9V032_AEC_ENABLE | MT9V032_AGC_ENABLE; |
829 | mt9v032->hblank = MT9V032_HORIZONTAL_BLANKING_DEF; | 972 | mt9v032->hblank = MT9V032_HORIZONTAL_BLANKING_DEF; |
830 | mt9v032->sysclk = MT9V032_SYSCLK_FREQ_DEF; | 973 | mt9v032->sysclk = MT9V032_SYSCLK_FREQ_DEF; |
@@ -855,7 +998,10 @@ static int mt9v032_remove(struct i2c_client *client) | |||
855 | } | 998 | } |
856 | 999 | ||
857 | static const struct i2c_device_id mt9v032_id[] = { | 1000 | static const struct i2c_device_id mt9v032_id[] = { |
858 | { "mt9v032", 0 }, | 1001 | { "mt9v032", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V032_COLOR] }, |
1002 | { "mt9v032m", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V032_MONO] }, | ||
1003 | { "mt9v034", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V034_COLOR] }, | ||
1004 | { "mt9v034m", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V034_MONO] }, | ||
859 | { } | 1005 | { } |
860 | }; | 1006 | }; |
861 | MODULE_DEVICE_TABLE(i2c, mt9v032_id); | 1007 | MODULE_DEVICE_TABLE(i2c, mt9v032_id); |