xref: /linux/drivers/media/usb/gspca/m5602/m5602_s5k4aa.c (revision 0526b56cbc3c489642bd6a5fe4b718dea7ef0ee8)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Driver for the s5k4aa sensor
4  *
5  * Copyright (C) 2008 Erik Andrén
6  * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
7  * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
8  *
9  * Portions of code to USB interface and ALi driver software,
10  * Copyright (c) 2006 Willem Duinker
11  * v4l2 interface modeled after the V4L2 driver
12  * for SN9C10x PC Camera Controllers
13  */
14 
15 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
16 
17 #include "m5602_s5k4aa.h"
18 
19 static const unsigned char preinit_s5k4aa[][4] = {
20 	{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
21 	{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
22 	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
23 	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
24 	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
25 	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00},
26 	{BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00},
27 
28 	{BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
29 	{BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
30 	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00},
31 	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00},
32 	{BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00},
33 	{BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00},
34 	{BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
35 	{BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
36 	{BRIDGE, M5602_XB_GPIO_DAT, 0x00, 0x00},
37 	{BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
38 	{BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
39 	{BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
40 	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
41 	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
42 	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
43 	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00},
44 
45 	{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
46 	{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
47 	{BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
48 	{BRIDGE, M5602_XB_GPIO_DAT, 0x14, 0x00},
49 	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
50 	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
51 	{BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
52 	{BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00},
53 	{BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
54 	{BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
55 	{BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
56 	{BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
57 	{BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00},
58 
59 	{SENSOR, S5K4AA_PAGE_MAP, 0x00, 0x00}
60 };
61 
62 static const unsigned char init_s5k4aa[][4] = {
63 	{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
64 	{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
65 	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
66 	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
67 	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
68 	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00},
69 	{BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00},
70 
71 	{BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
72 	{BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
73 	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00},
74 	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00},
75 	{BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00},
76 	{BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00},
77 	{BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
78 	{BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
79 	{BRIDGE, M5602_XB_GPIO_DAT, 0x00, 0x00},
80 	{BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
81 	{BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
82 	{BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
83 	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
84 	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
85 	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
86 	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00},
87 
88 	{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
89 	{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
90 	{BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
91 	{BRIDGE, M5602_XB_GPIO_DAT, 0x14, 0x00},
92 	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
93 	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
94 	{BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
95 	{BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00},
96 	{BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
97 	{BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
98 	{BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
99 	{BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
100 	{BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00},
101 
102 	{SENSOR, S5K4AA_PAGE_MAP, 0x07, 0x00},
103 	{SENSOR, 0x36, 0x01, 0x00},
104 	{SENSOR, S5K4AA_PAGE_MAP, 0x00, 0x00},
105 	{SENSOR, 0x7b, 0xff, 0x00},
106 	{SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
107 	{SENSOR, 0x0c, 0x05, 0x00},
108 	{SENSOR, 0x02, 0x0e, 0x00},
109 	{SENSOR, S5K4AA_READ_MODE, 0xa0, 0x00},
110 	{SENSOR, 0x37, 0x00, 0x00},
111 };
112 
113 static const unsigned char VGA_s5k4aa[][4] = {
114 	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
115 	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
116 	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
117 	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00},
118 	{BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
119 	{BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
120 	{BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
121 	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
122 	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
123 	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
124 	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
125 	/* VSYNC_PARA, VSYNC_PARA : img height 480 = 0x01e0 */
126 	{BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
127 	{BRIDGE, M5602_XB_VSYNC_PARA, 0xe0, 0x00},
128 	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
129 	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
130 	{BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
131 	{BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
132 	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
133 	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
134 	/* HSYNC_PARA, HSYNC_PARA : img width 640 = 0x0280 */
135 	{BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
136 	{BRIDGE, M5602_XB_HSYNC_PARA, 0x80, 0x00},
137 	{BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
138 	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
139 	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00}, /* 48 MHz */
140 
141 	{SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
142 	{SENSOR, S5K4AA_READ_MODE, S5K4AA_RM_H_FLIP | S5K4AA_RM_ROW_SKIP_2X
143 		| S5K4AA_RM_COL_SKIP_2X, 0x00},
144 	/* 0x37 : Fix image stability when light is too bright and improves
145 	 * image quality in 640x480, but worsens it in 1280x1024 */
146 	{SENSOR, 0x37, 0x01, 0x00},
147 	/* ROWSTART_HI, ROWSTART_LO : 10 + (1024-960)/2 = 42 = 0x002a */
148 	{SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00},
149 	{SENSOR, S5K4AA_ROWSTART_LO, 0x29, 0x00},
150 	{SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00},
151 	{SENSOR, S5K4AA_COLSTART_LO, 0x0c, 0x00},
152 	/* window_height_hi, window_height_lo : 960 = 0x03c0 */
153 	{SENSOR, S5K4AA_WINDOW_HEIGHT_HI, 0x03, 0x00},
154 	{SENSOR, S5K4AA_WINDOW_HEIGHT_LO, 0xc0, 0x00},
155 	/* window_width_hi, window_width_lo : 1280 = 0x0500 */
156 	{SENSOR, S5K4AA_WINDOW_WIDTH_HI, 0x05, 0x00},
157 	{SENSOR, S5K4AA_WINDOW_WIDTH_LO, 0x00, 0x00},
158 	{SENSOR, S5K4AA_H_BLANK_HI__, 0x00, 0x00},
159 	{SENSOR, S5K4AA_H_BLANK_LO__, 0xa8, 0x00}, /* helps to sync... */
160 	{SENSOR, S5K4AA_EXPOSURE_HI, 0x01, 0x00},
161 	{SENSOR, S5K4AA_EXPOSURE_LO, 0x00, 0x00},
162 	{SENSOR, 0x11, 0x04, 0x00},
163 	{SENSOR, 0x12, 0xc3, 0x00},
164 	{SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
165 	{SENSOR, 0x02, 0x0e, 0x00},
166 };
167 
168 static const unsigned char SXGA_s5k4aa[][4] = {
169 	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
170 	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
171 	{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
172 	{BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00},
173 	{BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
174 	{BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
175 	{BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
176 	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
177 	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
178 	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
179 	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
180 	/* VSYNC_PARA, VSYNC_PARA : img height 1024 = 0x0400 */
181 	{BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
182 	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
183 	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
184 	{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
185 	{BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
186 	{BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
187 	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
188 	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
189 	/* HSYNC_PARA, HSYNC_PARA : img width 1280 = 0x0500 */
190 	{BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00},
191 	{BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
192 	{BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
193 	{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
194 	{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00}, /* 48 MHz */
195 
196 	{SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
197 	{SENSOR, S5K4AA_READ_MODE, S5K4AA_RM_H_FLIP, 0x00},
198 	{SENSOR, 0x37, 0x01, 0x00},
199 	{SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00},
200 	{SENSOR, S5K4AA_ROWSTART_LO, 0x09, 0x00},
201 	{SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00},
202 	{SENSOR, S5K4AA_COLSTART_LO, 0x0a, 0x00},
203 	{SENSOR, S5K4AA_WINDOW_HEIGHT_HI, 0x04, 0x00},
204 	{SENSOR, S5K4AA_WINDOW_HEIGHT_LO, 0x00, 0x00},
205 	{SENSOR, S5K4AA_WINDOW_WIDTH_HI, 0x05, 0x00},
206 	{SENSOR, S5K4AA_WINDOW_WIDTH_LO, 0x00, 0x00},
207 	{SENSOR, S5K4AA_H_BLANK_HI__, 0x01, 0x00},
208 	{SENSOR, S5K4AA_H_BLANK_LO__, 0xa8, 0x00},
209 	{SENSOR, S5K4AA_EXPOSURE_HI, 0x01, 0x00},
210 	{SENSOR, S5K4AA_EXPOSURE_LO, 0x00, 0x00},
211 	{SENSOR, 0x11, 0x04, 0x00},
212 	{SENSOR, 0x12, 0xc3, 0x00},
213 	{SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
214 	{SENSOR, 0x02, 0x0e, 0x00},
215 };
216 
217 
218 static int s5k4aa_s_ctrl(struct v4l2_ctrl *ctrl);
219 static void s5k4aa_dump_registers(struct sd *sd);
220 
221 static const struct v4l2_ctrl_ops s5k4aa_ctrl_ops = {
222 	.s_ctrl = s5k4aa_s_ctrl,
223 };
224 
225 static
226     const
227 	struct dmi_system_id s5k4aa_vflip_dmi_table[] = {
228 	{
229 		.ident = "BRUNEINIT",
230 		.matches = {
231 			DMI_MATCH(DMI_SYS_VENDOR, "BRUNENIT"),
232 			DMI_MATCH(DMI_PRODUCT_NAME, "BRUNENIT"),
233 			DMI_MATCH(DMI_BOARD_VERSION, "00030D0000000001")
234 		}
235 	}, {
236 		.ident = "Fujitsu-Siemens Amilo Xa 2528",
237 		.matches = {
238 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
239 			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xa 2528")
240 		}
241 	}, {
242 		.ident = "Fujitsu-Siemens Amilo Xi 2428",
243 		.matches = {
244 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
245 			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2428")
246 		}
247 	}, {
248 		.ident = "Fujitsu-Siemens Amilo Xi 2528",
249 		.matches = {
250 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
251 			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2528")
252 		}
253 	}, {
254 		.ident = "Fujitsu-Siemens Amilo Xi 2550",
255 		.matches = {
256 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
257 			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550")
258 		}
259 	}, {
260 		.ident = "Fujitsu-Siemens Amilo Pa 2548",
261 		.matches = {
262 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
263 			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 2548")
264 		}
265 	}, {
266 		.ident = "Fujitsu-Siemens Amilo Pi 2530",
267 		.matches = {
268 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
269 			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 2530")
270 		}
271 	}, {
272 		.ident = "MSI GX700",
273 		.matches = {
274 			DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
275 			DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
276 			DMI_MATCH(DMI_BIOS_DATE, "12/02/2008")
277 		}
278 	}, {
279 		.ident = "MSI GX700",
280 		.matches = {
281 			DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
282 			DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
283 			DMI_MATCH(DMI_BIOS_DATE, "07/26/2007")
284 		}
285 	}, {
286 		.ident = "MSI GX700",
287 		.matches = {
288 			DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
289 			DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
290 			DMI_MATCH(DMI_BIOS_DATE, "07/19/2007")
291 		}
292 	}, {
293 		.ident = "MSI GX700/GX705/EX700",
294 		.matches = {
295 			DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
296 			DMI_MATCH(DMI_PRODUCT_NAME, "GX700/GX705/EX700")
297 		}
298 	}, {
299 		.ident = "MSI L735",
300 		.matches = {
301 			DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
302 			DMI_MATCH(DMI_PRODUCT_NAME, "MS-1717X")
303 		}
304 	}, {
305 		.ident = "Lenovo Y300",
306 		.matches = {
307 			DMI_MATCH(DMI_SYS_VENDOR, "L3000 Y300"),
308 			DMI_MATCH(DMI_PRODUCT_NAME, "Y300")
309 		}
310 	},
311 	{ }
312 };
313 
314 static struct v4l2_pix_format s5k4aa_modes[] = {
315 	{
316 		640,
317 		480,
318 		V4L2_PIX_FMT_SBGGR8,
319 		V4L2_FIELD_NONE,
320 		.sizeimage =
321 			640 * 480,
322 		.bytesperline = 640,
323 		.colorspace = V4L2_COLORSPACE_SRGB,
324 		.priv = 0
325 	},
326 	{
327 		1280,
328 		1024,
329 		V4L2_PIX_FMT_SBGGR8,
330 		V4L2_FIELD_NONE,
331 		.sizeimage =
332 			1280 * 1024,
333 		.bytesperline = 1280,
334 		.colorspace = V4L2_COLORSPACE_SRGB,
335 		.priv = 0
336 	}
337 };
338 
339 int s5k4aa_probe(struct sd *sd)
340 {
341 	u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
342 	const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75};
343 	struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
344 	int i, err = 0;
345 
346 	if (force_sensor) {
347 		if (force_sensor == S5K4AA_SENSOR) {
348 			pr_info("Forcing a %s sensor\n", s5k4aa.name);
349 			goto sensor_found;
350 		}
351 		/* If we want to force another sensor, don't try to probe this
352 		 * one */
353 		return -ENODEV;
354 	}
355 
356 	gspca_dbg(gspca_dev, D_PROBE, "Probing for a s5k4aa sensor\n");
357 
358 	/* Preinit the sensor */
359 	for (i = 0; i < ARRAY_SIZE(preinit_s5k4aa) && !err; i++) {
360 		u8 data[2] = {0x00, 0x00};
361 
362 		switch (preinit_s5k4aa[i][0]) {
363 		case BRIDGE:
364 			err = m5602_write_bridge(sd,
365 						 preinit_s5k4aa[i][1],
366 						 preinit_s5k4aa[i][2]);
367 			break;
368 
369 		case SENSOR:
370 			data[0] = preinit_s5k4aa[i][2];
371 			err = m5602_write_sensor(sd,
372 						  preinit_s5k4aa[i][1],
373 						  data, 1);
374 			break;
375 
376 		case SENSOR_LONG:
377 			data[0] = preinit_s5k4aa[i][2];
378 			data[1] = preinit_s5k4aa[i][3];
379 			err = m5602_write_sensor(sd,
380 						  preinit_s5k4aa[i][1],
381 						  data, 2);
382 			break;
383 		default:
384 			pr_info("Invalid stream command, exiting init\n");
385 			return -EINVAL;
386 		}
387 	}
388 
389 	/* Test some registers, but we don't know their exact meaning yet */
390 	if (m5602_read_sensor(sd, 0x00, prod_id, 2))
391 		return -ENODEV;
392 	if (m5602_read_sensor(sd, 0x02, prod_id+2, 2))
393 		return -ENODEV;
394 	if (m5602_read_sensor(sd, 0x04, prod_id+4, 2))
395 		return -ENODEV;
396 
397 	if (memcmp(prod_id, expected_prod_id, sizeof(prod_id)))
398 		return -ENODEV;
399 	else
400 		pr_info("Detected a s5k4aa sensor\n");
401 
402 sensor_found:
403 	sd->gspca_dev.cam.cam_mode = s5k4aa_modes;
404 	sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes);
405 
406 	return 0;
407 }
408 
409 int s5k4aa_start(struct sd *sd)
410 {
411 	int i, err = 0;
412 	u8 data[2];
413 	struct cam *cam = &sd->gspca_dev.cam;
414 	struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
415 
416 	switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) {
417 	case 1280:
418 		gspca_dbg(gspca_dev, D_CONF, "Configuring camera for SXGA mode\n");
419 
420 		for (i = 0; i < ARRAY_SIZE(SXGA_s5k4aa); i++) {
421 			switch (SXGA_s5k4aa[i][0]) {
422 			case BRIDGE:
423 				err = m5602_write_bridge(sd,
424 						 SXGA_s5k4aa[i][1],
425 						 SXGA_s5k4aa[i][2]);
426 			break;
427 
428 			case SENSOR:
429 				data[0] = SXGA_s5k4aa[i][2];
430 				err = m5602_write_sensor(sd,
431 						 SXGA_s5k4aa[i][1],
432 						 data, 1);
433 			break;
434 
435 			case SENSOR_LONG:
436 				data[0] = SXGA_s5k4aa[i][2];
437 				data[1] = SXGA_s5k4aa[i][3];
438 				err = m5602_write_sensor(sd,
439 						  SXGA_s5k4aa[i][1],
440 						  data, 2);
441 			break;
442 
443 			default:
444 				pr_err("Invalid stream command, exiting init\n");
445 				return -EINVAL;
446 			}
447 		}
448 		break;
449 
450 	case 640:
451 		gspca_dbg(gspca_dev, D_CONF, "Configuring camera for VGA mode\n");
452 
453 		for (i = 0; i < ARRAY_SIZE(VGA_s5k4aa); i++) {
454 			switch (VGA_s5k4aa[i][0]) {
455 			case BRIDGE:
456 				err = m5602_write_bridge(sd,
457 						 VGA_s5k4aa[i][1],
458 						 VGA_s5k4aa[i][2]);
459 			break;
460 
461 			case SENSOR:
462 				data[0] = VGA_s5k4aa[i][2];
463 				err = m5602_write_sensor(sd,
464 						 VGA_s5k4aa[i][1],
465 						 data, 1);
466 			break;
467 
468 			case SENSOR_LONG:
469 				data[0] = VGA_s5k4aa[i][2];
470 				data[1] = VGA_s5k4aa[i][3];
471 				err = m5602_write_sensor(sd,
472 						  VGA_s5k4aa[i][1],
473 						  data, 2);
474 			break;
475 
476 			default:
477 				pr_err("Invalid stream command, exiting init\n");
478 				return -EINVAL;
479 			}
480 		}
481 		break;
482 	}
483 	if (err < 0)
484 		return err;
485 
486 	return 0;
487 }
488 
489 int s5k4aa_init(struct sd *sd)
490 {
491 	int i, err = 0;
492 
493 	for (i = 0; i < ARRAY_SIZE(init_s5k4aa) && !err; i++) {
494 		u8 data[2] = {0x00, 0x00};
495 
496 		switch (init_s5k4aa[i][0]) {
497 		case BRIDGE:
498 			err = m5602_write_bridge(sd,
499 				init_s5k4aa[i][1],
500 				init_s5k4aa[i][2]);
501 			break;
502 
503 		case SENSOR:
504 			data[0] = init_s5k4aa[i][2];
505 			err = m5602_write_sensor(sd,
506 				init_s5k4aa[i][1], data, 1);
507 			break;
508 
509 		case SENSOR_LONG:
510 			data[0] = init_s5k4aa[i][2];
511 			data[1] = init_s5k4aa[i][3];
512 			err = m5602_write_sensor(sd,
513 				init_s5k4aa[i][1], data, 2);
514 			break;
515 		default:
516 			pr_info("Invalid stream command, exiting init\n");
517 			return -EINVAL;
518 		}
519 	}
520 
521 	if (dump_sensor)
522 		s5k4aa_dump_registers(sd);
523 
524 	return err;
525 }
526 
527 int s5k4aa_init_controls(struct sd *sd)
528 {
529 	struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
530 
531 	sd->gspca_dev.vdev.ctrl_handler = hdl;
532 	v4l2_ctrl_handler_init(hdl, 6);
533 
534 	v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_BRIGHTNESS,
535 			  0, 0x1f, 1, S5K4AA_DEFAULT_BRIGHTNESS);
536 
537 	v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_EXPOSURE,
538 			  13, 0xfff, 1, 0x100);
539 
540 	v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_GAIN,
541 			  0, 127, 1, S5K4AA_DEFAULT_GAIN);
542 
543 	v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_SHARPNESS,
544 			  0, 1, 1, 1);
545 
546 	sd->hflip = v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_HFLIP,
547 				      0, 1, 1, 0);
548 	sd->vflip = v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_VFLIP,
549 				      0, 1, 1, 0);
550 
551 	if (hdl->error) {
552 		pr_err("Could not initialize controls\n");
553 		return hdl->error;
554 	}
555 
556 	v4l2_ctrl_cluster(2, &sd->hflip);
557 
558 	return 0;
559 }
560 
561 static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
562 {
563 	struct sd *sd = (struct sd *) gspca_dev;
564 	u8 data = S5K4AA_PAGE_MAP_2;
565 	int err;
566 
567 	gspca_dbg(gspca_dev, D_CONF, "Set exposure to %d\n", val);
568 	err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
569 	if (err < 0)
570 		return err;
571 	data = (val >> 8) & 0xff;
572 	err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
573 	if (err < 0)
574 		return err;
575 	data = val & 0xff;
576 	err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
577 
578 	return err;
579 }
580 
581 static int s5k4aa_set_hvflip(struct gspca_dev *gspca_dev)
582 {
583 	struct sd *sd = (struct sd *) gspca_dev;
584 	u8 data = S5K4AA_PAGE_MAP_2;
585 	int err;
586 	int hflip = sd->hflip->val;
587 	int vflip = sd->vflip->val;
588 
589 	gspca_dbg(gspca_dev, D_CONF, "Set hvflip %d %d\n", hflip, vflip);
590 	err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
591 	if (err < 0)
592 		return err;
593 
594 	err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
595 	if (err < 0)
596 		return err;
597 
598 	if (dmi_check_system(s5k4aa_vflip_dmi_table)) {
599 		hflip = !hflip;
600 		vflip = !vflip;
601 	}
602 
603 	data = (data & 0x7f) | (vflip << 7) | (hflip << 6);
604 	err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
605 	if (err < 0)
606 		return err;
607 
608 	err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
609 	if (err < 0)
610 		return err;
611 	if (hflip)
612 		data &= 0xfe;
613 	else
614 		data |= 0x01;
615 	err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
616 	if (err < 0)
617 		return err;
618 
619 	err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
620 	if (err < 0)
621 		return err;
622 	if (vflip)
623 		data &= 0xfe;
624 	else
625 		data |= 0x01;
626 	err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
627 	if (err < 0)
628 		return err;
629 
630 	return 0;
631 }
632 
633 static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
634 {
635 	struct sd *sd = (struct sd *) gspca_dev;
636 	u8 data = S5K4AA_PAGE_MAP_2;
637 	int err;
638 
639 	gspca_dbg(gspca_dev, D_CONF, "Set gain to %d\n", val);
640 	err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
641 	if (err < 0)
642 		return err;
643 
644 	data = val & 0xff;
645 	err = m5602_write_sensor(sd, S5K4AA_GAIN, &data, 1);
646 
647 	return err;
648 }
649 
650 static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
651 {
652 	struct sd *sd = (struct sd *) gspca_dev;
653 	u8 data = S5K4AA_PAGE_MAP_2;
654 	int err;
655 
656 	gspca_dbg(gspca_dev, D_CONF, "Set brightness to %d\n", val);
657 	err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
658 	if (err < 0)
659 		return err;
660 
661 	data = val & 0xff;
662 	return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1);
663 }
664 
665 static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val)
666 {
667 	struct sd *sd = (struct sd *) gspca_dev;
668 	u8 data = S5K4AA_PAGE_MAP_2;
669 	int err;
670 
671 	gspca_dbg(gspca_dev, D_CONF, "Set noise to %d\n", val);
672 	err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
673 	if (err < 0)
674 		return err;
675 
676 	data = val & 0x01;
677 	return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1);
678 }
679 
680 static int s5k4aa_s_ctrl(struct v4l2_ctrl *ctrl)
681 {
682 	struct gspca_dev *gspca_dev =
683 		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
684 	int err;
685 
686 	if (!gspca_dev->streaming)
687 		return 0;
688 
689 	switch (ctrl->id) {
690 	case V4L2_CID_BRIGHTNESS:
691 		err = s5k4aa_set_brightness(gspca_dev, ctrl->val);
692 		break;
693 	case V4L2_CID_EXPOSURE:
694 		err = s5k4aa_set_exposure(gspca_dev, ctrl->val);
695 		break;
696 	case V4L2_CID_GAIN:
697 		err = s5k4aa_set_gain(gspca_dev, ctrl->val);
698 		break;
699 	case V4L2_CID_SHARPNESS:
700 		err = s5k4aa_set_noise(gspca_dev, ctrl->val);
701 		break;
702 	case V4L2_CID_HFLIP:
703 		err = s5k4aa_set_hvflip(gspca_dev);
704 		break;
705 	default:
706 		return -EINVAL;
707 	}
708 
709 	return err;
710 }
711 
712 void s5k4aa_disconnect(struct sd *sd)
713 {
714 	sd->sensor = NULL;
715 }
716 
717 static void s5k4aa_dump_registers(struct sd *sd)
718 {
719 	int address;
720 	u8 page, old_page;
721 	m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
722 	for (page = 0; page < 16; page++) {
723 		m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
724 		pr_info("Dumping the s5k4aa register state for page 0x%x\n",
725 			page);
726 		for (address = 0; address <= 0xff; address++) {
727 			u8 value = 0;
728 			m5602_read_sensor(sd, address, &value, 1);
729 			pr_info("register 0x%x contains 0x%x\n",
730 				address, value);
731 		}
732 	}
733 	pr_info("s5k4aa register state dump complete\n");
734 
735 	for (page = 0; page < 16; page++) {
736 		m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
737 		pr_info("Probing for which registers that are read/write for page 0x%x\n",
738 			page);
739 		for (address = 0; address <= 0xff; address++) {
740 			u8 old_value, ctrl_value, test_value = 0xff;
741 
742 			m5602_read_sensor(sd, address, &old_value, 1);
743 			m5602_write_sensor(sd, address, &test_value, 1);
744 			m5602_read_sensor(sd, address, &ctrl_value, 1);
745 
746 			if (ctrl_value == test_value)
747 				pr_info("register 0x%x is writeable\n",
748 					address);
749 			else
750 				pr_info("register 0x%x is read only\n",
751 					address);
752 
753 			/* Restore original value */
754 			m5602_write_sensor(sd, address, &old_value, 1);
755 		}
756 	}
757 	pr_info("Read/write register probing complete\n");
758 	m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
759 }
760