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