Commit | Line | Data |
---|---|---|
43619059 RRD |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * imx214.c - imx214 sensor driver | |
4 | * | |
5 | * Copyright 2018 Qtechnology A/S | |
6 | * | |
7 | * Ricardo Ribalda <ricardo.ribalda@gmail.com> | |
8 | */ | |
9 | #include <linux/clk.h> | |
10 | #include <linux/delay.h> | |
11 | #include <linux/gpio/consumer.h> | |
12 | #include <linux/i2c.h> | |
13 | #include <linux/module.h> | |
14 | #include <linux/pm_runtime.h> | |
15 | #include <linux/regmap.h> | |
16 | #include <linux/regulator/consumer.h> | |
17 | #include <media/media-entity.h> | |
18 | #include <media/v4l2-ctrls.h> | |
19 | #include <media/v4l2-fwnode.h> | |
20 | #include <media/v4l2-subdev.h> | |
21 | ||
22 | #define IMX214_DEFAULT_CLK_FREQ 24000000 | |
23 | #define IMX214_DEFAULT_LINK_FREQ 480000000 | |
24 | #define IMX214_DEFAULT_PIXEL_RATE ((IMX214_DEFAULT_LINK_FREQ * 8LL) / 10) | |
25 | #define IMX214_FPS 30 | |
26 | #define IMX214_MBUS_CODE MEDIA_BUS_FMT_SRGGB10_1X10 | |
27 | ||
28 | static const char * const imx214_supply_name[] = { | |
29 | "vdda", | |
30 | "vddd", | |
31 | "vdddo", | |
32 | }; | |
33 | ||
34 | #define IMX214_NUM_SUPPLIES ARRAY_SIZE(imx214_supply_name) | |
35 | ||
36 | struct imx214 { | |
37 | struct device *dev; | |
38 | struct clk *xclk; | |
39 | struct regmap *regmap; | |
40 | ||
41 | struct v4l2_subdev sd; | |
42 | struct media_pad pad; | |
43 | struct v4l2_mbus_framefmt fmt; | |
44 | struct v4l2_rect crop; | |
45 | ||
46 | struct v4l2_ctrl_handler ctrls; | |
47 | struct v4l2_ctrl *pixel_rate; | |
48 | struct v4l2_ctrl *link_freq; | |
49 | struct v4l2_ctrl *exposure; | |
50 | ||
51 | struct regulator_bulk_data supplies[IMX214_NUM_SUPPLIES]; | |
52 | ||
53 | struct gpio_desc *enable_gpio; | |
54 | ||
55 | /* | |
56 | * Serialize control access, get/set format, get selection | |
57 | * and start streaming. | |
58 | */ | |
59 | struct mutex mutex; | |
60 | ||
61 | bool streaming; | |
62 | }; | |
63 | ||
64 | struct reg_8 { | |
65 | u16 addr; | |
66 | u8 val; | |
67 | }; | |
68 | ||
69 | enum { | |
70 | IMX214_TABLE_WAIT_MS = 0, | |
71 | IMX214_TABLE_END, | |
72 | IMX214_MAX_RETRIES, | |
73 | IMX214_WAIT_MS | |
74 | }; | |
75 | ||
76 | /*From imx214_mode_tbls.h*/ | |
77 | static const struct reg_8 mode_4096x2304[] = { | |
78 | {0x0114, 0x03}, | |
79 | {0x0220, 0x00}, | |
80 | {0x0221, 0x11}, | |
81 | {0x0222, 0x01}, | |
82 | {0x0340, 0x0C}, | |
83 | {0x0341, 0x7A}, | |
84 | {0x0342, 0x13}, | |
85 | {0x0343, 0x90}, | |
86 | {0x0344, 0x00}, | |
87 | {0x0345, 0x38}, | |
88 | {0x0346, 0x01}, | |
89 | {0x0347, 0x98}, | |
90 | {0x0348, 0x10}, | |
91 | {0x0349, 0x37}, | |
92 | {0x034A, 0x0A}, | |
93 | {0x034B, 0x97}, | |
94 | {0x0381, 0x01}, | |
95 | {0x0383, 0x01}, | |
96 | {0x0385, 0x01}, | |
97 | {0x0387, 0x01}, | |
98 | {0x0900, 0x00}, | |
99 | {0x0901, 0x00}, | |
100 | {0x0902, 0x00}, | |
101 | {0x3000, 0x35}, | |
102 | {0x3054, 0x01}, | |
103 | {0x305C, 0x11}, | |
104 | ||
105 | {0x0112, 0x0A}, | |
106 | {0x0113, 0x0A}, | |
107 | {0x034C, 0x10}, | |
108 | {0x034D, 0x00}, | |
109 | {0x034E, 0x09}, | |
110 | {0x034F, 0x00}, | |
111 | {0x0401, 0x00}, | |
112 | {0x0404, 0x00}, | |
113 | {0x0405, 0x10}, | |
114 | {0x0408, 0x00}, | |
115 | {0x0409, 0x00}, | |
116 | {0x040A, 0x00}, | |
117 | {0x040B, 0x00}, | |
118 | {0x040C, 0x10}, | |
119 | {0x040D, 0x00}, | |
120 | {0x040E, 0x09}, | |
121 | {0x040F, 0x00}, | |
122 | ||
123 | {0x0301, 0x05}, | |
124 | {0x0303, 0x02}, | |
125 | {0x0305, 0x03}, | |
126 | {0x0306, 0x00}, | |
127 | {0x0307, 0x96}, | |
128 | {0x0309, 0x0A}, | |
129 | {0x030B, 0x01}, | |
130 | {0x0310, 0x00}, | |
131 | ||
132 | {0x0820, 0x12}, | |
133 | {0x0821, 0xC0}, | |
134 | {0x0822, 0x00}, | |
135 | {0x0823, 0x00}, | |
136 | ||
137 | {0x3A03, 0x09}, | |
138 | {0x3A04, 0x50}, | |
139 | {0x3A05, 0x01}, | |
140 | ||
141 | {0x0B06, 0x01}, | |
142 | {0x30A2, 0x00}, | |
143 | ||
144 | {0x30B4, 0x00}, | |
145 | ||
146 | {0x3A02, 0xFF}, | |
147 | ||
148 | {0x3011, 0x00}, | |
149 | {0x3013, 0x01}, | |
150 | ||
151 | {0x0202, 0x0C}, | |
152 | {0x0203, 0x70}, | |
153 | {0x0224, 0x01}, | |
154 | {0x0225, 0xF4}, | |
155 | ||
156 | {0x0204, 0x00}, | |
157 | {0x0205, 0x00}, | |
158 | {0x020E, 0x01}, | |
159 | {0x020F, 0x00}, | |
160 | {0x0210, 0x01}, | |
161 | {0x0211, 0x00}, | |
162 | {0x0212, 0x01}, | |
163 | {0x0213, 0x00}, | |
164 | {0x0214, 0x01}, | |
165 | {0x0215, 0x00}, | |
166 | {0x0216, 0x00}, | |
167 | {0x0217, 0x00}, | |
168 | ||
169 | {0x4170, 0x00}, | |
170 | {0x4171, 0x10}, | |
171 | {0x4176, 0x00}, | |
172 | {0x4177, 0x3C}, | |
173 | {0xAE20, 0x04}, | |
174 | {0xAE21, 0x5C}, | |
175 | ||
176 | {IMX214_TABLE_WAIT_MS, 10}, | |
177 | {0x0138, 0x01}, | |
178 | {IMX214_TABLE_END, 0x00} | |
179 | }; | |
180 | ||
181 | static const struct reg_8 mode_1920x1080[] = { | |
182 | {0x0114, 0x03}, | |
183 | {0x0220, 0x00}, | |
184 | {0x0221, 0x11}, | |
185 | {0x0222, 0x01}, | |
186 | {0x0340, 0x0C}, | |
187 | {0x0341, 0x7A}, | |
188 | {0x0342, 0x13}, | |
189 | {0x0343, 0x90}, | |
190 | {0x0344, 0x04}, | |
191 | {0x0345, 0x78}, | |
192 | {0x0346, 0x03}, | |
193 | {0x0347, 0xFC}, | |
194 | {0x0348, 0x0B}, | |
195 | {0x0349, 0xF7}, | |
196 | {0x034A, 0x08}, | |
197 | {0x034B, 0x33}, | |
198 | {0x0381, 0x01}, | |
199 | {0x0383, 0x01}, | |
200 | {0x0385, 0x01}, | |
201 | {0x0387, 0x01}, | |
202 | {0x0900, 0x00}, | |
203 | {0x0901, 0x00}, | |
204 | {0x0902, 0x00}, | |
205 | {0x3000, 0x35}, | |
206 | {0x3054, 0x01}, | |
207 | {0x305C, 0x11}, | |
208 | ||
209 | {0x0112, 0x0A}, | |
210 | {0x0113, 0x0A}, | |
211 | {0x034C, 0x07}, | |
212 | {0x034D, 0x80}, | |
213 | {0x034E, 0x04}, | |
214 | {0x034F, 0x38}, | |
215 | {0x0401, 0x00}, | |
216 | {0x0404, 0x00}, | |
217 | {0x0405, 0x10}, | |
218 | {0x0408, 0x00}, | |
219 | {0x0409, 0x00}, | |
220 | {0x040A, 0x00}, | |
221 | {0x040B, 0x00}, | |
222 | {0x040C, 0x07}, | |
223 | {0x040D, 0x80}, | |
224 | {0x040E, 0x04}, | |
225 | {0x040F, 0x38}, | |
226 | ||
227 | {0x0301, 0x05}, | |
228 | {0x0303, 0x02}, | |
229 | {0x0305, 0x03}, | |
230 | {0x0306, 0x00}, | |
231 | {0x0307, 0x96}, | |
232 | {0x0309, 0x0A}, | |
233 | {0x030B, 0x01}, | |
234 | {0x0310, 0x00}, | |
235 | ||
236 | {0x0820, 0x12}, | |
237 | {0x0821, 0xC0}, | |
238 | {0x0822, 0x00}, | |
239 | {0x0823, 0x00}, | |
240 | ||
241 | {0x3A03, 0x04}, | |
242 | {0x3A04, 0xF8}, | |
243 | {0x3A05, 0x02}, | |
244 | ||
245 | {0x0B06, 0x01}, | |
246 | {0x30A2, 0x00}, | |
247 | ||
248 | {0x30B4, 0x00}, | |
249 | ||
250 | {0x3A02, 0xFF}, | |
251 | ||
252 | {0x3011, 0x00}, | |
253 | {0x3013, 0x01}, | |
254 | ||
255 | {0x0202, 0x0C}, | |
256 | {0x0203, 0x70}, | |
257 | {0x0224, 0x01}, | |
258 | {0x0225, 0xF4}, | |
259 | ||
260 | {0x0204, 0x00}, | |
261 | {0x0205, 0x00}, | |
262 | {0x020E, 0x01}, | |
263 | {0x020F, 0x00}, | |
264 | {0x0210, 0x01}, | |
265 | {0x0211, 0x00}, | |
266 | {0x0212, 0x01}, | |
267 | {0x0213, 0x00}, | |
268 | {0x0214, 0x01}, | |
269 | {0x0215, 0x00}, | |
270 | {0x0216, 0x00}, | |
271 | {0x0217, 0x00}, | |
272 | ||
273 | {0x4170, 0x00}, | |
274 | {0x4171, 0x10}, | |
275 | {0x4176, 0x00}, | |
276 | {0x4177, 0x3C}, | |
277 | {0xAE20, 0x04}, | |
278 | {0xAE21, 0x5C}, | |
279 | ||
280 | {IMX214_TABLE_WAIT_MS, 10}, | |
281 | {0x0138, 0x01}, | |
282 | {IMX214_TABLE_END, 0x00} | |
283 | }; | |
284 | ||
285 | static const struct reg_8 mode_table_common[] = { | |
286 | /* software reset */ | |
287 | ||
288 | /* software standby settings */ | |
289 | {0x0100, 0x00}, | |
290 | ||
291 | /* ATR setting */ | |
292 | {0x9300, 0x02}, | |
293 | ||
294 | /* external clock setting */ | |
295 | {0x0136, 0x18}, | |
296 | {0x0137, 0x00}, | |
297 | ||
298 | /* global setting */ | |
299 | /* basic config */ | |
300 | {0x0101, 0x00}, | |
301 | {0x0105, 0x01}, | |
302 | {0x0106, 0x01}, | |
303 | {0x4550, 0x02}, | |
304 | {0x4601, 0x00}, | |
305 | {0x4642, 0x05}, | |
306 | {0x6227, 0x11}, | |
307 | {0x6276, 0x00}, | |
308 | {0x900E, 0x06}, | |
309 | {0xA802, 0x90}, | |
310 | {0xA803, 0x11}, | |
311 | {0xA804, 0x62}, | |
312 | {0xA805, 0x77}, | |
313 | {0xA806, 0xAE}, | |
314 | {0xA807, 0x34}, | |
315 | {0xA808, 0xAE}, | |
316 | {0xA809, 0x35}, | |
317 | {0xA80A, 0x62}, | |
318 | {0xA80B, 0x83}, | |
319 | {0xAE33, 0x00}, | |
320 | ||
321 | /* analog setting */ | |
322 | {0x4174, 0x00}, | |
323 | {0x4175, 0x11}, | |
324 | {0x4612, 0x29}, | |
325 | {0x461B, 0x12}, | |
326 | {0x461F, 0x06}, | |
327 | {0x4635, 0x07}, | |
328 | {0x4637, 0x30}, | |
329 | {0x463F, 0x18}, | |
330 | {0x4641, 0x0D}, | |
331 | {0x465B, 0x12}, | |
332 | {0x465F, 0x11}, | |
333 | {0x4663, 0x11}, | |
334 | {0x4667, 0x0F}, | |
335 | {0x466F, 0x0F}, | |
336 | {0x470E, 0x09}, | |
337 | {0x4909, 0xAB}, | |
338 | {0x490B, 0x95}, | |
339 | {0x4915, 0x5D}, | |
340 | {0x4A5F, 0xFF}, | |
341 | {0x4A61, 0xFF}, | |
342 | {0x4A73, 0x62}, | |
343 | {0x4A85, 0x00}, | |
344 | {0x4A87, 0xFF}, | |
345 | ||
346 | /* embedded data */ | |
347 | {0x5041, 0x04}, | |
348 | {0x583C, 0x04}, | |
349 | {0x620E, 0x04}, | |
350 | {0x6EB2, 0x01}, | |
351 | {0x6EB3, 0x00}, | |
352 | {0x9300, 0x02}, | |
353 | ||
354 | /* imagequality */ | |
355 | /* HDR setting */ | |
356 | {0x3001, 0x07}, | |
357 | {0x6D12, 0x3F}, | |
358 | {0x6D13, 0xFF}, | |
359 | {0x9344, 0x03}, | |
360 | {0x9706, 0x10}, | |
361 | {0x9707, 0x03}, | |
362 | {0x9708, 0x03}, | |
363 | {0x9E04, 0x01}, | |
364 | {0x9E05, 0x00}, | |
365 | {0x9E0C, 0x01}, | |
366 | {0x9E0D, 0x02}, | |
367 | {0x9E24, 0x00}, | |
368 | {0x9E25, 0x8C}, | |
369 | {0x9E26, 0x00}, | |
370 | {0x9E27, 0x94}, | |
371 | {0x9E28, 0x00}, | |
372 | {0x9E29, 0x96}, | |
373 | ||
374 | /* CNR parameter setting */ | |
375 | {0x69DB, 0x01}, | |
376 | ||
377 | /* Moire reduction */ | |
378 | {0x6957, 0x01}, | |
379 | ||
f8a7647d | 380 | /* image enhancement */ |
43619059 RRD |
381 | {0x6987, 0x17}, |
382 | {0x698A, 0x03}, | |
383 | {0x698B, 0x03}, | |
384 | ||
385 | /* white balanace */ | |
386 | {0x0B8E, 0x01}, | |
387 | {0x0B8F, 0x00}, | |
388 | {0x0B90, 0x01}, | |
389 | {0x0B91, 0x00}, | |
390 | {0x0B92, 0x01}, | |
391 | {0x0B93, 0x00}, | |
392 | {0x0B94, 0x01}, | |
393 | {0x0B95, 0x00}, | |
394 | ||
395 | /* ATR setting */ | |
396 | {0x6E50, 0x00}, | |
397 | {0x6E51, 0x32}, | |
398 | {0x9340, 0x00}, | |
399 | {0x9341, 0x3C}, | |
400 | {0x9342, 0x03}, | |
401 | {0x9343, 0xFF}, | |
402 | {IMX214_TABLE_END, 0x00} | |
403 | }; | |
404 | ||
405 | /* | |
406 | * Declare modes in order, from biggest | |
407 | * to smallest height. | |
408 | */ | |
409 | static const struct imx214_mode { | |
410 | u32 width; | |
411 | u32 height; | |
412 | const struct reg_8 *reg_table; | |
413 | } imx214_modes[] = { | |
414 | { | |
415 | .width = 4096, | |
416 | .height = 2304, | |
417 | .reg_table = mode_4096x2304, | |
418 | }, | |
419 | { | |
420 | .width = 1920, | |
421 | .height = 1080, | |
422 | .reg_table = mode_1920x1080, | |
423 | }, | |
424 | }; | |
425 | ||
426 | static inline struct imx214 *to_imx214(struct v4l2_subdev *sd) | |
427 | { | |
428 | return container_of(sd, struct imx214, sd); | |
429 | } | |
430 | ||
431 | static int __maybe_unused imx214_power_on(struct device *dev) | |
432 | { | |
433 | struct i2c_client *client = to_i2c_client(dev); | |
434 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | |
435 | struct imx214 *imx214 = to_imx214(sd); | |
436 | int ret; | |
437 | ||
438 | ret = regulator_bulk_enable(IMX214_NUM_SUPPLIES, imx214->supplies); | |
439 | if (ret < 0) { | |
440 | dev_err(imx214->dev, "failed to enable regulators: %d\n", ret); | |
441 | return ret; | |
442 | } | |
443 | ||
444 | usleep_range(2000, 3000); | |
445 | ||
446 | ret = clk_prepare_enable(imx214->xclk); | |
447 | if (ret < 0) { | |
448 | regulator_bulk_disable(IMX214_NUM_SUPPLIES, imx214->supplies); | |
449 | dev_err(imx214->dev, "clk prepare enable failed\n"); | |
450 | return ret; | |
451 | } | |
452 | ||
453 | gpiod_set_value_cansleep(imx214->enable_gpio, 1); | |
454 | usleep_range(12000, 15000); | |
455 | ||
456 | return 0; | |
457 | } | |
458 | ||
459 | static int __maybe_unused imx214_power_off(struct device *dev) | |
460 | { | |
461 | struct i2c_client *client = to_i2c_client(dev); | |
462 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | |
463 | struct imx214 *imx214 = to_imx214(sd); | |
464 | ||
465 | gpiod_set_value_cansleep(imx214->enable_gpio, 0); | |
466 | ||
467 | clk_disable_unprepare(imx214->xclk); | |
468 | ||
469 | regulator_bulk_disable(IMX214_NUM_SUPPLIES, imx214->supplies); | |
470 | usleep_range(10, 20); | |
471 | ||
472 | return 0; | |
473 | } | |
474 | ||
475 | static int imx214_enum_mbus_code(struct v4l2_subdev *sd, | |
476 | struct v4l2_subdev_pad_config *cfg, | |
477 | struct v4l2_subdev_mbus_code_enum *code) | |
478 | { | |
479 | if (code->index > 0) | |
480 | return -EINVAL; | |
481 | ||
482 | code->code = IMX214_MBUS_CODE; | |
483 | ||
484 | return 0; | |
485 | } | |
486 | ||
487 | static int imx214_enum_frame_size(struct v4l2_subdev *subdev, | |
488 | struct v4l2_subdev_pad_config *cfg, | |
489 | struct v4l2_subdev_frame_size_enum *fse) | |
490 | { | |
491 | if (fse->code != IMX214_MBUS_CODE) | |
492 | return -EINVAL; | |
493 | ||
494 | if (fse->index >= ARRAY_SIZE(imx214_modes)) | |
495 | return -EINVAL; | |
496 | ||
497 | fse->min_width = fse->max_width = imx214_modes[fse->index].width; | |
498 | fse->min_height = fse->max_height = imx214_modes[fse->index].height; | |
499 | ||
500 | return 0; | |
501 | } | |
502 | ||
503 | #ifdef CONFIG_VIDEO_ADV_DEBUG | |
504 | static int imx214_s_register(struct v4l2_subdev *subdev, | |
505 | const struct v4l2_dbg_register *reg) | |
506 | { | |
507 | struct imx214 *imx214 = container_of(subdev, struct imx214, sd); | |
508 | ||
509 | return regmap_write(imx214->regmap, reg->reg, reg->val); | |
510 | } | |
511 | ||
512 | static int imx214_g_register(struct v4l2_subdev *subdev, | |
513 | struct v4l2_dbg_register *reg) | |
514 | { | |
515 | struct imx214 *imx214 = container_of(subdev, struct imx214, sd); | |
516 | unsigned int aux; | |
517 | int ret; | |
518 | ||
519 | reg->size = 1; | |
520 | ret = regmap_read(imx214->regmap, reg->reg, &aux); | |
521 | reg->val = aux; | |
522 | ||
523 | return ret; | |
524 | } | |
525 | #endif | |
526 | ||
527 | static const struct v4l2_subdev_core_ops imx214_core_ops = { | |
528 | #ifdef CONFIG_VIDEO_ADV_DEBUG | |
529 | .g_register = imx214_g_register, | |
530 | .s_register = imx214_s_register, | |
531 | #endif | |
532 | }; | |
533 | ||
534 | static struct v4l2_mbus_framefmt * | |
535 | __imx214_get_pad_format(struct imx214 *imx214, | |
536 | struct v4l2_subdev_pad_config *cfg, | |
537 | unsigned int pad, | |
538 | enum v4l2_subdev_format_whence which) | |
539 | { | |
540 | switch (which) { | |
541 | case V4L2_SUBDEV_FORMAT_TRY: | |
542 | return v4l2_subdev_get_try_format(&imx214->sd, cfg, pad); | |
543 | case V4L2_SUBDEV_FORMAT_ACTIVE: | |
544 | return &imx214->fmt; | |
545 | default: | |
546 | return NULL; | |
547 | } | |
548 | } | |
549 | ||
550 | static int imx214_get_format(struct v4l2_subdev *sd, | |
551 | struct v4l2_subdev_pad_config *cfg, | |
552 | struct v4l2_subdev_format *format) | |
553 | { | |
554 | struct imx214 *imx214 = to_imx214(sd); | |
555 | ||
556 | mutex_lock(&imx214->mutex); | |
557 | format->format = *__imx214_get_pad_format(imx214, cfg, format->pad, | |
558 | format->which); | |
559 | mutex_unlock(&imx214->mutex); | |
560 | ||
561 | return 0; | |
562 | } | |
563 | ||
564 | static struct v4l2_rect * | |
565 | __imx214_get_pad_crop(struct imx214 *imx214, struct v4l2_subdev_pad_config *cfg, | |
566 | unsigned int pad, enum v4l2_subdev_format_whence which) | |
567 | { | |
568 | switch (which) { | |
569 | case V4L2_SUBDEV_FORMAT_TRY: | |
570 | return v4l2_subdev_get_try_crop(&imx214->sd, cfg, pad); | |
571 | case V4L2_SUBDEV_FORMAT_ACTIVE: | |
572 | return &imx214->crop; | |
573 | default: | |
574 | return NULL; | |
575 | } | |
576 | } | |
577 | ||
578 | static int imx214_set_format(struct v4l2_subdev *sd, | |
579 | struct v4l2_subdev_pad_config *cfg, | |
580 | struct v4l2_subdev_format *format) | |
581 | { | |
582 | struct imx214 *imx214 = to_imx214(sd); | |
583 | struct v4l2_mbus_framefmt *__format; | |
584 | struct v4l2_rect *__crop; | |
585 | const struct imx214_mode *mode; | |
586 | ||
587 | mutex_lock(&imx214->mutex); | |
588 | ||
589 | __crop = __imx214_get_pad_crop(imx214, cfg, format->pad, format->which); | |
590 | ||
153d11cc MCC |
591 | mode = v4l2_find_nearest_size(imx214_modes, |
592 | ARRAY_SIZE(imx214_modes), width, height, | |
593 | format->format.width, | |
594 | format->format.height); | |
43619059 RRD |
595 | |
596 | __crop->width = mode->width; | |
597 | __crop->height = mode->height; | |
598 | ||
599 | __format = __imx214_get_pad_format(imx214, cfg, format->pad, | |
600 | format->which); | |
601 | __format->width = __crop->width; | |
602 | __format->height = __crop->height; | |
603 | __format->code = IMX214_MBUS_CODE; | |
604 | __format->field = V4L2_FIELD_NONE; | |
605 | __format->colorspace = V4L2_COLORSPACE_SRGB; | |
606 | __format->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(__format->colorspace); | |
607 | __format->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, | |
608 | __format->colorspace, __format->ycbcr_enc); | |
609 | __format->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(__format->colorspace); | |
610 | ||
611 | format->format = *__format; | |
612 | ||
613 | mutex_unlock(&imx214->mutex); | |
614 | ||
615 | return 0; | |
616 | } | |
617 | ||
618 | static int imx214_get_selection(struct v4l2_subdev *sd, | |
619 | struct v4l2_subdev_pad_config *cfg, | |
620 | struct v4l2_subdev_selection *sel) | |
621 | { | |
622 | struct imx214 *imx214 = to_imx214(sd); | |
623 | ||
624 | if (sel->target != V4L2_SEL_TGT_CROP) | |
625 | return -EINVAL; | |
626 | ||
627 | mutex_lock(&imx214->mutex); | |
628 | sel->r = *__imx214_get_pad_crop(imx214, cfg, sel->pad, | |
629 | sel->which); | |
630 | mutex_unlock(&imx214->mutex); | |
631 | return 0; | |
632 | } | |
633 | ||
634 | static int imx214_entity_init_cfg(struct v4l2_subdev *subdev, | |
635 | struct v4l2_subdev_pad_config *cfg) | |
636 | { | |
637 | struct v4l2_subdev_format fmt = { }; | |
638 | ||
639 | fmt.which = cfg ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; | |
640 | fmt.format.width = imx214_modes[0].width; | |
641 | fmt.format.height = imx214_modes[0].height; | |
642 | ||
643 | imx214_set_format(subdev, cfg, &fmt); | |
644 | ||
645 | return 0; | |
646 | } | |
647 | ||
648 | static int imx214_set_ctrl(struct v4l2_ctrl *ctrl) | |
649 | { | |
650 | struct imx214 *imx214 = container_of(ctrl->handler, | |
651 | struct imx214, ctrls); | |
652 | u8 vals[2]; | |
653 | int ret; | |
654 | ||
655 | /* | |
656 | * Applying V4L2 control value only happens | |
657 | * when power is up for streaming | |
658 | */ | |
659 | if (!pm_runtime_get_if_in_use(imx214->dev)) | |
660 | return 0; | |
661 | ||
662 | switch (ctrl->id) { | |
663 | case V4L2_CID_EXPOSURE: | |
664 | vals[1] = ctrl->val; | |
665 | vals[0] = ctrl->val >> 8; | |
666 | ret = regmap_bulk_write(imx214->regmap, 0x202, vals, 2); | |
667 | if (ret < 0) | |
668 | dev_err(imx214->dev, "Error %d\n", ret); | |
669 | ret = 0; | |
670 | break; | |
671 | ||
672 | default: | |
673 | ret = -EINVAL; | |
674 | } | |
675 | ||
676 | pm_runtime_put(imx214->dev); | |
677 | ||
678 | return ret; | |
679 | } | |
680 | ||
681 | static const struct v4l2_ctrl_ops imx214_ctrl_ops = { | |
682 | .s_ctrl = imx214_set_ctrl, | |
683 | }; | |
684 | ||
685 | #define MAX_CMD 4 | |
686 | static int imx214_write_table(struct imx214 *imx214, | |
687 | const struct reg_8 table[]) | |
688 | { | |
689 | u8 vals[MAX_CMD]; | |
690 | int i; | |
691 | int ret; | |
692 | ||
cb24f1a0 | 693 | for (; table->addr != IMX214_TABLE_END ; table++) { |
43619059 RRD |
694 | if (table->addr == IMX214_TABLE_WAIT_MS) { |
695 | usleep_range(table->val * 1000, | |
696 | table->val * 1000 + 500); | |
697 | continue; | |
698 | } | |
699 | ||
700 | for (i = 0; i < MAX_CMD; i++) { | |
701 | if (table[i].addr != (table[0].addr + i)) | |
702 | break; | |
703 | vals[i] = table[i].val; | |
704 | } | |
705 | ||
706 | ret = regmap_bulk_write(imx214->regmap, table->addr, vals, i); | |
707 | ||
708 | if (ret) { | |
709 | dev_err(imx214->dev, "write_table error: %d\n", ret); | |
710 | return ret; | |
711 | } | |
712 | ||
713 | table += i - 1; | |
714 | } | |
715 | ||
716 | return 0; | |
717 | } | |
718 | ||
719 | static int imx214_start_streaming(struct imx214 *imx214) | |
720 | { | |
721 | const struct imx214_mode *mode; | |
722 | int ret; | |
723 | ||
724 | mutex_lock(&imx214->mutex); | |
725 | ret = imx214_write_table(imx214, mode_table_common); | |
726 | if (ret < 0) { | |
727 | dev_err(imx214->dev, "could not sent common table %d\n", ret); | |
728 | goto error; | |
729 | } | |
730 | ||
731 | mode = v4l2_find_nearest_size(imx214_modes, | |
732 | ARRAY_SIZE(imx214_modes), width, height, | |
733 | imx214->fmt.width, imx214->fmt.height); | |
734 | ret = imx214_write_table(imx214, mode->reg_table); | |
735 | if (ret < 0) { | |
736 | dev_err(imx214->dev, "could not sent mode table %d\n", ret); | |
737 | goto error; | |
738 | } | |
739 | ret = __v4l2_ctrl_handler_setup(&imx214->ctrls); | |
740 | if (ret < 0) { | |
741 | dev_err(imx214->dev, "could not sync v4l2 controls\n"); | |
742 | goto error; | |
743 | } | |
744 | ret = regmap_write(imx214->regmap, 0x100, 1); | |
745 | if (ret < 0) { | |
746 | dev_err(imx214->dev, "could not sent start table %d\n", ret); | |
747 | goto error; | |
748 | } | |
749 | ||
750 | mutex_unlock(&imx214->mutex); | |
751 | return 0; | |
752 | ||
753 | error: | |
754 | mutex_unlock(&imx214->mutex); | |
755 | return ret; | |
756 | } | |
757 | ||
758 | static int imx214_stop_streaming(struct imx214 *imx214) | |
759 | { | |
760 | int ret; | |
761 | ||
762 | ret = regmap_write(imx214->regmap, 0x100, 0); | |
763 | if (ret < 0) | |
764 | dev_err(imx214->dev, "could not sent stop table %d\n", ret); | |
765 | ||
766 | return ret; | |
767 | } | |
768 | ||
769 | static int imx214_s_stream(struct v4l2_subdev *subdev, int enable) | |
770 | { | |
771 | struct imx214 *imx214 = to_imx214(subdev); | |
772 | int ret; | |
773 | ||
774 | if (imx214->streaming == enable) | |
775 | return 0; | |
776 | ||
777 | if (enable) { | |
778 | ret = pm_runtime_get_sync(imx214->dev); | |
779 | if (ret < 0) { | |
780 | pm_runtime_put_noidle(imx214->dev); | |
781 | return ret; | |
782 | } | |
783 | ||
784 | ret = imx214_start_streaming(imx214); | |
785 | if (ret < 0) | |
786 | goto err_rpm_put; | |
787 | } else { | |
788 | ret = imx214_start_streaming(imx214); | |
789 | if (ret < 0) | |
790 | goto err_rpm_put; | |
791 | pm_runtime_put(imx214->dev); | |
792 | } | |
793 | ||
794 | imx214->streaming = enable; | |
795 | return 0; | |
796 | ||
797 | err_rpm_put: | |
798 | pm_runtime_put(imx214->dev); | |
799 | return ret; | |
800 | } | |
801 | ||
802 | static int imx214_g_frame_interval(struct v4l2_subdev *subdev, | |
803 | struct v4l2_subdev_frame_interval *fival) | |
804 | { | |
805 | fival->pad = 0; | |
806 | fival->interval.numerator = 1; | |
807 | fival->interval.denominator = IMX214_FPS; | |
808 | ||
809 | return 0; | |
810 | } | |
811 | ||
812 | static int imx214_enum_frame_interval(struct v4l2_subdev *subdev, | |
813 | struct v4l2_subdev_pad_config *cfg, | |
814 | struct v4l2_subdev_frame_interval_enum *fie) | |
815 | { | |
816 | const struct imx214_mode *mode; | |
817 | ||
818 | if (fie->index != 0) | |
819 | return -EINVAL; | |
820 | ||
821 | mode = v4l2_find_nearest_size(imx214_modes, | |
822 | ARRAY_SIZE(imx214_modes), width, height, | |
823 | fie->width, fie->height); | |
824 | ||
825 | fie->code = IMX214_MBUS_CODE; | |
826 | fie->width = mode->width; | |
827 | fie->height = mode->height; | |
828 | fie->interval.numerator = 1; | |
829 | fie->interval.denominator = IMX214_FPS; | |
830 | ||
831 | return 0; | |
832 | } | |
833 | ||
834 | static const struct v4l2_subdev_video_ops imx214_video_ops = { | |
835 | .s_stream = imx214_s_stream, | |
836 | .g_frame_interval = imx214_g_frame_interval, | |
837 | .s_frame_interval = imx214_g_frame_interval, | |
838 | }; | |
839 | ||
840 | static const struct v4l2_subdev_pad_ops imx214_subdev_pad_ops = { | |
841 | .enum_mbus_code = imx214_enum_mbus_code, | |
842 | .enum_frame_size = imx214_enum_frame_size, | |
843 | .enum_frame_interval = imx214_enum_frame_interval, | |
844 | .get_fmt = imx214_get_format, | |
845 | .set_fmt = imx214_set_format, | |
846 | .get_selection = imx214_get_selection, | |
847 | .init_cfg = imx214_entity_init_cfg, | |
848 | }; | |
849 | ||
850 | static const struct v4l2_subdev_ops imx214_subdev_ops = { | |
851 | .core = &imx214_core_ops, | |
852 | .video = &imx214_video_ops, | |
853 | .pad = &imx214_subdev_pad_ops, | |
854 | }; | |
855 | ||
856 | static const struct regmap_config sensor_regmap_config = { | |
857 | .reg_bits = 16, | |
858 | .val_bits = 8, | |
859 | .cache_type = REGCACHE_RBTREE, | |
860 | }; | |
861 | ||
862 | static int imx214_get_regulators(struct device *dev, struct imx214 *imx214) | |
863 | { | |
864 | unsigned int i; | |
865 | ||
866 | for (i = 0; i < IMX214_NUM_SUPPLIES; i++) | |
867 | imx214->supplies[i].supply = imx214_supply_name[i]; | |
868 | ||
869 | return devm_regulator_bulk_get(dev, IMX214_NUM_SUPPLIES, | |
870 | imx214->supplies); | |
871 | } | |
872 | ||
873 | static int imx214_parse_fwnode(struct device *dev) | |
874 | { | |
875 | struct fwnode_handle *endpoint; | |
876 | struct v4l2_fwnode_endpoint bus_cfg = { | |
877 | .bus_type = V4L2_MBUS_CSI2_DPHY, | |
878 | }; | |
879 | unsigned int i; | |
880 | int ret; | |
881 | ||
882 | endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL); | |
883 | if (!endpoint) { | |
884 | dev_err(dev, "endpoint node not found\n"); | |
885 | return -EINVAL; | |
886 | } | |
887 | ||
888 | ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &bus_cfg); | |
889 | if (ret) { | |
890 | dev_err(dev, "parsing endpoint node failed\n"); | |
891 | goto done; | |
892 | } | |
893 | ||
894 | for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) | |
895 | if (bus_cfg.link_frequencies[i] == IMX214_DEFAULT_LINK_FREQ) | |
896 | break; | |
897 | ||
898 | if (i == bus_cfg.nr_of_link_frequencies) { | |
899 | dev_err(dev, "link-frequencies %d not supported, Please review your DT\n", | |
900 | IMX214_DEFAULT_LINK_FREQ); | |
901 | ret = -EINVAL; | |
902 | goto done; | |
903 | } | |
904 | ||
905 | done: | |
906 | v4l2_fwnode_endpoint_free(&bus_cfg); | |
907 | fwnode_handle_put(endpoint); | |
908 | return ret; | |
909 | } | |
910 | ||
911 | static int __maybe_unused imx214_suspend(struct device *dev) | |
912 | { | |
913 | struct i2c_client *client = to_i2c_client(dev); | |
914 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | |
915 | struct imx214 *imx214 = to_imx214(sd); | |
916 | ||
917 | if (imx214->streaming) | |
918 | imx214_stop_streaming(imx214); | |
919 | ||
920 | return 0; | |
921 | } | |
922 | ||
923 | static int __maybe_unused imx214_resume(struct device *dev) | |
924 | { | |
925 | struct i2c_client *client = to_i2c_client(dev); | |
926 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | |
927 | struct imx214 *imx214 = to_imx214(sd); | |
928 | int ret; | |
929 | ||
930 | if (imx214->streaming) { | |
931 | ret = imx214_start_streaming(imx214); | |
932 | if (ret) | |
933 | goto error; | |
934 | } | |
935 | ||
936 | return 0; | |
937 | ||
938 | error: | |
939 | imx214_stop_streaming(imx214); | |
940 | imx214->streaming = 0; | |
941 | return ret; | |
942 | } | |
943 | ||
944 | static int imx214_probe(struct i2c_client *client) | |
945 | { | |
946 | struct device *dev = &client->dev; | |
947 | struct imx214 *imx214; | |
948 | static const s64 link_freq[] = { | |
949 | IMX214_DEFAULT_LINK_FREQ, | |
950 | }; | |
951 | int ret; | |
952 | ||
953 | ret = imx214_parse_fwnode(dev); | |
954 | if (ret) | |
955 | return ret; | |
956 | ||
957 | imx214 = devm_kzalloc(dev, sizeof(*imx214), GFP_KERNEL); | |
958 | if (!imx214) | |
959 | return -ENOMEM; | |
960 | ||
961 | imx214->dev = dev; | |
962 | ||
963 | imx214->xclk = devm_clk_get(dev, NULL); | |
964 | if (IS_ERR(imx214->xclk)) { | |
965 | dev_err(dev, "could not get xclk"); | |
966 | return PTR_ERR(imx214->xclk); | |
967 | } | |
968 | ||
969 | ret = clk_set_rate(imx214->xclk, IMX214_DEFAULT_CLK_FREQ); | |
970 | if (ret) { | |
971 | dev_err(dev, "could not set xclk frequency\n"); | |
972 | return ret; | |
973 | } | |
974 | ||
975 | ret = imx214_get_regulators(dev, imx214); | |
976 | if (ret < 0) { | |
977 | dev_err(dev, "cannot get regulators\n"); | |
978 | return ret; | |
979 | } | |
980 | ||
981 | imx214->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); | |
982 | if (IS_ERR(imx214->enable_gpio)) { | |
983 | dev_err(dev, "cannot get enable gpio\n"); | |
984 | return PTR_ERR(imx214->enable_gpio); | |
985 | } | |
986 | ||
987 | imx214->regmap = devm_regmap_init_i2c(client, &sensor_regmap_config); | |
988 | if (IS_ERR(imx214->regmap)) { | |
989 | dev_err(dev, "regmap init failed\n"); | |
990 | return PTR_ERR(imx214->regmap); | |
991 | } | |
992 | ||
993 | v4l2_i2c_subdev_init(&imx214->sd, client, &imx214_subdev_ops); | |
994 | ||
995 | /* | |
996 | * Enable power initially, to avoid warnings | |
997 | * from clk_disable on power_off | |
998 | */ | |
999 | imx214_power_on(imx214->dev); | |
1000 | ||
1001 | pm_runtime_set_active(imx214->dev); | |
1002 | pm_runtime_enable(imx214->dev); | |
1003 | pm_runtime_idle(imx214->dev); | |
1004 | ||
1005 | v4l2_ctrl_handler_init(&imx214->ctrls, 3); | |
1006 | ||
1007 | imx214->pixel_rate = v4l2_ctrl_new_std(&imx214->ctrls, NULL, | |
1008 | V4L2_CID_PIXEL_RATE, 0, | |
1009 | IMX214_DEFAULT_PIXEL_RATE, 1, | |
1010 | IMX214_DEFAULT_PIXEL_RATE); | |
1011 | imx214->link_freq = v4l2_ctrl_new_int_menu(&imx214->ctrls, NULL, | |
1012 | V4L2_CID_LINK_FREQ, | |
1013 | ARRAY_SIZE(link_freq) - 1, | |
1014 | 0, link_freq); | |
1015 | if (imx214->link_freq) | |
1016 | imx214->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; | |
1017 | ||
1018 | /* | |
1019 | * WARNING! | |
1020 | * Values obtained reverse engineering blobs and/or devices. | |
1021 | * Ranges and functionality might be wrong. | |
1022 | * | |
1023 | * Sony, please release some register set documentation for the | |
1024 | * device. | |
1025 | * | |
1026 | * Yours sincerely, Ricardo. | |
1027 | */ | |
1028 | imx214->exposure = v4l2_ctrl_new_std(&imx214->ctrls, &imx214_ctrl_ops, | |
1029 | V4L2_CID_EXPOSURE, | |
1030 | 0, 3184, 1, 0x0c70); | |
1031 | ||
1032 | ret = imx214->ctrls.error; | |
1033 | if (ret) { | |
1034 | dev_err(&client->dev, "%s control init failed (%d)\n", | |
1035 | __func__, ret); | |
1036 | goto free_ctrl; | |
1037 | } | |
1038 | ||
1039 | imx214->sd.ctrl_handler = &imx214->ctrls; | |
1040 | mutex_init(&imx214->mutex); | |
1041 | imx214->ctrls.lock = &imx214->mutex; | |
1042 | ||
1043 | imx214->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | |
1044 | imx214->pad.flags = MEDIA_PAD_FL_SOURCE; | |
1045 | imx214->sd.dev = &client->dev; | |
1046 | imx214->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; | |
1047 | ||
1048 | ret = media_entity_pads_init(&imx214->sd.entity, 1, &imx214->pad); | |
1049 | if (ret < 0) { | |
1050 | dev_err(dev, "could not register media entity\n"); | |
1051 | goto free_ctrl; | |
1052 | } | |
1053 | ||
1054 | imx214_entity_init_cfg(&imx214->sd, NULL); | |
1055 | ||
1056 | ret = v4l2_async_register_subdev_sensor_common(&imx214->sd); | |
1057 | if (ret < 0) { | |
1058 | dev_err(dev, "could not register v4l2 device\n"); | |
1059 | goto free_entity; | |
1060 | } | |
1061 | ||
1062 | return 0; | |
1063 | ||
1064 | free_entity: | |
1065 | media_entity_cleanup(&imx214->sd.entity); | |
1066 | free_ctrl: | |
1067 | mutex_destroy(&imx214->mutex); | |
1068 | v4l2_ctrl_handler_free(&imx214->ctrls); | |
1069 | pm_runtime_disable(imx214->dev); | |
1070 | ||
1071 | return ret; | |
1072 | } | |
1073 | ||
1074 | static int imx214_remove(struct i2c_client *client) | |
1075 | { | |
1076 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | |
1077 | struct imx214 *imx214 = to_imx214(sd); | |
1078 | ||
1079 | v4l2_async_unregister_subdev(&imx214->sd); | |
1080 | media_entity_cleanup(&imx214->sd.entity); | |
1081 | v4l2_ctrl_handler_free(&imx214->ctrls); | |
1082 | ||
1083 | pm_runtime_disable(&client->dev); | |
1084 | pm_runtime_set_suspended(&client->dev); | |
1085 | ||
1086 | mutex_destroy(&imx214->mutex); | |
1087 | ||
1088 | return 0; | |
1089 | } | |
1090 | ||
1091 | static const struct of_device_id imx214_of_match[] = { | |
1092 | { .compatible = "sony,imx214" }, | |
1093 | { } | |
1094 | }; | |
1095 | MODULE_DEVICE_TABLE(of, imx214_of_match); | |
1096 | ||
1097 | static const struct dev_pm_ops imx214_pm_ops = { | |
1098 | SET_SYSTEM_SLEEP_PM_OPS(imx214_suspend, imx214_resume) | |
1099 | SET_RUNTIME_PM_OPS(imx214_power_off, imx214_power_on, NULL) | |
1100 | }; | |
1101 | ||
1102 | static struct i2c_driver imx214_i2c_driver = { | |
1103 | .driver = { | |
1104 | .of_match_table = imx214_of_match, | |
1105 | .pm = &imx214_pm_ops, | |
1106 | .name = "imx214", | |
1107 | }, | |
1108 | .probe_new = imx214_probe, | |
1109 | .remove = imx214_remove, | |
1110 | }; | |
1111 | ||
1112 | module_i2c_driver(imx214_i2c_driver); | |
1113 | ||
1114 | MODULE_DESCRIPTION("Sony IMX214 Camera drier"); | |
1115 | MODULE_AUTHOR("Ricardo Ribalda <ricardo.ribalda@gmail.com>"); | |
1116 | MODULE_LICENSE("GPL v2"); |