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