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