1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // Copyright (c) 2022 Intel Corporation. |
3 | |
4 | #include <asm/unaligned.h> |
5 | #include <linux/acpi.h> |
6 | #include <linux/delay.h> |
7 | #include <linux/i2c.h> |
8 | #include <linux/module.h> |
9 | #include <linux/pm_runtime.h> |
10 | #include <media/v4l2-ctrls.h> |
11 | #include <media/v4l2-device.h> |
12 | #include <media/v4l2-fwnode.h> |
13 | |
14 | #define OG01A1B_REG_VALUE_08BIT 1 |
15 | #define OG01A1B_REG_VALUE_16BIT 2 |
16 | #define OG01A1B_REG_VALUE_24BIT 3 |
17 | |
18 | #define OG01A1B_LINK_FREQ_500MHZ 500000000ULL |
19 | #define OG01A1B_SCLK 120000000LL |
20 | #define OG01A1B_MCLK 19200000 |
21 | #define OG01A1B_DATA_LANES 2 |
22 | #define OG01A1B_RGB_DEPTH 10 |
23 | |
24 | #define OG01A1B_REG_CHIP_ID 0x300a |
25 | #define OG01A1B_CHIP_ID 0x470141 |
26 | |
27 | #define OG01A1B_REG_MODE_SELECT 0x0100 |
28 | #define OG01A1B_MODE_STANDBY 0x00 |
29 | #define OG01A1B_MODE_STREAMING 0x01 |
30 | |
31 | /* vertical-timings from sensor */ |
32 | #define OG01A1B_REG_VTS 0x380e |
33 | #define OG01A1B_VTS_120FPS 0x0498 |
34 | #define OG01A1B_VTS_120FPS_MIN 0x0498 |
35 | #define OG01A1B_VTS_MAX 0x7fff |
36 | |
37 | /* horizontal-timings from sensor */ |
38 | #define OG01A1B_REG_HTS 0x380c |
39 | |
40 | /* Exposure controls from sensor */ |
41 | #define OG01A1B_REG_EXPOSURE 0x3501 |
42 | #define OG01A1B_EXPOSURE_MIN 1 |
43 | #define OG01A1B_EXPOSURE_MAX_MARGIN 14 |
44 | #define OG01A1B_EXPOSURE_STEP 1 |
45 | |
46 | /* Analog gain controls from sensor */ |
47 | #define OG01A1B_REG_ANALOG_GAIN 0x3508 |
48 | #define OG01A1B_ANAL_GAIN_MIN 16 |
49 | #define OG01A1B_ANAL_GAIN_MAX 248 /* Max = 15.5x */ |
50 | #define OG01A1B_ANAL_GAIN_STEP 1 |
51 | |
52 | /* Digital gain controls from sensor */ |
53 | #define OG01A1B_REG_DIG_GAIN 0x350a |
54 | #define OG01A1B_DGTL_GAIN_MIN 1024 |
55 | #define OG01A1B_DGTL_GAIN_MAX 16384 /* Max = 16x */ |
56 | #define OG01A1B_DGTL_GAIN_STEP 1 |
57 | #define OG01A1B_DGTL_GAIN_DEFAULT 1024 |
58 | |
59 | /* Group Access */ |
60 | #define OG01A1B_REG_GROUP_ACCESS 0x3208 |
61 | #define OG01A1B_GROUP_HOLD_START 0x0 |
62 | #define OG01A1B_GROUP_HOLD_END 0x10 |
63 | #define OG01A1B_GROUP_HOLD_LAUNCH 0xa0 |
64 | |
65 | /* Test Pattern Control */ |
66 | #define OG01A1B_REG_TEST_PATTERN 0x5100 |
67 | #define OG01A1B_TEST_PATTERN_ENABLE BIT(7) |
68 | #define OG01A1B_TEST_PATTERN_BAR_SHIFT 2 |
69 | |
70 | #define to_og01a1b(_sd) container_of(_sd, struct og01a1b, sd) |
71 | |
72 | enum { |
73 | OG01A1B_LINK_FREQ_1000MBPS, |
74 | }; |
75 | |
76 | struct og01a1b_reg { |
77 | u16 address; |
78 | u8 val; |
79 | }; |
80 | |
81 | struct og01a1b_reg_list { |
82 | u32 num_of_regs; |
83 | const struct og01a1b_reg *regs; |
84 | }; |
85 | |
86 | struct og01a1b_link_freq_config { |
87 | const struct og01a1b_reg_list reg_list; |
88 | }; |
89 | |
90 | struct og01a1b_mode { |
91 | /* Frame width in pixels */ |
92 | u32 width; |
93 | |
94 | /* Frame height in pixels */ |
95 | u32 height; |
96 | |
97 | /* Horizontal timining size */ |
98 | u32 hts; |
99 | |
100 | /* Default vertical timining size */ |
101 | u32 vts_def; |
102 | |
103 | /* Min vertical timining size */ |
104 | u32 vts_min; |
105 | |
106 | /* Link frequency needed for this resolution */ |
107 | u32 link_freq_index; |
108 | |
109 | /* Sensor register settings for this resolution */ |
110 | const struct og01a1b_reg_list reg_list; |
111 | }; |
112 | |
113 | static const struct og01a1b_reg mipi_data_rate_1000mbps[] = { |
114 | {0x0103, 0x01}, |
115 | {0x0303, 0x02}, |
116 | {0x0304, 0x00}, |
117 | {0x0305, 0xd2}, |
118 | {0x0323, 0x02}, |
119 | {0x0324, 0x01}, |
120 | {0x0325, 0x77}, |
121 | }; |
122 | |
123 | static const struct og01a1b_reg mode_1280x1024_regs[] = { |
124 | {0x0300, 0x0a}, |
125 | {0x0301, 0x29}, |
126 | {0x0302, 0x31}, |
127 | {0x0303, 0x02}, |
128 | {0x0304, 0x00}, |
129 | {0x0305, 0xd2}, |
130 | {0x0306, 0x00}, |
131 | {0x0307, 0x01}, |
132 | {0x0308, 0x02}, |
133 | {0x0309, 0x00}, |
134 | {0x0310, 0x00}, |
135 | {0x0311, 0x00}, |
136 | {0x0312, 0x07}, |
137 | {0x0313, 0x00}, |
138 | {0x0314, 0x00}, |
139 | {0x0315, 0x00}, |
140 | {0x0320, 0x02}, |
141 | {0x0321, 0x01}, |
142 | {0x0322, 0x01}, |
143 | {0x0323, 0x02}, |
144 | {0x0324, 0x01}, |
145 | {0x0325, 0x77}, |
146 | {0x0326, 0xce}, |
147 | {0x0327, 0x04}, |
148 | {0x0329, 0x02}, |
149 | {0x032a, 0x04}, |
150 | {0x032b, 0x04}, |
151 | {0x032c, 0x02}, |
152 | {0x032d, 0x01}, |
153 | {0x032e, 0x00}, |
154 | {0x300d, 0x02}, |
155 | {0x300e, 0x04}, |
156 | {0x3021, 0x08}, |
157 | {0x301e, 0x03}, |
158 | {0x3103, 0x00}, |
159 | {0x3106, 0x08}, |
160 | {0x3107, 0x40}, |
161 | {0x3216, 0x01}, |
162 | {0x3217, 0x00}, |
163 | {0x3218, 0xc0}, |
164 | {0x3219, 0x55}, |
165 | {0x3500, 0x00}, |
166 | {0x3501, 0x04}, |
167 | {0x3502, 0x8a}, |
168 | {0x3506, 0x01}, |
169 | {0x3507, 0x72}, |
170 | {0x3508, 0x01}, |
171 | {0x3509, 0x00}, |
172 | {0x350a, 0x01}, |
173 | {0x350b, 0x00}, |
174 | {0x350c, 0x00}, |
175 | {0x3541, 0x00}, |
176 | {0x3542, 0x40}, |
177 | {0x3605, 0xe0}, |
178 | {0x3606, 0x41}, |
179 | {0x3614, 0x20}, |
180 | {0x3620, 0x0b}, |
181 | {0x3630, 0x07}, |
182 | {0x3636, 0xa0}, |
183 | {0x3637, 0xf9}, |
184 | {0x3638, 0x09}, |
185 | {0x3639, 0x38}, |
186 | {0x363f, 0x09}, |
187 | {0x3640, 0x17}, |
188 | {0x3662, 0x04}, |
189 | {0x3665, 0x80}, |
190 | {0x3670, 0x68}, |
191 | {0x3674, 0x00}, |
192 | {0x3677, 0x3f}, |
193 | {0x3679, 0x00}, |
194 | {0x369f, 0x19}, |
195 | {0x36a0, 0x03}, |
196 | {0x36a2, 0x19}, |
197 | {0x36a3, 0x03}, |
198 | {0x370d, 0x66}, |
199 | {0x370f, 0x00}, |
200 | {0x3710, 0x03}, |
201 | {0x3715, 0x03}, |
202 | {0x3716, 0x03}, |
203 | {0x3717, 0x06}, |
204 | {0x3733, 0x00}, |
205 | {0x3778, 0x00}, |
206 | {0x37a8, 0x0f}, |
207 | {0x37a9, 0x01}, |
208 | {0x37aa, 0x07}, |
209 | {0x37bd, 0x1c}, |
210 | {0x37c1, 0x2f}, |
211 | {0x37c3, 0x09}, |
212 | {0x37c8, 0x1d}, |
213 | {0x37ca, 0x30}, |
214 | {0x37df, 0x00}, |
215 | {0x3800, 0x00}, |
216 | {0x3801, 0x00}, |
217 | {0x3802, 0x00}, |
218 | {0x3803, 0x00}, |
219 | {0x3804, 0x05}, |
220 | {0x3805, 0x0f}, |
221 | {0x3806, 0x04}, |
222 | {0x3807, 0x0f}, |
223 | {0x3808, 0x05}, |
224 | {0x3809, 0x00}, |
225 | {0x380a, 0x04}, |
226 | {0x380b, 0x00}, |
227 | {0x380c, 0x03}, |
228 | {0x380d, 0x50}, |
229 | {0x380e, 0x04}, |
230 | {0x380f, 0x98}, |
231 | {0x3810, 0x00}, |
232 | {0x3811, 0x08}, |
233 | {0x3812, 0x00}, |
234 | {0x3813, 0x08}, |
235 | {0x3814, 0x11}, |
236 | {0x3815, 0x11}, |
237 | {0x3820, 0x40}, |
238 | {0x3821, 0x04}, |
239 | {0x3826, 0x00}, |
240 | {0x3827, 0x00}, |
241 | {0x382a, 0x08}, |
242 | {0x382b, 0x52}, |
243 | {0x382d, 0xba}, |
244 | {0x383d, 0x14}, |
245 | {0x384a, 0xa2}, |
246 | {0x3866, 0x0e}, |
247 | {0x3867, 0x07}, |
248 | {0x3884, 0x00}, |
249 | {0x3885, 0x08}, |
250 | {0x3893, 0x68}, |
251 | {0x3894, 0x2a}, |
252 | {0x3898, 0x00}, |
253 | {0x3899, 0x31}, |
254 | {0x389a, 0x04}, |
255 | {0x389b, 0x00}, |
256 | {0x389c, 0x0b}, |
257 | {0x389d, 0xad}, |
258 | {0x389f, 0x08}, |
259 | {0x38a0, 0x00}, |
260 | {0x38a1, 0x00}, |
261 | {0x38a8, 0x70}, |
262 | {0x38ac, 0xea}, |
263 | {0x38b2, 0x00}, |
264 | {0x38b3, 0x08}, |
265 | {0x38bc, 0x20}, |
266 | {0x38c4, 0x0c}, |
267 | {0x38c5, 0x3a}, |
268 | {0x38c7, 0x3a}, |
269 | {0x38e1, 0xc0}, |
270 | {0x38ec, 0x3c}, |
271 | {0x38f0, 0x09}, |
272 | {0x38f1, 0x6f}, |
273 | {0x38fe, 0x3c}, |
274 | {0x391e, 0x00}, |
275 | {0x391f, 0x00}, |
276 | {0x3920, 0xa5}, |
277 | {0x3921, 0x00}, |
278 | {0x3922, 0x00}, |
279 | {0x3923, 0x00}, |
280 | {0x3924, 0x05}, |
281 | {0x3925, 0x00}, |
282 | {0x3926, 0x00}, |
283 | {0x3927, 0x00}, |
284 | {0x3928, 0x1a}, |
285 | {0x3929, 0x01}, |
286 | {0x392a, 0xb4}, |
287 | {0x392b, 0x00}, |
288 | {0x392c, 0x10}, |
289 | {0x392f, 0x40}, |
290 | {0x4000, 0xcf}, |
291 | {0x4003, 0x40}, |
292 | {0x4008, 0x00}, |
293 | {0x4009, 0x07}, |
294 | {0x400a, 0x02}, |
295 | {0x400b, 0x54}, |
296 | {0x400c, 0x00}, |
297 | {0x400d, 0x07}, |
298 | {0x4010, 0xc0}, |
299 | {0x4012, 0x02}, |
300 | {0x4014, 0x04}, |
301 | {0x4015, 0x04}, |
302 | {0x4017, 0x02}, |
303 | {0x4042, 0x01}, |
304 | {0x4306, 0x04}, |
305 | {0x4307, 0x12}, |
306 | {0x4509, 0x00}, |
307 | {0x450b, 0x83}, |
308 | {0x4604, 0x68}, |
309 | {0x4608, 0x0a}, |
310 | {0x4700, 0x06}, |
311 | {0x4800, 0x64}, |
312 | {0x481b, 0x3c}, |
313 | {0x4825, 0x32}, |
314 | {0x4833, 0x18}, |
315 | {0x4837, 0x0f}, |
316 | {0x4850, 0x40}, |
317 | {0x4860, 0x00}, |
318 | {0x4861, 0xec}, |
319 | {0x4864, 0x00}, |
320 | {0x4883, 0x00}, |
321 | {0x4888, 0x90}, |
322 | {0x4889, 0x05}, |
323 | {0x488b, 0x04}, |
324 | {0x4f00, 0x04}, |
325 | {0x4f10, 0x04}, |
326 | {0x4f21, 0x01}, |
327 | {0x4f22, 0x40}, |
328 | {0x4f23, 0x44}, |
329 | {0x4f24, 0x51}, |
330 | {0x4f25, 0x41}, |
331 | {0x5000, 0x1f}, |
332 | {0x500a, 0x00}, |
333 | {0x5100, 0x00}, |
334 | {0x5111, 0x20}, |
335 | {0x3020, 0x20}, |
336 | {0x3613, 0x03}, |
337 | {0x38c9, 0x02}, |
338 | {0x5304, 0x01}, |
339 | {0x3620, 0x08}, |
340 | {0x3639, 0x58}, |
341 | {0x363a, 0x10}, |
342 | {0x3674, 0x04}, |
343 | {0x3780, 0xff}, |
344 | {0x3781, 0xff}, |
345 | {0x3782, 0x00}, |
346 | {0x3783, 0x01}, |
347 | {0x3798, 0xa3}, |
348 | {0x37aa, 0x10}, |
349 | {0x38a8, 0xf0}, |
350 | {0x38c4, 0x09}, |
351 | {0x38c5, 0xb0}, |
352 | {0x38df, 0x80}, |
353 | {0x38ff, 0x05}, |
354 | {0x4010, 0xf1}, |
355 | {0x4011, 0x70}, |
356 | {0x3667, 0x80}, |
357 | {0x4d00, 0x4a}, |
358 | {0x4d01, 0x18}, |
359 | {0x4d02, 0xbb}, |
360 | {0x4d03, 0xde}, |
361 | {0x4d04, 0x93}, |
362 | {0x4d05, 0xff}, |
363 | {0x4d09, 0x0a}, |
364 | {0x37aa, 0x16}, |
365 | {0x3606, 0x42}, |
366 | {0x3605, 0x00}, |
367 | {0x36a2, 0x17}, |
368 | {0x300d, 0x0a}, |
369 | {0x4d00, 0x4d}, |
370 | {0x4d01, 0x95}, |
371 | {0x3d8C, 0x70}, |
372 | {0x3d8d, 0xE9}, |
373 | {0x5300, 0x00}, |
374 | {0x5301, 0x10}, |
375 | {0x5302, 0x00}, |
376 | {0x5303, 0xE3}, |
377 | {0x3d88, 0x00}, |
378 | {0x3d89, 0x10}, |
379 | {0x3d8a, 0x00}, |
380 | {0x3d8b, 0xE3}, |
381 | {0x4f22, 0x00}, |
382 | }; |
383 | |
384 | static const char * const [] = { |
385 | "Disabled" , |
386 | "Standard Color Bar" , |
387 | "Top-Bottom Darker Color Bar" , |
388 | "Right-Left Darker Color Bar" , |
389 | "Bottom-Top Darker Color Bar" |
390 | }; |
391 | |
392 | static const s64 [] = { |
393 | OG01A1B_LINK_FREQ_500MHZ, |
394 | }; |
395 | |
396 | static const struct og01a1b_link_freq_config link_freq_configs[] = { |
397 | [OG01A1B_LINK_FREQ_1000MBPS] = { |
398 | .reg_list = { |
399 | .num_of_regs = ARRAY_SIZE(mipi_data_rate_1000mbps), |
400 | .regs = mipi_data_rate_1000mbps, |
401 | } |
402 | } |
403 | }; |
404 | |
405 | static const struct og01a1b_mode supported_modes[] = { |
406 | { |
407 | .width = 1280, |
408 | .height = 1024, |
409 | .hts = 848, |
410 | .vts_def = OG01A1B_VTS_120FPS, |
411 | .vts_min = OG01A1B_VTS_120FPS_MIN, |
412 | .reg_list = { |
413 | .num_of_regs = ARRAY_SIZE(mode_1280x1024_regs), |
414 | .regs = mode_1280x1024_regs, |
415 | }, |
416 | .link_freq_index = OG01A1B_LINK_FREQ_1000MBPS, |
417 | }, |
418 | }; |
419 | |
420 | struct og01a1b { |
421 | struct v4l2_subdev sd; |
422 | struct media_pad pad; |
423 | struct v4l2_ctrl_handler ctrl_handler; |
424 | |
425 | /* V4L2 Controls */ |
426 | struct v4l2_ctrl *link_freq; |
427 | struct v4l2_ctrl *pixel_rate; |
428 | struct v4l2_ctrl *vblank; |
429 | struct v4l2_ctrl *hblank; |
430 | struct v4l2_ctrl *exposure; |
431 | |
432 | /* Current mode */ |
433 | const struct og01a1b_mode *cur_mode; |
434 | |
435 | /* To serialize asynchronus callbacks */ |
436 | struct mutex mutex; |
437 | }; |
438 | |
439 | static u64 to_pixel_rate(u32 f_index) |
440 | { |
441 | u64 pixel_rate = link_freq_menu_items[f_index] * 2 * OG01A1B_DATA_LANES; |
442 | |
443 | do_div(pixel_rate, OG01A1B_RGB_DEPTH); |
444 | |
445 | return pixel_rate; |
446 | } |
447 | |
448 | static u64 to_pixels_per_line(u32 hts, u32 f_index) |
449 | { |
450 | u64 ppl = hts * to_pixel_rate(f_index); |
451 | |
452 | do_div(ppl, OG01A1B_SCLK); |
453 | |
454 | return ppl; |
455 | } |
456 | |
457 | static int og01a1b_read_reg(struct og01a1b *og01a1b, u16 reg, u16 len, u32 *val) |
458 | { |
459 | struct i2c_client *client = v4l2_get_subdevdata(sd: &og01a1b->sd); |
460 | struct i2c_msg msgs[2]; |
461 | u8 addr_buf[2]; |
462 | u8 data_buf[4] = {0}; |
463 | int ret; |
464 | |
465 | if (len > 4) |
466 | return -EINVAL; |
467 | |
468 | put_unaligned_be16(val: reg, p: addr_buf); |
469 | msgs[0].addr = client->addr; |
470 | msgs[0].flags = 0; |
471 | msgs[0].len = sizeof(addr_buf); |
472 | msgs[0].buf = addr_buf; |
473 | msgs[1].addr = client->addr; |
474 | msgs[1].flags = I2C_M_RD; |
475 | msgs[1].len = len; |
476 | msgs[1].buf = &data_buf[4 - len]; |
477 | |
478 | ret = i2c_transfer(adap: client->adapter, msgs, ARRAY_SIZE(msgs)); |
479 | if (ret != ARRAY_SIZE(msgs)) |
480 | return -EIO; |
481 | |
482 | *val = get_unaligned_be32(p: data_buf); |
483 | |
484 | return 0; |
485 | } |
486 | |
487 | static int og01a1b_write_reg(struct og01a1b *og01a1b, u16 reg, u16 len, u32 val) |
488 | { |
489 | struct i2c_client *client = v4l2_get_subdevdata(sd: &og01a1b->sd); |
490 | u8 buf[6]; |
491 | |
492 | if (len > 4) |
493 | return -EINVAL; |
494 | |
495 | put_unaligned_be16(val: reg, p: buf); |
496 | put_unaligned_be32(val: val << 8 * (4 - len), p: buf + 2); |
497 | if (i2c_master_send(client, buf, count: len + 2) != len + 2) |
498 | return -EIO; |
499 | |
500 | return 0; |
501 | } |
502 | |
503 | static int og01a1b_write_reg_list(struct og01a1b *og01a1b, |
504 | const struct og01a1b_reg_list *r_list) |
505 | { |
506 | struct i2c_client *client = v4l2_get_subdevdata(sd: &og01a1b->sd); |
507 | unsigned int i; |
508 | int ret; |
509 | |
510 | for (i = 0; i < r_list->num_of_regs; i++) { |
511 | ret = og01a1b_write_reg(og01a1b, reg: r_list->regs[i].address, len: 1, |
512 | val: r_list->regs[i].val); |
513 | if (ret) { |
514 | dev_err_ratelimited(&client->dev, |
515 | "failed to write reg 0x%4.4x. error = %d" , |
516 | r_list->regs[i].address, ret); |
517 | return ret; |
518 | } |
519 | } |
520 | |
521 | return 0; |
522 | } |
523 | |
524 | static int og01a1b_test_pattern(struct og01a1b *og01a1b, u32 pattern) |
525 | { |
526 | if (pattern) |
527 | pattern = (pattern - 1) << OG01A1B_TEST_PATTERN_BAR_SHIFT | |
528 | OG01A1B_TEST_PATTERN_ENABLE; |
529 | |
530 | return og01a1b_write_reg(og01a1b, OG01A1B_REG_TEST_PATTERN, |
531 | OG01A1B_REG_VALUE_08BIT, val: pattern); |
532 | } |
533 | |
534 | static int og01a1b_set_ctrl(struct v4l2_ctrl *ctrl) |
535 | { |
536 | struct og01a1b *og01a1b = container_of(ctrl->handler, |
537 | struct og01a1b, ctrl_handler); |
538 | struct i2c_client *client = v4l2_get_subdevdata(sd: &og01a1b->sd); |
539 | s64 exposure_max; |
540 | int ret = 0; |
541 | |
542 | /* Propagate change of current control to all related controls */ |
543 | if (ctrl->id == V4L2_CID_VBLANK) { |
544 | /* Update max exposure while meeting expected vblanking */ |
545 | exposure_max = og01a1b->cur_mode->height + ctrl->val - |
546 | OG01A1B_EXPOSURE_MAX_MARGIN; |
547 | __v4l2_ctrl_modify_range(ctrl: og01a1b->exposure, |
548 | min: og01a1b->exposure->minimum, |
549 | max: exposure_max, step: og01a1b->exposure->step, |
550 | def: exposure_max); |
551 | } |
552 | |
553 | /* V4L2 controls values will be applied only when power is already up */ |
554 | if (!pm_runtime_get_if_in_use(dev: &client->dev)) |
555 | return 0; |
556 | |
557 | switch (ctrl->id) { |
558 | case V4L2_CID_ANALOGUE_GAIN: |
559 | ret = og01a1b_write_reg(og01a1b, OG01A1B_REG_ANALOG_GAIN, |
560 | OG01A1B_REG_VALUE_16BIT, |
561 | val: ctrl->val << 4); |
562 | break; |
563 | |
564 | case V4L2_CID_DIGITAL_GAIN: |
565 | ret = og01a1b_write_reg(og01a1b, OG01A1B_REG_DIG_GAIN, |
566 | OG01A1B_REG_VALUE_24BIT, |
567 | val: ctrl->val << 6); |
568 | break; |
569 | |
570 | case V4L2_CID_EXPOSURE: |
571 | ret = og01a1b_write_reg(og01a1b, OG01A1B_REG_EXPOSURE, |
572 | OG01A1B_REG_VALUE_16BIT, val: ctrl->val); |
573 | break; |
574 | |
575 | case V4L2_CID_VBLANK: |
576 | ret = og01a1b_write_reg(og01a1b, OG01A1B_REG_VTS, |
577 | OG01A1B_REG_VALUE_16BIT, |
578 | val: og01a1b->cur_mode->height + ctrl->val); |
579 | break; |
580 | |
581 | case V4L2_CID_TEST_PATTERN: |
582 | ret = og01a1b_test_pattern(og01a1b, pattern: ctrl->val); |
583 | break; |
584 | |
585 | default: |
586 | ret = -EINVAL; |
587 | break; |
588 | } |
589 | |
590 | pm_runtime_put(dev: &client->dev); |
591 | |
592 | return ret; |
593 | } |
594 | |
595 | static const struct v4l2_ctrl_ops og01a1b_ctrl_ops = { |
596 | .s_ctrl = og01a1b_set_ctrl, |
597 | }; |
598 | |
599 | static int og01a1b_init_controls(struct og01a1b *og01a1b) |
600 | { |
601 | struct v4l2_ctrl_handler *ctrl_hdlr; |
602 | s64 exposure_max, h_blank; |
603 | int ret; |
604 | |
605 | ctrl_hdlr = &og01a1b->ctrl_handler; |
606 | ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8); |
607 | if (ret) |
608 | return ret; |
609 | |
610 | ctrl_hdlr->lock = &og01a1b->mutex; |
611 | og01a1b->link_freq = v4l2_ctrl_new_int_menu(hdl: ctrl_hdlr, |
612 | ops: &og01a1b_ctrl_ops, |
613 | V4L2_CID_LINK_FREQ, |
614 | ARRAY_SIZE |
615 | (link_freq_menu_items) - 1, |
616 | def: 0, qmenu_int: link_freq_menu_items); |
617 | if (og01a1b->link_freq) |
618 | og01a1b->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; |
619 | |
620 | og01a1b->pixel_rate = v4l2_ctrl_new_std(hdl: ctrl_hdlr, ops: &og01a1b_ctrl_ops, |
621 | V4L2_CID_PIXEL_RATE, min: 0, |
622 | max: to_pixel_rate |
623 | (f_index: OG01A1B_LINK_FREQ_1000MBPS), |
624 | step: 1, |
625 | def: to_pixel_rate |
626 | (f_index: OG01A1B_LINK_FREQ_1000MBPS)); |
627 | og01a1b->vblank = v4l2_ctrl_new_std(hdl: ctrl_hdlr, ops: &og01a1b_ctrl_ops, |
628 | V4L2_CID_VBLANK, |
629 | min: og01a1b->cur_mode->vts_min - |
630 | og01a1b->cur_mode->height, |
631 | OG01A1B_VTS_MAX - |
632 | og01a1b->cur_mode->height, step: 1, |
633 | def: og01a1b->cur_mode->vts_def - |
634 | og01a1b->cur_mode->height); |
635 | h_blank = to_pixels_per_line(hts: og01a1b->cur_mode->hts, |
636 | f_index: og01a1b->cur_mode->link_freq_index) - |
637 | og01a1b->cur_mode->width; |
638 | og01a1b->hblank = v4l2_ctrl_new_std(hdl: ctrl_hdlr, ops: &og01a1b_ctrl_ops, |
639 | V4L2_CID_HBLANK, min: h_blank, max: h_blank, |
640 | step: 1, def: h_blank); |
641 | if (og01a1b->hblank) |
642 | og01a1b->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; |
643 | |
644 | v4l2_ctrl_new_std(hdl: ctrl_hdlr, ops: &og01a1b_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, |
645 | OG01A1B_ANAL_GAIN_MIN, OG01A1B_ANAL_GAIN_MAX, |
646 | OG01A1B_ANAL_GAIN_STEP, OG01A1B_ANAL_GAIN_MIN); |
647 | v4l2_ctrl_new_std(hdl: ctrl_hdlr, ops: &og01a1b_ctrl_ops, V4L2_CID_DIGITAL_GAIN, |
648 | OG01A1B_DGTL_GAIN_MIN, OG01A1B_DGTL_GAIN_MAX, |
649 | OG01A1B_DGTL_GAIN_STEP, OG01A1B_DGTL_GAIN_DEFAULT); |
650 | exposure_max = (og01a1b->cur_mode->vts_def - |
651 | OG01A1B_EXPOSURE_MAX_MARGIN); |
652 | og01a1b->exposure = v4l2_ctrl_new_std(hdl: ctrl_hdlr, ops: &og01a1b_ctrl_ops, |
653 | V4L2_CID_EXPOSURE, |
654 | OG01A1B_EXPOSURE_MIN, |
655 | max: exposure_max, |
656 | OG01A1B_EXPOSURE_STEP, |
657 | def: exposure_max); |
658 | v4l2_ctrl_new_std_menu_items(hdl: ctrl_hdlr, ops: &og01a1b_ctrl_ops, |
659 | V4L2_CID_TEST_PATTERN, |
660 | ARRAY_SIZE(og01a1b_test_pattern_menu) - 1, |
661 | mask: 0, def: 0, qmenu: og01a1b_test_pattern_menu); |
662 | |
663 | if (ctrl_hdlr->error) |
664 | return ctrl_hdlr->error; |
665 | |
666 | og01a1b->sd.ctrl_handler = ctrl_hdlr; |
667 | |
668 | return 0; |
669 | } |
670 | |
671 | static void og01a1b_update_pad_format(const struct og01a1b_mode *mode, |
672 | struct v4l2_mbus_framefmt *fmt) |
673 | { |
674 | fmt->width = mode->width; |
675 | fmt->height = mode->height; |
676 | fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; |
677 | fmt->field = V4L2_FIELD_NONE; |
678 | } |
679 | |
680 | static int og01a1b_start_streaming(struct og01a1b *og01a1b) |
681 | { |
682 | struct i2c_client *client = v4l2_get_subdevdata(sd: &og01a1b->sd); |
683 | const struct og01a1b_reg_list *reg_list; |
684 | int link_freq_index, ret; |
685 | |
686 | link_freq_index = og01a1b->cur_mode->link_freq_index; |
687 | reg_list = &link_freq_configs[link_freq_index].reg_list; |
688 | |
689 | ret = og01a1b_write_reg_list(og01a1b, r_list: reg_list); |
690 | if (ret) { |
691 | dev_err(&client->dev, "failed to set plls" ); |
692 | return ret; |
693 | } |
694 | |
695 | reg_list = &og01a1b->cur_mode->reg_list; |
696 | ret = og01a1b_write_reg_list(og01a1b, r_list: reg_list); |
697 | if (ret) { |
698 | dev_err(&client->dev, "failed to set mode" ); |
699 | return ret; |
700 | } |
701 | |
702 | ret = __v4l2_ctrl_handler_setup(hdl: og01a1b->sd.ctrl_handler); |
703 | if (ret) |
704 | return ret; |
705 | |
706 | ret = og01a1b_write_reg(og01a1b, OG01A1B_REG_MODE_SELECT, |
707 | OG01A1B_REG_VALUE_08BIT, |
708 | OG01A1B_MODE_STREAMING); |
709 | if (ret) { |
710 | dev_err(&client->dev, "failed to set stream" ); |
711 | return ret; |
712 | } |
713 | |
714 | return 0; |
715 | } |
716 | |
717 | static void og01a1b_stop_streaming(struct og01a1b *og01a1b) |
718 | { |
719 | struct i2c_client *client = v4l2_get_subdevdata(sd: &og01a1b->sd); |
720 | |
721 | if (og01a1b_write_reg(og01a1b, OG01A1B_REG_MODE_SELECT, |
722 | OG01A1B_REG_VALUE_08BIT, OG01A1B_MODE_STANDBY)) |
723 | dev_err(&client->dev, "failed to set stream" ); |
724 | } |
725 | |
726 | static int og01a1b_set_stream(struct v4l2_subdev *sd, int enable) |
727 | { |
728 | struct og01a1b *og01a1b = to_og01a1b(sd); |
729 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
730 | int ret = 0; |
731 | |
732 | mutex_lock(&og01a1b->mutex); |
733 | if (enable) { |
734 | ret = pm_runtime_resume_and_get(dev: &client->dev); |
735 | if (ret) { |
736 | mutex_unlock(lock: &og01a1b->mutex); |
737 | return ret; |
738 | } |
739 | |
740 | ret = og01a1b_start_streaming(og01a1b); |
741 | if (ret) { |
742 | enable = 0; |
743 | og01a1b_stop_streaming(og01a1b); |
744 | pm_runtime_put(dev: &client->dev); |
745 | } |
746 | } else { |
747 | og01a1b_stop_streaming(og01a1b); |
748 | pm_runtime_put(dev: &client->dev); |
749 | } |
750 | |
751 | mutex_unlock(lock: &og01a1b->mutex); |
752 | |
753 | return ret; |
754 | } |
755 | |
756 | static int og01a1b_set_format(struct v4l2_subdev *sd, |
757 | struct v4l2_subdev_state *sd_state, |
758 | struct v4l2_subdev_format *fmt) |
759 | { |
760 | struct og01a1b *og01a1b = to_og01a1b(sd); |
761 | const struct og01a1b_mode *mode; |
762 | s32 vblank_def, h_blank; |
763 | |
764 | mode = v4l2_find_nearest_size(supported_modes, |
765 | ARRAY_SIZE(supported_modes), width, |
766 | height, fmt->format.width, |
767 | fmt->format.height); |
768 | |
769 | mutex_lock(&og01a1b->mutex); |
770 | og01a1b_update_pad_format(mode, fmt: &fmt->format); |
771 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { |
772 | *v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format; |
773 | } else { |
774 | og01a1b->cur_mode = mode; |
775 | __v4l2_ctrl_s_ctrl(ctrl: og01a1b->link_freq, val: mode->link_freq_index); |
776 | __v4l2_ctrl_s_ctrl_int64(ctrl: og01a1b->pixel_rate, |
777 | val: to_pixel_rate(f_index: mode->link_freq_index)); |
778 | |
779 | /* Update limits and set FPS to default */ |
780 | vblank_def = mode->vts_def - mode->height; |
781 | __v4l2_ctrl_modify_range(ctrl: og01a1b->vblank, |
782 | min: mode->vts_min - mode->height, |
783 | OG01A1B_VTS_MAX - mode->height, step: 1, |
784 | def: vblank_def); |
785 | __v4l2_ctrl_s_ctrl(ctrl: og01a1b->vblank, val: vblank_def); |
786 | h_blank = to_pixels_per_line(hts: mode->hts, f_index: mode->link_freq_index) - |
787 | mode->width; |
788 | __v4l2_ctrl_modify_range(ctrl: og01a1b->hblank, min: h_blank, max: h_blank, step: 1, |
789 | def: h_blank); |
790 | } |
791 | |
792 | mutex_unlock(lock: &og01a1b->mutex); |
793 | |
794 | return 0; |
795 | } |
796 | |
797 | static int og01a1b_get_format(struct v4l2_subdev *sd, |
798 | struct v4l2_subdev_state *sd_state, |
799 | struct v4l2_subdev_format *fmt) |
800 | { |
801 | struct og01a1b *og01a1b = to_og01a1b(sd); |
802 | |
803 | mutex_lock(&og01a1b->mutex); |
804 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) |
805 | fmt->format = *v4l2_subdev_state_get_format(sd_state, |
806 | fmt->pad); |
807 | else |
808 | og01a1b_update_pad_format(mode: og01a1b->cur_mode, fmt: &fmt->format); |
809 | |
810 | mutex_unlock(lock: &og01a1b->mutex); |
811 | |
812 | return 0; |
813 | } |
814 | |
815 | static int og01a1b_enum_mbus_code(struct v4l2_subdev *sd, |
816 | struct v4l2_subdev_state *sd_state, |
817 | struct v4l2_subdev_mbus_code_enum *code) |
818 | { |
819 | if (code->index > 0) |
820 | return -EINVAL; |
821 | |
822 | code->code = MEDIA_BUS_FMT_SGRBG10_1X10; |
823 | |
824 | return 0; |
825 | } |
826 | |
827 | static int og01a1b_enum_frame_size(struct v4l2_subdev *sd, |
828 | struct v4l2_subdev_state *sd_state, |
829 | struct v4l2_subdev_frame_size_enum *fse) |
830 | { |
831 | if (fse->index >= ARRAY_SIZE(supported_modes)) |
832 | return -EINVAL; |
833 | |
834 | if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10) |
835 | return -EINVAL; |
836 | |
837 | fse->min_width = supported_modes[fse->index].width; |
838 | fse->max_width = fse->min_width; |
839 | fse->min_height = supported_modes[fse->index].height; |
840 | fse->max_height = fse->min_height; |
841 | |
842 | return 0; |
843 | } |
844 | |
845 | static int og01a1b_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) |
846 | { |
847 | struct og01a1b *og01a1b = to_og01a1b(sd); |
848 | |
849 | mutex_lock(&og01a1b->mutex); |
850 | og01a1b_update_pad_format(mode: &supported_modes[0], |
851 | v4l2_subdev_state_get_format(fh->state, 0)); |
852 | mutex_unlock(lock: &og01a1b->mutex); |
853 | |
854 | return 0; |
855 | } |
856 | |
857 | static const struct v4l2_subdev_video_ops og01a1b_video_ops = { |
858 | .s_stream = og01a1b_set_stream, |
859 | }; |
860 | |
861 | static const struct v4l2_subdev_pad_ops og01a1b_pad_ops = { |
862 | .set_fmt = og01a1b_set_format, |
863 | .get_fmt = og01a1b_get_format, |
864 | .enum_mbus_code = og01a1b_enum_mbus_code, |
865 | .enum_frame_size = og01a1b_enum_frame_size, |
866 | }; |
867 | |
868 | static const struct v4l2_subdev_ops og01a1b_subdev_ops = { |
869 | .video = &og01a1b_video_ops, |
870 | .pad = &og01a1b_pad_ops, |
871 | }; |
872 | |
873 | static const struct media_entity_operations og01a1b_subdev_entity_ops = { |
874 | .link_validate = v4l2_subdev_link_validate, |
875 | }; |
876 | |
877 | static const struct v4l2_subdev_internal_ops og01a1b_internal_ops = { |
878 | .open = og01a1b_open, |
879 | }; |
880 | |
881 | static int og01a1b_identify_module(struct og01a1b *og01a1b) |
882 | { |
883 | struct i2c_client *client = v4l2_get_subdevdata(sd: &og01a1b->sd); |
884 | int ret; |
885 | u32 val; |
886 | |
887 | ret = og01a1b_read_reg(og01a1b, OG01A1B_REG_CHIP_ID, |
888 | OG01A1B_REG_VALUE_24BIT, val: &val); |
889 | if (ret) |
890 | return ret; |
891 | |
892 | if (val != OG01A1B_CHIP_ID) { |
893 | dev_err(&client->dev, "chip id mismatch: %x!=%x" , |
894 | OG01A1B_CHIP_ID, val); |
895 | return -ENXIO; |
896 | } |
897 | |
898 | return 0; |
899 | } |
900 | |
901 | static int og01a1b_check_hwcfg(struct device *dev) |
902 | { |
903 | struct fwnode_handle *ep; |
904 | struct fwnode_handle *fwnode = dev_fwnode(dev); |
905 | struct v4l2_fwnode_endpoint bus_cfg = { |
906 | .bus_type = V4L2_MBUS_CSI2_DPHY |
907 | }; |
908 | u32 mclk; |
909 | int ret; |
910 | unsigned int i, j; |
911 | |
912 | if (!fwnode) |
913 | return -ENXIO; |
914 | |
915 | ret = fwnode_property_read_u32(fwnode, propname: "clock-frequency" , val: &mclk); |
916 | |
917 | if (ret) { |
918 | dev_err(dev, "can't get clock frequency" ); |
919 | return ret; |
920 | } |
921 | |
922 | if (mclk != OG01A1B_MCLK) { |
923 | dev_err(dev, "external clock %d is not supported" , mclk); |
924 | return -EINVAL; |
925 | } |
926 | |
927 | ep = fwnode_graph_get_next_endpoint(fwnode, NULL); |
928 | if (!ep) |
929 | return -ENXIO; |
930 | |
931 | ret = v4l2_fwnode_endpoint_alloc_parse(fwnode: ep, vep: &bus_cfg); |
932 | fwnode_handle_put(fwnode: ep); |
933 | if (ret) |
934 | return ret; |
935 | |
936 | if (bus_cfg.bus.mipi_csi2.num_data_lanes != OG01A1B_DATA_LANES) { |
937 | dev_err(dev, "number of CSI2 data lanes %d is not supported" , |
938 | bus_cfg.bus.mipi_csi2.num_data_lanes); |
939 | ret = -EINVAL; |
940 | goto check_hwcfg_error; |
941 | } |
942 | |
943 | if (!bus_cfg.nr_of_link_frequencies) { |
944 | dev_err(dev, "no link frequencies defined" ); |
945 | ret = -EINVAL; |
946 | goto check_hwcfg_error; |
947 | } |
948 | |
949 | for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); i++) { |
950 | for (j = 0; j < bus_cfg.nr_of_link_frequencies; j++) { |
951 | if (link_freq_menu_items[i] == |
952 | bus_cfg.link_frequencies[j]) |
953 | break; |
954 | } |
955 | |
956 | if (j == bus_cfg.nr_of_link_frequencies) { |
957 | dev_err(dev, "no link frequency %lld supported" , |
958 | link_freq_menu_items[i]); |
959 | ret = -EINVAL; |
960 | goto check_hwcfg_error; |
961 | } |
962 | } |
963 | |
964 | check_hwcfg_error: |
965 | v4l2_fwnode_endpoint_free(vep: &bus_cfg); |
966 | |
967 | return ret; |
968 | } |
969 | |
970 | static void og01a1b_remove(struct i2c_client *client) |
971 | { |
972 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
973 | struct og01a1b *og01a1b = to_og01a1b(sd); |
974 | |
975 | v4l2_async_unregister_subdev(sd); |
976 | media_entity_cleanup(entity: &sd->entity); |
977 | v4l2_ctrl_handler_free(hdl: sd->ctrl_handler); |
978 | pm_runtime_disable(dev: &client->dev); |
979 | mutex_destroy(lock: &og01a1b->mutex); |
980 | } |
981 | |
982 | static int og01a1b_probe(struct i2c_client *client) |
983 | { |
984 | struct og01a1b *og01a1b; |
985 | int ret; |
986 | |
987 | ret = og01a1b_check_hwcfg(dev: &client->dev); |
988 | if (ret) { |
989 | dev_err(&client->dev, "failed to check HW configuration: %d" , |
990 | ret); |
991 | return ret; |
992 | } |
993 | |
994 | og01a1b = devm_kzalloc(dev: &client->dev, size: sizeof(*og01a1b), GFP_KERNEL); |
995 | if (!og01a1b) |
996 | return -ENOMEM; |
997 | |
998 | v4l2_i2c_subdev_init(sd: &og01a1b->sd, client, ops: &og01a1b_subdev_ops); |
999 | ret = og01a1b_identify_module(og01a1b); |
1000 | if (ret) { |
1001 | dev_err(&client->dev, "failed to find sensor: %d" , ret); |
1002 | return ret; |
1003 | } |
1004 | |
1005 | mutex_init(&og01a1b->mutex); |
1006 | og01a1b->cur_mode = &supported_modes[0]; |
1007 | ret = og01a1b_init_controls(og01a1b); |
1008 | if (ret) { |
1009 | dev_err(&client->dev, "failed to init controls: %d" , ret); |
1010 | goto probe_error_v4l2_ctrl_handler_free; |
1011 | } |
1012 | |
1013 | og01a1b->sd.internal_ops = &og01a1b_internal_ops; |
1014 | og01a1b->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; |
1015 | og01a1b->sd.entity.ops = &og01a1b_subdev_entity_ops; |
1016 | og01a1b->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; |
1017 | og01a1b->pad.flags = MEDIA_PAD_FL_SOURCE; |
1018 | ret = media_entity_pads_init(entity: &og01a1b->sd.entity, num_pads: 1, pads: &og01a1b->pad); |
1019 | if (ret) { |
1020 | dev_err(&client->dev, "failed to init entity pads: %d" , ret); |
1021 | goto probe_error_v4l2_ctrl_handler_free; |
1022 | } |
1023 | |
1024 | ret = v4l2_async_register_subdev_sensor(sd: &og01a1b->sd); |
1025 | if (ret < 0) { |
1026 | dev_err(&client->dev, "failed to register V4L2 subdev: %d" , |
1027 | ret); |
1028 | goto probe_error_media_entity_cleanup; |
1029 | } |
1030 | |
1031 | /* |
1032 | * Device is already turned on by i2c-core with ACPI domain PM. |
1033 | * Enable runtime PM and turn off the device. |
1034 | */ |
1035 | pm_runtime_set_active(dev: &client->dev); |
1036 | pm_runtime_enable(dev: &client->dev); |
1037 | pm_runtime_idle(dev: &client->dev); |
1038 | |
1039 | return 0; |
1040 | |
1041 | probe_error_media_entity_cleanup: |
1042 | media_entity_cleanup(entity: &og01a1b->sd.entity); |
1043 | |
1044 | probe_error_v4l2_ctrl_handler_free: |
1045 | v4l2_ctrl_handler_free(hdl: og01a1b->sd.ctrl_handler); |
1046 | mutex_destroy(lock: &og01a1b->mutex); |
1047 | |
1048 | return ret; |
1049 | } |
1050 | |
1051 | #ifdef CONFIG_ACPI |
1052 | static const struct acpi_device_id og01a1b_acpi_ids[] = { |
1053 | {"OVTI01AC" }, |
1054 | {} |
1055 | }; |
1056 | |
1057 | MODULE_DEVICE_TABLE(acpi, og01a1b_acpi_ids); |
1058 | #endif |
1059 | |
1060 | static struct i2c_driver og01a1b_i2c_driver = { |
1061 | .driver = { |
1062 | .name = "og01a1b" , |
1063 | .acpi_match_table = ACPI_PTR(og01a1b_acpi_ids), |
1064 | }, |
1065 | .probe = og01a1b_probe, |
1066 | .remove = og01a1b_remove, |
1067 | }; |
1068 | |
1069 | module_i2c_driver(og01a1b_i2c_driver); |
1070 | |
1071 | MODULE_AUTHOR("Shawn Tu" ); |
1072 | MODULE_DESCRIPTION("OmniVision OG01A1B sensor driver" ); |
1073 | MODULE_LICENSE("GPL v2" ); |
1074 | |