kernel: bump 6.1 to 6.1.53
[openwrt/staging/jow.git] / target / linux / bcm27xx / patches-6.1 / 950-0424-media-i2c-Add-driver-of-Arducam-64MP-camera.patch
1 From 1a28fde906ac8a8268b72879dd035e536d4c09c5 Mon Sep 17 00:00:00 2001
2 From: Lee Jackson <info@arducam.com>
3 Date: Fri, 13 May 2022 17:11:35 +0800
4 Subject: [PATCH] media: i2c: Add driver of Arducam 64MP camera
5
6 Add a driver for the Arducam 64MP camera sensor.
7 Whilst the sensor supports 2 or 4 CSI2 data lanes, this driver
8 currently only supports 2 lanes.
9
10 The following Bayer modes are currently available:
11
12 9152x6944 10-bit @ 2.7fps
13 4624x3472 10-bit (binned) @ 10fps
14 3840x2160 10-bit (cropped/binned) @ 20fps
15 2312x1736 10-bit (binned) @ 30fps
16 1920x1080 10-bit (cropped/binned) @ 60fps
17 1280x720 10-bit (cropped/binned) @ 120fps
18
19 Signed-off-by: Lee Jackson <info@arducam.com>
20 ---
21 drivers/media/i2c/Kconfig | 11 +
22 drivers/media/i2c/Makefile | 1 +
23 drivers/media/i2c/arducam_64mp.c | 2399 ++++++++++++++++++++++++++++++
24 3 files changed, 2411 insertions(+)
25 create mode 100644 drivers/media/i2c/arducam_64mp.c
26
27 --- a/drivers/media/i2c/Kconfig
28 +++ b/drivers/media/i2c/Kconfig
29 @@ -54,6 +54,17 @@ config VIDEO_AR0521
30 To compile this driver as a module, choose M here: the
31 module will be called ar0521.
32
33 +config VIDEO_ARDUCAM_64MP
34 + tristate "Arducam 64MP sensor support"
35 + depends on I2C && VIDEO_DEV
36 + select VIDEO_V4L2_SUBDEV_API
37 + help
38 + This is a Video4Linux2 sensor driver for the Arducam
39 + 64MP camera.
40 +
41 + To compile this driver as a module, choose M here: the
42 + module will be called arducam_64mp.
43 +
44 config VIDEO_ARDUCAM_PIVARIETY
45 tristate "Arducam Pivariety sensor support"
46 depends on I2C && VIDEO_DEV
47 --- a/drivers/media/i2c/Makefile
48 +++ b/drivers/media/i2c/Makefile
49 @@ -21,6 +21,7 @@ obj-$(CONFIG_VIDEO_AK7375) += ak7375.o
50 obj-$(CONFIG_VIDEO_AK881X) += ak881x.o
51 obj-$(CONFIG_VIDEO_APTINA_PLL) += aptina-pll.o
52 obj-$(CONFIG_VIDEO_AR0521) += ar0521.o
53 +obj-$(CONFIG_VIDEO_ARDUCAM_64MP) += arducam_64mp.o
54 obj-$(CONFIG_VIDEO_ARDUCAM_PIVARIETY) += arducam-pivariety.o
55 obj-$(CONFIG_VIDEO_BT819) += bt819.o
56 obj-$(CONFIG_VIDEO_BT856) += bt856.o
57 --- /dev/null
58 +++ b/drivers/media/i2c/arducam_64mp.c
59 @@ -0,0 +1,2399 @@
60 +// SPDX-License-Identifier: GPL-2.0
61 +/*
62 + * A V4L2 driver for Arducam 64MP cameras.
63 + * Copyright (C) 2021 Arducam Technology co., Ltd.
64 + *
65 + * Based on Sony IMX477 camera driver
66 + * Copyright (C) 2020 Raspberry Pi (Trading) Ltd
67 + */
68 +#include <asm/unaligned.h>
69 +#include <linux/clk.h>
70 +#include <linux/delay.h>
71 +#include <linux/gpio/consumer.h>
72 +#include <linux/i2c.h>
73 +#include <linux/module.h>
74 +#include <linux/of_device.h>
75 +#include <linux/pm_runtime.h>
76 +#include <linux/regulator/consumer.h>
77 +#include <media/v4l2-ctrls.h>
78 +#include <media/v4l2-device.h>
79 +#include <media/v4l2-event.h>
80 +#include <media/v4l2-fwnode.h>
81 +#include <media/v4l2-mediabus.h>
82 +
83 +#define ARDUCAM_64MP_REG_VALUE_08BIT 1
84 +#define ARDUCAM_64MP_REG_VALUE_16BIT 2
85 +
86 +/* Chip ID */
87 +#define ARDUCAM_64MP_REG_CHIP_ID 0x005E
88 +#define ARDUCAM_64MP_CHIP_ID 0x4136
89 +
90 +#define ARDUCAM_64MP_REG_MODE_SELECT 0x0100
91 +#define ARDUCAM_64MP_MODE_STANDBY 0x00
92 +#define ARDUCAM_64MP_MODE_STREAMING 0x01
93 +
94 +#define ARDUCAM_64MP_REG_ORIENTATION 0x101
95 +
96 +#define ARDUCAM_64MP_XCLK_FREQ 24000000
97 +
98 +#define ARDUCAM_64MP_DEFAULT_LINK_FREQ 456000000
99 +
100 +/* Pixel rate is fixed at 900MHz for all the modes */
101 +#define ARDUCAM_64MP_PIXEL_RATE 900000000
102 +
103 +/* V_TIMING internal */
104 +#define ARDUCAM_64MP_REG_FRAME_LENGTH 0x0340
105 +#define ARDUCAM_64MP_FRAME_LENGTH_MAX 0xffff
106 +
107 +/* Long exposure multiplier */
108 +#define ARDUCAM_64MP_LONG_EXP_SHIFT_MAX 7
109 +#define ARDUCAM_64MP_LONG_EXP_SHIFT_REG 0x3100
110 +
111 +/* Exposure control */
112 +#define ARDUCAM_64MP_REG_EXPOSURE 0x0202
113 +#define ARDUCAM_64MP_EXPOSURE_OFFSET 48
114 +#define ARDUCAM_64MP_EXPOSURE_MIN 9
115 +#define ARDUCAM_64MP_EXPOSURE_STEP 1
116 +#define ARDUCAM_64MP_EXPOSURE_DEFAULT 0x3e8
117 +#define ARDUCAM_64MP_EXPOSURE_MAX (ARDUCAM_64MP_FRAME_LENGTH_MAX - \
118 + ARDUCAM_64MP_EXPOSURE_OFFSET)
119 +
120 +/* Analog gain control */
121 +#define ARDUCAM_64MP_REG_ANALOG_GAIN 0x0204
122 +#define ARDUCAM_64MP_ANA_GAIN_MIN 0
123 +#define ARDUCAM_64MP_ANA_GAIN_MAX 1008
124 +#define ARDUCAM_64MP_ANA_GAIN_STEP 1
125 +#define ARDUCAM_64MP_ANA_GAIN_DEFAULT 0x0
126 +
127 +/* Digital gain control */
128 +#define ARDUCAM_64MP_REG_DIGITAL_GAIN 0x020e
129 +#define ARDUCAM_64MP_DGTL_GAIN_MIN 0x0100
130 +#define ARDUCAM_64MP_DGTL_GAIN_MAX 0x0fff
131 +#define ARDUCAM_64MP_DGTL_GAIN_DEFAULT 0x0100
132 +#define ARDUCAM_64MP_DGTL_GAIN_STEP 1
133 +
134 +/* Test Pattern Control */
135 +#define ARDUCAM_64MP_REG_TEST_PATTERN 0x0600
136 +#define ARDUCAM_64MP_TEST_PATTERN_DISABLE 0
137 +#define ARDUCAM_64MP_TEST_PATTERN_SOLID_COLOR 1
138 +#define ARDUCAM_64MP_TEST_PATTERN_COLOR_BARS 2
139 +#define ARDUCAM_64MP_TEST_PATTERN_GREY_COLOR 3
140 +#define ARDUCAM_64MP_TEST_PATTERN_PN9 4
141 +
142 +/* Test pattern colour components */
143 +#define ARDUCAM_64MP_REG_TEST_PATTERN_R 0x0602
144 +#define ARDUCAM_64MP_REG_TEST_PATTERN_GR 0x0604
145 +#define ARDUCAM_64MP_REG_TEST_PATTERN_B 0x0606
146 +#define ARDUCAM_64MP_REG_TEST_PATTERN_GB 0x0608
147 +#define ARDUCAM_64MP_TEST_PATTERN_COLOUR_MIN 0
148 +#define ARDUCAM_64MP_TEST_PATTERN_COLOUR_MAX 0x0fff
149 +#define ARDUCAM_64MP_TEST_PATTERN_COLOUR_STEP 1
150 +#define ARDUCAM_64MP_TEST_PATTERN_R_DEFAULT \
151 + ARDUCAM_64MP_TEST_PATTERN_COLOUR_MAX
152 +#define ARDUCAM_64MP_TEST_PATTERN_GR_DEFAULT 0
153 +#define ARDUCAM_64MP_TEST_PATTERN_B_DEFAULT 0
154 +#define ARDUCAM_64MP_TEST_PATTERN_GB_DEFAULT 0
155 +
156 +/* ARDUCAM_64MP native and active pixel array size. */
157 +#define ARDUCAM_64MP_NATIVE_WIDTH 9344U
158 +#define ARDUCAM_64MP_NATIVE_HEIGHT 7032U
159 +#define ARDUCAM_64MP_PIXEL_ARRAY_LEFT 48U
160 +#define ARDUCAM_64MP_PIXEL_ARRAY_TOP 40U
161 +#define ARDUCAM_64MP_PIXEL_ARRAY_WIDTH 9248U
162 +#define ARDUCAM_64MP_PIXEL_ARRAY_HEIGHT 6944U
163 +
164 +struct arducam_64mp_reg {
165 + u16 address;
166 + u8 val;
167 +};
168 +
169 +struct arducam_64mp_reg_list {
170 + unsigned int num_of_regs;
171 + const struct arducam_64mp_reg *regs;
172 +};
173 +
174 +/* Mode : resolution and related config&values */
175 +struct arducam_64mp_mode {
176 + /* Frame width */
177 + unsigned int width;
178 +
179 + /* Frame height */
180 + unsigned int height;
181 +
182 + /* H-timing in pixels */
183 + unsigned int line_length_pix;
184 +
185 + /* Analog crop rectangle. */
186 + struct v4l2_rect crop;
187 +
188 + /* Default framerate. */
189 + struct v4l2_fract timeperframe_default;
190 +
191 + /* Default register values */
192 + struct arducam_64mp_reg_list reg_list;
193 +};
194 +
195 +static const struct arducam_64mp_reg mode_common_regs[] = {
196 + {0x0136, 0x18},
197 + {0x0137, 0x00},
198 + {0x33F0, 0x01},
199 + {0x33F1, 0x03},
200 + {0x0111, 0x02},
201 + {0x3062, 0x00},
202 + {0x3063, 0x30},
203 + {0x3076, 0x00},
204 + {0x3077, 0x30},
205 + {0x1f06, 0x06},
206 + {0x1f07, 0x82},
207 + {0x1f04, 0x71},
208 + {0x1f05, 0x01},
209 + {0x1f08, 0x01},
210 + {0x5bfe, 0x14},
211 + {0x5c0d, 0x2d},
212 + {0x5c1c, 0x30},
213 + {0x5c2b, 0x32},
214 + {0x5c37, 0x2e},
215 + {0x5c40, 0x30},
216 + {0x5c50, 0x14},
217 + {0x5c5f, 0x28},
218 + {0x5c6e, 0x28},
219 + {0x5c7d, 0x32},
220 + {0x5c89, 0x37},
221 + {0x5c92, 0x56},
222 + {0x5bfc, 0x12},
223 + {0x5c0b, 0x2a},
224 + {0x5c1a, 0x2c},
225 + {0x5c29, 0x2f},
226 + {0x5c36, 0x2e},
227 + {0x5c3f, 0x2e},
228 + {0x5c4e, 0x06},
229 + {0x5c5d, 0x1e},
230 + {0x5c6c, 0x20},
231 + {0x5c7b, 0x1e},
232 + {0x5c88, 0x32},
233 + {0x5c91, 0x32},
234 + {0x5c02, 0x14},
235 + {0x5c11, 0x2f},
236 + {0x5c20, 0x32},
237 + {0x5c2f, 0x34},
238 + {0x5c39, 0x31},
239 + {0x5c42, 0x31},
240 + {0x5c8b, 0x28},
241 + {0x5c94, 0x28},
242 + {0x5c00, 0x10},
243 + {0x5c0f, 0x2c},
244 + {0x5c1e, 0x2e},
245 + {0x5c2d, 0x32},
246 + {0x5c38, 0x2e},
247 + {0x5c41, 0x2b},
248 + {0x5c61, 0x0a},
249 + {0x5c70, 0x0a},
250 + {0x5c7f, 0x0a},
251 + {0x5c8a, 0x1e},
252 + {0x5c93, 0x2a},
253 + {0x5bfa, 0x2b},
254 + {0x5c09, 0x2d},
255 + {0x5c18, 0x2e},
256 + {0x5c27, 0x30},
257 + {0x5c5b, 0x28},
258 + {0x5c6a, 0x22},
259 + {0x5c79, 0x42},
260 + {0x5bfb, 0x2c},
261 + {0x5c0a, 0x2f},
262 + {0x5c19, 0x2e},
263 + {0x5c28, 0x2e},
264 + {0x5c4d, 0x20},
265 + {0x5c5c, 0x1e},
266 + {0x5c6b, 0x32},
267 + {0x5c7a, 0x32},
268 + {0x5bfd, 0x30},
269 + {0x5c0c, 0x32},
270 + {0x5c1b, 0x2e},
271 + {0x5c2a, 0x30},
272 + {0x5c4f, 0x28},
273 + {0x5c5e, 0x32},
274 + {0x5c6d, 0x37},
275 + {0x5c7c, 0x56},
276 + {0x5bff, 0x2e},
277 + {0x5c0e, 0x32},
278 + {0x5c1d, 0x2e},
279 + {0x5c2c, 0x2b},
280 + {0x5c51, 0x0a},
281 + {0x5c60, 0x0a},
282 + {0x5c6f, 0x1e},
283 + {0x5c7e, 0x2a},
284 + {0x5c01, 0x32},
285 + {0x5c10, 0x34},
286 + {0x5c1f, 0x31},
287 + {0x5c2e, 0x31},
288 + {0x5c71, 0x28},
289 + {0x5c80, 0x28},
290 + {0x5c4c, 0x2a},
291 + {0x33f2, 0x01},
292 + {0x1f04, 0x73},
293 + {0x1f05, 0x01},
294 + {0x5bfa, 0x35},
295 + {0x5c09, 0x38},
296 + {0x5c18, 0x3a},
297 + {0x5c27, 0x38},
298 + {0x5c5b, 0x25},
299 + {0x5c6a, 0x24},
300 + {0x5c79, 0x47},
301 + {0x5bfc, 0x15},
302 + {0x5c0b, 0x2e},
303 + {0x5c1a, 0x36},
304 + {0x5c29, 0x38},
305 + {0x5c36, 0x36},
306 + {0x5c3f, 0x36},
307 + {0x5c4e, 0x0b},
308 + {0x5c5d, 0x20},
309 + {0x5c6c, 0x2a},
310 + {0x5c7b, 0x25},
311 + {0x5c88, 0x25},
312 + {0x5c91, 0x22},
313 + {0x5bfe, 0x15},
314 + {0x5c0d, 0x32},
315 + {0x5c1c, 0x36},
316 + {0x5c2b, 0x36},
317 + {0x5c37, 0x3a},
318 + {0x5c40, 0x39},
319 + {0x5c50, 0x06},
320 + {0x5c5f, 0x22},
321 + {0x5c6e, 0x23},
322 + {0x5c7d, 0x2e},
323 + {0x5c89, 0x44},
324 + {0x5c92, 0x51},
325 + {0x5d7f, 0x0a},
326 + {0x5c00, 0x17},
327 + {0x5c0f, 0x36},
328 + {0x5c1e, 0x38},
329 + {0x5c2d, 0x3c},
330 + {0x5c38, 0x38},
331 + {0x5c41, 0x36},
332 + {0x5c52, 0x0a},
333 + {0x5c61, 0x21},
334 + {0x5c70, 0x23},
335 + {0x5c7f, 0x1b},
336 + {0x5c8a, 0x22},
337 + {0x5c93, 0x20},
338 + {0x5c02, 0x1a},
339 + {0x5c11, 0x3e},
340 + {0x5c20, 0x3f},
341 + {0x5c2f, 0x3d},
342 + {0x5c39, 0x3e},
343 + {0x5c42, 0x3c},
344 + {0x5c54, 0x02},
345 + {0x5c63, 0x12},
346 + {0x5c72, 0x14},
347 + {0x5c81, 0x24},
348 + {0x5c8b, 0x1c},
349 + {0x5c94, 0x4e},
350 + {0x5d8a, 0x09},
351 + {0x5bfb, 0x36},
352 + {0x5c0a, 0x38},
353 + {0x5c19, 0x36},
354 + {0x5c28, 0x36},
355 + {0x5c4d, 0x2a},
356 + {0x5c5c, 0x25},
357 + {0x5c6b, 0x25},
358 + {0x5c7a, 0x22},
359 + {0x5bfd, 0x36},
360 + {0x5c0c, 0x36},
361 + {0x5c1b, 0x3a},
362 + {0x5c2a, 0x39},
363 + {0x5c4f, 0x23},
364 + {0x5c5e, 0x2e},
365 + {0x5c6d, 0x44},
366 + {0x5c7c, 0x51},
367 + {0x5d63, 0x0a},
368 + {0x5bff, 0x38},
369 + {0x5c0e, 0x3c},
370 + {0x5c1d, 0x38},
371 + {0x5c2c, 0x36},
372 + {0x5c51, 0x23},
373 + {0x5c60, 0x1b},
374 + {0x5c6f, 0x22},
375 + {0x5c7e, 0x20},
376 + {0x5c01, 0x3f},
377 + {0x5c10, 0x3d},
378 + {0x5c1f, 0x3e},
379 + {0x5c2e, 0x3c},
380 + {0x5c53, 0x14},
381 + {0x5c62, 0x24},
382 + {0x5c71, 0x1c},
383 + {0x5c80, 0x4e},
384 + {0x5d76, 0x09},
385 + {0x5c4c, 0x2a},
386 + {0x33f2, 0x02},
387 + {0x1f04, 0x78},
388 + {0x1f05, 0x01},
389 + {0x5bfa, 0x37},
390 + {0x5c09, 0x36},
391 + {0x5c18, 0x39},
392 + {0x5c27, 0x38},
393 + {0x5c5b, 0x27},
394 + {0x5c6a, 0x2b},
395 + {0x5c79, 0x48},
396 + {0x5bfc, 0x16},
397 + {0x5c0b, 0x32},
398 + {0x5c1a, 0x33},
399 + {0x5c29, 0x37},
400 + {0x5c36, 0x36},
401 + {0x5c3f, 0x35},
402 + {0x5c4e, 0x0d},
403 + {0x5c5d, 0x2d},
404 + {0x5c6c, 0x23},
405 + {0x5c7b, 0x25},
406 + {0x5c88, 0x31},
407 + {0x5c91, 0x2e},
408 + {0x5bfe, 0x15},
409 + {0x5c0d, 0x31},
410 + {0x5c1c, 0x35},
411 + {0x5c2b, 0x36},
412 + {0x5c37, 0x35},
413 + {0x5c40, 0x37},
414 + {0x5c50, 0x0f},
415 + {0x5c5f, 0x31},
416 + {0x5c6e, 0x30},
417 + {0x5c7d, 0x33},
418 + {0x5c89, 0x36},
419 + {0x5c92, 0x5b},
420 + {0x5c00, 0x13},
421 + {0x5c0f, 0x2f},
422 + {0x5c1e, 0x2e},
423 + {0x5c2d, 0x34},
424 + {0x5c38, 0x33},
425 + {0x5c41, 0x32},
426 + {0x5c52, 0x0d},
427 + {0x5c61, 0x27},
428 + {0x5c70, 0x28},
429 + {0x5c7f, 0x1f},
430 + {0x5c8a, 0x25},
431 + {0x5c93, 0x2c},
432 + {0x5c02, 0x15},
433 + {0x5c11, 0x36},
434 + {0x5c20, 0x39},
435 + {0x5c2f, 0x3a},
436 + {0x5c39, 0x37},
437 + {0x5c42, 0x37},
438 + {0x5c54, 0x04},
439 + {0x5c63, 0x1c},
440 + {0x5c72, 0x1c},
441 + {0x5c81, 0x1c},
442 + {0x5c8b, 0x28},
443 + {0x5c94, 0x24},
444 + {0x5bfb, 0x33},
445 + {0x5c0a, 0x37},
446 + {0x5c19, 0x36},
447 + {0x5c28, 0x35},
448 + {0x5c4d, 0x23},
449 + {0x5c5c, 0x25},
450 + {0x5c6b, 0x31},
451 + {0x5c7a, 0x2e},
452 + {0x5bfd, 0x35},
453 + {0x5c0c, 0x36},
454 + {0x5c1b, 0x35},
455 + {0x5c2a, 0x37},
456 + {0x5c4f, 0x30},
457 + {0x5c5e, 0x33},
458 + {0x5c6d, 0x36},
459 + {0x5c7c, 0x5b},
460 + {0x5bff, 0x2e},
461 + {0x5c0e, 0x34},
462 + {0x5c1d, 0x33},
463 + {0x5c2c, 0x32},
464 + {0x5c51, 0x28},
465 + {0x5c60, 0x1f},
466 + {0x5c6f, 0x25},
467 + {0x5c7e, 0x2c},
468 + {0x5c01, 0x39},
469 + {0x5c10, 0x3a},
470 + {0x5c1f, 0x37},
471 + {0x5c2e, 0x37},
472 + {0x5c53, 0x1c},
473 + {0x5c62, 0x1c},
474 + {0x5c71, 0x28},
475 + {0x5c80, 0x24},
476 + {0x5c4c, 0x2c},
477 + {0x33f2, 0x03},
478 + {0x1f08, 0x00},
479 + {0x32c8, 0x00},
480 + {0x4017, 0x40},
481 + {0x40a2, 0x01},
482 + {0x40ac, 0x01},
483 + {0x4328, 0x00},
484 + {0x4329, 0xb3},
485 + {0x4e15, 0x10},
486 + {0x4e19, 0x2f},
487 + {0x4e21, 0x0f},
488 + {0x4e2f, 0x10},
489 + {0x4e3d, 0x10},
490 + {0x4e41, 0x2f},
491 + {0x4e57, 0x29},
492 + {0x4ffb, 0x2f},
493 + {0x5011, 0x24},
494 + {0x501d, 0x03},
495 + {0x505f, 0x41},
496 + {0x5060, 0xdf},
497 + {0x5065, 0xdf},
498 + {0x5066, 0x37},
499 + {0x506e, 0x57},
500 + {0x5070, 0xc5},
501 + {0x5072, 0x57},
502 + {0x5075, 0x53},
503 + {0x5076, 0x55},
504 + {0x5077, 0xc1},
505 + {0x5078, 0xc3},
506 + {0x5079, 0x53},
507 + {0x507a, 0x55},
508 + {0x507d, 0x57},
509 + {0x507e, 0xdf},
510 + {0x507f, 0xc5},
511 + {0x5081, 0x57},
512 + {0x53c8, 0x01},
513 + {0x53c9, 0xe2},
514 + {0x53ca, 0x03},
515 + {0x5422, 0x7a},
516 + {0x548e, 0x40},
517 + {0x5497, 0x5e},
518 + {0x54a1, 0x40},
519 + {0x54a9, 0x40},
520 + {0x54b2, 0x5e},
521 + {0x54bc, 0x40},
522 + {0x57c6, 0x00},
523 + {0x583d, 0x0e},
524 + {0x583e, 0x0e},
525 + {0x583f, 0x0e},
526 + {0x5840, 0x0e},
527 + {0x5841, 0x0e},
528 + {0x5842, 0x0e},
529 + {0x5900, 0x12},
530 + {0x5901, 0x12},
531 + {0x5902, 0x14},
532 + {0x5903, 0x12},
533 + {0x5904, 0x14},
534 + {0x5905, 0x12},
535 + {0x5906, 0x14},
536 + {0x5907, 0x12},
537 + {0x590f, 0x12},
538 + {0x5911, 0x12},
539 + {0x5913, 0x12},
540 + {0x591c, 0x12},
541 + {0x591e, 0x12},
542 + {0x5920, 0x12},
543 + {0x5948, 0x08},
544 + {0x5949, 0x08},
545 + {0x594a, 0x08},
546 + {0x594b, 0x08},
547 + {0x594c, 0x08},
548 + {0x594d, 0x08},
549 + {0x594e, 0x08},
550 + {0x594f, 0x08},
551 + {0x595c, 0x08},
552 + {0x595e, 0x08},
553 + {0x5960, 0x08},
554 + {0x596e, 0x08},
555 + {0x5970, 0x08},
556 + {0x5972, 0x08},
557 + {0x597e, 0x0f},
558 + {0x597f, 0x0f},
559 + {0x599a, 0x0f},
560 + {0x59de, 0x08},
561 + {0x59df, 0x08},
562 + {0x59fa, 0x08},
563 + {0x5a59, 0x22},
564 + {0x5a5b, 0x22},
565 + {0x5a5d, 0x1a},
566 + {0x5a5f, 0x22},
567 + {0x5a61, 0x1a},
568 + {0x5a63, 0x22},
569 + {0x5a65, 0x1a},
570 + {0x5a67, 0x22},
571 + {0x5a77, 0x22},
572 + {0x5a7b, 0x22},
573 + {0x5a7f, 0x22},
574 + {0x5a91, 0x22},
575 + {0x5a95, 0x22},
576 + {0x5a99, 0x22},
577 + {0x5ae9, 0x66},
578 + {0x5aeb, 0x66},
579 + {0x5aed, 0x5e},
580 + {0x5aef, 0x66},
581 + {0x5af1, 0x5e},
582 + {0x5af3, 0x66},
583 + {0x5af5, 0x5e},
584 + {0x5af7, 0x66},
585 + {0x5b07, 0x66},
586 + {0x5b0b, 0x66},
587 + {0x5b0f, 0x66},
588 + {0x5b21, 0x66},
589 + {0x5b25, 0x66},
590 + {0x5b29, 0x66},
591 + {0x5b79, 0x46},
592 + {0x5b7b, 0x3e},
593 + {0x5b7d, 0x3e},
594 + {0x5b89, 0x46},
595 + {0x5b8b, 0x46},
596 + {0x5b97, 0x46},
597 + {0x5b99, 0x46},
598 + {0x5c9e, 0x0a},
599 + {0x5c9f, 0x08},
600 + {0x5ca0, 0x0a},
601 + {0x5ca1, 0x0a},
602 + {0x5ca2, 0x0b},
603 + {0x5ca3, 0x06},
604 + {0x5ca4, 0x04},
605 + {0x5ca5, 0x06},
606 + {0x5ca6, 0x04},
607 + {0x5cad, 0x0b},
608 + {0x5cae, 0x0a},
609 + {0x5caf, 0x0c},
610 + {0x5cb0, 0x0a},
611 + {0x5cb1, 0x0b},
612 + {0x5cb2, 0x08},
613 + {0x5cb3, 0x06},
614 + {0x5cb4, 0x08},
615 + {0x5cb5, 0x04},
616 + {0x5cbc, 0x0b},
617 + {0x5cbd, 0x09},
618 + {0x5cbe, 0x08},
619 + {0x5cbf, 0x09},
620 + {0x5cc0, 0x0a},
621 + {0x5cc1, 0x08},
622 + {0x5cc2, 0x06},
623 + {0x5cc3, 0x08},
624 + {0x5cc4, 0x06},
625 + {0x5ccb, 0x0a},
626 + {0x5ccc, 0x09},
627 + {0x5ccd, 0x0a},
628 + {0x5cce, 0x08},
629 + {0x5ccf, 0x0a},
630 + {0x5cd0, 0x08},
631 + {0x5cd1, 0x08},
632 + {0x5cd2, 0x08},
633 + {0x5cd3, 0x08},
634 + {0x5cda, 0x09},
635 + {0x5cdb, 0x09},
636 + {0x5cdc, 0x08},
637 + {0x5cdd, 0x08},
638 + {0x5ce3, 0x09},
639 + {0x5ce4, 0x08},
640 + {0x5ce5, 0x08},
641 + {0x5ce6, 0x08},
642 + {0x5cf4, 0x04},
643 + {0x5d04, 0x04},
644 + {0x5d13, 0x06},
645 + {0x5d22, 0x06},
646 + {0x5d23, 0x04},
647 + {0x5d2e, 0x06},
648 + {0x5d37, 0x06},
649 + {0x5d6f, 0x09},
650 + {0x5d72, 0x0f},
651 + {0x5d88, 0x0f},
652 + {0x5de6, 0x01},
653 + {0x5de7, 0x01},
654 + {0x5de8, 0x01},
655 + {0x5de9, 0x01},
656 + {0x5dea, 0x01},
657 + {0x5deb, 0x01},
658 + {0x5dec, 0x01},
659 + {0x5df2, 0x01},
660 + {0x5df3, 0x01},
661 + {0x5df4, 0x01},
662 + {0x5df5, 0x01},
663 + {0x5df6, 0x01},
664 + {0x5df7, 0x01},
665 + {0x5df8, 0x01},
666 + {0x5dfe, 0x01},
667 + {0x5dff, 0x01},
668 + {0x5e00, 0x01},
669 + {0x5e01, 0x01},
670 + {0x5e02, 0x01},
671 + {0x5e03, 0x01},
672 + {0x5e04, 0x01},
673 + {0x5e0a, 0x01},
674 + {0x5e0b, 0x01},
675 + {0x5e0c, 0x01},
676 + {0x5e0d, 0x01},
677 + {0x5e0e, 0x01},
678 + {0x5e0f, 0x01},
679 + {0x5e10, 0x01},
680 + {0x5e16, 0x01},
681 + {0x5e17, 0x01},
682 + {0x5e18, 0x01},
683 + {0x5e1e, 0x01},
684 + {0x5e1f, 0x01},
685 + {0x5e20, 0x01},
686 + {0x5e6e, 0x5a},
687 + {0x5e6f, 0x46},
688 + {0x5e70, 0x46},
689 + {0x5e71, 0x3c},
690 + {0x5e72, 0x3c},
691 + {0x5e73, 0x28},
692 + {0x5e74, 0x28},
693 + {0x5e75, 0x6e},
694 + {0x5e76, 0x6e},
695 + {0x5e81, 0x46},
696 + {0x5e83, 0x3c},
697 + {0x5e85, 0x28},
698 + {0x5e87, 0x6e},
699 + {0x5e92, 0x46},
700 + {0x5e94, 0x3c},
701 + {0x5e96, 0x28},
702 + {0x5e98, 0x6e},
703 + {0x5ecb, 0x26},
704 + {0x5ecc, 0x26},
705 + {0x5ecd, 0x26},
706 + {0x5ece, 0x26},
707 + {0x5ed2, 0x26},
708 + {0x5ed3, 0x26},
709 + {0x5ed4, 0x26},
710 + {0x5ed5, 0x26},
711 + {0x5ed9, 0x26},
712 + {0x5eda, 0x26},
713 + {0x5ee5, 0x08},
714 + {0x5ee6, 0x08},
715 + {0x5ee7, 0x08},
716 + {0x6006, 0x14},
717 + {0x6007, 0x14},
718 + {0x6008, 0x14},
719 + {0x6009, 0x14},
720 + {0x600a, 0x14},
721 + {0x600b, 0x14},
722 + {0x600c, 0x14},
723 + {0x600d, 0x22},
724 + {0x600e, 0x22},
725 + {0x600f, 0x14},
726 + {0x601a, 0x14},
727 + {0x601b, 0x14},
728 + {0x601c, 0x14},
729 + {0x601d, 0x14},
730 + {0x601e, 0x14},
731 + {0x601f, 0x14},
732 + {0x6020, 0x14},
733 + {0x6021, 0x22},
734 + {0x6022, 0x22},
735 + {0x6023, 0x14},
736 + {0x602e, 0x14},
737 + {0x602f, 0x14},
738 + {0x6030, 0x14},
739 + {0x6031, 0x22},
740 + {0x6039, 0x14},
741 + {0x603a, 0x14},
742 + {0x603b, 0x14},
743 + {0x603c, 0x22},
744 + {0x6132, 0x0f},
745 + {0x6133, 0x0f},
746 + {0x6134, 0x0f},
747 + {0x6135, 0x0f},
748 + {0x6136, 0x0f},
749 + {0x6137, 0x0f},
750 + {0x6138, 0x0f},
751 + {0x613e, 0x0f},
752 + {0x613f, 0x0f},
753 + {0x6140, 0x0f},
754 + {0x6141, 0x0f},
755 + {0x6142, 0x0f},
756 + {0x6143, 0x0f},
757 + {0x6144, 0x0f},
758 + {0x614a, 0x0f},
759 + {0x614b, 0x0f},
760 + {0x614c, 0x0f},
761 + {0x614d, 0x0f},
762 + {0x614e, 0x0f},
763 + {0x614f, 0x0f},
764 + {0x6150, 0x0f},
765 + {0x6156, 0x0f},
766 + {0x6157, 0x0f},
767 + {0x6158, 0x0f},
768 + {0x6159, 0x0f},
769 + {0x615a, 0x0f},
770 + {0x615b, 0x0f},
771 + {0x615c, 0x0f},
772 + {0x6162, 0x0f},
773 + {0x6163, 0x0f},
774 + {0x6164, 0x0f},
775 + {0x616a, 0x0f},
776 + {0x616b, 0x0f},
777 + {0x616c, 0x0f},
778 + {0x6226, 0x00},
779 + {0x84f8, 0x01},
780 + {0x8501, 0x00},
781 + {0x8502, 0x01},
782 + {0x8505, 0x00},
783 + {0x8744, 0x00},
784 + {0x883c, 0x01},
785 + {0x8845, 0x00},
786 + {0x8846, 0x01},
787 + {0x8849, 0x00},
788 + {0x9004, 0x1f},
789 + {0x9064, 0x4d},
790 + {0x9065, 0x3d},
791 + {0x922e, 0x91},
792 + {0x922f, 0x2a},
793 + {0x9230, 0xe2},
794 + {0x9231, 0xc0},
795 + {0x9232, 0xe2},
796 + {0x9233, 0xc1},
797 + {0x9234, 0xe2},
798 + {0x9235, 0xc2},
799 + {0x9236, 0xe2},
800 + {0x9237, 0xc3},
801 + {0x9238, 0xe2},
802 + {0x9239, 0xd4},
803 + {0x923a, 0xe2},
804 + {0x923b, 0xd5},
805 + {0x923c, 0x90},
806 + {0x923d, 0x64},
807 + {0xb0b9, 0x10},
808 + {0xbc76, 0x00},
809 + {0xbc77, 0x00},
810 + {0xbc78, 0x00},
811 + {0xbc79, 0x00},
812 + {0xbc7b, 0x28},
813 + {0xbc7c, 0x00},
814 + {0xbc7d, 0x00},
815 + {0xbc7f, 0xc0},
816 + {0xc6b9, 0x01},
817 + {0xecb5, 0x04},
818 + {0xecbf, 0x04},
819 + {0x0112, 0x0a},
820 + {0x0113, 0x0a},
821 + {0x0114, 0x01},
822 + {0x0301, 0x08},
823 + {0x0303, 0x02},
824 + {0x0305, 0x04},
825 + {0x0306, 0x01},
826 + {0x0307, 0x2c},
827 + {0x030b, 0x02},
828 + {0x030d, 0x04},
829 + {0x030e, 0x01},
830 + {0x030f, 0x30},
831 + {0x0310, 0x01},
832 + {0x4018, 0x00},
833 + {0x4019, 0x00},
834 + {0x401a, 0x00},
835 + {0x401b, 0x00},
836 + {0x3400, 0x01},
837 + {0x3092, 0x01},
838 + {0x3093, 0x00},
839 + {0x0350, 0x00},
840 +};
841 +
842 +/* 64 mpix 2.7fps */
843 +static const struct arducam_64mp_reg mode_9152x6944_regs[] = {
844 + {0x0342, 0xb6},
845 + {0x0343, 0xb2},
846 + {0x0340, 0x1b},
847 + {0x0341, 0x76},
848 + {0x0344, 0x00},
849 + {0x0345, 0x00},
850 + {0x0346, 0x00},
851 + {0x0347, 0x00},
852 + {0x0348, 0x24},
853 + {0x0349, 0x1f},
854 + {0x034a, 0x1b},
855 + {0x034b, 0x1f},
856 + {0x0900, 0x00},
857 + {0x0901, 0x11},
858 + {0x0902, 0x0a},
859 + {0x30d8, 0x00},
860 + {0x3200, 0x01},
861 + {0x3201, 0x01},
862 + {0x0408, 0x00},
863 + {0x0409, 0x00},
864 + {0x040a, 0x00},
865 + {0x040b, 0x00},
866 + {0x040c, 0x23},
867 + {0x040d, 0xc0},
868 + {0x040e, 0x1b},
869 + {0x040f, 0x20},
870 + {0x034c, 0x23},
871 + {0x034d, 0xc0},
872 + {0x034e, 0x1b},
873 + {0x034f, 0x20},
874 + {0x30d9, 0x01},
875 + {0x32d5, 0x01},
876 + {0x32d6, 0x00},
877 + {0x401e, 0x00},
878 + {0x40b8, 0x04},
879 + {0x40b9, 0x20},
880 + {0x40bc, 0x02},
881 + {0x40bd, 0x58},
882 + {0x40be, 0x02},
883 + {0x40bf, 0x58},
884 + {0x41a4, 0x00},
885 + {0x5a09, 0x01},
886 + {0x5a17, 0x01},
887 + {0x5a25, 0x01},
888 + {0x5a33, 0x01},
889 + {0x98d7, 0x14},
890 + {0x98d8, 0x14},
891 + {0x98d9, 0x00},
892 + {0x99c4, 0x00},
893 + {0x0202, 0x03},
894 + {0x0203, 0xe8},
895 + {0x0204, 0x00},
896 + {0x0205, 0x00},
897 + {0x020e, 0x01},
898 + {0x020f, 0x00},
899 +};
900 +
901 +/* 16 mpix 10fps */
902 +static const struct arducam_64mp_reg mode_4624x3472_regs[] = {
903 + {0x0342, 0x63},
904 + {0x0343, 0x97},
905 + {0x0340, 0x0d},
906 + {0x0341, 0xca},
907 + {0x0344, 0x00},
908 + {0x0345, 0x00},
909 + {0x0346, 0x00},
910 + {0x0347, 0x00},
911 + {0x0348, 0x24},
912 + {0x0349, 0x1f},
913 + {0x034a, 0x1b},
914 + {0x034b, 0x1f},
915 + {0x0900, 0x01},
916 + {0x0901, 0x22},
917 + {0x0902, 0x08},
918 + {0x30d8, 0x04},
919 + {0x3200, 0x41},
920 + {0x3201, 0x41},
921 + {0x0408, 0x00},
922 + {0x0409, 0x00},
923 + {0x040a, 0x00},
924 + {0x040b, 0x00},
925 + {0x040c, 0x12},
926 + {0x040d, 0x10},
927 + {0x040e, 0x0d},
928 + {0x040f, 0x90},
929 + {0x034c, 0x12},
930 + {0x034d, 0x10},
931 + {0x034e, 0x0d},
932 + {0x034f, 0x90},
933 + {0x30d9, 0x00},
934 + {0x32d5, 0x00},
935 + {0x32d6, 0x00},
936 + {0x401e, 0x00},
937 + {0x40b8, 0x01},
938 + {0x40b9, 0x2c},
939 + {0x40bc, 0x01},
940 + {0x40bd, 0x18},
941 + {0x40be, 0x00},
942 + {0x40bf, 0x00},
943 + {0x41a4, 0x00},
944 + {0x5a09, 0x01},
945 + {0x5a17, 0x01},
946 + {0x5a25, 0x01},
947 + {0x5a33, 0x01},
948 + {0x98d7, 0xb4},
949 + {0x98d8, 0x8c},
950 + {0x98d9, 0x0a},
951 + {0x99c4, 0x16},
952 +};
953 +
954 +/* 4k 20fps mode */
955 +static const struct arducam_64mp_reg mode_3840x2160_regs[] = {
956 + {0x0342, 0x4e},
957 + {0x0343, 0xb7},
958 + {0x0340, 0x08},
959 + {0x0341, 0xb9},
960 + {0x0344, 0x03},
961 + {0x0345, 0x10},
962 + {0x0346, 0x05},
963 + {0x0347, 0x20},
964 + {0x0348, 0x21},
965 + {0x0349, 0x0f},
966 + {0x034a, 0x15},
967 + {0x034b, 0xff},
968 + {0x0900, 0x01},
969 + {0x0901, 0x22},
970 + {0x0902, 0x08},
971 + {0x30d8, 0x04},
972 + {0x3200, 0x41},
973 + {0x3201, 0x41},
974 + {0x0408, 0x00},
975 + {0x0409, 0x00},
976 + {0x040a, 0x00},
977 + {0x040b, 0x00},
978 + {0x040c, 0x0f},
979 + {0x040d, 0x00},
980 + {0x040e, 0x08},
981 + {0x040f, 0x70},
982 + {0x034c, 0x0f},
983 + {0x034d, 0x00},
984 + {0x034e, 0x08},
985 + {0x034f, 0x70},
986 + {0x30d9, 0x00},
987 + {0x32d5, 0x00},
988 + {0x32d6, 0x00},
989 + {0x401e, 0x00},
990 + {0x40b8, 0x01},
991 + {0x40b9, 0x2c},
992 + {0x40bc, 0x01},
993 + {0x40bd, 0x18},
994 + {0x40be, 0x00},
995 + {0x40bf, 0x00},
996 + {0x41a4, 0x00},
997 + {0x5a09, 0x01},
998 + {0x5a17, 0x01},
999 + {0x5a25, 0x01},
1000 + {0x5a33, 0x01},
1001 + {0x98d7, 0xb4},
1002 + {0x98d8, 0x8c},
1003 + {0x98d9, 0x0a},
1004 + {0x99c4, 0x16},
1005 +};
1006 +
1007 +/* 4x4 binned 30fps mode */
1008 +static const struct arducam_64mp_reg mode_2312x1736_regs[] = {
1009 + {0x0342, 0x33},
1010 + {0x0343, 0x60},
1011 + {0x0340, 0x08},
1012 + {0x0341, 0xe9},
1013 + {0x0344, 0x00},
1014 + {0x0345, 0x00},
1015 + {0x0346, 0x00},
1016 + {0x0347, 0x00},
1017 + {0x0348, 0x24},
1018 + {0x0349, 0x1f},
1019 + {0x034a, 0x1b},
1020 + {0x034b, 0x1f},
1021 + {0x0900, 0x01},
1022 + {0x0901, 0x44},
1023 + {0x0902, 0x08},
1024 + {0x30d8, 0x00},
1025 + {0x3200, 0x43},
1026 + {0x3201, 0x43},
1027 + {0x0408, 0x00},
1028 + {0x0409, 0x00},
1029 + {0x040a, 0x00},
1030 + {0x040b, 0x00},
1031 + {0x040c, 0x09},
1032 + {0x040d, 0x08},
1033 + {0x040e, 0x06},
1034 + {0x040f, 0xc8},
1035 + {0x034c, 0x09},
1036 + {0x034d, 0x08},
1037 + {0x034e, 0x06},
1038 + {0x034f, 0xc8},
1039 + {0x30d9, 0x01},
1040 + {0x32d5, 0x00},
1041 + {0x32d6, 0x00},
1042 + {0x401e, 0x00},
1043 + {0x40b8, 0x01},
1044 + {0x40b9, 0x2c},
1045 + {0x40bc, 0x01},
1046 + {0x40bd, 0x18},
1047 + {0x40be, 0x00},
1048 + {0x40bf, 0x00},
1049 + {0x41a4, 0x00},
1050 + {0x5a09, 0x01},
1051 + {0x5a17, 0x01},
1052 + {0x5a25, 0x01},
1053 + {0x5a33, 0x01},
1054 + {0x98d7, 0xb4},
1055 + {0x98d8, 0x8c},
1056 + {0x98d9, 0x0a},
1057 + {0x99c4, 0x16},
1058 +};
1059 +
1060 +/* 1080p 60fps mode */
1061 +static const struct arducam_64mp_reg mode_1920x1080_regs[] = {
1062 + {0x0342, 0x29},
1063 + {0x0343, 0xe3},
1064 + {0x0340, 0x05},
1065 + {0x0341, 0x76},
1066 + {0x0344, 0x03},
1067 + {0x0345, 0x10},
1068 + {0x0346, 0x05},
1069 + {0x0347, 0x20},
1070 + {0x0348, 0x21},
1071 + {0x0349, 0x0f},
1072 + {0x034a, 0x16},
1073 + {0x034b, 0x0f},
1074 + {0x0900, 0x01},
1075 + {0x0901, 0x44},
1076 + {0x0902, 0x08},
1077 + {0x30d8, 0x04},
1078 + {0x3200, 0x43},
1079 + {0x3201, 0x43},
1080 + {0x0408, 0x00},
1081 + {0x0409, 0x00},
1082 + {0x040a, 0x00},
1083 + {0x040b, 0x00},
1084 + {0x040c, 0x07},
1085 + {0x040d, 0x80},
1086 + {0x040e, 0x04},
1087 + {0x040f, 0x38},
1088 + {0x034c, 0x07},
1089 + {0x034d, 0x80},
1090 + {0x034e, 0x04},
1091 + {0x034f, 0x38},
1092 + {0x30d9, 0x00},
1093 + {0x32d5, 0x00},
1094 + {0x32d6, 0x00},
1095 + {0x401e, 0x00},
1096 + {0x40b8, 0x01},
1097 + {0x40b9, 0x2c},
1098 + {0x40bc, 0x01},
1099 + {0x40bd, 0x18},
1100 + {0x40be, 0x00},
1101 + {0x40bf, 0x00},
1102 + {0x41a4, 0x00},
1103 + {0x5a09, 0x01},
1104 + {0x5a17, 0x01},
1105 + {0x5a25, 0x01},
1106 + {0x5a33, 0x01},
1107 + {0x98d7, 0xb4},
1108 + {0x98d8, 0x8c},
1109 + {0x98d9, 0x0a},
1110 + {0x99c4, 0x16},
1111 +};
1112 +
1113 +/* 720p 120fps mode */
1114 +static const struct arducam_64mp_reg mode_1280x720_regs[] = {
1115 + {0x0342, 0x1d},
1116 + {0x0343, 0xc4},
1117 + {0x0340, 0x03},
1118 + {0x0341, 0xd8},
1119 + {0x0344, 0x08},
1120 + {0x0345, 0x10},
1121 + {0x0346, 0x07},
1122 + {0x0347, 0xf0},
1123 + {0x0348, 0x1c},
1124 + {0x0349, 0x0f},
1125 + {0x034a, 0x13},
1126 + {0x034b, 0x3f},
1127 + {0x0900, 0x01},
1128 + {0x0901, 0x44},
1129 + {0x0902, 0x08},
1130 + {0x30d8, 0x04},
1131 + {0x3200, 0x43},
1132 + {0x3201, 0x43},
1133 + {0x0408, 0x00},
1134 + {0x0409, 0x00},
1135 + {0x040a, 0x00},
1136 + {0x040b, 0x00},
1137 + {0x040c, 0x05},
1138 + {0x040d, 0x00},
1139 + {0x040e, 0x02},
1140 + {0x040f, 0xd0},
1141 + {0x034c, 0x05},
1142 + {0x034d, 0x00},
1143 + {0x034e, 0x02},
1144 + {0x034f, 0xd0},
1145 + {0x30d9, 0x00},
1146 + {0x32d5, 0x00},
1147 + {0x32d6, 0x00},
1148 + {0x401e, 0x00},
1149 + {0x40b8, 0x01},
1150 + {0x40b9, 0x2c},
1151 + {0x40bc, 0x01},
1152 + {0x40bd, 0x18},
1153 + {0x40be, 0x00},
1154 + {0x40bf, 0x00},
1155 + {0x41a4, 0x00},
1156 + {0x5a09, 0x01},
1157 + {0x5a17, 0x01},
1158 + {0x5a25, 0x01},
1159 + {0x5a33, 0x01},
1160 + {0x98d7, 0xb4},
1161 + {0x98d8, 0x8c},
1162 + {0x98d9, 0x0a},
1163 + {0x99c4, 0x16},
1164 +};
1165 +
1166 +/* Mode configs */
1167 +static const struct arducam_64mp_mode supported_modes[] = {
1168 + {
1169 + .width = 9152,
1170 + .height = 6944,
1171 + .line_length_pix = 0xb6b2,
1172 + .crop = {
1173 + .left = ARDUCAM_64MP_PIXEL_ARRAY_LEFT,
1174 + .top = ARDUCAM_64MP_PIXEL_ARRAY_TOP,
1175 + .width = 9248,
1176 + .height = 6944,
1177 + },
1178 + .timeperframe_default = {
1179 + .numerator = 100,
1180 + .denominator = 270
1181 + },
1182 + .reg_list = {
1183 + .num_of_regs = ARRAY_SIZE(mode_9152x6944_regs),
1184 + .regs = mode_9152x6944_regs,
1185 + }
1186 + }, {
1187 + .width = 4624,
1188 + .height = 3472,
1189 + .line_length_pix = 0x6397,
1190 + .crop = {
1191 + .left = ARDUCAM_64MP_PIXEL_ARRAY_LEFT,
1192 + .top = ARDUCAM_64MP_PIXEL_ARRAY_TOP,
1193 + .width = 9248,
1194 + .height = 6944,
1195 + },
1196 + .timeperframe_default = {
1197 + .numerator = 100,
1198 + .denominator = 1000
1199 + },
1200 + .reg_list = {
1201 + .num_of_regs = ARRAY_SIZE(mode_4624x3472_regs),
1202 + .regs = mode_4624x3472_regs,
1203 + }
1204 + }, {
1205 + .width = 3840,
1206 + .height = 2160,
1207 + .line_length_pix = 0x4eb7,
1208 + .crop = {
1209 + .left = ARDUCAM_64MP_PIXEL_ARRAY_LEFT + 784,
1210 + .top = ARDUCAM_64MP_PIXEL_ARRAY_TOP + 1312,
1211 + .width = 7680,
1212 + .height = 4320,
1213 + },
1214 + .timeperframe_default = {
1215 + .numerator = 100,
1216 + .denominator = 2000
1217 + },
1218 + .reg_list = {
1219 + .num_of_regs = ARRAY_SIZE(mode_3840x2160_regs),
1220 + .regs = mode_3840x2160_regs,
1221 + }
1222 + }, {
1223 + .width = 2312,
1224 + .height = 1736,
1225 + .line_length_pix = 0x3360,
1226 + .crop = {
1227 + .left = ARDUCAM_64MP_PIXEL_ARRAY_LEFT,
1228 + .top = ARDUCAM_64MP_PIXEL_ARRAY_TOP,
1229 + .width = 9248,
1230 + .height = 6944,
1231 + },
1232 + .timeperframe_default = {
1233 + .numerator = 100,
1234 + .denominator = 3000
1235 + },
1236 + .reg_list = {
1237 + .num_of_regs = ARRAY_SIZE(mode_2312x1736_regs),
1238 + .regs = mode_2312x1736_regs,
1239 + }
1240 + }, {
1241 + .width = 1920,
1242 + .height = 1080,
1243 + .line_length_pix = 0x29e3,
1244 + .crop = {
1245 + .left = ARDUCAM_64MP_PIXEL_ARRAY_LEFT + 784,
1246 + .top = ARDUCAM_64MP_PIXEL_ARRAY_TOP + 1312,
1247 + .width = 7680,
1248 + .height = 4320,
1249 + },
1250 + .timeperframe_default = {
1251 + .numerator = 100,
1252 + .denominator = 6000
1253 + },
1254 + .reg_list = {
1255 + .num_of_regs = ARRAY_SIZE(mode_1920x1080_regs),
1256 + .regs = mode_1920x1080_regs,
1257 + }
1258 + }, {
1259 + .width = 1280,
1260 + .height = 720,
1261 + .line_length_pix = 0x1dc4,
1262 + .crop = {
1263 + .left = ARDUCAM_64MP_PIXEL_ARRAY_LEFT + 2064,
1264 + .top = ARDUCAM_64MP_PIXEL_ARRAY_TOP + 2032,
1265 + .width = 5120,
1266 + .height = 2880,
1267 + },
1268 + .timeperframe_default = {
1269 + .numerator = 100,
1270 + .denominator = 12000
1271 + },
1272 + .reg_list = {
1273 + .num_of_regs = ARRAY_SIZE(mode_1280x720_regs),
1274 + .regs = mode_1280x720_regs,
1275 + }
1276 + },
1277 +};
1278 +
1279 +/*
1280 + * The supported formats.
1281 + * This table MUST contain 4 entries per format, to cover the various flip
1282 + * combinations in the order
1283 + * - no flip
1284 + * - h flip
1285 + * - v flip
1286 + * - h&v flips
1287 + */
1288 +static const u32 codes[] = {
1289 + /* 10-bit modes. */
1290 + MEDIA_BUS_FMT_SRGGB10_1X10,
1291 + MEDIA_BUS_FMT_SGRBG10_1X10,
1292 + MEDIA_BUS_FMT_SGBRG10_1X10,
1293 + MEDIA_BUS_FMT_SBGGR10_1X10,
1294 +};
1295 +
1296 +static const char * const arducam_64mp_test_pattern_menu[] = {
1297 + "Disabled",
1298 + "Color Bars",
1299 + "Solid Color",
1300 + "Grey Color Bars",
1301 + "PN9"
1302 +};
1303 +
1304 +static const int arducam_64mp_test_pattern_val[] = {
1305 + ARDUCAM_64MP_TEST_PATTERN_DISABLE,
1306 + ARDUCAM_64MP_TEST_PATTERN_COLOR_BARS,
1307 + ARDUCAM_64MP_TEST_PATTERN_SOLID_COLOR,
1308 + ARDUCAM_64MP_TEST_PATTERN_GREY_COLOR,
1309 + ARDUCAM_64MP_TEST_PATTERN_PN9,
1310 +};
1311 +
1312 +/* regulator supplies */
1313 +static const char * const arducam_64mp_supply_name[] = {
1314 + /* Supplies can be enabled in any order */
1315 + "VANA", /* Analog (2.8V) supply */
1316 + "VDIG", /* Digital Core (1.05V) supply */
1317 + "VDDL", /* IF (1.8V) supply */
1318 +};
1319 +
1320 +#define ARDUCAM_64MP_NUM_SUPPLIES ARRAY_SIZE(arducam_64mp_supply_name)
1321 +
1322 +/*
1323 + * Initialisation delay between XCLR low->high and the moment when the sensor
1324 + * can start capture (i.e. can leave software standby), given by T7 in the
1325 + * datasheet is 7.7ms. This does include I2C setup time as well.
1326 + *
1327 + * Note, that delay between XCLR low->high and reading the CCI ID register (T6
1328 + * in the datasheet) is much smaller - 1ms.
1329 + */
1330 +#define ARDUCAM_64MP_XCLR_MIN_DELAY_US 8000
1331 +#define ARDUCAM_64MP_XCLR_DELAY_RANGE_US 1000
1332 +
1333 +struct arducam_64mp {
1334 + struct v4l2_subdev sd;
1335 + struct media_pad pad;
1336 +
1337 + unsigned int fmt_code;
1338 +
1339 + struct clk *xclk;
1340 +
1341 + struct gpio_desc *reset_gpio;
1342 + struct regulator_bulk_data supplies[ARDUCAM_64MP_NUM_SUPPLIES];
1343 +
1344 + struct v4l2_ctrl_handler ctrl_handler;
1345 + /* V4L2 Controls */
1346 + struct v4l2_ctrl *pixel_rate;
1347 + struct v4l2_ctrl *exposure;
1348 + struct v4l2_ctrl *vflip;
1349 + struct v4l2_ctrl *hflip;
1350 + struct v4l2_ctrl *vblank;
1351 + struct v4l2_ctrl *hblank;
1352 +
1353 + /* Current mode */
1354 + const struct arducam_64mp_mode *mode;
1355 +
1356 + /*
1357 + * Mutex for serialized access:
1358 + * Protect sensor module set pad format and start/stop streaming safely.
1359 + */
1360 + struct mutex mutex;
1361 +
1362 + /* Streaming on/off */
1363 + bool streaming;
1364 +
1365 + /* Rewrite common registers on stream on? */
1366 + bool common_regs_written;
1367 +
1368 + /* Current long exposure factor in use. Set through V4L2_CID_VBLANK */
1369 + unsigned int long_exp_shift;
1370 +};
1371 +
1372 +static inline struct arducam_64mp *to_arducam_64mp(struct v4l2_subdev *_sd)
1373 +{
1374 + return container_of(_sd, struct arducam_64mp, sd);
1375 +}
1376 +
1377 +/* Read registers up to 2 at a time */
1378 +static int arducam_64mp_read_reg(struct i2c_client *client,
1379 + u16 reg, u32 len, u32 *val)
1380 +{
1381 + struct i2c_msg msgs[2];
1382 + u8 addr_buf[2] = { reg >> 8, reg & 0xff };
1383 + u8 data_buf[4] = { 0, };
1384 + int ret;
1385 +
1386 + if (len > 4)
1387 + return -EINVAL;
1388 +
1389 + /* Write register address */
1390 + msgs[0].addr = client->addr;
1391 + msgs[0].flags = 0;
1392 + msgs[0].len = ARRAY_SIZE(addr_buf);
1393 + msgs[0].buf = addr_buf;
1394 +
1395 + /* Read data from register */
1396 + msgs[1].addr = client->addr;
1397 + msgs[1].flags = I2C_M_RD;
1398 + msgs[1].len = len;
1399 + msgs[1].buf = &data_buf[4 - len];
1400 +
1401 + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
1402 + if (ret != ARRAY_SIZE(msgs))
1403 + return -EIO;
1404 +
1405 + *val = get_unaligned_be32(data_buf);
1406 +
1407 + return 0;
1408 +}
1409 +
1410 +/* Write registers up to 2 at a time */
1411 +static int arducam_64mp_write_reg(struct arducam_64mp *arducam_64mp,
1412 + u16 reg, u32 len, u32 val)
1413 +{
1414 + struct i2c_client *client = v4l2_get_subdevdata(&arducam_64mp->sd);
1415 + u8 buf[6];
1416 +
1417 + if (len > 4)
1418 + return -EINVAL;
1419 +
1420 + put_unaligned_be16(reg, buf);
1421 + put_unaligned_be32(val << (8 * (4 - len)), buf + 2);
1422 + if (i2c_master_send(client, buf, len + 2) != len + 2)
1423 + return -EIO;
1424 +
1425 + return 0;
1426 +}
1427 +
1428 +/* Write a list of registers */
1429 +static int arducam_64mp_write_regs(struct arducam_64mp *arducam_64mp,
1430 + const struct arducam_64mp_reg *regs, u32 len)
1431 +{
1432 + struct i2c_client *client = v4l2_get_subdevdata(&arducam_64mp->sd);
1433 + unsigned int i;
1434 + int ret;
1435 +
1436 + for (i = 0; i < len; i++) {
1437 + ret = arducam_64mp_write_reg(arducam_64mp, regs[i].address, 1,
1438 + regs[i].val);
1439 + if (ret) {
1440 + dev_err_ratelimited(&client->dev,
1441 + "Failed to write reg 0x%4.4x. error = %d\n",
1442 + regs[i].address, ret);
1443 +
1444 + return ret;
1445 + }
1446 + }
1447 +
1448 + return 0;
1449 +}
1450 +
1451 +/* Get bayer order based on flip setting. */
1452 +static u32 arducam_64mp_get_format_code(struct arducam_64mp *arducam_64mp)
1453 +{
1454 + unsigned int i;
1455 +
1456 + lockdep_assert_held(&arducam_64mp->mutex);
1457 +
1458 + i = (arducam_64mp->vflip->val ? 2 : 0) |
1459 + (arducam_64mp->hflip->val ? 1 : 0);
1460 +
1461 + return codes[i];
1462 +}
1463 +
1464 +static int arducam_64mp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
1465 +{
1466 + struct arducam_64mp *arducam_64mp = to_arducam_64mp(sd);
1467 + struct v4l2_mbus_framefmt *try_fmt_img =
1468 + v4l2_subdev_get_try_format(sd, fh->state, 0);
1469 + struct v4l2_rect *try_crop;
1470 +
1471 + mutex_lock(&arducam_64mp->mutex);
1472 +
1473 + /* Initialize try_fmt for the image pad */
1474 + try_fmt_img->width = supported_modes[0].width;
1475 + try_fmt_img->height = supported_modes[0].height;
1476 + try_fmt_img->code = arducam_64mp_get_format_code(arducam_64mp);
1477 + try_fmt_img->field = V4L2_FIELD_NONE;
1478 +
1479 + /* Initialize try_crop */
1480 + try_crop = v4l2_subdev_get_try_crop(sd, fh->state, 0);
1481 + try_crop->left = ARDUCAM_64MP_PIXEL_ARRAY_LEFT;
1482 + try_crop->top = ARDUCAM_64MP_PIXEL_ARRAY_TOP;
1483 + try_crop->width = ARDUCAM_64MP_PIXEL_ARRAY_WIDTH;
1484 + try_crop->height = ARDUCAM_64MP_PIXEL_ARRAY_HEIGHT;
1485 +
1486 + mutex_unlock(&arducam_64mp->mutex);
1487 +
1488 + return 0;
1489 +}
1490 +
1491 +static void
1492 +arducam_64mp_adjust_exposure_range(struct arducam_64mp *arducam_64mp)
1493 +{
1494 + int exposure_max, exposure_def;
1495 +
1496 + /* Honour the VBLANK limits when setting exposure. */
1497 + exposure_max = arducam_64mp->mode->height + arducam_64mp->vblank->val -
1498 + ARDUCAM_64MP_EXPOSURE_OFFSET;
1499 + exposure_def = min(exposure_max, arducam_64mp->exposure->val);
1500 + __v4l2_ctrl_modify_range(arducam_64mp->exposure,
1501 + arducam_64mp->exposure->minimum,
1502 + exposure_max, arducam_64mp->exposure->step,
1503 + exposure_def);
1504 +}
1505 +
1506 +static int arducam_64mp_set_frame_length(struct arducam_64mp *arducam_64mp,
1507 + unsigned int vblank)
1508 +{
1509 + unsigned int val = vblank + arducam_64mp->mode->height;
1510 + int ret = 0;
1511 +
1512 + arducam_64mp->long_exp_shift = 0;
1513 +
1514 + while (val > ARDUCAM_64MP_FRAME_LENGTH_MAX) {
1515 + arducam_64mp->long_exp_shift++;
1516 + val >>= 1;
1517 + }
1518 +
1519 + ret = arducam_64mp_write_reg(arducam_64mp,
1520 + ARDUCAM_64MP_REG_FRAME_LENGTH,
1521 + ARDUCAM_64MP_REG_VALUE_16BIT, val);
1522 + if (ret)
1523 + return ret;
1524 +
1525 + return arducam_64mp_write_reg(arducam_64mp,
1526 + ARDUCAM_64MP_LONG_EXP_SHIFT_REG,
1527 + ARDUCAM_64MP_REG_VALUE_08BIT,
1528 + arducam_64mp->long_exp_shift);
1529 +}
1530 +
1531 +static int arducam_64mp_set_ctrl(struct v4l2_ctrl *ctrl)
1532 +{
1533 + struct arducam_64mp *arducam_64mp =
1534 + container_of(ctrl->handler, struct arducam_64mp, ctrl_handler);
1535 + struct i2c_client *client = v4l2_get_subdevdata(&arducam_64mp->sd);
1536 + int ret;
1537 + u32 val;
1538 + /*
1539 + * The VBLANK control may change the limits of usable exposure, so check
1540 + * and adjust if necessary.
1541 + */
1542 + if (ctrl->id == V4L2_CID_VBLANK)
1543 + arducam_64mp_adjust_exposure_range(arducam_64mp);
1544 +
1545 + /*
1546 + * Applying V4L2 control value only happens
1547 + * when power is up for streaming
1548 + */
1549 + if (pm_runtime_get_if_in_use(&client->dev) == 0)
1550 + return 0;
1551 +
1552 + switch (ctrl->id) {
1553 + case V4L2_CID_ANALOGUE_GAIN:
1554 + ret = arducam_64mp_write_reg(arducam_64mp,
1555 + ARDUCAM_64MP_REG_ANALOG_GAIN,
1556 + ARDUCAM_64MP_REG_VALUE_16BIT,
1557 + ctrl->val);
1558 + break;
1559 + case V4L2_CID_EXPOSURE:
1560 + val = ctrl->val >> arducam_64mp->long_exp_shift;
1561 + ret = arducam_64mp_write_reg(arducam_64mp,
1562 + ARDUCAM_64MP_REG_EXPOSURE,
1563 + ARDUCAM_64MP_REG_VALUE_16BIT,
1564 + val);
1565 + break;
1566 + case V4L2_CID_DIGITAL_GAIN:
1567 + ret = arducam_64mp_write_reg(arducam_64mp,
1568 + ARDUCAM_64MP_REG_DIGITAL_GAIN,
1569 + ARDUCAM_64MP_REG_VALUE_16BIT,
1570 + ctrl->val);
1571 + break;
1572 + case V4L2_CID_TEST_PATTERN:
1573 + val = arducam_64mp_test_pattern_val[ctrl->val];
1574 + ret = arducam_64mp_write_reg(arducam_64mp,
1575 + ARDUCAM_64MP_REG_TEST_PATTERN,
1576 + ARDUCAM_64MP_REG_VALUE_16BIT,
1577 + val);
1578 + break;
1579 + case V4L2_CID_TEST_PATTERN_RED:
1580 + ret = arducam_64mp_write_reg(arducam_64mp,
1581 + ARDUCAM_64MP_REG_TEST_PATTERN_R,
1582 + ARDUCAM_64MP_REG_VALUE_16BIT,
1583 + ctrl->val);
1584 + break;
1585 + case V4L2_CID_TEST_PATTERN_GREENR:
1586 + ret = arducam_64mp_write_reg(arducam_64mp,
1587 + ARDUCAM_64MP_REG_TEST_PATTERN_GR,
1588 + ARDUCAM_64MP_REG_VALUE_16BIT,
1589 + ctrl->val);
1590 + break;
1591 + case V4L2_CID_TEST_PATTERN_BLUE:
1592 + ret = arducam_64mp_write_reg(arducam_64mp,
1593 + ARDUCAM_64MP_REG_TEST_PATTERN_B,
1594 + ARDUCAM_64MP_REG_VALUE_16BIT,
1595 + ctrl->val);
1596 + break;
1597 + case V4L2_CID_TEST_PATTERN_GREENB:
1598 + ret = arducam_64mp_write_reg(arducam_64mp,
1599 + ARDUCAM_64MP_REG_TEST_PATTERN_GB,
1600 + ARDUCAM_64MP_REG_VALUE_16BIT,
1601 + ctrl->val);
1602 + break;
1603 + case V4L2_CID_HFLIP:
1604 + case V4L2_CID_VFLIP:
1605 + ret = arducam_64mp_write_reg(arducam_64mp,
1606 + ARDUCAM_64MP_REG_ORIENTATION, 1,
1607 + arducam_64mp->hflip->val |
1608 + arducam_64mp->vflip->val << 1);
1609 + break;
1610 + case V4L2_CID_VBLANK:
1611 + ret = arducam_64mp_set_frame_length(arducam_64mp, ctrl->val);
1612 + break;
1613 + default:
1614 + dev_info(&client->dev,
1615 + "ctrl(id:0x%x,val:0x%x) is not handled\n",
1616 + ctrl->id, ctrl->val);
1617 + ret = -EINVAL;
1618 + break;
1619 + }
1620 +
1621 + pm_runtime_put(&client->dev);
1622 +
1623 + return ret;
1624 +}
1625 +
1626 +static const struct v4l2_ctrl_ops arducam_64mp_ctrl_ops = {
1627 + .s_ctrl = arducam_64mp_set_ctrl,
1628 +};
1629 +
1630 +static int arducam_64mp_enum_mbus_code(struct v4l2_subdev *sd,
1631 + struct v4l2_subdev_state *sd_state,
1632 + struct v4l2_subdev_mbus_code_enum *code)
1633 +{
1634 + struct arducam_64mp *arducam_64mp = to_arducam_64mp(sd);
1635 +
1636 + if (code->index > 0)
1637 + return -EINVAL;
1638 +
1639 + code->code = arducam_64mp_get_format_code(arducam_64mp);
1640 +
1641 + return 0;
1642 +}
1643 +
1644 +static int arducam_64mp_enum_frame_size(struct v4l2_subdev *sd,
1645 + struct v4l2_subdev_state *sd_state,
1646 + struct v4l2_subdev_frame_size_enum *fse)
1647 +{
1648 + struct arducam_64mp *arducam_64mp = to_arducam_64mp(sd);
1649 +
1650 + if (fse->index >= ARRAY_SIZE(supported_modes))
1651 + return -EINVAL;
1652 +
1653 + if (fse->code != arducam_64mp_get_format_code(arducam_64mp))
1654 + return -EINVAL;
1655 +
1656 + fse->min_width = supported_modes[fse->index].width;
1657 + fse->max_width = fse->min_width;
1658 + fse->min_height = supported_modes[fse->index].height;
1659 + fse->max_height = fse->min_height;
1660 +
1661 + return 0;
1662 +}
1663 +
1664 +static void arducam_64mp_reset_colorspace(struct v4l2_mbus_framefmt *fmt)
1665 +{
1666 + fmt->colorspace = V4L2_COLORSPACE_RAW;
1667 + fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
1668 + fmt->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true,
1669 + fmt->colorspace,
1670 + fmt->ycbcr_enc);
1671 + fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
1672 +}
1673 +
1674 +static void
1675 +arducam_64mp_update_image_pad_format(struct arducam_64mp *arducam_64mp,
1676 + const struct arducam_64mp_mode *mode,
1677 + struct v4l2_subdev_format *fmt)
1678 +{
1679 + fmt->format.width = mode->width;
1680 + fmt->format.height = mode->height;
1681 + fmt->format.field = V4L2_FIELD_NONE;
1682 + arducam_64mp_reset_colorspace(&fmt->format);
1683 +}
1684 +
1685 +static int arducam_64mp_get_pad_format(struct v4l2_subdev *sd,
1686 + struct v4l2_subdev_state *sd_state,
1687 + struct v4l2_subdev_format *fmt)
1688 +{
1689 + struct arducam_64mp *arducam_64mp = to_arducam_64mp(sd);
1690 +
1691 + if (fmt->pad != 0)
1692 + return -EINVAL;
1693 +
1694 + mutex_lock(&arducam_64mp->mutex);
1695 +
1696 + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
1697 + struct v4l2_mbus_framefmt *try_fmt =
1698 + v4l2_subdev_get_try_format(&arducam_64mp->sd, sd_state,
1699 + fmt->pad);
1700 + /* update the code which could change due to vflip or hflip: */
1701 + try_fmt->code = arducam_64mp_get_format_code(arducam_64mp);
1702 + fmt->format = *try_fmt;
1703 + } else {
1704 + arducam_64mp_update_image_pad_format(arducam_64mp,
1705 + arducam_64mp->mode,
1706 + fmt);
1707 + fmt->format.code =
1708 + arducam_64mp_get_format_code(arducam_64mp);
1709 + }
1710 +
1711 + mutex_unlock(&arducam_64mp->mutex);
1712 + return 0;
1713 +}
1714 +
1715 +static unsigned int
1716 +arducam_64mp_get_frame_length(const struct arducam_64mp_mode *mode,
1717 + const struct v4l2_fract *timeperframe)
1718 +{
1719 + u64 frame_length;
1720 +
1721 + frame_length = (u64)timeperframe->numerator * ARDUCAM_64MP_PIXEL_RATE;
1722 + do_div(frame_length,
1723 + (u64)timeperframe->denominator * mode->line_length_pix);
1724 +
1725 + if (WARN_ON(frame_length > ARDUCAM_64MP_FRAME_LENGTH_MAX))
1726 + frame_length = ARDUCAM_64MP_FRAME_LENGTH_MAX;
1727 +
1728 + return max_t(unsigned int, frame_length, mode->height);
1729 +}
1730 +
1731 +static void arducam_64mp_set_framing_limits(struct arducam_64mp *arducam_64mp)
1732 +{
1733 + unsigned int frm_length_min, frm_length_default, hblank;
1734 + const struct arducam_64mp_mode *mode = arducam_64mp->mode;
1735 +
1736 + /* The default framerate is highest possible framerate. */
1737 + frm_length_min =
1738 + arducam_64mp_get_frame_length(mode,
1739 + &mode->timeperframe_default);
1740 + frm_length_default =
1741 + arducam_64mp_get_frame_length(mode,
1742 + &mode->timeperframe_default);
1743 +
1744 + /* Default to no long exposure multiplier. */
1745 + arducam_64mp->long_exp_shift = 0;
1746 +
1747 + /* Update limits and set FPS to default */
1748 + __v4l2_ctrl_modify_range(arducam_64mp->vblank,
1749 + frm_length_min - mode->height,
1750 + ((1 << ARDUCAM_64MP_LONG_EXP_SHIFT_MAX) *
1751 + ARDUCAM_64MP_FRAME_LENGTH_MAX) - mode->height,
1752 + 1, frm_length_default - mode->height);
1753 +
1754 + /* Setting this will adjust the exposure limits as well. */
1755 + __v4l2_ctrl_s_ctrl(arducam_64mp->vblank,
1756 + frm_length_default - mode->height);
1757 +
1758 + /*
1759 + * Currently PPL is fixed to the mode specified value, so hblank
1760 + * depends on mode->width only, and is not changeable in any
1761 + * way other than changing the mode.
1762 + */
1763 + hblank = mode->line_length_pix - mode->width;
1764 + __v4l2_ctrl_modify_range(arducam_64mp->hblank, hblank, hblank, 1,
1765 + hblank);
1766 +}
1767 +
1768 +static int arducam_64mp_set_pad_format(struct v4l2_subdev *sd,
1769 + struct v4l2_subdev_state *sd_state,
1770 + struct v4l2_subdev_format *fmt)
1771 +{
1772 + struct v4l2_mbus_framefmt *framefmt;
1773 + const struct arducam_64mp_mode *mode;
1774 + struct arducam_64mp *arducam_64mp = to_arducam_64mp(sd);
1775 +
1776 + if (fmt->pad != 0)
1777 + return -EINVAL;
1778 +
1779 + mutex_lock(&arducam_64mp->mutex);
1780 +
1781 + /* Bayer order varies with flips */
1782 + fmt->format.code = arducam_64mp_get_format_code(arducam_64mp);
1783 +
1784 + mode = v4l2_find_nearest_size(supported_modes,
1785 + ARRAY_SIZE(supported_modes),
1786 + width, height,
1787 + fmt->format.width,
1788 + fmt->format.height);
1789 + arducam_64mp_update_image_pad_format(arducam_64mp, mode, fmt);
1790 + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
1791 + framefmt = v4l2_subdev_get_try_format(sd, sd_state,
1792 + fmt->pad);
1793 + *framefmt = fmt->format;
1794 + } else {
1795 + arducam_64mp->mode = mode;
1796 + arducam_64mp->fmt_code = fmt->format.code;
1797 + arducam_64mp_set_framing_limits(arducam_64mp);
1798 + }
1799 +
1800 + mutex_unlock(&arducam_64mp->mutex);
1801 +
1802 + return 0;
1803 +}
1804 +
1805 +static const struct v4l2_rect *
1806 +__arducam_64mp_get_pad_crop(struct arducam_64mp *arducam_64mp,
1807 + struct v4l2_subdev_state *sd_state,
1808 + unsigned int pad,
1809 + enum v4l2_subdev_format_whence which)
1810 +{
1811 + switch (which) {
1812 + case V4L2_SUBDEV_FORMAT_TRY:
1813 + return v4l2_subdev_get_try_crop(&arducam_64mp->sd, sd_state,
1814 + pad);
1815 + case V4L2_SUBDEV_FORMAT_ACTIVE:
1816 + return &arducam_64mp->mode->crop;
1817 + }
1818 +
1819 + return NULL;
1820 +}
1821 +
1822 +static int arducam_64mp_get_selection(struct v4l2_subdev *sd,
1823 + struct v4l2_subdev_state *sd_state,
1824 + struct v4l2_subdev_selection *sel)
1825 +{
1826 + switch (sel->target) {
1827 + case V4L2_SEL_TGT_CROP: {
1828 + struct arducam_64mp *arducam_64mp = to_arducam_64mp(sd);
1829 +
1830 + mutex_lock(&arducam_64mp->mutex);
1831 + sel->r = *__arducam_64mp_get_pad_crop(arducam_64mp, sd_state,
1832 + sel->pad, sel->which);
1833 + mutex_unlock(&arducam_64mp->mutex);
1834 +
1835 + return 0;
1836 + }
1837 +
1838 + case V4L2_SEL_TGT_NATIVE_SIZE:
1839 + sel->r.left = 0;
1840 + sel->r.top = 0;
1841 + sel->r.width = ARDUCAM_64MP_NATIVE_WIDTH;
1842 + sel->r.height = ARDUCAM_64MP_NATIVE_HEIGHT;
1843 +
1844 + return 0;
1845 +
1846 + case V4L2_SEL_TGT_CROP_DEFAULT:
1847 + case V4L2_SEL_TGT_CROP_BOUNDS:
1848 + sel->r.left = ARDUCAM_64MP_PIXEL_ARRAY_LEFT;
1849 + sel->r.top = ARDUCAM_64MP_PIXEL_ARRAY_TOP;
1850 + sel->r.width = ARDUCAM_64MP_PIXEL_ARRAY_WIDTH;
1851 + sel->r.height = ARDUCAM_64MP_PIXEL_ARRAY_HEIGHT;
1852 +
1853 + return 0;
1854 + }
1855 +
1856 + return -EINVAL;
1857 +}
1858 +
1859 +/* Start streaming */
1860 +static int arducam_64mp_start_streaming(struct arducam_64mp *arducam_64mp)
1861 +{
1862 + struct i2c_client *client = v4l2_get_subdevdata(&arducam_64mp->sd);
1863 + const struct arducam_64mp_reg_list *reg_list;
1864 + int ret;
1865 +
1866 + if (!arducam_64mp->common_regs_written) {
1867 + ret = arducam_64mp_write_regs(arducam_64mp, mode_common_regs,
1868 + ARRAY_SIZE(mode_common_regs));
1869 +
1870 + if (ret) {
1871 + dev_err(&client->dev, "%s failed to set common settings\n",
1872 + __func__);
1873 + return ret;
1874 + }
1875 + arducam_64mp->common_regs_written = true;
1876 + }
1877 +
1878 + /* Apply default values of current mode */
1879 + reg_list = &arducam_64mp->mode->reg_list;
1880 + ret = arducam_64mp_write_regs(arducam_64mp, reg_list->regs,
1881 + reg_list->num_of_regs);
1882 + if (ret) {
1883 + dev_err(&client->dev, "%s failed to set mode\n", __func__);
1884 + return ret;
1885 + }
1886 +
1887 + /* Apply customized values from user */
1888 + ret = __v4l2_ctrl_handler_setup(arducam_64mp->sd.ctrl_handler);
1889 + if (ret)
1890 + return ret;
1891 +
1892 + /* set stream on register */
1893 + return arducam_64mp_write_reg(arducam_64mp,
1894 + ARDUCAM_64MP_REG_MODE_SELECT,
1895 + ARDUCAM_64MP_REG_VALUE_08BIT,
1896 + ARDUCAM_64MP_MODE_STREAMING);
1897 +}
1898 +
1899 +/* Stop streaming */
1900 +static void arducam_64mp_stop_streaming(struct arducam_64mp *arducam_64mp)
1901 +{
1902 + struct i2c_client *client = v4l2_get_subdevdata(&arducam_64mp->sd);
1903 + int ret;
1904 +
1905 + /* set stream off register */
1906 + ret = arducam_64mp_write_reg(arducam_64mp, ARDUCAM_64MP_REG_MODE_SELECT,
1907 + ARDUCAM_64MP_REG_VALUE_08BIT,
1908 + ARDUCAM_64MP_MODE_STANDBY);
1909 + if (ret)
1910 + dev_err(&client->dev, "%s failed to set stream\n", __func__);
1911 +}
1912 +
1913 +static int arducam_64mp_set_stream(struct v4l2_subdev *sd, int enable)
1914 +{
1915 + struct arducam_64mp *arducam_64mp = to_arducam_64mp(sd);
1916 + struct i2c_client *client = v4l2_get_subdevdata(sd);
1917 + int ret = 0;
1918 +
1919 + mutex_lock(&arducam_64mp->mutex);
1920 + if (arducam_64mp->streaming == enable) {
1921 + mutex_unlock(&arducam_64mp->mutex);
1922 + return 0;
1923 + }
1924 +
1925 + if (enable) {
1926 + ret = pm_runtime_get_sync(&client->dev);
1927 + if (ret < 0) {
1928 + pm_runtime_put_noidle(&client->dev);
1929 + goto err_unlock;
1930 + }
1931 +
1932 + /*
1933 + * Apply default & customized values
1934 + * and then start streaming.
1935 + */
1936 + ret = arducam_64mp_start_streaming(arducam_64mp);
1937 + if (ret)
1938 + goto err_rpm_put;
1939 + } else {
1940 + arducam_64mp_stop_streaming(arducam_64mp);
1941 + pm_runtime_put(&client->dev);
1942 + }
1943 +
1944 + arducam_64mp->streaming = enable;
1945 +
1946 + /* vflip and hflip cannot change during streaming */
1947 + __v4l2_ctrl_grab(arducam_64mp->vflip, enable);
1948 + __v4l2_ctrl_grab(arducam_64mp->hflip, enable);
1949 +
1950 + mutex_unlock(&arducam_64mp->mutex);
1951 +
1952 + return ret;
1953 +
1954 +err_rpm_put:
1955 + pm_runtime_put(&client->dev);
1956 +err_unlock:
1957 + mutex_unlock(&arducam_64mp->mutex);
1958 +
1959 + return ret;
1960 +}
1961 +
1962 +/* Power/clock management functions */
1963 +static int arducam_64mp_power_on(struct device *dev)
1964 +{
1965 + struct i2c_client *client = to_i2c_client(dev);
1966 + struct v4l2_subdev *sd = i2c_get_clientdata(client);
1967 + struct arducam_64mp *arducam_64mp = to_arducam_64mp(sd);
1968 + int ret;
1969 +
1970 + ret = regulator_bulk_enable(ARDUCAM_64MP_NUM_SUPPLIES,
1971 + arducam_64mp->supplies);
1972 + if (ret) {
1973 + dev_err(&client->dev, "%s: failed to enable regulators\n",
1974 + __func__);
1975 + return ret;
1976 + }
1977 +
1978 + ret = clk_prepare_enable(arducam_64mp->xclk);
1979 + if (ret) {
1980 + dev_err(&client->dev, "%s: failed to enable clock\n",
1981 + __func__);
1982 + goto reg_off;
1983 + }
1984 +
1985 + gpiod_set_value_cansleep(arducam_64mp->reset_gpio, 1);
1986 + usleep_range(ARDUCAM_64MP_XCLR_MIN_DELAY_US,
1987 + ARDUCAM_64MP_XCLR_MIN_DELAY_US +
1988 + ARDUCAM_64MP_XCLR_DELAY_RANGE_US);
1989 +
1990 + return 0;
1991 +
1992 +reg_off:
1993 + regulator_bulk_disable(ARDUCAM_64MP_NUM_SUPPLIES,
1994 + arducam_64mp->supplies);
1995 + return ret;
1996 +}
1997 +
1998 +static int arducam_64mp_power_off(struct device *dev)
1999 +{
2000 + struct i2c_client *client = to_i2c_client(dev);
2001 + struct v4l2_subdev *sd = i2c_get_clientdata(client);
2002 + struct arducam_64mp *arducam_64mp = to_arducam_64mp(sd);
2003 +
2004 + gpiod_set_value_cansleep(arducam_64mp->reset_gpio, 0);
2005 + regulator_bulk_disable(ARDUCAM_64MP_NUM_SUPPLIES,
2006 + arducam_64mp->supplies);
2007 + clk_disable_unprepare(arducam_64mp->xclk);
2008 +
2009 + /* Force reprogramming of the common registers when powered up again. */
2010 + arducam_64mp->common_regs_written = false;
2011 +
2012 + return 0;
2013 +}
2014 +
2015 +static int __maybe_unused arducam_64mp_suspend(struct device *dev)
2016 +{
2017 + struct i2c_client *client = to_i2c_client(dev);
2018 + struct v4l2_subdev *sd = i2c_get_clientdata(client);
2019 + struct arducam_64mp *arducam_64mp = to_arducam_64mp(sd);
2020 +
2021 + if (arducam_64mp->streaming)
2022 + arducam_64mp_stop_streaming(arducam_64mp);
2023 +
2024 + return 0;
2025 +}
2026 +
2027 +static int __maybe_unused arducam_64mp_resume(struct device *dev)
2028 +{
2029 + struct i2c_client *client = to_i2c_client(dev);
2030 + struct v4l2_subdev *sd = i2c_get_clientdata(client);
2031 + struct arducam_64mp *arducam_64mp = to_arducam_64mp(sd);
2032 + int ret;
2033 +
2034 + if (arducam_64mp->streaming) {
2035 + ret = arducam_64mp_start_streaming(arducam_64mp);
2036 + if (ret)
2037 + goto error;
2038 + }
2039 +
2040 + return 0;
2041 +
2042 +error:
2043 + arducam_64mp_stop_streaming(arducam_64mp);
2044 + arducam_64mp->streaming = 0;
2045 + return ret;
2046 +}
2047 +
2048 +static int arducam_64mp_get_regulators(struct arducam_64mp *arducam_64mp)
2049 +{
2050 + struct i2c_client *client = v4l2_get_subdevdata(&arducam_64mp->sd);
2051 + unsigned int i;
2052 +
2053 + for (i = 0; i < ARDUCAM_64MP_NUM_SUPPLIES; i++)
2054 + arducam_64mp->supplies[i].supply = arducam_64mp_supply_name[i];
2055 +
2056 + return devm_regulator_bulk_get(&client->dev,
2057 + ARDUCAM_64MP_NUM_SUPPLIES,
2058 + arducam_64mp->supplies);
2059 +}
2060 +
2061 +/* Verify chip ID */
2062 +static int arducam_64mp_identify_module(struct arducam_64mp *arducam_64mp)
2063 +{
2064 + struct i2c_client *client = v4l2_get_subdevdata(&arducam_64mp->sd);
2065 + struct i2c_client *arducam_identifier;
2066 + int ret;
2067 + u32 val;
2068 +
2069 + arducam_identifier = i2c_new_dummy_device(client->adapter, 0x50);
2070 + if (IS_ERR(arducam_identifier)) {
2071 + dev_err(&client->dev, "failed to create arducam_identifier\n");
2072 + return PTR_ERR(arducam_identifier);
2073 + }
2074 +
2075 + ret = arducam_64mp_read_reg(arducam_identifier,
2076 + ARDUCAM_64MP_REG_CHIP_ID,
2077 + ARDUCAM_64MP_REG_VALUE_16BIT, &val);
2078 + if (ret) {
2079 + dev_err(&client->dev, "failed to read chip id %x, with error %d\n",
2080 + ARDUCAM_64MP_CHIP_ID, ret);
2081 + goto error;
2082 + }
2083 +
2084 + if (val != ARDUCAM_64MP_CHIP_ID) {
2085 + dev_err(&client->dev, "chip id mismatch: %x!=%x\n",
2086 + ARDUCAM_64MP_CHIP_ID, val);
2087 + ret = -EIO;
2088 + goto error;
2089 + }
2090 +
2091 + dev_info(&client->dev, "Device found Arducam 64MP.\n");
2092 +
2093 +error:
2094 + i2c_unregister_device(arducam_identifier);
2095 +
2096 + return ret;
2097 +}
2098 +
2099 +static const struct v4l2_subdev_core_ops arducam_64mp_core_ops = {
2100 + .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
2101 + .unsubscribe_event = v4l2_event_subdev_unsubscribe,
2102 +};
2103 +
2104 +static const struct v4l2_subdev_video_ops arducam_64mp_video_ops = {
2105 + .s_stream = arducam_64mp_set_stream,
2106 +};
2107 +
2108 +static const struct v4l2_subdev_pad_ops arducam_64mp_pad_ops = {
2109 + .enum_mbus_code = arducam_64mp_enum_mbus_code,
2110 + .get_fmt = arducam_64mp_get_pad_format,
2111 + .set_fmt = arducam_64mp_set_pad_format,
2112 + .get_selection = arducam_64mp_get_selection,
2113 + .enum_frame_size = arducam_64mp_enum_frame_size,
2114 +};
2115 +
2116 +static const struct v4l2_subdev_ops arducam_64mp_subdev_ops = {
2117 + .core = &arducam_64mp_core_ops,
2118 + .video = &arducam_64mp_video_ops,
2119 + .pad = &arducam_64mp_pad_ops,
2120 +};
2121 +
2122 +static const struct v4l2_subdev_internal_ops arducam_64mp_internal_ops = {
2123 + .open = arducam_64mp_open,
2124 +};
2125 +
2126 +/* Initialize control handlers */
2127 +static int arducam_64mp_init_controls(struct arducam_64mp *arducam_64mp)
2128 +{
2129 + struct v4l2_ctrl_handler *ctrl_hdlr;
2130 + struct i2c_client *client = v4l2_get_subdevdata(&arducam_64mp->sd);
2131 + struct v4l2_fwnode_device_properties props;
2132 + unsigned int i;
2133 + int ret;
2134 + u8 test_pattern_max;
2135 +
2136 + ctrl_hdlr = &arducam_64mp->ctrl_handler;
2137 + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 16);
2138 + if (ret)
2139 + return ret;
2140 +
2141 + mutex_init(&arducam_64mp->mutex);
2142 + ctrl_hdlr->lock = &arducam_64mp->mutex;
2143 +
2144 + /* By default, PIXEL_RATE is read only */
2145 + arducam_64mp->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr,
2146 + &arducam_64mp_ctrl_ops,
2147 + V4L2_CID_PIXEL_RATE,
2148 + ARDUCAM_64MP_PIXEL_RATE,
2149 + ARDUCAM_64MP_PIXEL_RATE, 1,
2150 + ARDUCAM_64MP_PIXEL_RATE);
2151 +
2152 + /*
2153 + * Create the controls here, but mode specific limits are setup
2154 + * in the arducam_64mp_set_framing_limits() call below.
2155 + */
2156 + arducam_64mp->vblank = v4l2_ctrl_new_std(ctrl_hdlr,
2157 + &arducam_64mp_ctrl_ops,
2158 + V4L2_CID_VBLANK,
2159 + 0, 0xffff, 1, 0);
2160 + arducam_64mp->hblank = v4l2_ctrl_new_std(ctrl_hdlr,
2161 + &arducam_64mp_ctrl_ops,
2162 + V4L2_CID_HBLANK,
2163 + 0, 0xffff, 1, 0);
2164 +
2165 + /* HBLANK is read-only, but does change with mode. */
2166 + if (arducam_64mp->hblank)
2167 + arducam_64mp->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
2168 +
2169 + arducam_64mp->exposure =
2170 + v4l2_ctrl_new_std(ctrl_hdlr,
2171 + &arducam_64mp_ctrl_ops,
2172 + V4L2_CID_EXPOSURE,
2173 + ARDUCAM_64MP_EXPOSURE_MIN,
2174 + ARDUCAM_64MP_EXPOSURE_MAX,
2175 + ARDUCAM_64MP_EXPOSURE_STEP,
2176 + ARDUCAM_64MP_EXPOSURE_DEFAULT);
2177 +
2178 + v4l2_ctrl_new_std(ctrl_hdlr, &arducam_64mp_ctrl_ops,
2179 + V4L2_CID_ANALOGUE_GAIN, ARDUCAM_64MP_ANA_GAIN_MIN,
2180 + ARDUCAM_64MP_ANA_GAIN_MAX, ARDUCAM_64MP_ANA_GAIN_STEP,
2181 + ARDUCAM_64MP_ANA_GAIN_DEFAULT);
2182 +
2183 + v4l2_ctrl_new_std(ctrl_hdlr, &arducam_64mp_ctrl_ops,
2184 + V4L2_CID_DIGITAL_GAIN, ARDUCAM_64MP_DGTL_GAIN_MIN,
2185 + ARDUCAM_64MP_DGTL_GAIN_MAX,
2186 + ARDUCAM_64MP_DGTL_GAIN_STEP,
2187 + ARDUCAM_64MP_DGTL_GAIN_DEFAULT);
2188 +
2189 + arducam_64mp->hflip = v4l2_ctrl_new_std(ctrl_hdlr,
2190 + &arducam_64mp_ctrl_ops,
2191 + V4L2_CID_HFLIP, 0, 1, 1, 0);
2192 + if (arducam_64mp->hflip)
2193 + arducam_64mp->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
2194 +
2195 + arducam_64mp->vflip = v4l2_ctrl_new_std(ctrl_hdlr,
2196 + &arducam_64mp_ctrl_ops,
2197 + V4L2_CID_VFLIP, 0, 1, 1, 0);
2198 + if (arducam_64mp->vflip)
2199 + arducam_64mp->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
2200 +
2201 + test_pattern_max = ARRAY_SIZE(arducam_64mp_test_pattern_menu) - 1;
2202 + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &arducam_64mp_ctrl_ops,
2203 + V4L2_CID_TEST_PATTERN,
2204 + test_pattern_max,
2205 + 0, 0, arducam_64mp_test_pattern_menu);
2206 + for (i = 0; i < 4; i++) {
2207 + /*
2208 + * The assumption is that
2209 + * V4L2_CID_TEST_PATTERN_GREENR == V4L2_CID_TEST_PATTERN_RED + 1
2210 + * V4L2_CID_TEST_PATTERN_BLUE == V4L2_CID_TEST_PATTERN_RED + 2
2211 + * V4L2_CID_TEST_PATTERN_GREENB == V4L2_CID_TEST_PATTERN_RED + 3
2212 + */
2213 + v4l2_ctrl_new_std(ctrl_hdlr, &arducam_64mp_ctrl_ops,
2214 + V4L2_CID_TEST_PATTERN_RED + i,
2215 + ARDUCAM_64MP_TEST_PATTERN_COLOUR_MIN,
2216 + ARDUCAM_64MP_TEST_PATTERN_COLOUR_MAX,
2217 + ARDUCAM_64MP_TEST_PATTERN_COLOUR_STEP,
2218 + ARDUCAM_64MP_TEST_PATTERN_COLOUR_MAX);
2219 + /* The "Solid color" pattern is white by default */
2220 + }
2221 +
2222 + if (ctrl_hdlr->error) {
2223 + ret = ctrl_hdlr->error;
2224 + dev_err(&client->dev, "%s control init failed (%d)\n",
2225 + __func__, ret);
2226 + goto error;
2227 + }
2228 +
2229 + ret = v4l2_fwnode_device_parse(&client->dev, &props);
2230 + if (ret)
2231 + goto error;
2232 +
2233 + ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &arducam_64mp_ctrl_ops,
2234 + &props);
2235 + if (ret)
2236 + goto error;
2237 +
2238 + arducam_64mp->sd.ctrl_handler = ctrl_hdlr;
2239 +
2240 + /* Setup exposure and frame/line length limits. */
2241 + arducam_64mp_set_framing_limits(arducam_64mp);
2242 +
2243 + return 0;
2244 +
2245 +error:
2246 + v4l2_ctrl_handler_free(ctrl_hdlr);
2247 + mutex_destroy(&arducam_64mp->mutex);
2248 +
2249 + return ret;
2250 +}
2251 +
2252 +static void arducam_64mp_free_controls(struct arducam_64mp *arducam_64mp)
2253 +{
2254 + v4l2_ctrl_handler_free(arducam_64mp->sd.ctrl_handler);
2255 + mutex_destroy(&arducam_64mp->mutex);
2256 +}
2257 +
2258 +static int arducam_64mp_check_hwcfg(struct device *dev)
2259 +{
2260 + struct fwnode_handle *endpoint;
2261 + struct v4l2_fwnode_endpoint ep_cfg = {
2262 + .bus_type = V4L2_MBUS_CSI2_DPHY
2263 + };
2264 + int ret = -EINVAL;
2265 +
2266 + endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL);
2267 + if (!endpoint) {
2268 + dev_err(dev, "endpoint node not found\n");
2269 + return -EINVAL;
2270 + }
2271 +
2272 + if (v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep_cfg)) {
2273 + dev_err(dev, "could not parse endpoint\n");
2274 + goto error_out;
2275 + }
2276 +
2277 + /* Check the number of MIPI CSI2 data lanes */
2278 + if (ep_cfg.bus.mipi_csi2.num_data_lanes != 2) {
2279 + dev_err(dev, "only 2 data lanes are currently supported\n");
2280 + goto error_out;
2281 + }
2282 +
2283 + /* Check the link frequency set in device tree */
2284 + if (!ep_cfg.nr_of_link_frequencies) {
2285 + dev_err(dev, "link-frequency property not found in DT\n");
2286 + goto error_out;
2287 + }
2288 +
2289 + if (ep_cfg.nr_of_link_frequencies != 1 ||
2290 + ep_cfg.link_frequencies[0] != ARDUCAM_64MP_DEFAULT_LINK_FREQ) {
2291 + dev_err(dev, "Link frequency not supported: %lld\n",
2292 + ep_cfg.link_frequencies[0]);
2293 + goto error_out;
2294 + }
2295 +
2296 + ret = 0;
2297 +
2298 +error_out:
2299 + v4l2_fwnode_endpoint_free(&ep_cfg);
2300 + fwnode_handle_put(endpoint);
2301 +
2302 + return ret;
2303 +}
2304 +
2305 +static const struct of_device_id arducam_64mp_dt_ids[] = {
2306 + { .compatible = "arducam,64mp"},
2307 + { /* sentinel */ }
2308 +};
2309 +
2310 +static int arducam_64mp_probe(struct i2c_client *client)
2311 +{
2312 + struct device *dev = &client->dev;
2313 + struct arducam_64mp *arducam_64mp;
2314 + const struct of_device_id *match;
2315 + u32 xclk_freq;
2316 + int ret;
2317 +
2318 + arducam_64mp = devm_kzalloc(&client->dev, sizeof(*arducam_64mp),
2319 + GFP_KERNEL);
2320 + if (!arducam_64mp)
2321 + return -ENOMEM;
2322 +
2323 + v4l2_i2c_subdev_init(&arducam_64mp->sd, client,
2324 + &arducam_64mp_subdev_ops);
2325 +
2326 + match = of_match_device(arducam_64mp_dt_ids, dev);
2327 + if (!match)
2328 + return -ENODEV;
2329 +
2330 + /* Check the hardware configuration in device tree */
2331 + if (arducam_64mp_check_hwcfg(dev))
2332 + return -EINVAL;
2333 +
2334 + /* Get system clock (xclk) */
2335 + arducam_64mp->xclk = devm_clk_get(dev, NULL);
2336 + if (IS_ERR(arducam_64mp->xclk)) {
2337 + dev_err(dev, "failed to get xclk\n");
2338 + return PTR_ERR(arducam_64mp->xclk);
2339 + }
2340 +
2341 + xclk_freq = clk_get_rate(arducam_64mp->xclk);
2342 + if (xclk_freq != ARDUCAM_64MP_XCLK_FREQ) {
2343 + dev_err(dev, "xclk frequency not supported: %d Hz\n",
2344 + xclk_freq);
2345 + return -EINVAL;
2346 + }
2347 +
2348 + ret = arducam_64mp_get_regulators(arducam_64mp);
2349 + if (ret) {
2350 + dev_err(dev, "failed to get regulators\n");
2351 + return ret;
2352 + }
2353 +
2354 + /* Request optional enable pin */
2355 + arducam_64mp->reset_gpio = devm_gpiod_get_optional(dev, "reset",
2356 + GPIOD_OUT_HIGH);
2357 +
2358 + /*
2359 + * The sensor must be powered for arducam_64mp_identify_module()
2360 + * to be able to read the CHIP_ID from arducam_identifier.
2361 + */
2362 + ret = arducam_64mp_power_on(dev);
2363 + if (ret)
2364 + return ret;
2365 +
2366 + ret = arducam_64mp_identify_module(arducam_64mp);
2367 + if (ret)
2368 + goto error_power_off;
2369 +
2370 + /* Set default mode to max resolution */
2371 + arducam_64mp->mode = &supported_modes[0];
2372 + arducam_64mp->fmt_code = MEDIA_BUS_FMT_SRGGB10_1X10;
2373 +
2374 + /* Enable runtime PM and turn off the device */
2375 + pm_runtime_set_active(dev);
2376 + pm_runtime_enable(dev);
2377 + pm_runtime_idle(dev);
2378 +
2379 + /* This needs the pm runtime to be registered. */
2380 + ret = arducam_64mp_init_controls(arducam_64mp);
2381 + if (ret)
2382 + goto error_power_off;
2383 +
2384 + /* Initialize subdev */
2385 + arducam_64mp->sd.internal_ops = &arducam_64mp_internal_ops;
2386 + arducam_64mp->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
2387 + V4L2_SUBDEV_FL_HAS_EVENTS;
2388 + arducam_64mp->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
2389 +
2390 + /* Initialize source pads */
2391 + arducam_64mp->pad.flags = MEDIA_PAD_FL_SOURCE;
2392 +
2393 + ret = media_entity_pads_init(&arducam_64mp->sd.entity, 1,
2394 + &arducam_64mp->pad);
2395 + if (ret) {
2396 + dev_err(dev, "failed to init entity pads: %d\n", ret);
2397 + goto error_handler_free;
2398 + }
2399 +
2400 + ret = v4l2_async_register_subdev_sensor(&arducam_64mp->sd);
2401 + if (ret < 0) {
2402 + dev_err(dev, "failed to register sensor sub-device: %d\n", ret);
2403 + goto error_media_entity;
2404 + }
2405 +
2406 + return 0;
2407 +
2408 +error_media_entity:
2409 + media_entity_cleanup(&arducam_64mp->sd.entity);
2410 +
2411 +error_handler_free:
2412 + arducam_64mp_free_controls(arducam_64mp);
2413 +
2414 +error_power_off:
2415 + pm_runtime_disable(&client->dev);
2416 + pm_runtime_set_suspended(&client->dev);
2417 + arducam_64mp_power_off(&client->dev);
2418 +
2419 + return ret;
2420 +}
2421 +
2422 +static void arducam_64mp_remove(struct i2c_client *client)
2423 +{
2424 + struct v4l2_subdev *sd = i2c_get_clientdata(client);
2425 + struct arducam_64mp *arducam_64mp = to_arducam_64mp(sd);
2426 +
2427 + v4l2_async_unregister_subdev(sd);
2428 + media_entity_cleanup(&sd->entity);
2429 + arducam_64mp_free_controls(arducam_64mp);
2430 +
2431 + pm_runtime_disable(&client->dev);
2432 + if (!pm_runtime_status_suspended(&client->dev))
2433 + arducam_64mp_power_off(&client->dev);
2434 + pm_runtime_set_suspended(&client->dev);
2435 +}
2436 +
2437 +MODULE_DEVICE_TABLE(of, arducam_64mp_dt_ids);
2438 +
2439 +static const struct dev_pm_ops arducam_64mp_pm_ops = {
2440 + SET_SYSTEM_SLEEP_PM_OPS(arducam_64mp_suspend, arducam_64mp_resume)
2441 + SET_RUNTIME_PM_OPS(arducam_64mp_power_off, arducam_64mp_power_on, NULL)
2442 +};
2443 +
2444 +static struct i2c_driver arducam_64mp_i2c_driver = {
2445 + .driver = {
2446 + .name = "arducam_64mp",
2447 + .of_match_table = arducam_64mp_dt_ids,
2448 + .pm = &arducam_64mp_pm_ops,
2449 + },
2450 + .probe_new = arducam_64mp_probe,
2451 + .remove = arducam_64mp_remove,
2452 +};
2453 +
2454 +module_i2c_driver(arducam_64mp_i2c_driver);
2455 +
2456 +MODULE_AUTHOR("Lee Jackson <info@arducam.com>");
2457 +MODULE_DESCRIPTION("Arducam 64MP sensor driver");
2458 +MODULE_LICENSE("GPL v2");