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