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
23static int s5k4aa_s_ctrl(struct v4l2_ctrl *ctrl);
24static void s5k4aa_dump_registers(struct sd *sd);
25
26static const struct v4l2_ctrl_ops s5k4aa_ctrl_ops = {
27	.s_ctrl = s5k4aa_s_ctrl,
28};
29
30static
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
119static 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
144int 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
207sensor_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
214int 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
294int 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
332int 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
366static 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
386static 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
438static 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
455static 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
470static 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
485static 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
517void s5k4aa_disconnect(struct sd *sd)
518{
519	sd->sensor = NULL;
520}
521
522static 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