Commit | Line | Data |
---|---|---|
472377fe ST |
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 og01a1b_test_pattern_menu[] = { | |
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 link_freq_menu_items[] = { | |
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 | /* Streaming on/off */ | |
439 | bool streaming; | |
440 | }; | |
441 | ||
442 | static u64 to_pixel_rate(u32 f_index) | |
443 | { | |
444 | u64 pixel_rate = link_freq_menu_items[f_index] * 2 * OG01A1B_DATA_LANES; | |
445 | ||
446 | do_div(pixel_rate, OG01A1B_RGB_DEPTH); | |
447 | ||
448 | return pixel_rate; | |
449 | } | |
450 | ||
451 | static u64 to_pixels_per_line(u32 hts, u32 f_index) | |
452 | { | |
453 | u64 ppl = hts * to_pixel_rate(f_index); | |
454 | ||
455 | do_div(ppl, OG01A1B_SCLK); | |
456 | ||
457 | return ppl; | |
458 | } | |
459 | ||
460 | static int og01a1b_read_reg(struct og01a1b *og01a1b, u16 reg, u16 len, u32 *val) | |
461 | { | |
462 | struct i2c_client *client = v4l2_get_subdevdata(&og01a1b->sd); | |
463 | struct i2c_msg msgs[2]; | |
464 | u8 addr_buf[2]; | |
465 | u8 data_buf[4] = {0}; | |
466 | int ret; | |
467 | ||
468 | if (len > 4) | |
469 | return -EINVAL; | |
470 | ||
471 | put_unaligned_be16(reg, addr_buf); | |
472 | msgs[0].addr = client->addr; | |
473 | msgs[0].flags = 0; | |
474 | msgs[0].len = sizeof(addr_buf); | |
475 | msgs[0].buf = addr_buf; | |
476 | msgs[1].addr = client->addr; | |
477 | msgs[1].flags = I2C_M_RD; | |
478 | msgs[1].len = len; | |
479 | msgs[1].buf = &data_buf[4 - len]; | |
480 | ||
481 | ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); | |
482 | if (ret != ARRAY_SIZE(msgs)) | |
483 | return -EIO; | |
484 | ||
485 | *val = get_unaligned_be32(data_buf); | |
486 | ||
487 | return 0; | |
488 | } | |
489 | ||
490 | static int og01a1b_write_reg(struct og01a1b *og01a1b, u16 reg, u16 len, u32 val) | |
491 | { | |
492 | struct i2c_client *client = v4l2_get_subdevdata(&og01a1b->sd); | |
493 | u8 buf[6]; | |
494 | ||
495 | if (len > 4) | |
496 | return -EINVAL; | |
497 | ||
498 | put_unaligned_be16(reg, buf); | |
499 | put_unaligned_be32(val << 8 * (4 - len), buf + 2); | |
500 | if (i2c_master_send(client, buf, len + 2) != len + 2) | |
501 | return -EIO; | |
502 | ||
503 | return 0; | |
504 | } | |
505 | ||
506 | static int og01a1b_write_reg_list(struct og01a1b *og01a1b, | |
507 | const struct og01a1b_reg_list *r_list) | |
508 | { | |
509 | struct i2c_client *client = v4l2_get_subdevdata(&og01a1b->sd); | |
510 | unsigned int i; | |
511 | int ret; | |
512 | ||
513 | for (i = 0; i < r_list->num_of_regs; i++) { | |
514 | ret = og01a1b_write_reg(og01a1b, r_list->regs[i].address, 1, | |
515 | r_list->regs[i].val); | |
516 | if (ret) { | |
517 | dev_err_ratelimited(&client->dev, | |
518 | "failed to write reg 0x%4.4x. error = %d", | |
519 | r_list->regs[i].address, ret); | |
520 | return ret; | |
521 | } | |
522 | } | |
523 | ||
524 | return 0; | |
525 | } | |
526 | ||
527 | static int og01a1b_test_pattern(struct og01a1b *og01a1b, u32 pattern) | |
528 | { | |
529 | if (pattern) | |
530 | pattern = (pattern - 1) << OG01A1B_TEST_PATTERN_BAR_SHIFT | | |
531 | OG01A1B_TEST_PATTERN_ENABLE; | |
532 | ||
533 | return og01a1b_write_reg(og01a1b, OG01A1B_REG_TEST_PATTERN, | |
534 | OG01A1B_REG_VALUE_08BIT, pattern); | |
535 | } | |
536 | ||
537 | static int og01a1b_set_ctrl(struct v4l2_ctrl *ctrl) | |
538 | { | |
539 | struct og01a1b *og01a1b = container_of(ctrl->handler, | |
540 | struct og01a1b, ctrl_handler); | |
541 | struct i2c_client *client = v4l2_get_subdevdata(&og01a1b->sd); | |
542 | s64 exposure_max; | |
543 | int ret = 0; | |
544 | ||
545 | /* Propagate change of current control to all related controls */ | |
546 | if (ctrl->id == V4L2_CID_VBLANK) { | |
547 | /* Update max exposure while meeting expected vblanking */ | |
548 | exposure_max = og01a1b->cur_mode->height + ctrl->val - | |
549 | OG01A1B_EXPOSURE_MAX_MARGIN; | |
550 | __v4l2_ctrl_modify_range(og01a1b->exposure, | |
551 | og01a1b->exposure->minimum, | |
552 | exposure_max, og01a1b->exposure->step, | |
553 | exposure_max); | |
554 | } | |
555 | ||
556 | /* V4L2 controls values will be applied only when power is already up */ | |
557 | if (!pm_runtime_get_if_in_use(&client->dev)) | |
558 | return 0; | |
559 | ||
560 | switch (ctrl->id) { | |
561 | case V4L2_CID_ANALOGUE_GAIN: | |
562 | ret = og01a1b_write_reg(og01a1b, OG01A1B_REG_ANALOG_GAIN, | |
563 | OG01A1B_REG_VALUE_16BIT, | |
564 | ctrl->val << 4); | |
565 | break; | |
566 | ||
567 | case V4L2_CID_DIGITAL_GAIN: | |
568 | ret = og01a1b_write_reg(og01a1b, OG01A1B_REG_DIG_GAIN, | |
569 | OG01A1B_REG_VALUE_24BIT, | |
570 | ctrl->val << 6); | |
571 | break; | |
572 | ||
573 | case V4L2_CID_EXPOSURE: | |
574 | ret = og01a1b_write_reg(og01a1b, OG01A1B_REG_EXPOSURE, | |
575 | OG01A1B_REG_VALUE_16BIT, ctrl->val); | |
576 | break; | |
577 | ||
578 | case V4L2_CID_VBLANK: | |
579 | ret = og01a1b_write_reg(og01a1b, OG01A1B_REG_VTS, | |
580 | OG01A1B_REG_VALUE_16BIT, | |
581 | og01a1b->cur_mode->height + ctrl->val); | |
582 | break; | |
583 | ||
584 | case V4L2_CID_TEST_PATTERN: | |
585 | ret = og01a1b_test_pattern(og01a1b, ctrl->val); | |
586 | break; | |
587 | ||
588 | default: | |
589 | ret = -EINVAL; | |
590 | break; | |
591 | } | |
592 | ||
593 | pm_runtime_put(&client->dev); | |
594 | ||
595 | return ret; | |
596 | } | |
597 | ||
598 | static const struct v4l2_ctrl_ops og01a1b_ctrl_ops = { | |
599 | .s_ctrl = og01a1b_set_ctrl, | |
600 | }; | |
601 | ||
602 | static int og01a1b_init_controls(struct og01a1b *og01a1b) | |
603 | { | |
604 | struct v4l2_ctrl_handler *ctrl_hdlr; | |
605 | s64 exposure_max, h_blank; | |
606 | int ret; | |
607 | ||
608 | ctrl_hdlr = &og01a1b->ctrl_handler; | |
609 | ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8); | |
610 | if (ret) | |
611 | return ret; | |
612 | ||
613 | ctrl_hdlr->lock = &og01a1b->mutex; | |
614 | og01a1b->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, | |
615 | &og01a1b_ctrl_ops, | |
616 | V4L2_CID_LINK_FREQ, | |
617 | ARRAY_SIZE | |
618 | (link_freq_menu_items) - 1, | |
619 | 0, link_freq_menu_items); | |
620 | if (og01a1b->link_freq) | |
621 | og01a1b->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; | |
622 | ||
623 | og01a1b->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &og01a1b_ctrl_ops, | |
624 | V4L2_CID_PIXEL_RATE, 0, | |
625 | to_pixel_rate | |
626 | (OG01A1B_LINK_FREQ_1000MBPS), | |
627 | 1, | |
628 | to_pixel_rate | |
629 | (OG01A1B_LINK_FREQ_1000MBPS)); | |
630 | og01a1b->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &og01a1b_ctrl_ops, | |
631 | V4L2_CID_VBLANK, | |
632 | og01a1b->cur_mode->vts_min - | |
633 | og01a1b->cur_mode->height, | |
634 | OG01A1B_VTS_MAX - | |
635 | og01a1b->cur_mode->height, 1, | |
636 | og01a1b->cur_mode->vts_def - | |
637 | og01a1b->cur_mode->height); | |
638 | h_blank = to_pixels_per_line(og01a1b->cur_mode->hts, | |
639 | og01a1b->cur_mode->link_freq_index) - | |
640 | og01a1b->cur_mode->width; | |
641 | og01a1b->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &og01a1b_ctrl_ops, | |
642 | V4L2_CID_HBLANK, h_blank, h_blank, | |
643 | 1, h_blank); | |
644 | if (og01a1b->hblank) | |
645 | og01a1b->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; | |
646 | ||
647 | v4l2_ctrl_new_std(ctrl_hdlr, &og01a1b_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, | |
648 | OG01A1B_ANAL_GAIN_MIN, OG01A1B_ANAL_GAIN_MAX, | |
649 | OG01A1B_ANAL_GAIN_STEP, OG01A1B_ANAL_GAIN_MIN); | |
650 | v4l2_ctrl_new_std(ctrl_hdlr, &og01a1b_ctrl_ops, V4L2_CID_DIGITAL_GAIN, | |
651 | OG01A1B_DGTL_GAIN_MIN, OG01A1B_DGTL_GAIN_MAX, | |
652 | OG01A1B_DGTL_GAIN_STEP, OG01A1B_DGTL_GAIN_DEFAULT); | |
653 | exposure_max = (og01a1b->cur_mode->vts_def - | |
654 | OG01A1B_EXPOSURE_MAX_MARGIN); | |
655 | og01a1b->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &og01a1b_ctrl_ops, | |
656 | V4L2_CID_EXPOSURE, | |
657 | OG01A1B_EXPOSURE_MIN, | |
658 | exposure_max, | |
659 | OG01A1B_EXPOSURE_STEP, | |
660 | exposure_max); | |
661 | v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &og01a1b_ctrl_ops, | |
662 | V4L2_CID_TEST_PATTERN, | |
663 | ARRAY_SIZE(og01a1b_test_pattern_menu) - 1, | |
664 | 0, 0, og01a1b_test_pattern_menu); | |
665 | ||
666 | if (ctrl_hdlr->error) | |
667 | return ctrl_hdlr->error; | |
668 | ||
669 | og01a1b->sd.ctrl_handler = ctrl_hdlr; | |
670 | ||
671 | return 0; | |
672 | } | |
673 | ||
674 | static void og01a1b_update_pad_format(const struct og01a1b_mode *mode, | |
675 | struct v4l2_mbus_framefmt *fmt) | |
676 | { | |
677 | fmt->width = mode->width; | |
678 | fmt->height = mode->height; | |
679 | fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; | |
680 | fmt->field = V4L2_FIELD_NONE; | |
681 | } | |
682 | ||
683 | static int og01a1b_start_streaming(struct og01a1b *og01a1b) | |
684 | { | |
685 | struct i2c_client *client = v4l2_get_subdevdata(&og01a1b->sd); | |
686 | const struct og01a1b_reg_list *reg_list; | |
687 | int link_freq_index, ret; | |
688 | ||
689 | link_freq_index = og01a1b->cur_mode->link_freq_index; | |
690 | reg_list = &link_freq_configs[link_freq_index].reg_list; | |
691 | ||
692 | ret = og01a1b_write_reg_list(og01a1b, reg_list); | |
693 | if (ret) { | |
694 | dev_err(&client->dev, "failed to set plls"); | |
695 | return ret; | |
696 | } | |
697 | ||
698 | reg_list = &og01a1b->cur_mode->reg_list; | |
699 | ret = og01a1b_write_reg_list(og01a1b, reg_list); | |
700 | if (ret) { | |
701 | dev_err(&client->dev, "failed to set mode"); | |
702 | return ret; | |
703 | } | |
704 | ||
705 | ret = __v4l2_ctrl_handler_setup(og01a1b->sd.ctrl_handler); | |
706 | if (ret) | |
707 | return ret; | |
708 | ||
709 | ret = og01a1b_write_reg(og01a1b, OG01A1B_REG_MODE_SELECT, | |
710 | OG01A1B_REG_VALUE_08BIT, | |
711 | OG01A1B_MODE_STREAMING); | |
712 | if (ret) { | |
713 | dev_err(&client->dev, "failed to set stream"); | |
714 | return ret; | |
715 | } | |
716 | ||
717 | return 0; | |
718 | } | |
719 | ||
720 | static void og01a1b_stop_streaming(struct og01a1b *og01a1b) | |
721 | { | |
722 | struct i2c_client *client = v4l2_get_subdevdata(&og01a1b->sd); | |
723 | ||
724 | if (og01a1b_write_reg(og01a1b, OG01A1B_REG_MODE_SELECT, | |
725 | OG01A1B_REG_VALUE_08BIT, OG01A1B_MODE_STANDBY)) | |
726 | dev_err(&client->dev, "failed to set stream"); | |
727 | } | |
728 | ||
729 | static int og01a1b_set_stream(struct v4l2_subdev *sd, int enable) | |
730 | { | |
731 | struct og01a1b *og01a1b = to_og01a1b(sd); | |
732 | struct i2c_client *client = v4l2_get_subdevdata(sd); | |
733 | int ret = 0; | |
734 | ||
735 | if (og01a1b->streaming == enable) | |
736 | return 0; | |
737 | ||
738 | mutex_lock(&og01a1b->mutex); | |
739 | if (enable) { | |
740 | ret = pm_runtime_get_sync(&client->dev); | |
741 | if (ret < 0) { | |
742 | pm_runtime_put_noidle(&client->dev); | |
743 | mutex_unlock(&og01a1b->mutex); | |
744 | return ret; | |
745 | } | |
746 | ||
747 | ret = og01a1b_start_streaming(og01a1b); | |
748 | if (ret) { | |
749 | enable = 0; | |
750 | og01a1b_stop_streaming(og01a1b); | |
751 | pm_runtime_put(&client->dev); | |
752 | } | |
753 | } else { | |
754 | og01a1b_stop_streaming(og01a1b); | |
755 | pm_runtime_put(&client->dev); | |
756 | } | |
757 | ||
758 | og01a1b->streaming = enable; | |
759 | mutex_unlock(&og01a1b->mutex); | |
760 | ||
761 | return ret; | |
762 | } | |
763 | ||
764 | static int __maybe_unused og01a1b_suspend(struct device *dev) | |
765 | { | |
766 | struct i2c_client *client = to_i2c_client(dev); | |
767 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | |
768 | struct og01a1b *og01a1b = to_og01a1b(sd); | |
769 | ||
770 | mutex_lock(&og01a1b->mutex); | |
771 | if (og01a1b->streaming) | |
772 | og01a1b_stop_streaming(og01a1b); | |
773 | ||
774 | mutex_unlock(&og01a1b->mutex); | |
775 | ||
776 | return 0; | |
777 | } | |
778 | ||
779 | static int __maybe_unused og01a1b_resume(struct device *dev) | |
780 | { | |
781 | struct i2c_client *client = to_i2c_client(dev); | |
782 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | |
783 | struct og01a1b *og01a1b = to_og01a1b(sd); | |
784 | int ret; | |
785 | ||
786 | mutex_lock(&og01a1b->mutex); | |
787 | if (og01a1b->streaming) { | |
788 | ret = og01a1b_start_streaming(og01a1b); | |
789 | if (ret) { | |
790 | og01a1b->streaming = false; | |
791 | og01a1b_stop_streaming(og01a1b); | |
792 | mutex_unlock(&og01a1b->mutex); | |
793 | return ret; | |
794 | } | |
795 | } | |
796 | ||
797 | mutex_unlock(&og01a1b->mutex); | |
798 | ||
799 | return 0; | |
800 | } | |
801 | ||
802 | static int og01a1b_set_format(struct v4l2_subdev *sd, | |
803 | struct v4l2_subdev_state *sd_state, | |
804 | struct v4l2_subdev_format *fmt) | |
805 | { | |
806 | struct og01a1b *og01a1b = to_og01a1b(sd); | |
807 | const struct og01a1b_mode *mode; | |
808 | s32 vblank_def, h_blank; | |
809 | ||
810 | mode = v4l2_find_nearest_size(supported_modes, | |
811 | ARRAY_SIZE(supported_modes), width, | |
812 | height, fmt->format.width, | |
813 | fmt->format.height); | |
814 | ||
815 | mutex_lock(&og01a1b->mutex); | |
816 | og01a1b_update_pad_format(mode, &fmt->format); | |
817 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { | |
818 | *v4l2_subdev_get_try_format(sd, sd_state, | |
819 | fmt->pad) = fmt->format; | |
820 | } else { | |
821 | og01a1b->cur_mode = mode; | |
822 | __v4l2_ctrl_s_ctrl(og01a1b->link_freq, mode->link_freq_index); | |
823 | __v4l2_ctrl_s_ctrl_int64(og01a1b->pixel_rate, | |
824 | to_pixel_rate(mode->link_freq_index)); | |
825 | ||
826 | /* Update limits and set FPS to default */ | |
827 | vblank_def = mode->vts_def - mode->height; | |
828 | __v4l2_ctrl_modify_range(og01a1b->vblank, | |
829 | mode->vts_min - mode->height, | |
830 | OG01A1B_VTS_MAX - mode->height, 1, | |
831 | vblank_def); | |
832 | __v4l2_ctrl_s_ctrl(og01a1b->vblank, vblank_def); | |
833 | h_blank = to_pixels_per_line(mode->hts, mode->link_freq_index) - | |
834 | mode->width; | |
835 | __v4l2_ctrl_modify_range(og01a1b->hblank, h_blank, h_blank, 1, | |
836 | h_blank); | |
837 | } | |
838 | ||
839 | mutex_unlock(&og01a1b->mutex); | |
840 | ||
841 | return 0; | |
842 | } | |
843 | ||
844 | static int og01a1b_get_format(struct v4l2_subdev *sd, | |
845 | struct v4l2_subdev_state *sd_state, | |
846 | struct v4l2_subdev_format *fmt) | |
847 | { | |
848 | struct og01a1b *og01a1b = to_og01a1b(sd); | |
849 | ||
850 | mutex_lock(&og01a1b->mutex); | |
851 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) | |
852 | fmt->format = *v4l2_subdev_get_try_format(&og01a1b->sd, | |
853 | sd_state, | |
854 | fmt->pad); | |
855 | else | |
856 | og01a1b_update_pad_format(og01a1b->cur_mode, &fmt->format); | |
857 | ||
858 | mutex_unlock(&og01a1b->mutex); | |
859 | ||
860 | return 0; | |
861 | } | |
862 | ||
863 | static int og01a1b_enum_mbus_code(struct v4l2_subdev *sd, | |
864 | struct v4l2_subdev_state *sd_state, | |
865 | struct v4l2_subdev_mbus_code_enum *code) | |
866 | { | |
867 | if (code->index > 0) | |
868 | return -EINVAL; | |
869 | ||
870 | code->code = MEDIA_BUS_FMT_SGRBG10_1X10; | |
871 | ||
872 | return 0; | |
873 | } | |
874 | ||
875 | static int og01a1b_enum_frame_size(struct v4l2_subdev *sd, | |
876 | struct v4l2_subdev_state *sd_state, | |
877 | struct v4l2_subdev_frame_size_enum *fse) | |
878 | { | |
879 | if (fse->index >= ARRAY_SIZE(supported_modes)) | |
880 | return -EINVAL; | |
881 | ||
882 | if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10) | |
883 | return -EINVAL; | |
884 | ||
885 | fse->min_width = supported_modes[fse->index].width; | |
886 | fse->max_width = fse->min_width; | |
887 | fse->min_height = supported_modes[fse->index].height; | |
888 | fse->max_height = fse->min_height; | |
889 | ||
890 | return 0; | |
891 | } | |
892 | ||
893 | static int og01a1b_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | |
894 | { | |
895 | struct og01a1b *og01a1b = to_og01a1b(sd); | |
896 | ||
897 | mutex_lock(&og01a1b->mutex); | |
898 | og01a1b_update_pad_format(&supported_modes[0], | |
899 | v4l2_subdev_get_try_format(sd, fh->state, 0)); | |
900 | mutex_unlock(&og01a1b->mutex); | |
901 | ||
902 | return 0; | |
903 | } | |
904 | ||
905 | static const struct v4l2_subdev_video_ops og01a1b_video_ops = { | |
906 | .s_stream = og01a1b_set_stream, | |
907 | }; | |
908 | ||
909 | static const struct v4l2_subdev_pad_ops og01a1b_pad_ops = { | |
910 | .set_fmt = og01a1b_set_format, | |
911 | .get_fmt = og01a1b_get_format, | |
912 | .enum_mbus_code = og01a1b_enum_mbus_code, | |
913 | .enum_frame_size = og01a1b_enum_frame_size, | |
914 | }; | |
915 | ||
916 | static const struct v4l2_subdev_ops og01a1b_subdev_ops = { | |
917 | .video = &og01a1b_video_ops, | |
918 | .pad = &og01a1b_pad_ops, | |
919 | }; | |
920 | ||
921 | static const struct media_entity_operations og01a1b_subdev_entity_ops = { | |
922 | .link_validate = v4l2_subdev_link_validate, | |
923 | }; | |
924 | ||
925 | static const struct v4l2_subdev_internal_ops og01a1b_internal_ops = { | |
926 | .open = og01a1b_open, | |
927 | }; | |
928 | ||
929 | static int og01a1b_identify_module(struct og01a1b *og01a1b) | |
930 | { | |
931 | struct i2c_client *client = v4l2_get_subdevdata(&og01a1b->sd); | |
932 | int ret; | |
933 | u32 val; | |
934 | ||
935 | ret = og01a1b_read_reg(og01a1b, OG01A1B_REG_CHIP_ID, | |
936 | OG01A1B_REG_VALUE_24BIT, &val); | |
937 | if (ret) | |
938 | return ret; | |
939 | ||
940 | if (val != OG01A1B_CHIP_ID) { | |
941 | dev_err(&client->dev, "chip id mismatch: %x!=%x", | |
942 | OG01A1B_CHIP_ID, val); | |
943 | return -ENXIO; | |
944 | } | |
945 | ||
946 | return 0; | |
947 | } | |
948 | ||
949 | static int og01a1b_check_hwcfg(struct device *dev) | |
950 | { | |
951 | struct fwnode_handle *ep; | |
952 | struct fwnode_handle *fwnode = dev_fwnode(dev); | |
953 | struct v4l2_fwnode_endpoint bus_cfg = { | |
954 | .bus_type = V4L2_MBUS_CSI2_DPHY | |
955 | }; | |
956 | u32 mclk; | |
957 | int ret; | |
958 | unsigned int i, j; | |
959 | ||
960 | if (!fwnode) | |
961 | return -ENXIO; | |
962 | ||
963 | ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk); | |
964 | ||
965 | if (ret) { | |
966 | dev_err(dev, "can't get clock frequency"); | |
967 | return ret; | |
968 | } | |
969 | ||
970 | if (mclk != OG01A1B_MCLK) { | |
971 | dev_err(dev, "external clock %d is not supported", mclk); | |
972 | return -EINVAL; | |
973 | } | |
974 | ||
975 | ep = fwnode_graph_get_next_endpoint(fwnode, NULL); | |
976 | if (!ep) | |
977 | return -ENXIO; | |
978 | ||
979 | ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); | |
980 | fwnode_handle_put(ep); | |
981 | if (ret) | |
982 | return ret; | |
983 | ||
984 | if (bus_cfg.bus.mipi_csi2.num_data_lanes != OG01A1B_DATA_LANES) { | |
985 | dev_err(dev, "number of CSI2 data lanes %d is not supported", | |
986 | bus_cfg.bus.mipi_csi2.num_data_lanes); | |
987 | ret = -EINVAL; | |
988 | goto check_hwcfg_error; | |
989 | } | |
990 | ||
991 | if (!bus_cfg.nr_of_link_frequencies) { | |
992 | dev_err(dev, "no link frequencies defined"); | |
993 | ret = -EINVAL; | |
994 | goto check_hwcfg_error; | |
995 | } | |
996 | ||
997 | for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); i++) { | |
998 | for (j = 0; j < bus_cfg.nr_of_link_frequencies; j++) { | |
999 | if (link_freq_menu_items[i] == | |
1000 | bus_cfg.link_frequencies[j]) | |
1001 | break; | |
1002 | } | |
1003 | ||
1004 | if (j == bus_cfg.nr_of_link_frequencies) { | |
1005 | dev_err(dev, "no link frequency %lld supported", | |
1006 | link_freq_menu_items[i]); | |
1007 | ret = -EINVAL; | |
1008 | goto check_hwcfg_error; | |
1009 | } | |
1010 | } | |
1011 | ||
1012 | check_hwcfg_error: | |
1013 | v4l2_fwnode_endpoint_free(&bus_cfg); | |
1014 | ||
1015 | return ret; | |
1016 | } | |
1017 | ||
ed5c2f5f | 1018 | static void og01a1b_remove(struct i2c_client *client) |
472377fe ST |
1019 | { |
1020 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | |
1021 | struct og01a1b *og01a1b = to_og01a1b(sd); | |
1022 | ||
1023 | v4l2_async_unregister_subdev(sd); | |
1024 | media_entity_cleanup(&sd->entity); | |
1025 | v4l2_ctrl_handler_free(sd->ctrl_handler); | |
1026 | pm_runtime_disable(&client->dev); | |
1027 | mutex_destroy(&og01a1b->mutex); | |
472377fe ST |
1028 | } |
1029 | ||
1030 | static int og01a1b_probe(struct i2c_client *client) | |
1031 | { | |
1032 | struct og01a1b *og01a1b; | |
1033 | int ret; | |
1034 | ||
1035 | ret = og01a1b_check_hwcfg(&client->dev); | |
1036 | if (ret) { | |
1037 | dev_err(&client->dev, "failed to check HW configuration: %d", | |
1038 | ret); | |
1039 | return ret; | |
1040 | } | |
1041 | ||
1042 | og01a1b = devm_kzalloc(&client->dev, sizeof(*og01a1b), GFP_KERNEL); | |
1043 | if (!og01a1b) | |
1044 | return -ENOMEM; | |
1045 | ||
1046 | v4l2_i2c_subdev_init(&og01a1b->sd, client, &og01a1b_subdev_ops); | |
1047 | ret = og01a1b_identify_module(og01a1b); | |
1048 | if (ret) { | |
1049 | dev_err(&client->dev, "failed to find sensor: %d", ret); | |
1050 | return ret; | |
1051 | } | |
1052 | ||
1053 | mutex_init(&og01a1b->mutex); | |
1054 | og01a1b->cur_mode = &supported_modes[0]; | |
1055 | ret = og01a1b_init_controls(og01a1b); | |
1056 | if (ret) { | |
1057 | dev_err(&client->dev, "failed to init controls: %d", ret); | |
1058 | goto probe_error_v4l2_ctrl_handler_free; | |
1059 | } | |
1060 | ||
1061 | og01a1b->sd.internal_ops = &og01a1b_internal_ops; | |
1062 | og01a1b->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | |
1063 | og01a1b->sd.entity.ops = &og01a1b_subdev_entity_ops; | |
1064 | og01a1b->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; | |
1065 | og01a1b->pad.flags = MEDIA_PAD_FL_SOURCE; | |
1066 | ret = media_entity_pads_init(&og01a1b->sd.entity, 1, &og01a1b->pad); | |
1067 | if (ret) { | |
1068 | dev_err(&client->dev, "failed to init entity pads: %d", ret); | |
1069 | goto probe_error_v4l2_ctrl_handler_free; | |
1070 | } | |
1071 | ||
1072 | ret = v4l2_async_register_subdev_sensor(&og01a1b->sd); | |
1073 | if (ret < 0) { | |
1074 | dev_err(&client->dev, "failed to register V4L2 subdev: %d", | |
1075 | ret); | |
1076 | goto probe_error_media_entity_cleanup; | |
1077 | } | |
1078 | ||
1079 | /* | |
1080 | * Device is already turned on by i2c-core with ACPI domain PM. | |
1081 | * Enable runtime PM and turn off the device. | |
1082 | */ | |
1083 | pm_runtime_set_active(&client->dev); | |
1084 | pm_runtime_enable(&client->dev); | |
1085 | pm_runtime_idle(&client->dev); | |
1086 | ||
1087 | return 0; | |
1088 | ||
1089 | probe_error_media_entity_cleanup: | |
1090 | media_entity_cleanup(&og01a1b->sd.entity); | |
1091 | ||
1092 | probe_error_v4l2_ctrl_handler_free: | |
1093 | v4l2_ctrl_handler_free(og01a1b->sd.ctrl_handler); | |
1094 | mutex_destroy(&og01a1b->mutex); | |
1095 | ||
1096 | return ret; | |
1097 | } | |
1098 | ||
1099 | static const struct dev_pm_ops og01a1b_pm_ops = { | |
1100 | SET_SYSTEM_SLEEP_PM_OPS(og01a1b_suspend, og01a1b_resume) | |
1101 | }; | |
1102 | ||
1103 | #ifdef CONFIG_ACPI | |
1104 | static const struct acpi_device_id og01a1b_acpi_ids[] = { | |
1105 | {"OVTI01AC"}, | |
1106 | {} | |
1107 | }; | |
1108 | ||
1109 | MODULE_DEVICE_TABLE(acpi, og01a1b_acpi_ids); | |
1110 | #endif | |
1111 | ||
1112 | static struct i2c_driver og01a1b_i2c_driver = { | |
1113 | .driver = { | |
1114 | .name = "og01a1b", | |
1115 | .pm = &og01a1b_pm_ops, | |
1116 | .acpi_match_table = ACPI_PTR(og01a1b_acpi_ids), | |
1117 | }, | |
1118 | .probe_new = og01a1b_probe, | |
1119 | .remove = og01a1b_remove, | |
1120 | }; | |
1121 | ||
1122 | module_i2c_driver(og01a1b_i2c_driver); | |
1123 | ||
1124 | MODULE_AUTHOR("Shawn Tu <shawnx.tu@intel.com>"); | |
1125 | MODULE_DESCRIPTION("OmniVision OG01A1B sensor driver"); | |
1126 | MODULE_LICENSE("GPL v2"); |