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_s_ctrl(struct v4l2_ctrl *ctrl);
24 static void s5k4aa_dump_registers(struct sd *sd);
25 
26 static const struct v4l2_ctrl_ops s5k4aa_ctrl_ops = {
27 	.s_ctrl = s5k4aa_s_ctrl,
28 };
29 
30 static
31     const
32 	struct dmi_system_id s5k4aa_vflip_dmi_table[] = {
33 	{
34 		.ident = "BRUNEINIT",
35 		.matches = {
36 			DMI_MATCH(DMI_SYS_VENDOR, "BRUNENIT"),
37 			DMI_MATCH(DMI_PRODUCT_NAME, "BRUNENIT"),
38 			DMI_MATCH(DMI_BOARD_VERSION, "00030D0000000001")
39 		}
40 	}, {
41 		.ident = "Fujitsu-Siemens Amilo Xa 2528",
42 		.matches = {
43 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
44 			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xa 2528")
45 		}
46 	}, {
47 		.ident = "Fujitsu-Siemens Amilo Xi 2428",
48 		.matches = {
49 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
50 			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2428")
51 		}
52 	}, {
53 		.ident = "Fujitsu-Siemens Amilo Xi 2528",
54 		.matches = {
55 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
56 			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2528")
57 		}
58 	}, {
59 		.ident = "Fujitsu-Siemens Amilo Xi 2550",
60 		.matches = {
61 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
62 			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550")
63 		}
64 	}, {
65 		.ident = "Fujitsu-Siemens Amilo Pa 2548",
66 		.matches = {
67 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
68 			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 2548")
69 		}
70 	}, {
71 		.ident = "Fujitsu-Siemens Amilo Pi 2530",
72 		.matches = {
73 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
74 			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 2530")
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 int s5k4aa_probe(struct sd *sd)
145 {
146 	u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
147 	const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75};
148 	struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
149 	int i, err = 0;
150 
151 	if (force_sensor) {
152 		if (force_sensor == S5K4AA_SENSOR) {
153 			pr_info("Forcing a %s sensor\n", s5k4aa.name);
154 			goto sensor_found;
155 		}
156 		/* If we want to force another sensor, don't try to probe this
157 		 * one */
158 		return -ENODEV;
159 	}
160 
161 	PDEBUG(D_PROBE, "Probing for a s5k4aa sensor");
162 
163 	/* Preinit the sensor */
164 	for (i = 0; i < ARRAY_SIZE(preinit_s5k4aa) && !err; i++) {
165 		u8 data[2] = {0x00, 0x00};
166 
167 		switch (preinit_s5k4aa[i][0]) {
168 		case BRIDGE:
169 			err = m5602_write_bridge(sd,
170 						 preinit_s5k4aa[i][1],
171 						 preinit_s5k4aa[i][2]);
172 			break;
173 
174 		case SENSOR:
175 			data[0] = preinit_s5k4aa[i][2];
176 			err = m5602_write_sensor(sd,
177 						  preinit_s5k4aa[i][1],
178 						  data, 1);
179 			break;
180 
181 		case SENSOR_LONG:
182 			data[0] = preinit_s5k4aa[i][2];
183 			data[1] = preinit_s5k4aa[i][3];
184 			err = m5602_write_sensor(sd,
185 						  preinit_s5k4aa[i][1],
186 						  data, 2);
187 			break;
188 		default:
189 			pr_info("Invalid stream command, exiting init\n");
190 			return -EINVAL;
191 		}
192 	}
193 
194 	/* Test some registers, but we don't know their exact meaning yet */
195 	if (m5602_read_sensor(sd, 0x00, prod_id, 2))
196 		return -ENODEV;
197 	if (m5602_read_sensor(sd, 0x02, prod_id+2, 2))
198 		return -ENODEV;
199 	if (m5602_read_sensor(sd, 0x04, prod_id+4, 2))
200 		return -ENODEV;
201 
202 	if (memcmp(prod_id, expected_prod_id, sizeof(prod_id)))
203 		return -ENODEV;
204 	else
205 		pr_info("Detected a s5k4aa sensor\n");
206 
207 sensor_found:
208 	sd->gspca_dev.cam.cam_mode = s5k4aa_modes;
209 	sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes);
210 
211 	return 0;
212 }
213 
214 int s5k4aa_start(struct sd *sd)
215 {
216 	int i, err = 0;
217 	u8 data[2];
218 	struct cam *cam = &sd->gspca_dev.cam;
219 	struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
220 
221 	switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) {
222 	case 1280:
223 		PDEBUG(D_CONF, "Configuring camera for SXGA mode");
224 
225 		for (i = 0; i < ARRAY_SIZE(SXGA_s5k4aa); i++) {
226 			switch (SXGA_s5k4aa[i][0]) {
227 			case BRIDGE:
228 				err = m5602_write_bridge(sd,
229 						 SXGA_s5k4aa[i][1],
230 						 SXGA_s5k4aa[i][2]);
231 			break;
232 
233 			case SENSOR:
234 				data[0] = SXGA_s5k4aa[i][2];
235 				err = m5602_write_sensor(sd,
236 						 SXGA_s5k4aa[i][1],
237 						 data, 1);
238 			break;
239 
240 			case SENSOR_LONG:
241 				data[0] = SXGA_s5k4aa[i][2];
242 				data[1] = SXGA_s5k4aa[i][3];
243 				err = m5602_write_sensor(sd,
244 						  SXGA_s5k4aa[i][1],
245 						  data, 2);
246 			break;
247 
248 			default:
249 				pr_err("Invalid stream command, exiting init\n");
250 				return -EINVAL;
251 			}
252 		}
253 		break;
254 
255 	case 640:
256 		PDEBUG(D_CONF, "Configuring camera for VGA mode");
257 
258 		for (i = 0; i < ARRAY_SIZE(VGA_s5k4aa); i++) {
259 			switch (VGA_s5k4aa[i][0]) {
260 			case BRIDGE:
261 				err = m5602_write_bridge(sd,
262 						 VGA_s5k4aa[i][1],
263 						 VGA_s5k4aa[i][2]);
264 			break;
265 
266 			case SENSOR:
267 				data[0] = VGA_s5k4aa[i][2];
268 				err = m5602_write_sensor(sd,
269 						 VGA_s5k4aa[i][1],
270 						 data, 1);
271 			break;
272 
273 			case SENSOR_LONG:
274 				data[0] = VGA_s5k4aa[i][2];
275 				data[1] = VGA_s5k4aa[i][3];
276 				err = m5602_write_sensor(sd,
277 						  VGA_s5k4aa[i][1],
278 						  data, 2);
279 			break;
280 
281 			default:
282 				pr_err("Invalid stream command, exiting init\n");
283 				return -EINVAL;
284 			}
285 		}
286 		break;
287 	}
288 	if (err < 0)
289 		return err;
290 
291 	return 0;
292 }
293 
294 int s5k4aa_init(struct sd *sd)
295 {
296 	int i, err = 0;
297 
298 	for (i = 0; i < ARRAY_SIZE(init_s5k4aa) && !err; i++) {
299 		u8 data[2] = {0x00, 0x00};
300 
301 		switch (init_s5k4aa[i][0]) {
302 		case BRIDGE:
303 			err = m5602_write_bridge(sd,
304 				init_s5k4aa[i][1],
305 				init_s5k4aa[i][2]);
306 			break;
307 
308 		case SENSOR:
309 			data[0] = init_s5k4aa[i][2];
310 			err = m5602_write_sensor(sd,
311 				init_s5k4aa[i][1], data, 1);
312 			break;
313 
314 		case SENSOR_LONG:
315 			data[0] = init_s5k4aa[i][2];
316 			data[1] = init_s5k4aa[i][3];
317 			err = m5602_write_sensor(sd,
318 				init_s5k4aa[i][1], data, 2);
319 			break;
320 		default:
321 			pr_info("Invalid stream command, exiting init\n");
322 			return -EINVAL;
323 		}
324 	}
325 
326 	if (dump_sensor)
327 		s5k4aa_dump_registers(sd);
328 
329 	return err;
330 }
331 
332 int s5k4aa_init_controls(struct sd *sd)
333 {
334 	struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
335 
336 	sd->gspca_dev.vdev.ctrl_handler = hdl;
337 	v4l2_ctrl_handler_init(hdl, 6);
338 
339 	v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_BRIGHTNESS,
340 			  0, 0x1f, 1, S5K4AA_DEFAULT_BRIGHTNESS);
341 
342 	v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_EXPOSURE,
343 			  13, 0xfff, 1, 0x100);
344 
345 	v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_GAIN,
346 			  0, 127, 1, S5K4AA_DEFAULT_GAIN);
347 
348 	v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_SHARPNESS,
349 			  0, 1, 1, 1);
350 
351 	sd->hflip = v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_HFLIP,
352 				      0, 1, 1, 0);
353 	sd->vflip = v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_VFLIP,
354 				      0, 1, 1, 0);
355 
356 	if (hdl->error) {
357 		pr_err("Could not initialize controls\n");
358 		return hdl->error;
359 	}
360 
361 	v4l2_ctrl_cluster(2, &sd->hflip);
362 
363 	return 0;
364 }
365 
366 static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
367 {
368 	struct sd *sd = (struct sd *) gspca_dev;
369 	u8 data = S5K4AA_PAGE_MAP_2;
370 	int err;
371 
372 	PDEBUG(D_CONF, "Set exposure to %d", val);
373 	err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
374 	if (err < 0)
375 		return err;
376 	data = (val >> 8) & 0xff;
377 	err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
378 	if (err < 0)
379 		return err;
380 	data = val & 0xff;
381 	err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
382 
383 	return err;
384 }
385 
386 static int s5k4aa_set_hvflip(struct gspca_dev *gspca_dev)
387 {
388 	struct sd *sd = (struct sd *) gspca_dev;
389 	u8 data = S5K4AA_PAGE_MAP_2;
390 	int err;
391 	int hflip = sd->hflip->val;
392 	int vflip = sd->vflip->val;
393 
394 	PDEBUG(D_CONF, "Set hvflip %d %d", hflip, vflip);
395 	err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
396 	if (err < 0)
397 		return err;
398 
399 	err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
400 	if (err < 0)
401 		return err;
402 
403 	if (dmi_check_system(s5k4aa_vflip_dmi_table)) {
404 		hflip = !hflip;
405 		vflip = !vflip;
406 	}
407 
408 	data = (data & 0x7f) | (vflip << 7) | (hflip << 6);
409 	err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
410 	if (err < 0)
411 		return err;
412 
413 	err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
414 	if (err < 0)
415 		return err;
416 	if (hflip)
417 		data &= 0xfe;
418 	else
419 		data |= 0x01;
420 	err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
421 	if (err < 0)
422 		return err;
423 
424 	err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
425 	if (err < 0)
426 		return err;
427 	if (vflip)
428 		data &= 0xfe;
429 	else
430 		data |= 0x01;
431 	err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
432 	if (err < 0)
433 		return err;
434 
435 	return 0;
436 }
437 
438 static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
439 {
440 	struct sd *sd = (struct sd *) gspca_dev;
441 	u8 data = S5K4AA_PAGE_MAP_2;
442 	int err;
443 
444 	PDEBUG(D_CONF, "Set gain to %d", val);
445 	err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
446 	if (err < 0)
447 		return err;
448 
449 	data = val & 0xff;
450 	err = m5602_write_sensor(sd, S5K4AA_GAIN, &data, 1);
451 
452 	return err;
453 }
454 
455 static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
456 {
457 	struct sd *sd = (struct sd *) gspca_dev;
458 	u8 data = S5K4AA_PAGE_MAP_2;
459 	int err;
460 
461 	PDEBUG(D_CONF, "Set brightness to %d", val);
462 	err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
463 	if (err < 0)
464 		return err;
465 
466 	data = val & 0xff;
467 	return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1);
468 }
469 
470 static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val)
471 {
472 	struct sd *sd = (struct sd *) gspca_dev;
473 	u8 data = S5K4AA_PAGE_MAP_2;
474 	int err;
475 
476 	PDEBUG(D_CONF, "Set noise to %d", val);
477 	err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
478 	if (err < 0)
479 		return err;
480 
481 	data = val & 0x01;
482 	return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1);
483 }
484 
485 static int s5k4aa_s_ctrl(struct v4l2_ctrl *ctrl)
486 {
487 	struct gspca_dev *gspca_dev =
488 		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
489 	int err;
490 
491 	if (!gspca_dev->streaming)
492 		return 0;
493 
494 	switch (ctrl->id) {
495 	case V4L2_CID_BRIGHTNESS:
496 		err = s5k4aa_set_brightness(gspca_dev, ctrl->val);
497 		break;
498 	case V4L2_CID_EXPOSURE:
499 		err = s5k4aa_set_exposure(gspca_dev, ctrl->val);
500 		break;
501 	case V4L2_CID_GAIN:
502 		err = s5k4aa_set_gain(gspca_dev, ctrl->val);
503 		break;
504 	case V4L2_CID_SHARPNESS:
505 		err = s5k4aa_set_noise(gspca_dev, ctrl->val);
506 		break;
507 	case V4L2_CID_HFLIP:
508 		err = s5k4aa_set_hvflip(gspca_dev);
509 		break;
510 	default:
511 		return -EINVAL;
512 	}
513 
514 	return err;
515 }
516 
517 void s5k4aa_disconnect(struct sd *sd)
518 {
519 	sd->sensor = NULL;
520 }
521 
522 static void s5k4aa_dump_registers(struct sd *sd)
523 {
524 	int address;
525 	u8 page, old_page;
526 	m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
527 	for (page = 0; page < 16; page++) {
528 		m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
529 		pr_info("Dumping the s5k4aa register state for page 0x%x\n",
530 			page);
531 		for (address = 0; address <= 0xff; address++) {
532 			u8 value = 0;
533 			m5602_read_sensor(sd, address, &value, 1);
534 			pr_info("register 0x%x contains 0x%x\n",
535 				address, value);
536 		}
537 	}
538 	pr_info("s5k4aa register state dump complete\n");
539 
540 	for (page = 0; page < 16; page++) {
541 		m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
542 		pr_info("Probing for which registers that are read/write for page 0x%x\n",
543 			page);
544 		for (address = 0; address <= 0xff; address++) {
545 			u8 old_value, ctrl_value, test_value = 0xff;
546 
547 			m5602_read_sensor(sd, address, &old_value, 1);
548 			m5602_write_sensor(sd, address, &test_value, 1);
549 			m5602_read_sensor(sd, address, &ctrl_value, 1);
550 
551 			if (ctrl_value == test_value)
552 				pr_info("register 0x%x is writeable\n",
553 					address);
554 			else
555 				pr_info("register 0x%x is read only\n",
556 					address);
557 
558 			/* Restore original value */
559 			m5602_write_sensor(sd, address, &old_value, 1);
560 		}
561 	}
562 	pr_info("Read/write register probing complete\n");
563 	m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
564 }
565