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