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