xref: /linux/drivers/media/i2c/s5k3m5.c (revision c17ee635fd3a482b2ad2bf5e269755c2eae5f25e)
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2025 Linaro Ltd
3 
4 #include <linux/clk.h>
5 #include <linux/delay.h>
6 #include <linux/gpio/consumer.h>
7 #include <linux/i2c.h>
8 #include <linux/module.h>
9 #include <linux/pm_runtime.h>
10 #include <linux/regulator/consumer.h>
11 #include <linux/units.h>
12 #include <media/v4l2-cci.h>
13 #include <media/v4l2-ctrls.h>
14 #include <media/v4l2-device.h>
15 #include <media/v4l2-fwnode.h>
16 
17 #define S5K3M5_LINK_FREQ_602P5MHZ	(602500ULL * HZ_PER_KHZ)
18 #define S5K3M5_MCLK_FREQ_24MHZ		(24 * HZ_PER_MHZ)
19 #define S5K3M5_DATA_LANES		4
20 
21 /* Register map is similar to MIPI CCS compliant camera sensors */
22 #define S5K3M5_REG_CHIP_ID		CCI_REG16(0x0000)
23 #define S5K3M5_CHIP_ID			0x30d5
24 
25 /* Both streaming and flipping settings are controlled at the same time */
26 #define S5K3M5_REG_CTRL_MODE		CCI_REG16(0x0100)
27 #define S5K3M5_MODE_STREAMING		BIT(8)
28 #define S5K3M5_VFLIP			BIT(1)
29 #define S5K3M5_HFLIP			BIT(0)
30 
31 #define S5K3M5_REG_EXPOSURE		CCI_REG16(0x0202)
32 #define S5K3M5_EXPOSURE_MIN		8
33 #define S5K3M5_EXPOSURE_STEP		1
34 #define S5K3M5_EXPOSURE_MARGIN		4
35 
36 #define S5K3M5_REG_AGAIN		CCI_REG16(0x0204)
37 #define S5K3M5_AGAIN_MIN		1
38 #define S5K3M5_AGAIN_MAX		16
39 #define S5K3M5_AGAIN_STEP		1
40 #define S5K3M5_AGAIN_DEFAULT		1
41 #define S5K3M5_AGAIN_SHIFT		5
42 
43 #define S5K3M5_REG_VTS			CCI_REG16(0x0340)
44 #define S5K3M5_VTS_MAX			0xffff
45 
46 #define S5K3M5_REG_HTS			CCI_REG16(0x0342)
47 #define S5K3M5_REG_X_ADDR_START		CCI_REG16(0x0344)
48 #define S5K3M5_REG_Y_ADDR_START		CCI_REG16(0x0346)
49 #define S5K3M5_REG_X_ADDR_END		CCI_REG16(0x0348)
50 #define S5K3M5_REG_Y_ADDR_END		CCI_REG16(0x034a)
51 #define S5K3M5_REG_X_OUTPUT_SIZE	CCI_REG16(0x034c)
52 #define S5K3M5_REG_Y_OUTPUT_SIZE	CCI_REG16(0x034e)
53 
54 #define S5K3M5_REG_TEST_PATTERN		CCI_REG16(0x0600)
55 
56 #define to_s5k3m5(_sd)			container_of(_sd, struct s5k3m5, sd)
57 
58 static const s64 s5k3m5_link_freq_menu[] = {
59 	S5K3M5_LINK_FREQ_602P5MHZ,
60 };
61 
62 /* List of supported formats to cover horizontal and vertical flip controls */
63 static const u32 s5k3m5_mbus_formats[] = {
64 	MEDIA_BUS_FMT_SGRBG10_1X10,	MEDIA_BUS_FMT_SRGGB10_1X10,
65 	MEDIA_BUS_FMT_SBGGR10_1X10,	MEDIA_BUS_FMT_SGBRG10_1X10,
66 };
67 
68 struct s5k3m5_reg_list {
69 	const struct cci_reg_sequence *regs;
70 	unsigned int num_regs;
71 };
72 
73 struct s5k3m5_mode {
74 	u32 width;			/* Frame width in pixels */
75 	u32 height;			/* Frame height in pixels */
76 	u32 hts;			/* Horizontal timing size */
77 	u32 vts;			/* Default vertical timing size */
78 	u32 exposure;			/* Default exposure value */
79 
80 	const struct s5k3m5_reg_list reg_list;	/* Sensor register setting */
81 };
82 
83 static const char * const s5k3m5_test_pattern_menu[] = {
84 	"Disabled",
85 	"Solid colour",
86 	"Colour bars",
87 	"Fade to grey colour bars",
88 	"PN9",
89 };
90 
91 static const char * const s5k3m5_supply_names[] = {
92 	"afvdd",	/* Autofocus power */
93 	"vdda",		/* Analog power */
94 	"vddd",		/* Digital core power */
95 	"vddio",	/* Digital I/O power */
96 };
97 
98 #define S5K3M5_NUM_SUPPLIES	ARRAY_SIZE(s5k3m5_supply_names)
99 
100 struct s5k3m5 {
101 	struct device *dev;
102 	struct regmap *regmap;
103 	struct clk *mclk;
104 	struct gpio_desc *reset_gpio;
105 	struct regulator_bulk_data supplies[S5K3M5_NUM_SUPPLIES];
106 
107 	struct v4l2_subdev sd;
108 	struct media_pad pad;
109 
110 	struct v4l2_ctrl_handler ctrl_handler;
111 	struct v4l2_ctrl *link_freq;
112 	struct v4l2_ctrl *pixel_rate;
113 	struct v4l2_ctrl *hblank;
114 	struct v4l2_ctrl *vblank;
115 	struct v4l2_ctrl *exposure;
116 	struct v4l2_ctrl *vflip;
117 	struct v4l2_ctrl *hflip;
118 
119 	const struct s5k3m5_mode *mode;
120 };
121 
122 static const struct cci_reg_sequence burst_array_setting[] = {
123 	{ CCI_REG16(0x6f12), 0x0000 },
124 	{ CCI_REG16(0x6f12), 0x0000 },
125 	{ CCI_REG16(0x6f12), 0x0549 },
126 	{ CCI_REG16(0x6f12), 0x0448 },
127 	{ CCI_REG16(0x6f12), 0x054a },
128 	{ CCI_REG16(0x6f12), 0xc1f8 },
129 	{ CCI_REG16(0x6f12), 0xc804 },
130 	{ CCI_REG16(0x6f12), 0x101a },
131 	{ CCI_REG16(0x6f12), 0xa1f8 },
132 	{ CCI_REG16(0x6f12), 0xcc04 },
133 	{ CCI_REG16(0x6f12), 0x00f0 },
134 	{ CCI_REG16(0x6f12), 0x1bb9 },
135 	{ CCI_REG16(0x6f12), 0x2000 },
136 	{ CCI_REG16(0x6f12), 0x4210 },
137 	{ CCI_REG16(0x6f12), 0x2000 },
138 	{ CCI_REG16(0x6f12), 0x2e50 },
139 	{ CCI_REG16(0x6f12), 0x2000 },
140 	{ CCI_REG16(0x6f12), 0x7000 },
141 	{ CCI_REG16(0x6f12), 0x10b5 },
142 	{ CCI_REG16(0x6f12), 0x00f0 },
143 	{ CCI_REG16(0x6f12), 0x4ff9 },
144 	{ CCI_REG16(0x6f12), 0x9949 },
145 	{ CCI_REG16(0x6f12), 0x0120 },
146 	{ CCI_REG16(0x6f12), 0x0880 },
147 	{ CCI_REG16(0x6f12), 0x10bd },
148 	{ CCI_REG16(0x6f12), 0x2de9 },
149 	{ CCI_REG16(0x6f12), 0xf041 },
150 	{ CCI_REG16(0x6f12), 0x974c },
151 	{ CCI_REG16(0x6f12), 0x954f },
152 	{ CCI_REG16(0x6f12), 0x0026 },
153 	{ CCI_REG16(0x6f12), 0xb4f8 },
154 	{ CCI_REG16(0x6f12), 0x6a52 },
155 	{ CCI_REG16(0x6f12), 0x3888 },
156 	{ CCI_REG16(0x6f12), 0x08b1 },
157 	{ CCI_REG16(0x6f12), 0xa4f8 },
158 	{ CCI_REG16(0x6f12), 0x6a62 },
159 	{ CCI_REG16(0x6f12), 0x00f0 },
160 	{ CCI_REG16(0x6f12), 0x43f9 },
161 	{ CCI_REG16(0x6f12), 0x3e80 },
162 	{ CCI_REG16(0x6f12), 0xa4f8 },
163 	{ CCI_REG16(0x6f12), 0x6a52 },
164 	{ CCI_REG16(0x6f12), 0xbde8 },
165 	{ CCI_REG16(0x6f12), 0xf081 },
166 	{ CCI_REG16(0x6f12), 0x2de9 },
167 	{ CCI_REG16(0x6f12), 0xf041 },
168 	{ CCI_REG16(0x6f12), 0x0746 },
169 	{ CCI_REG16(0x6f12), 0x8c48 },
170 	{ CCI_REG16(0x6f12), 0x0e46 },
171 	{ CCI_REG16(0x6f12), 0x0022 },
172 	{ CCI_REG16(0x6f12), 0x4068 },
173 	{ CCI_REG16(0x6f12), 0x84b2 },
174 	{ CCI_REG16(0x6f12), 0x050c },
175 	{ CCI_REG16(0x6f12), 0x2146 },
176 	{ CCI_REG16(0x6f12), 0x2846 },
177 	{ CCI_REG16(0x6f12), 0x00f0 },
178 	{ CCI_REG16(0x6f12), 0x36f9 },
179 	{ CCI_REG16(0x6f12), 0x3146 },
180 	{ CCI_REG16(0x6f12), 0x3846 },
181 	{ CCI_REG16(0x6f12), 0x00f0 },
182 	{ CCI_REG16(0x6f12), 0x37f9 },
183 	{ CCI_REG16(0x6f12), 0x874f },
184 	{ CCI_REG16(0x6f12), 0x4df2 },
185 	{ CCI_REG16(0x6f12), 0x0c26 },
186 	{ CCI_REG16(0x6f12), 0x4ff4 },
187 	{ CCI_REG16(0x6f12), 0x8061 },
188 	{ CCI_REG16(0x6f12), 0x3a78 },
189 	{ CCI_REG16(0x6f12), 0x3046 },
190 	{ CCI_REG16(0x6f12), 0x00f0 },
191 	{ CCI_REG16(0x6f12), 0x29f9 },
192 	{ CCI_REG16(0x6f12), 0x7878 },
193 	{ CCI_REG16(0x6f12), 0xb8b3 },
194 	{ CCI_REG16(0x6f12), 0x0022 },
195 	{ CCI_REG16(0x6f12), 0x8021 },
196 	{ CCI_REG16(0x6f12), 0x3046 },
197 	{ CCI_REG16(0x6f12), 0x00f0 },
198 	{ CCI_REG16(0x6f12), 0x22f9 },
199 	{ CCI_REG16(0x6f12), 0x8048 },
200 	{ CCI_REG16(0x6f12), 0x0088 },
201 	{ CCI_REG16(0x6f12), 0x804b },
202 	{ CCI_REG16(0x6f12), 0xa3f8 },
203 	{ CCI_REG16(0x6f12), 0x5c02 },
204 	{ CCI_REG16(0x6f12), 0x7e48 },
205 	{ CCI_REG16(0x6f12), 0x001d },
206 	{ CCI_REG16(0x6f12), 0x0088 },
207 	{ CCI_REG16(0x6f12), 0xa3f8 },
208 	{ CCI_REG16(0x6f12), 0x5e02 },
209 	{ CCI_REG16(0x6f12), 0xb3f8 },
210 	{ CCI_REG16(0x6f12), 0x5c02 },
211 	{ CCI_REG16(0x6f12), 0xb3f8 },
212 	{ CCI_REG16(0x6f12), 0x5e12 },
213 	{ CCI_REG16(0x6f12), 0x4218 },
214 	{ CCI_REG16(0x6f12), 0x02d0 },
215 	{ CCI_REG16(0x6f12), 0x8002 },
216 	{ CCI_REG16(0x6f12), 0xb0fb },
217 	{ CCI_REG16(0x6f12), 0xf2f2 },
218 	{ CCI_REG16(0x6f12), 0x91b2 },
219 	{ CCI_REG16(0x6f12), 0x784a },
220 	{ CCI_REG16(0x6f12), 0xa3f8 },
221 	{ CCI_REG16(0x6f12), 0x6012 },
222 	{ CCI_REG16(0x6f12), 0xb2f8 },
223 	{ CCI_REG16(0x6f12), 0x1602 },
224 	{ CCI_REG16(0x6f12), 0xb2f8 },
225 	{ CCI_REG16(0x6f12), 0x1422 },
226 	{ CCI_REG16(0x6f12), 0xa3f8 },
227 	{ CCI_REG16(0x6f12), 0x9805 },
228 	{ CCI_REG16(0x6f12), 0xa3f8 },
229 	{ CCI_REG16(0x6f12), 0x9a25 },
230 	{ CCI_REG16(0x6f12), 0x8018 },
231 	{ CCI_REG16(0x6f12), 0x04d0 },
232 	{ CCI_REG16(0x6f12), 0x9202 },
233 	{ CCI_REG16(0x6f12), 0xb2fb },
234 	{ CCI_REG16(0x6f12), 0xf0f0 },
235 	{ CCI_REG16(0x6f12), 0xa3f8 },
236 	{ CCI_REG16(0x6f12), 0x9c05 },
237 	{ CCI_REG16(0x6f12), 0xb3f8 },
238 	{ CCI_REG16(0x6f12), 0x9c05 },
239 	{ CCI_REG16(0x6f12), 0x0a18 },
240 	{ CCI_REG16(0x6f12), 0x01fb },
241 	{ CCI_REG16(0x6f12), 0x1020 },
242 	{ CCI_REG16(0x6f12), 0x40f3 },
243 	{ CCI_REG16(0x6f12), 0x9510 },
244 	{ CCI_REG16(0x6f12), 0x1028 },
245 	{ CCI_REG16(0x6f12), 0x06dc },
246 	{ CCI_REG16(0x6f12), 0x0028 },
247 	{ CCI_REG16(0x6f12), 0x05da },
248 	{ CCI_REG16(0x6f12), 0x0020 },
249 	{ CCI_REG16(0x6f12), 0x03e0 },
250 	{ CCI_REG16(0x6f12), 0xffe7 },
251 	{ CCI_REG16(0x6f12), 0x0122 },
252 	{ CCI_REG16(0x6f12), 0xc5e7 },
253 	{ CCI_REG16(0x6f12), 0x1020 },
254 	{ CCI_REG16(0x6f12), 0x6849 },
255 	{ CCI_REG16(0x6f12), 0x0880 },
256 	{ CCI_REG16(0x6f12), 0x2146 },
257 	{ CCI_REG16(0x6f12), 0x2846 },
258 	{ CCI_REG16(0x6f12), 0xbde8 },
259 	{ CCI_REG16(0x6f12), 0xf041 },
260 	{ CCI_REG16(0x6f12), 0x0122 },
261 	{ CCI_REG16(0x6f12), 0x00f0 },
262 	{ CCI_REG16(0x6f12), 0xe2b8 },
263 	{ CCI_REG16(0x6f12), 0xf0b5 },
264 	{ CCI_REG16(0x6f12), 0x644c },
265 	{ CCI_REG16(0x6f12), 0xdde9 },
266 	{ CCI_REG16(0x6f12), 0x0565 },
267 	{ CCI_REG16(0x6f12), 0x08b1 },
268 	{ CCI_REG16(0x6f12), 0x2788 },
269 	{ CCI_REG16(0x6f12), 0x0760 },
270 	{ CCI_REG16(0x6f12), 0x09b1 },
271 	{ CCI_REG16(0x6f12), 0x6088 },
272 	{ CCI_REG16(0x6f12), 0x0860 },
273 	{ CCI_REG16(0x6f12), 0x12b1 },
274 	{ CCI_REG16(0x6f12), 0xa088 },
275 	{ CCI_REG16(0x6f12), 0x401c },
276 	{ CCI_REG16(0x6f12), 0x1060 },
277 	{ CCI_REG16(0x6f12), 0x0bb1 },
278 	{ CCI_REG16(0x6f12), 0xe088 },
279 	{ CCI_REG16(0x6f12), 0x1860 },
280 	{ CCI_REG16(0x6f12), 0x0eb1 },
281 	{ CCI_REG16(0x6f12), 0xa07b },
282 	{ CCI_REG16(0x6f12), 0x3060 },
283 	{ CCI_REG16(0x6f12), 0x002d },
284 	{ CCI_REG16(0x6f12), 0x01d0 },
285 	{ CCI_REG16(0x6f12), 0xe07b },
286 	{ CCI_REG16(0x6f12), 0x2860 },
287 	{ CCI_REG16(0x6f12), 0xf0bd },
288 	{ CCI_REG16(0x6f12), 0x70b5 },
289 	{ CCI_REG16(0x6f12), 0x0646 },
290 	{ CCI_REG16(0x6f12), 0x5048 },
291 	{ CCI_REG16(0x6f12), 0x0022 },
292 	{ CCI_REG16(0x6f12), 0x8068 },
293 	{ CCI_REG16(0x6f12), 0x84b2 },
294 	{ CCI_REG16(0x6f12), 0x050c },
295 	{ CCI_REG16(0x6f12), 0x2146 },
296 	{ CCI_REG16(0x6f12), 0x2846 },
297 	{ CCI_REG16(0x6f12), 0x00f0 },
298 	{ CCI_REG16(0x6f12), 0xbef8 },
299 	{ CCI_REG16(0x6f12), 0x3046 },
300 	{ CCI_REG16(0x6f12), 0x00f0 },
301 	{ CCI_REG16(0x6f12), 0xc5f8 },
302 	{ CCI_REG16(0x6f12), 0x5248 },
303 	{ CCI_REG16(0x6f12), 0x0368 },
304 	{ CCI_REG16(0x6f12), 0xb3f8 },
305 	{ CCI_REG16(0x6f12), 0x7401 },
306 	{ CCI_REG16(0x6f12), 0x010a },
307 	{ CCI_REG16(0x6f12), 0x5048 },
308 	{ CCI_REG16(0x6f12), 0x4268 },
309 	{ CCI_REG16(0x6f12), 0x82f8 },
310 	{ CCI_REG16(0x6f12), 0x5010 },
311 	{ CCI_REG16(0x6f12), 0x93f8 },
312 	{ CCI_REG16(0x6f12), 0x7511 },
313 	{ CCI_REG16(0x6f12), 0x82f8 },
314 	{ CCI_REG16(0x6f12), 0x5210 },
315 	{ CCI_REG16(0x6f12), 0xb3f8 },
316 	{ CCI_REG16(0x6f12), 0x7811 },
317 	{ CCI_REG16(0x6f12), 0x090a },
318 	{ CCI_REG16(0x6f12), 0x82f8 },
319 	{ CCI_REG16(0x6f12), 0x5810 },
320 	{ CCI_REG16(0x6f12), 0x93f8 },
321 	{ CCI_REG16(0x6f12), 0x7911 },
322 	{ CCI_REG16(0x6f12), 0x82f8 },
323 	{ CCI_REG16(0x6f12), 0x5a10 },
324 	{ CCI_REG16(0x6f12), 0x33f8 },
325 	{ CCI_REG16(0x6f12), 0xf01f },
326 	{ CCI_REG16(0x6f12), 0x0068 },
327 	{ CCI_REG16(0x6f12), 0x090a },
328 	{ CCI_REG16(0x6f12), 0x00f8 },
329 	{ CCI_REG16(0x6f12), 0xce1f },
330 	{ CCI_REG16(0x6f12), 0x5978 },
331 	{ CCI_REG16(0x6f12), 0x8170 },
332 	{ CCI_REG16(0x6f12), 0x5988 },
333 	{ CCI_REG16(0x6f12), 0x090a },
334 	{ CCI_REG16(0x6f12), 0x0171 },
335 	{ CCI_REG16(0x6f12), 0xd978 },
336 	{ CCI_REG16(0x6f12), 0x8171 },
337 	{ CCI_REG16(0x6f12), 0x988c },
338 	{ CCI_REG16(0x6f12), 0x000a },
339 	{ CCI_REG16(0x6f12), 0x9074 },
340 	{ CCI_REG16(0x6f12), 0x93f8 },
341 	{ CCI_REG16(0x6f12), 0x2500 },
342 	{ CCI_REG16(0x6f12), 0x1075 },
343 	{ CCI_REG16(0x6f12), 0xd88c },
344 	{ CCI_REG16(0x6f12), 0x000a },
345 	{ CCI_REG16(0x6f12), 0x9075 },
346 	{ CCI_REG16(0x6f12), 0x93f8 },
347 	{ CCI_REG16(0x6f12), 0x2700 },
348 	{ CCI_REG16(0x6f12), 0x1076 },
349 	{ CCI_REG16(0x6f12), 0xb3f8 },
350 	{ CCI_REG16(0x6f12), 0xb000 },
351 	{ CCI_REG16(0x6f12), 0x000a },
352 	{ CCI_REG16(0x6f12), 0x82f8 },
353 	{ CCI_REG16(0x6f12), 0x7e00 },
354 	{ CCI_REG16(0x6f12), 0x93f8 },
355 	{ CCI_REG16(0x6f12), 0xb100 },
356 	{ CCI_REG16(0x6f12), 0x82f8 },
357 	{ CCI_REG16(0x6f12), 0x8000 },
358 	{ CCI_REG16(0x6f12), 0x2f48 },
359 	{ CCI_REG16(0x6f12), 0x90f8 },
360 	{ CCI_REG16(0x6f12), 0xb313 },
361 	{ CCI_REG16(0x6f12), 0x82f8 },
362 	{ CCI_REG16(0x6f12), 0x8210 },
363 	{ CCI_REG16(0x6f12), 0x90f8 },
364 	{ CCI_REG16(0x6f12), 0xb103 },
365 	{ CCI_REG16(0x6f12), 0x82f8 },
366 	{ CCI_REG16(0x6f12), 0x8400 },
367 	{ CCI_REG16(0x6f12), 0x93f8 },
368 	{ CCI_REG16(0x6f12), 0xb400 },
369 	{ CCI_REG16(0x6f12), 0x82f8 },
370 	{ CCI_REG16(0x6f12), 0x8600 },
371 	{ CCI_REG16(0x6f12), 0x0020 },
372 	{ CCI_REG16(0x6f12), 0x82f8 },
373 	{ CCI_REG16(0x6f12), 0x8800 },
374 	{ CCI_REG16(0x6f12), 0x93f8 },
375 	{ CCI_REG16(0x6f12), 0x6211 },
376 	{ CCI_REG16(0x6f12), 0x82f8 },
377 	{ CCI_REG16(0x6f12), 0x9610 },
378 	{ CCI_REG16(0x6f12), 0x93f8 },
379 	{ CCI_REG16(0x6f12), 0x0112 },
380 	{ CCI_REG16(0x6f12), 0x82f8 },
381 	{ CCI_REG16(0x6f12), 0x9e10 },
382 	{ CCI_REG16(0x6f12), 0x93f8 },
383 	{ CCI_REG16(0x6f12), 0x0212 },
384 	{ CCI_REG16(0x6f12), 0x82f8 },
385 	{ CCI_REG16(0x6f12), 0xa010 },
386 	{ CCI_REG16(0x6f12), 0x82f8 },
387 	{ CCI_REG16(0x6f12), 0xa200 },
388 	{ CCI_REG16(0x6f12), 0x82f8 },
389 	{ CCI_REG16(0x6f12), 0xa400 },
390 	{ CCI_REG16(0x6f12), 0x93f8 },
391 	{ CCI_REG16(0x6f12), 0x0512 },
392 	{ CCI_REG16(0x6f12), 0x82f8 },
393 	{ CCI_REG16(0x6f12), 0xa610 },
394 	{ CCI_REG16(0x6f12), 0x93f8 },
395 	{ CCI_REG16(0x6f12), 0x0612 },
396 	{ CCI_REG16(0x6f12), 0x82f8 },
397 	{ CCI_REG16(0x6f12), 0xa810 },
398 	{ CCI_REG16(0x6f12), 0x93f8 },
399 	{ CCI_REG16(0x6f12), 0x0712 },
400 	{ CCI_REG16(0x6f12), 0x82f8 },
401 	{ CCI_REG16(0x6f12), 0xaa10 },
402 	{ CCI_REG16(0x6f12), 0x82f8 },
403 	{ CCI_REG16(0x6f12), 0xac00 },
404 	{ CCI_REG16(0x6f12), 0x5a20 },
405 	{ CCI_REG16(0x6f12), 0x82f8 },
406 	{ CCI_REG16(0x6f12), 0xad00 },
407 	{ CCI_REG16(0x6f12), 0x93f8 },
408 	{ CCI_REG16(0x6f12), 0x0902 },
409 	{ CCI_REG16(0x6f12), 0x82f8 },
410 	{ CCI_REG16(0x6f12), 0xae00 },
411 	{ CCI_REG16(0x6f12), 0x2146 },
412 	{ CCI_REG16(0x6f12), 0x2846 },
413 	{ CCI_REG16(0x6f12), 0xbde8 },
414 	{ CCI_REG16(0x6f12), 0x7040 },
415 	{ CCI_REG16(0x6f12), 0x0122 },
416 	{ CCI_REG16(0x6f12), 0x00f0 },
417 	{ CCI_REG16(0x6f12), 0x47b8 },
418 	{ CCI_REG16(0x6f12), 0x10b5 },
419 	{ CCI_REG16(0x6f12), 0x0f4c },
420 	{ CCI_REG16(0x6f12), 0x0020 },
421 	{ CCI_REG16(0x6f12), 0x2080 },
422 	{ CCI_REG16(0x6f12), 0xaff2 },
423 	{ CCI_REG16(0x6f12), 0x3321 },
424 	{ CCI_REG16(0x6f12), 0x1748 },
425 	{ CCI_REG16(0x6f12), 0x0161 },
426 	{ CCI_REG16(0x6f12), 0xaff2 },
427 	{ CCI_REG16(0x6f12), 0x2d21 },
428 	{ CCI_REG16(0x6f12), 0x0022 },
429 	{ CCI_REG16(0x6f12), 0x8161 },
430 	{ CCI_REG16(0x6f12), 0xaff2 },
431 	{ CCI_REG16(0x6f12), 0x1121 },
432 	{ CCI_REG16(0x6f12), 0x1448 },
433 	{ CCI_REG16(0x6f12), 0x00f0 },
434 	{ CCI_REG16(0x6f12), 0x45f8 },
435 	{ CCI_REG16(0x6f12), 0x0022 },
436 	{ CCI_REG16(0x6f12), 0xaff2 },
437 	{ CCI_REG16(0x6f12), 0x2911 },
438 	{ CCI_REG16(0x6f12), 0x6060 },
439 	{ CCI_REG16(0x6f12), 0x1148 },
440 	{ CCI_REG16(0x6f12), 0x00f0 },
441 	{ CCI_REG16(0x6f12), 0x3ef8 },
442 	{ CCI_REG16(0x6f12), 0x0022 },
443 	{ CCI_REG16(0x6f12), 0xaff2 },
444 	{ CCI_REG16(0x6f12), 0x6b11 },
445 	{ CCI_REG16(0x6f12), 0xa060 },
446 	{ CCI_REG16(0x6f12), 0x0f48 },
447 	{ CCI_REG16(0x6f12), 0x00f0 },
448 	{ CCI_REG16(0x6f12), 0x37f8 },
449 	{ CCI_REG16(0x6f12), 0xe060 },
450 	{ CCI_REG16(0x6f12), 0x10bd },
451 	{ CCI_REG16(0x6f12), 0x2000 },
452 	{ CCI_REG16(0x6f12), 0x4200 },
453 	{ CCI_REG16(0x6f12), 0x2000 },
454 	{ CCI_REG16(0x6f12), 0x2e50 },
455 	{ CCI_REG16(0x6f12), 0x2000 },
456 	{ CCI_REG16(0x6f12), 0x41d0 },
457 	{ CCI_REG16(0x6f12), 0x4000 },
458 	{ CCI_REG16(0x6f12), 0x9404 },
459 	{ CCI_REG16(0x6f12), 0x2000 },
460 	{ CCI_REG16(0x6f12), 0x38e0 },
461 	{ CCI_REG16(0x6f12), 0x4000 },
462 	{ CCI_REG16(0x6f12), 0xd000 },
463 	{ CCI_REG16(0x6f12), 0x4000 },
464 	{ CCI_REG16(0x6f12), 0xa410 },
465 	{ CCI_REG16(0x6f12), 0x2000 },
466 	{ CCI_REG16(0x6f12), 0x2c66 },
467 	{ CCI_REG16(0x6f12), 0x2000 },
468 	{ CCI_REG16(0x6f12), 0x0890 },
469 	{ CCI_REG16(0x6f12), 0x2000 },
470 	{ CCI_REG16(0x6f12), 0x3620 },
471 	{ CCI_REG16(0x6f12), 0x2000 },
472 	{ CCI_REG16(0x6f12), 0x0840 },
473 	{ CCI_REG16(0x6f12), 0x0001 },
474 	{ CCI_REG16(0x6f12), 0x020d },
475 	{ CCI_REG16(0x6f12), 0x0000 },
476 	{ CCI_REG16(0x6f12), 0x67cd },
477 	{ CCI_REG16(0x6f12), 0x0000 },
478 	{ CCI_REG16(0x6f12), 0x3ae1 },
479 	{ CCI_REG16(0x6f12), 0x45f6 },
480 	{ CCI_REG16(0x6f12), 0x250c },
481 	{ CCI_REG16(0x6f12), 0xc0f2 },
482 	{ CCI_REG16(0x6f12), 0x000c },
483 	{ CCI_REG16(0x6f12), 0x6047 },
484 	{ CCI_REG16(0x6f12), 0x45f6 },
485 	{ CCI_REG16(0x6f12), 0xf31c },
486 	{ CCI_REG16(0x6f12), 0xc0f2 },
487 	{ CCI_REG16(0x6f12), 0x000c },
488 	{ CCI_REG16(0x6f12), 0x6047 },
489 	{ CCI_REG16(0x6f12), 0x4af2 },
490 	{ CCI_REG16(0x6f12), 0xd74c },
491 	{ CCI_REG16(0x6f12), 0xc0f2 },
492 	{ CCI_REG16(0x6f12), 0x000c },
493 	{ CCI_REG16(0x6f12), 0x6047 },
494 	{ CCI_REG16(0x6f12), 0x40f2 },
495 	{ CCI_REG16(0x6f12), 0x0d2c },
496 	{ CCI_REG16(0x6f12), 0xc0f2 },
497 	{ CCI_REG16(0x6f12), 0x010c },
498 	{ CCI_REG16(0x6f12), 0x6047 },
499 	{ CCI_REG16(0x6f12), 0x46f2 },
500 	{ CCI_REG16(0x6f12), 0xcd7c },
501 	{ CCI_REG16(0x6f12), 0xc0f2 },
502 	{ CCI_REG16(0x6f12), 0x000c },
503 	{ CCI_REG16(0x6f12), 0x6047 },
504 	{ CCI_REG16(0x6f12), 0x4af6 },
505 	{ CCI_REG16(0x6f12), 0xe75c },
506 	{ CCI_REG16(0x6f12), 0xc0f2 },
507 	{ CCI_REG16(0x6f12), 0x000c },
508 	{ CCI_REG16(0x6f12), 0x6047 },
509 	{ CCI_REG16(0x6f12), 0x30d5 },
510 	{ CCI_REG16(0x6f12), 0x00fc },
511 	{ CCI_REG16(0x6f12), 0x0000 },
512 	{ CCI_REG16(0x6f12), 0x000e },
513 };
514 
515 static const struct cci_reg_sequence init_array_setting[] = {
516 	{ CCI_REG16(0x602a), 0x41d0 },
517 	{ CCI_REG16(0x6f12), 0x0100 },
518 	{ CCI_REG16(0x602a), 0x1662 },
519 	{ CCI_REG16(0x6f12), 0x1e00 },
520 	{ CCI_REG16(0x602a), 0x1c9a },
521 	{ CCI_REG16(0x6f12), 0x0000 },
522 	{ CCI_REG16(0x6f12), 0x0000 },
523 	{ CCI_REG16(0x6f12), 0x0000 },
524 	{ CCI_REG16(0x6f12), 0x0000 },
525 	{ CCI_REG16(0x6f12), 0x0000 },
526 	{ CCI_REG16(0x6f12), 0x0000 },
527 	{ CCI_REG16(0x6f12), 0x0000 },
528 	{ CCI_REG16(0x6f12), 0x0000 },
529 	{ CCI_REG16(0x6f12), 0x0000 },
530 	{ CCI_REG16(0x6f12), 0x0000 },
531 	{ CCI_REG16(0x6f12), 0x0000 },
532 	{ CCI_REG16(0x6f12), 0x0000 },
533 	{ CCI_REG16(0x6f12), 0x0000 },
534 	{ CCI_REG16(0x6f12), 0x0000 },
535 	{ CCI_REG16(0x6f12), 0x0000 },
536 	{ CCI_REG16(0x6f12), 0x0000 },
537 	{ CCI_REG16(0x602a), 0x0ff2 },
538 	{ CCI_REG16(0x6f12), 0x0020 },
539 	{ CCI_REG16(0x602a), 0x0ef6 },
540 	{ CCI_REG16(0x6f12), 0x0100 },
541 	{ CCI_REG16(0x602a), 0x23b2 },
542 	{ CCI_REG16(0x6f12), 0x0001 },
543 	{ CCI_REG16(0x602a), 0x0fe4 },
544 	{ CCI_REG16(0x6f12), 0x0107 },
545 	{ CCI_REG16(0x6f12), 0x07d0 },
546 	{ CCI_REG16(0x602a), 0x12f8 },
547 	{ CCI_REG16(0x6f12), 0x3d09 },
548 	{ CCI_REG16(0x602a), 0x0e18 },
549 	{ CCI_REG16(0x6f12), 0x0040 },
550 	{ CCI_REG16(0x602a), 0x1066 },
551 	{ CCI_REG16(0x6f12), 0x000c },
552 	{ CCI_REG16(0x602a), 0x13de },
553 	{ CCI_REG16(0x6f12), 0x0000 },
554 	{ CCI_REG16(0x602a), 0x12f2 },
555 	{ CCI_REG16(0x6f12), 0x0f0f },
556 	{ CCI_REG16(0x602a), 0x13dc },
557 	{ CCI_REG16(0x6f12), 0x806f },
558 	{ CCI_REG16(0xf46e), 0x00c3 },
559 	{ CCI_REG16(0xf46c), 0xbfa0 },
560 	{ CCI_REG16(0xf44a), 0x0007 },
561 	{ CCI_REG16(0xf456), 0x000a },
562 	{ CCI_REG16(0x6028), 0x2000 },
563 	{ CCI_REG16(0x602a), 0x12f6 },
564 	{ CCI_REG16(0x6f12), 0x7008 },
565 	{ CCI_REG16(0x0bc6), 0x0000 },
566 	{ CCI_REG16(0x0b36), 0x0001 },
567 };
568 
569 static const struct cci_reg_sequence s5k3m5_4208x3120_30fps_mode[] = {
570 	{ CCI_REG16(0x6214), 0x7971 },
571 	{ CCI_REG16(0x6218), 0x7150 },
572 	{ S5K3M5_REG_X_ADDR_START,  0x0000 },
573 	{ S5K3M5_REG_Y_ADDR_START,  0x0008 },
574 	{ S5K3M5_REG_X_ADDR_END,    0x1077 },
575 	{ S5K3M5_REG_Y_ADDR_END,    0x0c37 },
576 	{ S5K3M5_REG_X_OUTPUT_SIZE, 0x1070 },
577 	{ S5K3M5_REG_Y_OUTPUT_SIZE, 0x0c30 },
578 	{ S5K3M5_REG_VTS, 0x0cf2 },
579 	{ S5K3M5_REG_HTS, 0x12f0 },
580 
581 	{ CCI_REG16(0x0900), 0x0011 },
582 	{ CCI_REG16(0x0380), 0x0001 },
583 	{ CCI_REG16(0x0382), 0x0001 },
584 	{ CCI_REG16(0x0384), 0x0001 },
585 	{ CCI_REG16(0x0386), 0x0001 },
586 	{ CCI_REG16(0x0402), 0x1010 },
587 	{ CCI_REG16(0x0404), 0x1000 },
588 	{ CCI_REG16(0x0350), 0x0008 },
589 	{ CCI_REG16(0x0352), 0x0000 },
590 
591 	/* Clock settings */
592 	{ CCI_REG16(0x0136), 0x1800 },
593 	{ CCI_REG16(0x013e), 0x0000 },
594 	{ CCI_REG16(0x0300), 0x0008 },
595 	{ CCI_REG16(0x0302), 0x0001 },
596 	{ CCI_REG16(0x0304), 0x0006 },
597 	{ CCI_REG16(0x0306), 0x00f1 },
598 	{ CCI_REG16(0x0308), 0x0008 },
599 	{ CCI_REG16(0x030a), 0x0001 },
600 	{ CCI_REG16(0x030c), 0x0000 },
601 	{ CCI_REG16(0x030e), 0x0003 },
602 	{ CCI_REG16(0x0310), 0x005a },
603 	{ CCI_REG16(0x0312), 0x0000 },
604 
605 	{ CCI_REG16(0x0b06), 0x0101 },
606 	{ CCI_REG16(0x6028), 0x2000 },
607 	{ CCI_REG16(0x602a), 0x1ff6 },
608 	{ CCI_REG16(0x6f12), 0x0000 },
609 	{ CCI_REG16(0x021e), 0x0000 },
610 	{ CCI_REG16(0x0202), 0x0100 },
611 	{ CCI_REG16(0x0204), 0x0020 },
612 	{ CCI_REG16(0x0d00), 0x0100 },
613 	{ CCI_REG16(0x0d02), 0x0001 },
614 	{ CCI_REG16(0x0114), 0x0301 },
615 	{ CCI_REG16(0x0d06), 0x0208 },
616 	{ CCI_REG16(0x0d08), 0x0300 },
617 	{ CCI_REG16(0x6028), 0x2000 },
618 	{ CCI_REG16(0x602a), 0x0f10 },
619 	{ CCI_REG16(0x6f12), 0x0003 },
620 	{ CCI_REG16(0x602a), 0x0f12 },
621 	{ CCI_REG16(0x6f12), 0x0200 },
622 	{ CCI_REG16(0x602a), 0x2bc0 },
623 	{ CCI_REG16(0x6f12), 0x0001 },
624 	{ CCI_REG16(0x0b30), 0x0000 },
625 	{ CCI_REG16(0x0b32), 0x0000 },
626 	{ CCI_REG16(0x0b34), 0x0001 },
627 	{ CCI_REG16(0x0804), 0x0200 },
628 	{ CCI_REG16(0x0810), 0x0020 },
629 };
630 
631 static const struct cci_reg_sequence s5k3m5_2104x1184_60fps_mode[] = {
632 	{ CCI_REG16(0x6214), 0x7971 },
633 	{ CCI_REG16(0x6218), 0x7150 },
634 	{ S5K3M5_REG_X_ADDR_START,  0x0000 },
635 	{ S5K3M5_REG_Y_ADDR_START,  0x0180 },
636 	{ S5K3M5_REG_X_ADDR_END,    0x1077 },
637 	{ S5K3M5_REG_Y_ADDR_END,    0x0abf },
638 	{ S5K3M5_REG_X_OUTPUT_SIZE, 0x0838 },
639 	{ S5K3M5_REG_Y_OUTPUT_SIZE, 0x04a0 },
640 	{ S5K3M5_REG_VTS, 0x0658 },
641 	{ S5K3M5_REG_HTS, 0x1340 },
642 
643 	{ CCI_REG16(0x0900), 0x0112 },
644 	{ CCI_REG16(0x0380), 0x0001 },
645 	{ CCI_REG16(0x0382), 0x0001 },
646 	{ CCI_REG16(0x0384), 0x0001 },
647 	{ CCI_REG16(0x0386), 0x0003 },
648 	{ CCI_REG16(0x0402), 0x1010 },
649 	{ CCI_REG16(0x0404), 0x2000 },
650 	{ CCI_REG16(0x0350), 0x0004 },
651 	{ CCI_REG16(0x0352), 0x0000 },
652 
653 	/* Clock settings */
654 	{ CCI_REG16(0x0136), 0x1800 },
655 	{ CCI_REG16(0x013e), 0x0000 },
656 	{ CCI_REG16(0x0300), 0x0008 },
657 	{ CCI_REG16(0x0302), 0x0001 },
658 	{ CCI_REG16(0x0304), 0x0006 },
659 	{ CCI_REG16(0x0306), 0x00f1 },
660 	{ CCI_REG16(0x0308), 0x0008 },
661 	{ CCI_REG16(0x030a), 0x0001 },
662 	{ CCI_REG16(0x030c), 0x0000 },
663 	{ CCI_REG16(0x030e), 0x0003 },
664 	{ CCI_REG16(0x0310), 0x0063 },
665 	{ CCI_REG16(0x0312), 0x0001 },
666 
667 	{ CCI_REG16(0x0b06), 0x0101 },
668 	{ CCI_REG16(0x6028), 0x2000 },
669 	{ CCI_REG16(0x602a), 0x1ff6 },
670 	{ CCI_REG16(0x6f12), 0x0000 },
671 	{ CCI_REG16(0x021e), 0x0000 },
672 	{ CCI_REG16(0x0202), 0x0100 },
673 	{ CCI_REG16(0x0204), 0x0020 },
674 	{ CCI_REG16(0x0d00), 0x0101 },
675 	{ CCI_REG16(0x0d02), 0x0101 },
676 	{ CCI_REG16(0x0114), 0x0301 },
677 	{ CCI_REG16(0x0d06), 0x0208 },
678 	{ CCI_REG16(0x0d08), 0x0300 },
679 	{ CCI_REG16(0x6028), 0x2000 },
680 	{ CCI_REG16(0x602a), 0x0f10 },
681 	{ CCI_REG16(0x6f12), 0x0003 },
682 	{ CCI_REG16(0x602a), 0x0f12 },
683 	{ CCI_REG16(0x6f12), 0x0200 },
684 	{ CCI_REG16(0x602a), 0x2bc0 },
685 	{ CCI_REG16(0x6f12), 0x0001 },
686 	{ CCI_REG16(0x0b30), 0x0000 },
687 	{ CCI_REG16(0x0b32), 0x0000 },
688 	{ CCI_REG16(0x0b34), 0x0001 },
689 	{ CCI_REG16(0x0804), 0x0200 },
690 	{ CCI_REG16(0x0810), 0x0020 },
691 };
692 
693 static const struct s5k3m5_mode s5k3m5_supported_modes[] = {
694 	{
695 		.width = 4208,
696 		.height = 3120,
697 		.hts = 4848,
698 		.vts = 3314,
699 		.exposure = 256,
700 		.reg_list = {
701 			.regs = s5k3m5_4208x3120_30fps_mode,
702 			.num_regs = ARRAY_SIZE(s5k3m5_4208x3120_30fps_mode),
703 		},
704 	},
705 	{
706 		.width = 2104,
707 		.height = 1184,
708 		.hts = 4928,
709 		.vts = 1624,
710 		.exposure = 256,
711 		.reg_list = {
712 			.regs = s5k3m5_2104x1184_60fps_mode,
713 			.num_regs = ARRAY_SIZE(s5k3m5_2104x1184_60fps_mode),
714 		},
715 	},
716 };
717 
718 static int s5k3m5_set_ctrl(struct v4l2_ctrl *ctrl)
719 {
720 	struct s5k3m5 *s5k3m5 = container_of(ctrl->handler, struct s5k3m5,
721 					     ctrl_handler);
722 	const struct s5k3m5_mode *mode = s5k3m5->mode;
723 	s64 exposure_max;
724 	int ret;
725 
726 	/* Propagate change of current control to all related controls */
727 	switch (ctrl->id) {
728 	case V4L2_CID_HFLIP:
729 	case V4L2_CID_VFLIP:
730 		/* The orientation settings are applied along with streaming */
731 		return 0;
732 	case V4L2_CID_VBLANK:
733 		/* Update max exposure while meeting expected vblanking */
734 		exposure_max = mode->height + ctrl->val - S5K3M5_EXPOSURE_MARGIN;
735 		__v4l2_ctrl_modify_range(s5k3m5->exposure,
736 					 s5k3m5->exposure->minimum,
737 					 exposure_max,
738 					 s5k3m5->exposure->step,
739 					 s5k3m5->exposure->default_value);
740 		break;
741 	}
742 
743 	/* V4L2 controls are applied, when sensor is powered up for streaming */
744 	if (!pm_runtime_get_if_active(s5k3m5->dev))
745 		return 0;
746 
747 	switch (ctrl->id) {
748 	case V4L2_CID_ANALOGUE_GAIN:
749 		ret = cci_write(s5k3m5->regmap, S5K3M5_REG_AGAIN,
750 				ctrl->val << S5K3M5_AGAIN_SHIFT, NULL);
751 		break;
752 	case V4L2_CID_EXPOSURE:
753 		ret = cci_write(s5k3m5->regmap, S5K3M5_REG_EXPOSURE,
754 				ctrl->val, NULL);
755 		break;
756 	case V4L2_CID_VBLANK:
757 		ret = cci_write(s5k3m5->regmap, S5K3M5_REG_VTS,
758 				ctrl->val + mode->height, NULL);
759 		break;
760 	case V4L2_CID_TEST_PATTERN:
761 		ret = cci_write(s5k3m5->regmap, S5K3M5_REG_TEST_PATTERN,
762 				ctrl->val, NULL);
763 		break;
764 	default:
765 		ret = -EINVAL;
766 		break;
767 	}
768 
769 	pm_runtime_put(s5k3m5->dev);
770 
771 	return ret;
772 }
773 
774 static const struct v4l2_ctrl_ops s5k3m5_ctrl_ops = {
775 	.s_ctrl = s5k3m5_set_ctrl,
776 };
777 
778 static inline u64 s5k3m5_freq_to_pixel_rate(const u64 freq)
779 {
780 	return div_u64(freq * 2 * S5K3M5_DATA_LANES, 10);
781 }
782 
783 static int s5k3m5_init_controls(struct s5k3m5 *s5k3m5)
784 {
785 	struct v4l2_ctrl_handler *ctrl_hdlr = &s5k3m5->ctrl_handler;
786 	const struct s5k3m5_mode *mode = s5k3m5->mode;
787 	s64 pixel_rate, hblank, vblank, exposure_max;
788 	struct v4l2_fwnode_device_properties props;
789 	int ret;
790 
791 	v4l2_ctrl_handler_init(ctrl_hdlr, 9);
792 
793 	s5k3m5->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &s5k3m5_ctrl_ops,
794 					V4L2_CID_LINK_FREQ,
795 					ARRAY_SIZE(s5k3m5_link_freq_menu) - 1,
796 					0, s5k3m5_link_freq_menu);
797 	if (s5k3m5->link_freq)
798 		s5k3m5->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
799 
800 	pixel_rate = s5k3m5_freq_to_pixel_rate(s5k3m5_link_freq_menu[0]);
801 	s5k3m5->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &s5k3m5_ctrl_ops,
802 					       V4L2_CID_PIXEL_RATE,
803 					       0, pixel_rate, 1, pixel_rate);
804 
805 	hblank = mode->hts - mode->width;
806 	s5k3m5->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &s5k3m5_ctrl_ops,
807 					   V4L2_CID_HBLANK, hblank,
808 					   hblank, 1, hblank);
809 	if (s5k3m5->hblank)
810 		s5k3m5->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
811 
812 	vblank = mode->vts - mode->height;
813 	s5k3m5->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &s5k3m5_ctrl_ops,
814 					   V4L2_CID_VBLANK, vblank,
815 					   S5K3M5_VTS_MAX - mode->height, 1,
816 					   vblank);
817 
818 	v4l2_ctrl_new_std(ctrl_hdlr, &s5k3m5_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
819 			  S5K3M5_AGAIN_MIN, S5K3M5_AGAIN_MAX,
820 			  S5K3M5_AGAIN_STEP, S5K3M5_AGAIN_DEFAULT);
821 
822 	exposure_max = mode->vts - S5K3M5_EXPOSURE_MARGIN;
823 	s5k3m5->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &s5k3m5_ctrl_ops,
824 					     V4L2_CID_EXPOSURE,
825 					     S5K3M5_EXPOSURE_MIN,
826 					     exposure_max,
827 					     S5K3M5_EXPOSURE_STEP,
828 					     mode->exposure);
829 
830 	v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &s5k3m5_ctrl_ops,
831 				     V4L2_CID_TEST_PATTERN,
832 				     ARRAY_SIZE(s5k3m5_test_pattern_menu) - 1,
833 				     0, 0, s5k3m5_test_pattern_menu);
834 
835 	s5k3m5->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &s5k3m5_ctrl_ops,
836 					  V4L2_CID_HFLIP, 0, 1, 1, 0);
837 	if (s5k3m5->hflip)
838 		s5k3m5->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
839 
840 	s5k3m5->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &s5k3m5_ctrl_ops,
841 					  V4L2_CID_VFLIP, 0, 1, 1, 0);
842 	if (s5k3m5->vflip)
843 		s5k3m5->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
844 
845 	ret = v4l2_fwnode_device_parse(s5k3m5->dev, &props);
846 	if (ret)
847 		goto error_free_hdlr;
848 
849 	ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &s5k3m5_ctrl_ops,
850 					      &props);
851 	if (ret)
852 		goto error_free_hdlr;
853 
854 	s5k3m5->sd.ctrl_handler = ctrl_hdlr;
855 
856 	return 0;
857 
858 error_free_hdlr:
859 	v4l2_ctrl_handler_free(ctrl_hdlr);
860 
861 	return ret;
862 }
863 
864 static int s5k3m5_enable_streams(struct v4l2_subdev *sd,
865 				 struct v4l2_subdev_state *state, u32 pad,
866 				 u64 streams_mask)
867 {
868 	struct s5k3m5 *s5k3m5 = to_s5k3m5(sd);
869 	const struct s5k3m5_reg_list *reg_list = &s5k3m5->mode->reg_list;
870 	int ret;
871 
872 	ret = pm_runtime_resume_and_get(s5k3m5->dev);
873 	if (ret)
874 		return ret;
875 
876 	/* Page pointer */
877 	cci_write(s5k3m5->regmap, CCI_REG16(0x6028), 0x4000, &ret);
878 
879 	/* Set version */
880 	cci_write(s5k3m5->regmap, CCI_REG16(0x0000), 0x0006, &ret);
881 	cci_write(s5k3m5->regmap, CCI_REG16(0x0000), S5K3M5_CHIP_ID, &ret);
882 	cci_write(s5k3m5->regmap, CCI_REG16(0x6214), 0x7971, &ret);
883 	cci_write(s5k3m5->regmap, CCI_REG16(0x6218), 0x7150, &ret);
884 	if (ret)
885 		goto error;
886 
887 	usleep_range(4 * USEC_PER_MSEC, 5 * USEC_PER_MSEC);
888 
889 	cci_write(s5k3m5->regmap, CCI_REG16(0x0a02), 0x7800, &ret);
890 	cci_write(s5k3m5->regmap, CCI_REG16(0x6028), 0x2000, &ret);
891 	cci_write(s5k3m5->regmap, CCI_REG16(0x602a), 0x3eac, &ret);
892 
893 	/* Sensor init settings */
894 	cci_multi_reg_write(s5k3m5->regmap, burst_array_setting,
895 			    ARRAY_SIZE(burst_array_setting), &ret);
896 	cci_multi_reg_write(s5k3m5->regmap, init_array_setting,
897 			    ARRAY_SIZE(init_array_setting), &ret);
898 	cci_multi_reg_write(s5k3m5->regmap, reg_list->regs,
899 			    reg_list->num_regs, &ret);
900 	if (ret)
901 		goto error;
902 
903 	ret = __v4l2_ctrl_handler_setup(s5k3m5->sd.ctrl_handler);
904 
905 	cci_write(s5k3m5->regmap, S5K3M5_REG_CTRL_MODE,
906 		  S5K3M5_MODE_STREAMING |
907 		  (s5k3m5->vflip->val ? S5K3M5_VFLIP : 0) |
908 		  (s5k3m5->hflip->val ? S5K3M5_HFLIP : 0), &ret);
909 	if (ret)
910 		goto error;
911 
912 	return 0;
913 
914 error:
915 	dev_err(s5k3m5->dev, "failed to start streaming: %d\n", ret);
916 	pm_runtime_put_autosuspend(s5k3m5->dev);
917 
918 	return ret;
919 }
920 
921 static int s5k3m5_disable_streams(struct v4l2_subdev *sd,
922 				  struct v4l2_subdev_state *state, u32 pad,
923 				  u64 streams_mask)
924 {
925 	struct s5k3m5 *s5k3m5 = to_s5k3m5(sd);
926 	int ret;
927 
928 	ret = cci_write(s5k3m5->regmap, S5K3M5_REG_CTRL_MODE, 0, NULL);
929 	if (ret)
930 		dev_err(s5k3m5->dev, "failed to stop streaming: %d\n", ret);
931 
932 	pm_runtime_put_autosuspend(s5k3m5->dev);
933 
934 	return ret;
935 }
936 
937 static u32 s5k3m5_get_format_code(struct s5k3m5 *s5k3m5)
938 {
939 	unsigned int i;
940 
941 	i = (s5k3m5->vflip->val ? 2 : 0) | (s5k3m5->hflip->val ? 1 : 0);
942 
943 	return s5k3m5_mbus_formats[i];
944 }
945 
946 static void s5k3m5_update_pad_format(struct s5k3m5 *s5k3m5,
947 				     const struct s5k3m5_mode *mode,
948 				     struct v4l2_mbus_framefmt *fmt)
949 {
950 	fmt->code = s5k3m5_get_format_code(s5k3m5);
951 	fmt->width = mode->width;
952 	fmt->height = mode->height;
953 	fmt->field = V4L2_FIELD_NONE;
954 	fmt->colorspace = V4L2_COLORSPACE_SRGB;
955 	fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
956 	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
957 	fmt->xfer_func = V4L2_XFER_FUNC_NONE;
958 }
959 
960 static int s5k3m5_set_pad_format(struct v4l2_subdev *sd,
961 				 struct v4l2_subdev_state *state,
962 				 struct v4l2_subdev_format *fmt)
963 {
964 	struct s5k3m5 *s5k3m5 = to_s5k3m5(sd);
965 	s64 hblank, vblank, exposure_max;
966 	const struct s5k3m5_mode *mode;
967 
968 	mode = v4l2_find_nearest_size(s5k3m5_supported_modes,
969 				      ARRAY_SIZE(s5k3m5_supported_modes),
970 				      width, height,
971 				      fmt->format.width, fmt->format.height);
972 
973 	s5k3m5_update_pad_format(s5k3m5, mode, &fmt->format);
974 
975 	/* Format code could be updated with respect to flip controls */
976 	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY || s5k3m5->mode == mode)
977 		goto set_format;
978 
979 	/* Update limits and set FPS and exposure to default values */
980 	hblank = mode->hts - mode->width;
981 	__v4l2_ctrl_modify_range(s5k3m5->hblank, hblank, hblank, 1, hblank);
982 
983 	vblank = mode->vts - mode->height;
984 	__v4l2_ctrl_modify_range(s5k3m5->vblank, vblank,
985 				 S5K3M5_VTS_MAX - mode->height, 1, vblank);
986 	__v4l2_ctrl_s_ctrl(s5k3m5->vblank, vblank);
987 
988 	exposure_max = mode->vts - S5K3M5_EXPOSURE_MARGIN;
989 	__v4l2_ctrl_modify_range(s5k3m5->exposure, S5K3M5_EXPOSURE_MIN,
990 				 exposure_max, S5K3M5_EXPOSURE_STEP,
991 				 mode->exposure);
992 	__v4l2_ctrl_s_ctrl(s5k3m5->exposure, mode->exposure);
993 
994 	if (s5k3m5->sd.ctrl_handler->error)
995 		return s5k3m5->sd.ctrl_handler->error;
996 
997 	s5k3m5->mode = mode;
998 
999 set_format:
1000 	*v4l2_subdev_state_get_format(state, 0) = fmt->format;
1001 
1002 	return 0;
1003 }
1004 
1005 static int s5k3m5_enum_mbus_code(struct v4l2_subdev *sd,
1006 				 struct v4l2_subdev_state *sd_state,
1007 				 struct v4l2_subdev_mbus_code_enum *code)
1008 {
1009 	struct s5k3m5 *s5k3m5 = to_s5k3m5(sd);
1010 
1011 	/* Media bus code index is constant, but code formats are not */
1012 	if (code->index > 0)
1013 		return -EINVAL;
1014 
1015 	code->code = s5k3m5_get_format_code(s5k3m5);
1016 
1017 	return 0;
1018 }
1019 
1020 static int s5k3m5_enum_frame_size(struct v4l2_subdev *sd,
1021 				  struct v4l2_subdev_state *sd_state,
1022 				  struct v4l2_subdev_frame_size_enum *fse)
1023 {
1024 	struct s5k3m5 *s5k3m5 = to_s5k3m5(sd);
1025 
1026 	if (fse->index >= ARRAY_SIZE(s5k3m5_supported_modes))
1027 		return -EINVAL;
1028 
1029 	if (fse->code != s5k3m5_get_format_code(s5k3m5))
1030 		return -EINVAL;
1031 
1032 	fse->min_width = s5k3m5_supported_modes[fse->index].width;
1033 	fse->max_width = fse->min_width;
1034 	fse->min_height = s5k3m5_supported_modes[fse->index].height;
1035 	fse->max_height = fse->min_height;
1036 
1037 	return 0;
1038 }
1039 
1040 static int s5k3m5_get_selection(struct v4l2_subdev *sd,
1041 				struct v4l2_subdev_state *sd_state,
1042 				struct v4l2_subdev_selection *sel)
1043 {
1044 	struct s5k3m5 *s5k3m5 = to_s5k3m5(sd);
1045 
1046 	if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
1047 		return -EINVAL;
1048 
1049 	switch (sel->target) {
1050 	case V4L2_SEL_TGT_CROP:
1051 	case V4L2_SEL_TGT_CROP_BOUNDS:
1052 		sel->r.left = 0;
1053 		sel->r.top = 0;
1054 		sel->r.width = s5k3m5->mode->width;
1055 		sel->r.height = s5k3m5->mode->width;
1056 		return 0;
1057 	default:
1058 		return -EINVAL;
1059 	}
1060 
1061 	return 0;
1062 }
1063 
1064 static int s5k3m5_init_state(struct v4l2_subdev *sd,
1065 			     struct v4l2_subdev_state *state)
1066 {
1067 	struct s5k3m5 *s5k3m5 = to_s5k3m5(sd);
1068 	struct v4l2_subdev_format fmt = {
1069 		.which = V4L2_SUBDEV_FORMAT_TRY,
1070 		.pad = 0,
1071 		.format = {
1072 			/* Media bus code depends on current flip controls */
1073 			.width = s5k3m5->mode->width,
1074 			.height = s5k3m5->mode->height,
1075 		},
1076 	};
1077 
1078 	s5k3m5_set_pad_format(sd, state, &fmt);
1079 
1080 	return 0;
1081 }
1082 
1083 static const struct v4l2_subdev_video_ops s5k3m5_video_ops = {
1084 	.s_stream = v4l2_subdev_s_stream_helper,
1085 };
1086 
1087 static const struct v4l2_subdev_pad_ops s5k3m5_pad_ops = {
1088 	.set_fmt = s5k3m5_set_pad_format,
1089 	.get_fmt = v4l2_subdev_get_fmt,
1090 	.get_selection = s5k3m5_get_selection,
1091 	.enum_mbus_code = s5k3m5_enum_mbus_code,
1092 	.enum_frame_size = s5k3m5_enum_frame_size,
1093 	.enable_streams = s5k3m5_enable_streams,
1094 	.disable_streams = s5k3m5_disable_streams,
1095 };
1096 
1097 static const struct v4l2_subdev_ops s5k3m5_subdev_ops = {
1098 	.video = &s5k3m5_video_ops,
1099 	.pad = &s5k3m5_pad_ops,
1100 };
1101 
1102 static const struct v4l2_subdev_internal_ops s5k3m5_internal_ops = {
1103 	.init_state = s5k3m5_init_state,
1104 };
1105 
1106 static const struct media_entity_operations s5k3m5_subdev_entity_ops = {
1107 	.link_validate = v4l2_subdev_link_validate,
1108 };
1109 
1110 static int s5k3m5_identify_sensor(struct s5k3m5 *s5k3m5)
1111 {
1112 	u64 val;
1113 	int ret;
1114 
1115 	ret = cci_read(s5k3m5->regmap, S5K3M5_REG_CHIP_ID, &val, NULL);
1116 	if (ret) {
1117 		dev_err(s5k3m5->dev, "failed to read chip id: %d\n", ret);
1118 		return ret;
1119 	}
1120 
1121 	if (val != S5K3M5_CHIP_ID) {
1122 		dev_err(s5k3m5->dev, "chip id mismatch: %x!=%llx\n",
1123 			S5K3M5_CHIP_ID, val);
1124 		return -ENODEV;
1125 	}
1126 
1127 	return 0;
1128 }
1129 
1130 static int s5k3m5_check_hwcfg(struct s5k3m5 *s5k3m5)
1131 {
1132 	struct fwnode_handle *fwnode = dev_fwnode(s5k3m5->dev), *ep;
1133 	struct v4l2_fwnode_endpoint bus_cfg = {
1134 		.bus = {
1135 			.mipi_csi2 = {
1136 				.num_data_lanes = S5K3M5_DATA_LANES,
1137 			},
1138 		},
1139 		.bus_type = V4L2_MBUS_CSI2_DPHY,
1140 	};
1141 	unsigned long freq_bitmap;
1142 	int ret;
1143 
1144 	if (!fwnode)
1145 		return -ENODEV;
1146 
1147 	ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
1148 	if (!ep)
1149 		return -EINVAL;
1150 
1151 	ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
1152 	fwnode_handle_put(ep);
1153 	if (ret)
1154 		return ret;
1155 
1156 	if (bus_cfg.bus.mipi_csi2.num_data_lanes != S5K3M5_DATA_LANES) {
1157 		dev_err(s5k3m5->dev, "Invalid number of data lanes: %u\n",
1158 			bus_cfg.bus.mipi_csi2.num_data_lanes);
1159 		ret = -EINVAL;
1160 		goto endpoint_free;
1161 	}
1162 
1163 	ret = v4l2_link_freq_to_bitmap(s5k3m5->dev, bus_cfg.link_frequencies,
1164 				       bus_cfg.nr_of_link_frequencies,
1165 				       s5k3m5_link_freq_menu,
1166 				       ARRAY_SIZE(s5k3m5_link_freq_menu),
1167 				       &freq_bitmap);
1168 
1169 endpoint_free:
1170 	v4l2_fwnode_endpoint_free(&bus_cfg);
1171 
1172 	return ret;
1173 }
1174 
1175 static int s5k3m5_power_on(struct device *dev)
1176 {
1177 	struct v4l2_subdev *sd = dev_get_drvdata(dev);
1178 	struct s5k3m5 *s5k3m5 = to_s5k3m5(sd);
1179 	int ret;
1180 
1181 	ret = regulator_bulk_enable(S5K3M5_NUM_SUPPLIES, s5k3m5->supplies);
1182 	if (ret)
1183 		return ret;
1184 
1185 	ret = clk_prepare_enable(s5k3m5->mclk);
1186 	if (ret)
1187 		goto disable_regulators;
1188 
1189 	gpiod_set_value_cansleep(s5k3m5->reset_gpio, 0);
1190 	usleep_range(10 * USEC_PER_MSEC, 15 * USEC_PER_MSEC);
1191 
1192 	return 0;
1193 
1194 disable_regulators:
1195 	regulator_bulk_disable(S5K3M5_NUM_SUPPLIES, s5k3m5->supplies);
1196 
1197 	return ret;
1198 }
1199 
1200 static int s5k3m5_power_off(struct device *dev)
1201 {
1202 	struct v4l2_subdev *sd = dev_get_drvdata(dev);
1203 	struct s5k3m5 *s5k3m5 = to_s5k3m5(sd);
1204 
1205 	gpiod_set_value_cansleep(s5k3m5->reset_gpio, 1);
1206 
1207 	clk_disable_unprepare(s5k3m5->mclk);
1208 
1209 	regulator_bulk_disable(S5K3M5_NUM_SUPPLIES, s5k3m5->supplies);
1210 
1211 	return 0;
1212 }
1213 
1214 static int s5k3m5_probe(struct i2c_client *client)
1215 {
1216 	struct s5k3m5 *s5k3m5;
1217 	unsigned long freq;
1218 	unsigned int i;
1219 	int ret;
1220 
1221 	s5k3m5 = devm_kzalloc(&client->dev, sizeof(*s5k3m5), GFP_KERNEL);
1222 	if (!s5k3m5)
1223 		return -ENOMEM;
1224 
1225 	s5k3m5->dev = &client->dev;
1226 	v4l2_i2c_subdev_init(&s5k3m5->sd, client, &s5k3m5_subdev_ops);
1227 
1228 	s5k3m5->regmap = devm_cci_regmap_init_i2c(client, 16);
1229 	if (IS_ERR(s5k3m5->regmap))
1230 		return dev_err_probe(s5k3m5->dev, PTR_ERR(s5k3m5->regmap),
1231 				     "failed to init CCI\n");
1232 
1233 	s5k3m5->mclk = devm_v4l2_sensor_clk_get(s5k3m5->dev, NULL);
1234 	if (IS_ERR(s5k3m5->mclk))
1235 		return dev_err_probe(s5k3m5->dev, PTR_ERR(s5k3m5->mclk),
1236 				     "failed to get MCLK clock\n");
1237 
1238 	freq = clk_get_rate(s5k3m5->mclk);
1239 	if (freq != S5K3M5_MCLK_FREQ_24MHZ)
1240 		return dev_err_probe(s5k3m5->dev, -EINVAL,
1241 				     "MCLK clock frequency %lu is not supported\n",
1242 				     freq);
1243 
1244 	ret = s5k3m5_check_hwcfg(s5k3m5);
1245 	if (ret)
1246 		return dev_err_probe(s5k3m5->dev, ret,
1247 				     "failed to check HW configuration\n");
1248 
1249 	s5k3m5->reset_gpio = devm_gpiod_get_optional(s5k3m5->dev, "reset",
1250 						     GPIOD_OUT_HIGH);
1251 	if (IS_ERR(s5k3m5->reset_gpio))
1252 		return dev_err_probe(s5k3m5->dev, PTR_ERR(s5k3m5->reset_gpio),
1253 				     "cannot get reset GPIO\n");
1254 
1255 	for (i = 0; i < S5K3M5_NUM_SUPPLIES; i++)
1256 		s5k3m5->supplies[i].supply = s5k3m5_supply_names[i];
1257 
1258 	ret = devm_regulator_bulk_get(s5k3m5->dev, S5K3M5_NUM_SUPPLIES,
1259 				      s5k3m5->supplies);
1260 	if (ret)
1261 		return dev_err_probe(s5k3m5->dev, ret,
1262 				     "failed to get supply regulators\n");
1263 
1264 	/* The sensor must be powered on to read the CHIP_ID register */
1265 	ret = s5k3m5_power_on(s5k3m5->dev);
1266 	if (ret)
1267 		return ret;
1268 
1269 	ret = s5k3m5_identify_sensor(s5k3m5);
1270 	if (ret) {
1271 		dev_err_probe(s5k3m5->dev, ret, "failed to find sensor\n");
1272 		goto power_off;
1273 	}
1274 
1275 	s5k3m5->mode = &s5k3m5_supported_modes[0];
1276 	ret = s5k3m5_init_controls(s5k3m5);
1277 	if (ret) {
1278 		dev_err_probe(s5k3m5->dev, ret, "failed to init controls\n");
1279 		goto power_off;
1280 	}
1281 
1282 	s5k3m5->sd.state_lock = s5k3m5->ctrl_handler.lock;
1283 	s5k3m5->sd.internal_ops = &s5k3m5_internal_ops;
1284 	s5k3m5->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1285 	s5k3m5->sd.entity.ops = &s5k3m5_subdev_entity_ops;
1286 	s5k3m5->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
1287 	s5k3m5->pad.flags = MEDIA_PAD_FL_SOURCE;
1288 
1289 	ret = media_entity_pads_init(&s5k3m5->sd.entity, 1, &s5k3m5->pad);
1290 	if (ret) {
1291 		dev_err_probe(s5k3m5->dev, ret,
1292 			      "failed to init media entity pads\n");
1293 		goto v4l2_ctrl_handler_free;
1294 	}
1295 
1296 	ret = v4l2_subdev_init_finalize(&s5k3m5->sd);
1297 	if (ret < 0) {
1298 		dev_err_probe(s5k3m5->dev, ret,
1299 			      "failed to init media entity pads\n");
1300 		goto media_entity_cleanup;
1301 	}
1302 
1303 	pm_runtime_set_active(s5k3m5->dev);
1304 	pm_runtime_enable(s5k3m5->dev);
1305 
1306 	ret = v4l2_async_register_subdev_sensor(&s5k3m5->sd);
1307 	if (ret < 0) {
1308 		dev_err_probe(s5k3m5->dev, ret,
1309 			      "failed to register V4L2 subdev\n");
1310 		goto subdev_cleanup;
1311 	}
1312 
1313 	pm_runtime_set_autosuspend_delay(s5k3m5->dev, 1000);
1314 	pm_runtime_use_autosuspend(s5k3m5->dev);
1315 	pm_runtime_idle(s5k3m5->dev);
1316 
1317 	return 0;
1318 
1319 subdev_cleanup:
1320 	v4l2_subdev_cleanup(&s5k3m5->sd);
1321 	pm_runtime_disable(s5k3m5->dev);
1322 	pm_runtime_set_suspended(s5k3m5->dev);
1323 
1324 media_entity_cleanup:
1325 	media_entity_cleanup(&s5k3m5->sd.entity);
1326 
1327 v4l2_ctrl_handler_free:
1328 	v4l2_ctrl_handler_free(s5k3m5->sd.ctrl_handler);
1329 
1330 power_off:
1331 	s5k3m5_power_off(s5k3m5->dev);
1332 
1333 	return ret;
1334 }
1335 
1336 static void s5k3m5_remove(struct i2c_client *client)
1337 {
1338 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
1339 	struct s5k3m5 *s5k3m5 = to_s5k3m5(sd);
1340 
1341 	v4l2_async_unregister_subdev(sd);
1342 	v4l2_subdev_cleanup(sd);
1343 	media_entity_cleanup(&sd->entity);
1344 	v4l2_ctrl_handler_free(sd->ctrl_handler);
1345 	pm_runtime_disable(s5k3m5->dev);
1346 
1347 	if (!pm_runtime_status_suspended(s5k3m5->dev)) {
1348 		s5k3m5_power_off(s5k3m5->dev);
1349 		pm_runtime_set_suspended(s5k3m5->dev);
1350 	}
1351 }
1352 
1353 static const struct dev_pm_ops s5k3m5_pm_ops = {
1354 	SET_RUNTIME_PM_OPS(s5k3m5_power_off, s5k3m5_power_on, NULL)
1355 };
1356 
1357 static const struct of_device_id s5k3m5_of_match[] = {
1358 	{ .compatible = "samsung,s5k3m5" },
1359 	{ /* sentinel */ }
1360 };
1361 MODULE_DEVICE_TABLE(of, s5k3m5_of_match);
1362 
1363 static struct i2c_driver s5k3m5_i2c_driver = {
1364 	.driver = {
1365 		.name = "s5k3m5",
1366 		.pm = &s5k3m5_pm_ops,
1367 		.of_match_table = s5k3m5_of_match,
1368 	},
1369 	.probe = s5k3m5_probe,
1370 	.remove = s5k3m5_remove,
1371 };
1372 
1373 module_i2c_driver(s5k3m5_i2c_driver);
1374 
1375 MODULE_AUTHOR("Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>");
1376 MODULE_DESCRIPTION("Samsung S5K3M5 image sensor driver");
1377 MODULE_LICENSE("GPL");
1378