1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // Copyright (C) 2021 Intel Corporation |
3 | |
4 | #include <linux/acpi.h> |
5 | #include <linux/delay.h> |
6 | #include <linux/i2c.h> |
7 | #include <linux/module.h> |
8 | #include <linux/pm_runtime.h> |
9 | #include <media/v4l2-ctrls.h> |
10 | #include <media/v4l2-device.h> |
11 | #include <asm/unaligned.h> |
12 | |
13 | #define IMX208_REG_MODE_SELECT 0x0100 |
14 | #define IMX208_MODE_STANDBY 0x00 |
15 | #define IMX208_MODE_STREAMING 0x01 |
16 | |
17 | /* Chip ID */ |
18 | #define IMX208_REG_CHIP_ID 0x0000 |
19 | #define IMX208_CHIP_ID 0x0208 |
20 | |
21 | /* V_TIMING internal */ |
22 | #define IMX208_REG_VTS 0x0340 |
23 | #define IMX208_VTS_60FPS 0x0472 |
24 | #define IMX208_VTS_BINNING 0x0239 |
25 | #define IMX208_VTS_60FPS_MIN 0x0458 |
26 | #define IMX208_VTS_BINNING_MIN 0x0230 |
27 | #define IMX208_VTS_MAX 0xffff |
28 | |
29 | /* HBLANK control - read only */ |
30 | #define IMX208_PPL_384MHZ 2248 |
31 | #define IMX208_PPL_96MHZ 2248 |
32 | |
33 | /* Exposure control */ |
34 | #define IMX208_REG_EXPOSURE 0x0202 |
35 | #define IMX208_EXPOSURE_MIN 4 |
36 | #define IMX208_EXPOSURE_STEP 1 |
37 | #define IMX208_EXPOSURE_DEFAULT 0x190 |
38 | #define IMX208_EXPOSURE_MAX 65535 |
39 | |
40 | /* Analog gain control */ |
41 | #define IMX208_REG_ANALOG_GAIN 0x0204 |
42 | #define IMX208_ANA_GAIN_MIN 0 |
43 | #define IMX208_ANA_GAIN_MAX 0x00e0 |
44 | #define IMX208_ANA_GAIN_STEP 1 |
45 | #define IMX208_ANA_GAIN_DEFAULT 0x0 |
46 | |
47 | /* Digital gain control */ |
48 | #define IMX208_REG_GR_DIGITAL_GAIN 0x020e |
49 | #define IMX208_REG_R_DIGITAL_GAIN 0x0210 |
50 | #define IMX208_REG_B_DIGITAL_GAIN 0x0212 |
51 | #define IMX208_REG_GB_DIGITAL_GAIN 0x0214 |
52 | #define IMX208_DIGITAL_GAIN_SHIFT 8 |
53 | |
54 | /* Orientation */ |
55 | #define IMX208_REG_ORIENTATION_CONTROL 0x0101 |
56 | |
57 | /* Test Pattern Control */ |
58 | #define IMX208_REG_TEST_PATTERN_MODE 0x0600 |
59 | #define IMX208_TEST_PATTERN_DISABLE 0x0 |
60 | #define IMX208_TEST_PATTERN_SOLID_COLOR 0x1 |
61 | #define IMX208_TEST_PATTERN_COLOR_BARS 0x2 |
62 | #define IMX208_TEST_PATTERN_GREY_COLOR 0x3 |
63 | #define IMX208_TEST_PATTERN_PN9 0x4 |
64 | #define IMX208_TEST_PATTERN_FIX_1 0x100 |
65 | #define IMX208_TEST_PATTERN_FIX_2 0x101 |
66 | #define IMX208_TEST_PATTERN_FIX_3 0x102 |
67 | #define IMX208_TEST_PATTERN_FIX_4 0x103 |
68 | #define IMX208_TEST_PATTERN_FIX_5 0x104 |
69 | #define IMX208_TEST_PATTERN_FIX_6 0x105 |
70 | |
71 | /* OTP Access */ |
72 | #define IMX208_OTP_BASE 0x3500 |
73 | #define IMX208_OTP_SIZE 40 |
74 | |
75 | struct imx208_reg { |
76 | u16 address; |
77 | u8 val; |
78 | }; |
79 | |
80 | struct imx208_reg_list { |
81 | u32 num_of_regs; |
82 | const struct imx208_reg *regs; |
83 | }; |
84 | |
85 | /* Link frequency config */ |
86 | struct imx208_link_freq_config { |
87 | u32 pixels_per_line; |
88 | |
89 | /* PLL registers for this link frequency */ |
90 | struct imx208_reg_list reg_list; |
91 | }; |
92 | |
93 | /* Mode : resolution and related config&values */ |
94 | struct imx208_mode { |
95 | /* Frame width */ |
96 | u32 width; |
97 | /* Frame height */ |
98 | u32 height; |
99 | |
100 | /* V-timing */ |
101 | u32 vts_def; |
102 | u32 vts_min; |
103 | |
104 | /* Index of Link frequency config to be used */ |
105 | u32 link_freq_index; |
106 | /* Default register values */ |
107 | struct imx208_reg_list reg_list; |
108 | }; |
109 | |
110 | static const struct imx208_reg pll_ctrl_reg[] = { |
111 | {0x0305, 0x02}, |
112 | {0x0307, 0x50}, |
113 | {0x303C, 0x3C}, |
114 | }; |
115 | |
116 | static const struct imx208_reg mode_1936x1096_60fps_regs[] = { |
117 | {0x0340, 0x04}, |
118 | {0x0341, 0x72}, |
119 | {0x0342, 0x04}, |
120 | {0x0343, 0x64}, |
121 | {0x034C, 0x07}, |
122 | {0x034D, 0x90}, |
123 | {0x034E, 0x04}, |
124 | {0x034F, 0x48}, |
125 | {0x0381, 0x01}, |
126 | {0x0383, 0x01}, |
127 | {0x0385, 0x01}, |
128 | {0x0387, 0x01}, |
129 | {0x3048, 0x00}, |
130 | {0x3050, 0x01}, |
131 | {0x30D5, 0x00}, |
132 | {0x3301, 0x00}, |
133 | {0x3318, 0x62}, |
134 | {0x0202, 0x01}, |
135 | {0x0203, 0x90}, |
136 | {0x0205, 0x00}, |
137 | }; |
138 | |
139 | static const struct imx208_reg mode_968_548_60fps_regs[] = { |
140 | {0x0340, 0x02}, |
141 | {0x0341, 0x39}, |
142 | {0x0342, 0x08}, |
143 | {0x0343, 0xC8}, |
144 | {0x034C, 0x03}, |
145 | {0x034D, 0xC8}, |
146 | {0x034E, 0x02}, |
147 | {0x034F, 0x24}, |
148 | {0x0381, 0x01}, |
149 | {0x0383, 0x03}, |
150 | {0x0385, 0x01}, |
151 | {0x0387, 0x03}, |
152 | {0x3048, 0x01}, |
153 | {0x3050, 0x02}, |
154 | {0x30D5, 0x03}, |
155 | {0x3301, 0x10}, |
156 | {0x3318, 0x75}, |
157 | {0x0202, 0x01}, |
158 | {0x0203, 0x90}, |
159 | {0x0205, 0x00}, |
160 | }; |
161 | |
162 | static const s64 imx208_discrete_digital_gain[] = { |
163 | 1, 2, 4, 8, 16, |
164 | }; |
165 | |
166 | static const char * const [] = { |
167 | "Disabled" , |
168 | "Solid Color" , |
169 | "100% Color Bar" , |
170 | "Fade to Grey Color Bar" , |
171 | "PN9" , |
172 | "Fixed Pattern1" , |
173 | "Fixed Pattern2" , |
174 | "Fixed Pattern3" , |
175 | "Fixed Pattern4" , |
176 | "Fixed Pattern5" , |
177 | "Fixed Pattern6" |
178 | }; |
179 | |
180 | static const int imx208_test_pattern_val[] = { |
181 | IMX208_TEST_PATTERN_DISABLE, |
182 | IMX208_TEST_PATTERN_SOLID_COLOR, |
183 | IMX208_TEST_PATTERN_COLOR_BARS, |
184 | IMX208_TEST_PATTERN_GREY_COLOR, |
185 | IMX208_TEST_PATTERN_PN9, |
186 | IMX208_TEST_PATTERN_FIX_1, |
187 | IMX208_TEST_PATTERN_FIX_2, |
188 | IMX208_TEST_PATTERN_FIX_3, |
189 | IMX208_TEST_PATTERN_FIX_4, |
190 | IMX208_TEST_PATTERN_FIX_5, |
191 | IMX208_TEST_PATTERN_FIX_6, |
192 | }; |
193 | |
194 | /* Configurations for supported link frequencies */ |
195 | #define IMX208_MHZ (1000 * 1000ULL) |
196 | #define IMX208_LINK_FREQ_384MHZ (384ULL * IMX208_MHZ) |
197 | #define IMX208_LINK_FREQ_96MHZ (96ULL * IMX208_MHZ) |
198 | |
199 | #define IMX208_DATA_RATE_DOUBLE 2 |
200 | #define IMX208_NUM_OF_LANES 2 |
201 | #define IMX208_PIXEL_BITS 10 |
202 | |
203 | enum { |
204 | IMX208_LINK_FREQ_384MHZ_INDEX, |
205 | IMX208_LINK_FREQ_96MHZ_INDEX, |
206 | }; |
207 | |
208 | /* |
209 | * pixel_rate = link_freq * data-rate * nr_of_lanes / bits_per_sample |
210 | * data rate => double data rate; number of lanes => 2; bits per pixel => 10 |
211 | */ |
212 | static u64 link_freq_to_pixel_rate(u64 f) |
213 | { |
214 | f *= IMX208_DATA_RATE_DOUBLE * IMX208_NUM_OF_LANES; |
215 | do_div(f, IMX208_PIXEL_BITS); |
216 | |
217 | return f; |
218 | } |
219 | |
220 | /* Menu items for LINK_FREQ V4L2 control */ |
221 | static const s64 [] = { |
222 | [IMX208_LINK_FREQ_384MHZ_INDEX] = IMX208_LINK_FREQ_384MHZ, |
223 | [IMX208_LINK_FREQ_96MHZ_INDEX] = IMX208_LINK_FREQ_96MHZ, |
224 | }; |
225 | |
226 | /* Link frequency configs */ |
227 | static const struct imx208_link_freq_config link_freq_configs[] = { |
228 | [IMX208_LINK_FREQ_384MHZ_INDEX] = { |
229 | .pixels_per_line = IMX208_PPL_384MHZ, |
230 | .reg_list = { |
231 | .num_of_regs = ARRAY_SIZE(pll_ctrl_reg), |
232 | .regs = pll_ctrl_reg, |
233 | } |
234 | }, |
235 | [IMX208_LINK_FREQ_96MHZ_INDEX] = { |
236 | .pixels_per_line = IMX208_PPL_96MHZ, |
237 | .reg_list = { |
238 | .num_of_regs = ARRAY_SIZE(pll_ctrl_reg), |
239 | .regs = pll_ctrl_reg, |
240 | } |
241 | }, |
242 | }; |
243 | |
244 | /* Mode configs */ |
245 | static const struct imx208_mode supported_modes[] = { |
246 | { |
247 | .width = 1936, |
248 | .height = 1096, |
249 | .vts_def = IMX208_VTS_60FPS, |
250 | .vts_min = IMX208_VTS_60FPS_MIN, |
251 | .reg_list = { |
252 | .num_of_regs = ARRAY_SIZE(mode_1936x1096_60fps_regs), |
253 | .regs = mode_1936x1096_60fps_regs, |
254 | }, |
255 | .link_freq_index = IMX208_LINK_FREQ_384MHZ_INDEX, |
256 | }, |
257 | { |
258 | .width = 968, |
259 | .height = 548, |
260 | .vts_def = IMX208_VTS_BINNING, |
261 | .vts_min = IMX208_VTS_BINNING_MIN, |
262 | .reg_list = { |
263 | .num_of_regs = ARRAY_SIZE(mode_968_548_60fps_regs), |
264 | .regs = mode_968_548_60fps_regs, |
265 | }, |
266 | .link_freq_index = IMX208_LINK_FREQ_96MHZ_INDEX, |
267 | }, |
268 | }; |
269 | |
270 | struct imx208 { |
271 | struct v4l2_subdev sd; |
272 | struct media_pad pad; |
273 | |
274 | struct v4l2_ctrl_handler ctrl_handler; |
275 | /* V4L2 Controls */ |
276 | struct v4l2_ctrl *link_freq; |
277 | struct v4l2_ctrl *pixel_rate; |
278 | struct v4l2_ctrl *vblank; |
279 | struct v4l2_ctrl *hblank; |
280 | struct v4l2_ctrl *vflip; |
281 | struct v4l2_ctrl *hflip; |
282 | |
283 | /* Current mode */ |
284 | const struct imx208_mode *cur_mode; |
285 | |
286 | /* |
287 | * Mutex for serialized access: |
288 | * Protect sensor set pad format and start/stop streaming safely. |
289 | * Protect access to sensor v4l2 controls. |
290 | */ |
291 | struct mutex imx208_mx; |
292 | |
293 | /* OTP data */ |
294 | bool otp_read; |
295 | char otp_data[IMX208_OTP_SIZE]; |
296 | |
297 | /* True if the device has been identified */ |
298 | bool identified; |
299 | }; |
300 | |
301 | static inline struct imx208 *to_imx208(struct v4l2_subdev *_sd) |
302 | { |
303 | return container_of(_sd, struct imx208, sd); |
304 | } |
305 | |
306 | /* Get bayer order based on flip setting. */ |
307 | static u32 imx208_get_format_code(struct imx208 *imx208) |
308 | { |
309 | /* |
310 | * Only one bayer order is supported. |
311 | * It depends on the flip settings. |
312 | */ |
313 | static const u32 codes[2][2] = { |
314 | { MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SGRBG10_1X10, }, |
315 | { MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SBGGR10_1X10, }, |
316 | }; |
317 | |
318 | return codes[imx208->vflip->val][imx208->hflip->val]; |
319 | } |
320 | |
321 | /* Read registers up to 4 at a time */ |
322 | static int imx208_read_reg(struct imx208 *imx208, u16 reg, u32 len, u32 *val) |
323 | { |
324 | struct i2c_client *client = v4l2_get_subdevdata(sd: &imx208->sd); |
325 | struct i2c_msg msgs[2]; |
326 | u8 addr_buf[2] = { reg >> 8, reg & 0xff }; |
327 | u8 data_buf[4] = { 0, }; |
328 | int ret; |
329 | |
330 | if (len > 4) |
331 | return -EINVAL; |
332 | |
333 | /* Write register address */ |
334 | msgs[0].addr = client->addr; |
335 | msgs[0].flags = 0; |
336 | msgs[0].len = ARRAY_SIZE(addr_buf); |
337 | msgs[0].buf = addr_buf; |
338 | |
339 | /* Read data from register */ |
340 | msgs[1].addr = client->addr; |
341 | msgs[1].flags = I2C_M_RD; |
342 | msgs[1].len = len; |
343 | msgs[1].buf = &data_buf[4 - len]; |
344 | |
345 | ret = i2c_transfer(adap: client->adapter, msgs, ARRAY_SIZE(msgs)); |
346 | if (ret != ARRAY_SIZE(msgs)) |
347 | return -EIO; |
348 | |
349 | *val = get_unaligned_be32(p: data_buf); |
350 | |
351 | return 0; |
352 | } |
353 | |
354 | /* Write registers up to 4 at a time */ |
355 | static int imx208_write_reg(struct imx208 *imx208, u16 reg, u32 len, u32 val) |
356 | { |
357 | struct i2c_client *client = v4l2_get_subdevdata(sd: &imx208->sd); |
358 | u8 buf[6]; |
359 | |
360 | if (len > 4) |
361 | return -EINVAL; |
362 | |
363 | put_unaligned_be16(val: reg, p: buf); |
364 | put_unaligned_be32(val: val << (8 * (4 - len)), p: buf + 2); |
365 | if (i2c_master_send(client, buf, count: len + 2) != len + 2) |
366 | return -EIO; |
367 | |
368 | return 0; |
369 | } |
370 | |
371 | /* Write a list of registers */ |
372 | static int imx208_write_regs(struct imx208 *imx208, |
373 | const struct imx208_reg *regs, u32 len) |
374 | { |
375 | struct i2c_client *client = v4l2_get_subdevdata(sd: &imx208->sd); |
376 | unsigned int i; |
377 | int ret; |
378 | |
379 | for (i = 0; i < len; i++) { |
380 | ret = imx208_write_reg(imx208, reg: regs[i].address, len: 1, |
381 | val: regs[i].val); |
382 | if (ret) { |
383 | dev_err_ratelimited(&client->dev, |
384 | "Failed to write reg 0x%4.4x. error = %d\n" , |
385 | regs[i].address, ret); |
386 | |
387 | return ret; |
388 | } |
389 | } |
390 | |
391 | return 0; |
392 | } |
393 | |
394 | /* Open sub-device */ |
395 | static int imx208_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) |
396 | { |
397 | struct v4l2_mbus_framefmt *try_fmt = |
398 | v4l2_subdev_state_get_format(fh->state, 0); |
399 | |
400 | /* Initialize try_fmt */ |
401 | try_fmt->width = supported_modes[0].width; |
402 | try_fmt->height = supported_modes[0].height; |
403 | try_fmt->code = MEDIA_BUS_FMT_SRGGB10_1X10; |
404 | try_fmt->field = V4L2_FIELD_NONE; |
405 | |
406 | return 0; |
407 | } |
408 | |
409 | static int imx208_update_digital_gain(struct imx208 *imx208, u32 len, u32 val) |
410 | { |
411 | int ret; |
412 | |
413 | val = imx208_discrete_digital_gain[val] << IMX208_DIGITAL_GAIN_SHIFT; |
414 | |
415 | ret = imx208_write_reg(imx208, IMX208_REG_GR_DIGITAL_GAIN, len: 2, val); |
416 | if (ret) |
417 | return ret; |
418 | |
419 | ret = imx208_write_reg(imx208, IMX208_REG_GB_DIGITAL_GAIN, len: 2, val); |
420 | if (ret) |
421 | return ret; |
422 | |
423 | ret = imx208_write_reg(imx208, IMX208_REG_R_DIGITAL_GAIN, len: 2, val); |
424 | if (ret) |
425 | return ret; |
426 | |
427 | return imx208_write_reg(imx208, IMX208_REG_B_DIGITAL_GAIN, len: 2, val); |
428 | } |
429 | |
430 | static int imx208_set_ctrl(struct v4l2_ctrl *ctrl) |
431 | { |
432 | struct imx208 *imx208 = |
433 | container_of(ctrl->handler, struct imx208, ctrl_handler); |
434 | struct i2c_client *client = v4l2_get_subdevdata(sd: &imx208->sd); |
435 | int ret; |
436 | |
437 | /* |
438 | * Applying V4L2 control value only happens |
439 | * when power is up for streaming |
440 | */ |
441 | if (!pm_runtime_get_if_in_use(dev: &client->dev)) |
442 | return 0; |
443 | |
444 | switch (ctrl->id) { |
445 | case V4L2_CID_ANALOGUE_GAIN: |
446 | ret = imx208_write_reg(imx208, IMX208_REG_ANALOG_GAIN, |
447 | len: 2, val: ctrl->val); |
448 | break; |
449 | case V4L2_CID_EXPOSURE: |
450 | ret = imx208_write_reg(imx208, IMX208_REG_EXPOSURE, |
451 | len: 2, val: ctrl->val); |
452 | break; |
453 | case V4L2_CID_DIGITAL_GAIN: |
454 | ret = imx208_update_digital_gain(imx208, len: 2, val: ctrl->val); |
455 | break; |
456 | case V4L2_CID_VBLANK: |
457 | /* Update VTS that meets expected vertical blanking */ |
458 | ret = imx208_write_reg(imx208, IMX208_REG_VTS, len: 2, |
459 | val: imx208->cur_mode->height + ctrl->val); |
460 | break; |
461 | case V4L2_CID_TEST_PATTERN: |
462 | ret = imx208_write_reg(imx208, IMX208_REG_TEST_PATTERN_MODE, |
463 | len: 2, val: imx208_test_pattern_val[ctrl->val]); |
464 | break; |
465 | case V4L2_CID_HFLIP: |
466 | case V4L2_CID_VFLIP: |
467 | ret = imx208_write_reg(imx208, IMX208_REG_ORIENTATION_CONTROL, |
468 | len: 1, |
469 | val: imx208->hflip->val | |
470 | imx208->vflip->val << 1); |
471 | break; |
472 | default: |
473 | ret = -EINVAL; |
474 | dev_err(&client->dev, |
475 | "ctrl(id:0x%x,val:0x%x) is not handled\n" , |
476 | ctrl->id, ctrl->val); |
477 | break; |
478 | } |
479 | |
480 | pm_runtime_put(dev: &client->dev); |
481 | |
482 | return ret; |
483 | } |
484 | |
485 | static const struct v4l2_ctrl_ops imx208_ctrl_ops = { |
486 | .s_ctrl = imx208_set_ctrl, |
487 | }; |
488 | |
489 | static const struct v4l2_ctrl_config imx208_digital_gain_control = { |
490 | .ops = &imx208_ctrl_ops, |
491 | .id = V4L2_CID_DIGITAL_GAIN, |
492 | .name = "Digital Gain" , |
493 | .type = V4L2_CTRL_TYPE_INTEGER_MENU, |
494 | .min = 0, |
495 | .max = ARRAY_SIZE(imx208_discrete_digital_gain) - 1, |
496 | .step = 0, |
497 | .def = 0, |
498 | .menu_skip_mask = 0, |
499 | .qmenu_int = imx208_discrete_digital_gain, |
500 | }; |
501 | |
502 | static int imx208_enum_mbus_code(struct v4l2_subdev *sd, |
503 | struct v4l2_subdev_state *sd_state, |
504 | struct v4l2_subdev_mbus_code_enum *code) |
505 | { |
506 | struct imx208 *imx208 = to_imx208(sd: sd); |
507 | |
508 | if (code->index > 0) |
509 | return -EINVAL; |
510 | |
511 | code->code = imx208_get_format_code(imx208); |
512 | |
513 | return 0; |
514 | } |
515 | |
516 | static int imx208_enum_frame_size(struct v4l2_subdev *sd, |
517 | struct v4l2_subdev_state *sd_state, |
518 | struct v4l2_subdev_frame_size_enum *fse) |
519 | { |
520 | struct imx208 *imx208 = to_imx208(sd: sd); |
521 | |
522 | if (fse->index >= ARRAY_SIZE(supported_modes)) |
523 | return -EINVAL; |
524 | |
525 | if (fse->code != imx208_get_format_code(imx208)) |
526 | return -EINVAL; |
527 | |
528 | fse->min_width = supported_modes[fse->index].width; |
529 | fse->max_width = fse->min_width; |
530 | fse->min_height = supported_modes[fse->index].height; |
531 | fse->max_height = fse->min_height; |
532 | |
533 | return 0; |
534 | } |
535 | |
536 | static void imx208_mode_to_pad_format(struct imx208 *imx208, |
537 | const struct imx208_mode *mode, |
538 | struct v4l2_subdev_format *fmt) |
539 | { |
540 | fmt->format.width = mode->width; |
541 | fmt->format.height = mode->height; |
542 | fmt->format.code = imx208_get_format_code(imx208); |
543 | fmt->format.field = V4L2_FIELD_NONE; |
544 | } |
545 | |
546 | static int __imx208_get_pad_format(struct imx208 *imx208, |
547 | struct v4l2_subdev_state *sd_state, |
548 | struct v4l2_subdev_format *fmt) |
549 | { |
550 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) |
551 | fmt->format = *v4l2_subdev_state_get_format(sd_state, |
552 | fmt->pad); |
553 | else |
554 | imx208_mode_to_pad_format(imx208, mode: imx208->cur_mode, fmt); |
555 | |
556 | return 0; |
557 | } |
558 | |
559 | static int imx208_get_pad_format(struct v4l2_subdev *sd, |
560 | struct v4l2_subdev_state *sd_state, |
561 | struct v4l2_subdev_format *fmt) |
562 | { |
563 | struct imx208 *imx208 = to_imx208(sd: sd); |
564 | int ret; |
565 | |
566 | mutex_lock(&imx208->imx208_mx); |
567 | ret = __imx208_get_pad_format(imx208, sd_state, fmt); |
568 | mutex_unlock(lock: &imx208->imx208_mx); |
569 | |
570 | return ret; |
571 | } |
572 | |
573 | static int imx208_set_pad_format(struct v4l2_subdev *sd, |
574 | struct v4l2_subdev_state *sd_state, |
575 | struct v4l2_subdev_format *fmt) |
576 | { |
577 | struct imx208 *imx208 = to_imx208(sd: sd); |
578 | const struct imx208_mode *mode; |
579 | s32 vblank_def; |
580 | s32 vblank_min; |
581 | s64 h_blank; |
582 | s64 pixel_rate; |
583 | s64 link_freq; |
584 | |
585 | mutex_lock(&imx208->imx208_mx); |
586 | |
587 | fmt->format.code = imx208_get_format_code(imx208); |
588 | mode = v4l2_find_nearest_size(supported_modes, |
589 | ARRAY_SIZE(supported_modes), width, height, |
590 | fmt->format.width, fmt->format.height); |
591 | imx208_mode_to_pad_format(imx208, mode, fmt); |
592 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { |
593 | *v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format; |
594 | } else { |
595 | imx208->cur_mode = mode; |
596 | __v4l2_ctrl_s_ctrl(ctrl: imx208->link_freq, val: mode->link_freq_index); |
597 | link_freq = link_freq_menu_items[mode->link_freq_index]; |
598 | pixel_rate = link_freq_to_pixel_rate(f: link_freq); |
599 | __v4l2_ctrl_s_ctrl_int64(ctrl: imx208->pixel_rate, val: pixel_rate); |
600 | /* Update limits and set FPS to default */ |
601 | vblank_def = imx208->cur_mode->vts_def - |
602 | imx208->cur_mode->height; |
603 | vblank_min = imx208->cur_mode->vts_min - |
604 | imx208->cur_mode->height; |
605 | __v4l2_ctrl_modify_range(ctrl: imx208->vblank, min: vblank_min, |
606 | IMX208_VTS_MAX - imx208->cur_mode->height, |
607 | step: 1, def: vblank_def); |
608 | __v4l2_ctrl_s_ctrl(ctrl: imx208->vblank, val: vblank_def); |
609 | h_blank = |
610 | link_freq_configs[mode->link_freq_index].pixels_per_line |
611 | - imx208->cur_mode->width; |
612 | __v4l2_ctrl_modify_range(ctrl: imx208->hblank, min: h_blank, |
613 | max: h_blank, step: 1, def: h_blank); |
614 | } |
615 | |
616 | mutex_unlock(lock: &imx208->imx208_mx); |
617 | |
618 | return 0; |
619 | } |
620 | |
621 | static int imx208_identify_module(struct imx208 *imx208) |
622 | { |
623 | struct i2c_client *client = v4l2_get_subdevdata(sd: &imx208->sd); |
624 | int ret; |
625 | u32 val; |
626 | |
627 | if (imx208->identified) |
628 | return 0; |
629 | |
630 | ret = imx208_read_reg(imx208, IMX208_REG_CHIP_ID, |
631 | len: 2, val: &val); |
632 | if (ret) { |
633 | dev_err(&client->dev, "failed to read chip id %x\n" , |
634 | IMX208_CHIP_ID); |
635 | return ret; |
636 | } |
637 | |
638 | if (val != IMX208_CHIP_ID) { |
639 | dev_err(&client->dev, "chip id mismatch: %x!=%x\n" , |
640 | IMX208_CHIP_ID, val); |
641 | return -EIO; |
642 | } |
643 | |
644 | imx208->identified = true; |
645 | |
646 | return 0; |
647 | } |
648 | |
649 | /* Start streaming */ |
650 | static int imx208_start_streaming(struct imx208 *imx208) |
651 | { |
652 | struct i2c_client *client = v4l2_get_subdevdata(sd: &imx208->sd); |
653 | const struct imx208_reg_list *reg_list; |
654 | int ret, link_freq_index; |
655 | |
656 | ret = imx208_identify_module(imx208); |
657 | if (ret) |
658 | return ret; |
659 | |
660 | /* Setup PLL */ |
661 | link_freq_index = imx208->cur_mode->link_freq_index; |
662 | reg_list = &link_freq_configs[link_freq_index].reg_list; |
663 | ret = imx208_write_regs(imx208, regs: reg_list->regs, len: reg_list->num_of_regs); |
664 | if (ret) { |
665 | dev_err(&client->dev, "%s failed to set plls\n" , __func__); |
666 | return ret; |
667 | } |
668 | |
669 | /* Apply default values of current mode */ |
670 | reg_list = &imx208->cur_mode->reg_list; |
671 | ret = imx208_write_regs(imx208, regs: reg_list->regs, len: reg_list->num_of_regs); |
672 | if (ret) { |
673 | dev_err(&client->dev, "%s failed to set mode\n" , __func__); |
674 | return ret; |
675 | } |
676 | |
677 | /* Apply customized values from user */ |
678 | ret = __v4l2_ctrl_handler_setup(hdl: imx208->sd.ctrl_handler); |
679 | if (ret) |
680 | return ret; |
681 | |
682 | /* set stream on register */ |
683 | return imx208_write_reg(imx208, IMX208_REG_MODE_SELECT, |
684 | len: 1, IMX208_MODE_STREAMING); |
685 | } |
686 | |
687 | /* Stop streaming */ |
688 | static int imx208_stop_streaming(struct imx208 *imx208) |
689 | { |
690 | struct i2c_client *client = v4l2_get_subdevdata(sd: &imx208->sd); |
691 | int ret; |
692 | |
693 | /* set stream off register */ |
694 | ret = imx208_write_reg(imx208, IMX208_REG_MODE_SELECT, |
695 | len: 1, IMX208_MODE_STANDBY); |
696 | if (ret) |
697 | dev_err(&client->dev, "%s failed to set stream\n" , __func__); |
698 | |
699 | /* |
700 | * Return success even if it was an error, as there is nothing the |
701 | * caller can do about it. |
702 | */ |
703 | return 0; |
704 | } |
705 | |
706 | static int imx208_set_stream(struct v4l2_subdev *sd, int enable) |
707 | { |
708 | struct imx208 *imx208 = to_imx208(sd: sd); |
709 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
710 | int ret = 0; |
711 | |
712 | mutex_lock(&imx208->imx208_mx); |
713 | |
714 | if (enable) { |
715 | ret = pm_runtime_resume_and_get(dev: &client->dev); |
716 | if (ret) { |
717 | mutex_unlock(lock: &imx208->imx208_mx); |
718 | return ret; |
719 | } |
720 | |
721 | /* |
722 | * Apply default & customized values |
723 | * and then start streaming. |
724 | */ |
725 | ret = imx208_start_streaming(imx208); |
726 | if (ret) |
727 | goto err_rpm_put; |
728 | } else { |
729 | imx208_stop_streaming(imx208); |
730 | pm_runtime_put(dev: &client->dev); |
731 | } |
732 | |
733 | mutex_unlock(lock: &imx208->imx208_mx); |
734 | |
735 | /* vflip and hflip cannot change during streaming */ |
736 | v4l2_ctrl_grab(ctrl: imx208->vflip, grabbed: enable); |
737 | v4l2_ctrl_grab(ctrl: imx208->hflip, grabbed: enable); |
738 | |
739 | return ret; |
740 | |
741 | err_rpm_put: |
742 | pm_runtime_put(dev: &client->dev); |
743 | mutex_unlock(lock: &imx208->imx208_mx); |
744 | |
745 | return ret; |
746 | } |
747 | |
748 | /* Verify chip ID */ |
749 | static const struct v4l2_subdev_video_ops imx208_video_ops = { |
750 | .s_stream = imx208_set_stream, |
751 | }; |
752 | |
753 | static const struct v4l2_subdev_pad_ops imx208_pad_ops = { |
754 | .enum_mbus_code = imx208_enum_mbus_code, |
755 | .get_fmt = imx208_get_pad_format, |
756 | .set_fmt = imx208_set_pad_format, |
757 | .enum_frame_size = imx208_enum_frame_size, |
758 | }; |
759 | |
760 | static const struct v4l2_subdev_ops imx208_subdev_ops = { |
761 | .video = &imx208_video_ops, |
762 | .pad = &imx208_pad_ops, |
763 | }; |
764 | |
765 | static const struct v4l2_subdev_internal_ops imx208_internal_ops = { |
766 | .open = imx208_open, |
767 | }; |
768 | |
769 | static int imx208_read_otp(struct imx208 *imx208) |
770 | { |
771 | struct i2c_client *client = v4l2_get_subdevdata(sd: &imx208->sd); |
772 | struct i2c_msg msgs[2]; |
773 | u8 addr_buf[2] = { IMX208_OTP_BASE >> 8, IMX208_OTP_BASE & 0xff }; |
774 | int ret = 0; |
775 | |
776 | mutex_lock(&imx208->imx208_mx); |
777 | |
778 | if (imx208->otp_read) |
779 | goto out_unlock; |
780 | |
781 | ret = pm_runtime_resume_and_get(dev: &client->dev); |
782 | if (ret) |
783 | goto out_unlock; |
784 | |
785 | ret = imx208_identify_module(imx208); |
786 | if (ret) |
787 | goto out_pm_put; |
788 | |
789 | /* Write register address */ |
790 | msgs[0].addr = client->addr; |
791 | msgs[0].flags = 0; |
792 | msgs[0].len = ARRAY_SIZE(addr_buf); |
793 | msgs[0].buf = addr_buf; |
794 | |
795 | /* Read data from registers */ |
796 | msgs[1].addr = client->addr; |
797 | msgs[1].flags = I2C_M_RD; |
798 | msgs[1].len = sizeof(imx208->otp_data); |
799 | msgs[1].buf = imx208->otp_data; |
800 | |
801 | ret = i2c_transfer(adap: client->adapter, msgs, ARRAY_SIZE(msgs)); |
802 | if (ret == ARRAY_SIZE(msgs)) { |
803 | imx208->otp_read = true; |
804 | ret = 0; |
805 | } |
806 | |
807 | out_pm_put: |
808 | pm_runtime_put(dev: &client->dev); |
809 | |
810 | out_unlock: |
811 | mutex_unlock(lock: &imx208->imx208_mx); |
812 | |
813 | return ret; |
814 | } |
815 | |
816 | static ssize_t otp_read(struct file *filp, struct kobject *kobj, |
817 | struct bin_attribute *bin_attr, |
818 | char *buf, loff_t off, size_t count) |
819 | { |
820 | struct i2c_client *client = to_i2c_client(kobj_to_dev(kobj)); |
821 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
822 | struct imx208 *imx208 = to_imx208(sd: sd); |
823 | int ret; |
824 | |
825 | ret = imx208_read_otp(imx208); |
826 | if (ret) |
827 | return ret; |
828 | |
829 | memcpy(buf, &imx208->otp_data[off], count); |
830 | return count; |
831 | } |
832 | |
833 | static const BIN_ATTR_RO(otp, IMX208_OTP_SIZE); |
834 | |
835 | /* Initialize control handlers */ |
836 | static int imx208_init_controls(struct imx208 *imx208) |
837 | { |
838 | struct i2c_client *client = v4l2_get_subdevdata(sd: &imx208->sd); |
839 | struct v4l2_ctrl_handler *ctrl_hdlr = &imx208->ctrl_handler; |
840 | s64 exposure_max; |
841 | s64 vblank_def; |
842 | s64 vblank_min; |
843 | s64 pixel_rate_min; |
844 | s64 pixel_rate_max; |
845 | int ret; |
846 | |
847 | ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8); |
848 | if (ret) |
849 | return ret; |
850 | |
851 | mutex_init(&imx208->imx208_mx); |
852 | ctrl_hdlr->lock = &imx208->imx208_mx; |
853 | imx208->link_freq = |
854 | v4l2_ctrl_new_int_menu(hdl: ctrl_hdlr, |
855 | ops: &imx208_ctrl_ops, |
856 | V4L2_CID_LINK_FREQ, |
857 | ARRAY_SIZE(link_freq_menu_items) - 1, |
858 | def: 0, qmenu_int: link_freq_menu_items); |
859 | |
860 | if (imx208->link_freq) |
861 | imx208->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; |
862 | |
863 | pixel_rate_max = link_freq_to_pixel_rate(f: link_freq_menu_items[0]); |
864 | pixel_rate_min = |
865 | link_freq_to_pixel_rate(f: link_freq_menu_items[ARRAY_SIZE(link_freq_menu_items) - 1]); |
866 | /* By default, PIXEL_RATE is read only */ |
867 | imx208->pixel_rate = v4l2_ctrl_new_std(hdl: ctrl_hdlr, ops: &imx208_ctrl_ops, |
868 | V4L2_CID_PIXEL_RATE, |
869 | min: pixel_rate_min, max: pixel_rate_max, |
870 | step: 1, def: pixel_rate_max); |
871 | |
872 | vblank_def = imx208->cur_mode->vts_def - imx208->cur_mode->height; |
873 | vblank_min = imx208->cur_mode->vts_min - imx208->cur_mode->height; |
874 | imx208->vblank = |
875 | v4l2_ctrl_new_std(hdl: ctrl_hdlr, ops: &imx208_ctrl_ops, V4L2_CID_VBLANK, |
876 | min: vblank_min, |
877 | IMX208_VTS_MAX - imx208->cur_mode->height, step: 1, |
878 | def: vblank_def); |
879 | |
880 | imx208->hblank = |
881 | v4l2_ctrl_new_std(hdl: ctrl_hdlr, ops: &imx208_ctrl_ops, V4L2_CID_HBLANK, |
882 | IMX208_PPL_384MHZ - imx208->cur_mode->width, |
883 | IMX208_PPL_384MHZ - imx208->cur_mode->width, |
884 | step: 1, |
885 | IMX208_PPL_384MHZ - imx208->cur_mode->width); |
886 | |
887 | if (imx208->hblank) |
888 | imx208->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; |
889 | |
890 | exposure_max = imx208->cur_mode->vts_def - 8; |
891 | v4l2_ctrl_new_std(hdl: ctrl_hdlr, ops: &imx208_ctrl_ops, V4L2_CID_EXPOSURE, |
892 | IMX208_EXPOSURE_MIN, max: exposure_max, |
893 | IMX208_EXPOSURE_STEP, IMX208_EXPOSURE_DEFAULT); |
894 | |
895 | imx208->hflip = v4l2_ctrl_new_std(hdl: ctrl_hdlr, ops: &imx208_ctrl_ops, |
896 | V4L2_CID_HFLIP, min: 0, max: 1, step: 1, def: 0); |
897 | if (imx208->hflip) |
898 | imx208->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; |
899 | imx208->vflip = v4l2_ctrl_new_std(hdl: ctrl_hdlr, ops: &imx208_ctrl_ops, |
900 | V4L2_CID_VFLIP, min: 0, max: 1, step: 1, def: 0); |
901 | if (imx208->vflip) |
902 | imx208->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; |
903 | |
904 | v4l2_ctrl_new_std(hdl: ctrl_hdlr, ops: &imx208_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, |
905 | IMX208_ANA_GAIN_MIN, IMX208_ANA_GAIN_MAX, |
906 | IMX208_ANA_GAIN_STEP, IMX208_ANA_GAIN_DEFAULT); |
907 | |
908 | v4l2_ctrl_new_custom(hdl: ctrl_hdlr, cfg: &imx208_digital_gain_control, NULL); |
909 | |
910 | v4l2_ctrl_new_std_menu_items(hdl: ctrl_hdlr, ops: &imx208_ctrl_ops, |
911 | V4L2_CID_TEST_PATTERN, |
912 | ARRAY_SIZE(imx208_test_pattern_menu) - 1, |
913 | mask: 0, def: 0, qmenu: imx208_test_pattern_menu); |
914 | |
915 | if (ctrl_hdlr->error) { |
916 | ret = ctrl_hdlr->error; |
917 | dev_err(&client->dev, "%s control init failed (%d)\n" , |
918 | __func__, ret); |
919 | goto error; |
920 | } |
921 | |
922 | imx208->sd.ctrl_handler = ctrl_hdlr; |
923 | |
924 | return 0; |
925 | |
926 | error: |
927 | v4l2_ctrl_handler_free(hdl: ctrl_hdlr); |
928 | mutex_destroy(lock: &imx208->imx208_mx); |
929 | |
930 | return ret; |
931 | } |
932 | |
933 | static void imx208_free_controls(struct imx208 *imx208) |
934 | { |
935 | v4l2_ctrl_handler_free(hdl: imx208->sd.ctrl_handler); |
936 | } |
937 | |
938 | static int imx208_probe(struct i2c_client *client) |
939 | { |
940 | struct imx208 *imx208; |
941 | int ret; |
942 | bool full_power; |
943 | u32 val = 0; |
944 | |
945 | device_property_read_u32(dev: &client->dev, propname: "clock-frequency" , val: &val); |
946 | if (val != 19200000) { |
947 | dev_err(&client->dev, |
948 | "Unsupported clock-frequency %u. Expected 19200000.\n" , |
949 | val); |
950 | return -EINVAL; |
951 | } |
952 | |
953 | imx208 = devm_kzalloc(dev: &client->dev, size: sizeof(*imx208), GFP_KERNEL); |
954 | if (!imx208) |
955 | return -ENOMEM; |
956 | |
957 | /* Initialize subdev */ |
958 | v4l2_i2c_subdev_init(sd: &imx208->sd, client, ops: &imx208_subdev_ops); |
959 | |
960 | full_power = acpi_dev_state_d0(dev: &client->dev); |
961 | if (full_power) { |
962 | /* Check module identity */ |
963 | ret = imx208_identify_module(imx208); |
964 | if (ret) { |
965 | dev_err(&client->dev, "failed to find sensor: %d" , ret); |
966 | goto error_probe; |
967 | } |
968 | } |
969 | |
970 | /* Set default mode to max resolution */ |
971 | imx208->cur_mode = &supported_modes[0]; |
972 | |
973 | ret = imx208_init_controls(imx208); |
974 | if (ret) { |
975 | dev_err(&client->dev, "failed to init controls: %d" , ret); |
976 | goto error_probe; |
977 | } |
978 | |
979 | /* Initialize subdev */ |
980 | imx208->sd.internal_ops = &imx208_internal_ops; |
981 | imx208->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; |
982 | imx208->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; |
983 | |
984 | /* Initialize source pad */ |
985 | imx208->pad.flags = MEDIA_PAD_FL_SOURCE; |
986 | ret = media_entity_pads_init(entity: &imx208->sd.entity, num_pads: 1, pads: &imx208->pad); |
987 | if (ret) { |
988 | dev_err(&client->dev, "%s failed:%d\n" , __func__, ret); |
989 | goto error_handler_free; |
990 | } |
991 | |
992 | ret = v4l2_async_register_subdev_sensor(sd: &imx208->sd); |
993 | if (ret < 0) |
994 | goto error_media_entity; |
995 | |
996 | ret = device_create_bin_file(dev: &client->dev, attr: &bin_attr_otp); |
997 | if (ret) { |
998 | dev_err(&client->dev, "sysfs otp creation failed\n" ); |
999 | goto error_async_subdev; |
1000 | } |
1001 | |
1002 | /* Set the device's state to active if it's in D0 state. */ |
1003 | if (full_power) |
1004 | pm_runtime_set_active(dev: &client->dev); |
1005 | pm_runtime_enable(dev: &client->dev); |
1006 | pm_runtime_idle(dev: &client->dev); |
1007 | |
1008 | return 0; |
1009 | |
1010 | error_async_subdev: |
1011 | v4l2_async_unregister_subdev(sd: &imx208->sd); |
1012 | |
1013 | error_media_entity: |
1014 | media_entity_cleanup(entity: &imx208->sd.entity); |
1015 | |
1016 | error_handler_free: |
1017 | imx208_free_controls(imx208); |
1018 | |
1019 | error_probe: |
1020 | mutex_destroy(lock: &imx208->imx208_mx); |
1021 | |
1022 | return ret; |
1023 | } |
1024 | |
1025 | static void imx208_remove(struct i2c_client *client) |
1026 | { |
1027 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
1028 | struct imx208 *imx208 = to_imx208(sd: sd); |
1029 | |
1030 | device_remove_bin_file(dev: &client->dev, attr: &bin_attr_otp); |
1031 | v4l2_async_unregister_subdev(sd); |
1032 | media_entity_cleanup(entity: &sd->entity); |
1033 | imx208_free_controls(imx208); |
1034 | |
1035 | pm_runtime_disable(dev: &client->dev); |
1036 | pm_runtime_set_suspended(dev: &client->dev); |
1037 | |
1038 | mutex_destroy(lock: &imx208->imx208_mx); |
1039 | } |
1040 | |
1041 | #ifdef CONFIG_ACPI |
1042 | static const struct acpi_device_id imx208_acpi_ids[] = { |
1043 | { "INT3478" }, |
1044 | { /* sentinel */ } |
1045 | }; |
1046 | |
1047 | MODULE_DEVICE_TABLE(acpi, imx208_acpi_ids); |
1048 | #endif |
1049 | |
1050 | static struct i2c_driver imx208_i2c_driver = { |
1051 | .driver = { |
1052 | .name = "imx208" , |
1053 | .acpi_match_table = ACPI_PTR(imx208_acpi_ids), |
1054 | }, |
1055 | .probe = imx208_probe, |
1056 | .remove = imx208_remove, |
1057 | .flags = I2C_DRV_ACPI_WAIVE_D0_PROBE, |
1058 | }; |
1059 | |
1060 | module_i2c_driver(imx208_i2c_driver); |
1061 | |
1062 | MODULE_AUTHOR("Yeh, Andy <andy.yeh@intel.com>" ); |
1063 | MODULE_AUTHOR("Chen, Ping-chung <ping-chung.chen@intel.com>" ); |
1064 | MODULE_AUTHOR("Shawn Tu" ); |
1065 | MODULE_DESCRIPTION("Sony IMX208 sensor driver" ); |
1066 | MODULE_LICENSE("GPL v2" ); |
1067 | |