2 * Driver for the s5k4aa sensor
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>
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
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.
19 #include "m5602_s5k4aa.h"
21 static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
22 static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
23 static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
24 static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
25 static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
26 static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
27 static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
28 static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val);
29 static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val);
30 static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val);
31 static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
32 static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
36 struct dmi_system_id s5k4aa_vflip_dmi_table[] = {
40 DMI_MATCH(DMI_SYS_VENDOR, "BRUNENIT"),
41 DMI_MATCH(DMI_PRODUCT_NAME, "BRUNENIT"),
42 DMI_MATCH(DMI_BOARD_VERSION, "00030D0000000001")
45 .ident = "Fujitsu-Siemens Amilo Xa 2528",
47 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
48 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xa 2528")
51 .ident = "Fujitsu-Siemens Amilo Xi 2528",
53 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
54 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2528")
57 .ident = "Fujitsu-Siemens Amilo Xi 2550",
59 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
60 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550")
63 .ident = "Fujitsu-Siemens Amilo Pa 2548",
65 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
66 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 2548")
71 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
72 DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
73 DMI_MATCH(DMI_BIOS_DATE, "12/02/2008")
78 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
79 DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
80 DMI_MATCH(DMI_BIOS_DATE, "07/26/2007")
85 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
86 DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
87 DMI_MATCH(DMI_BIOS_DATE, "07/19/2007")
90 .ident = "MSI GX700/GX705/EX700",
92 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
93 DMI_MATCH(DMI_PRODUCT_NAME, "GX700/GX705/EX700")
98 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
99 DMI_MATCH(DMI_PRODUCT_NAME, "MS-1717X")
102 .ident = "Lenovo Y300",
104 DMI_MATCH(DMI_SYS_VENDOR, "L3000 Y300"),
105 DMI_MATCH(DMI_PRODUCT_NAME, "Y300")
111 static struct v4l2_pix_format s5k4aa_modes[] = {
120 .colorspace = V4L2_COLORSPACE_SRGB,
130 .bytesperline = 1280,
131 .colorspace = V4L2_COLORSPACE_SRGB,
136 static const struct ctrl s5k4aa_ctrls[] = {
140 .id = V4L2_CID_VFLIP,
141 .type = V4L2_CTRL_TYPE_BOOLEAN,
142 .name = "vertical flip",
148 .set = s5k4aa_set_vflip,
149 .get = s5k4aa_get_vflip
154 .id = V4L2_CID_HFLIP,
155 .type = V4L2_CTRL_TYPE_BOOLEAN,
156 .name = "horizontal flip",
162 .set = s5k4aa_set_hflip,
163 .get = s5k4aa_get_hflip
169 .type = V4L2_CTRL_TYPE_INTEGER,
174 .default_value = S5K4AA_DEFAULT_GAIN,
175 .flags = V4L2_CTRL_FLAG_SLIDER
177 .set = s5k4aa_set_gain,
178 .get = s5k4aa_get_gain
180 #define EXPOSURE_IDX 3
183 .id = V4L2_CID_EXPOSURE,
184 .type = V4L2_CTRL_TYPE_INTEGER,
189 .default_value = 0x100,
190 .flags = V4L2_CTRL_FLAG_SLIDER
192 .set = s5k4aa_set_exposure,
193 .get = s5k4aa_get_exposure
195 #define NOISE_SUPP_IDX 4
198 .id = V4L2_CID_PRIVATE_BASE,
199 .type = V4L2_CTRL_TYPE_BOOLEAN,
200 .name = "Noise suppression (smoothing)",
206 .set = s5k4aa_set_noise,
207 .get = s5k4aa_get_noise
209 #define BRIGHTNESS_IDX 5
212 .id = V4L2_CID_BRIGHTNESS,
213 .type = V4L2_CTRL_TYPE_INTEGER,
214 .name = "Brightness",
218 .default_value = S5K4AA_DEFAULT_BRIGHTNESS,
220 .set = s5k4aa_set_brightness,
221 .get = s5k4aa_get_brightness
226 static void s5k4aa_dump_registers(struct sd *sd);
228 int s5k4aa_probe(struct sd *sd)
230 u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
231 const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75};
233 s32 *sensor_settings;
236 if (force_sensor == S5K4AA_SENSOR) {
237 info("Forcing a %s sensor", s5k4aa.name);
240 /* If we want to force another sensor, don't try to probe this
245 info("Probing for a s5k4aa sensor");
247 /* Preinit the sensor */
248 for (i = 0; i < ARRAY_SIZE(preinit_s5k4aa) && !err; i++) {
249 u8 data[2] = {0x00, 0x00};
251 switch (preinit_s5k4aa[i][0]) {
253 err = m5602_write_bridge(sd,
254 preinit_s5k4aa[i][1],
255 preinit_s5k4aa[i][2]);
259 data[0] = preinit_s5k4aa[i][2];
260 err = m5602_write_sensor(sd,
261 preinit_s5k4aa[i][1],
266 data[0] = preinit_s5k4aa[i][2];
267 data[1] = preinit_s5k4aa[i][3];
268 err = m5602_write_sensor(sd,
269 preinit_s5k4aa[i][1],
273 info("Invalid stream command, exiting init");
278 /* Test some registers, but we don't know their exact meaning yet */
279 if (m5602_read_sensor(sd, 0x00, prod_id, 2))
281 if (m5602_read_sensor(sd, 0x02, prod_id+2, 2))
283 if (m5602_read_sensor(sd, 0x04, prod_id+4, 2))
286 if (memcmp(prod_id, expected_prod_id, sizeof(prod_id)))
289 info("Detected a s5k4aa sensor");
292 sensor_settings = kmalloc(
293 ARRAY_SIZE(s5k4aa_ctrls) * sizeof(s32), GFP_KERNEL);
294 if (!sensor_settings)
297 sd->gspca_dev.cam.cam_mode = s5k4aa_modes;
298 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes);
299 sd->desc->ctrls = s5k4aa_ctrls;
300 sd->desc->nctrls = ARRAY_SIZE(s5k4aa_ctrls);
302 for (i = 0; i < ARRAY_SIZE(s5k4aa_ctrls); i++)
303 sensor_settings[i] = s5k4aa_ctrls[i].qctrl.default_value;
304 sd->sensor_priv = sensor_settings;
309 int s5k4aa_start(struct sd *sd)
313 struct cam *cam = &sd->gspca_dev.cam;
314 s32 *sensor_settings = sd->sensor_priv;
316 switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) {
318 PDEBUG(D_V4L2, "Configuring camera for SXGA mode");
320 for (i = 0; i < ARRAY_SIZE(SXGA_s5k4aa); i++) {
321 switch (SXGA_s5k4aa[i][0]) {
323 err = m5602_write_bridge(sd,
329 data[0] = SXGA_s5k4aa[i][2];
330 err = m5602_write_sensor(sd,
336 data[0] = SXGA_s5k4aa[i][2];
337 data[1] = SXGA_s5k4aa[i][3];
338 err = m5602_write_sensor(sd,
344 err("Invalid stream command, exiting init");
348 err = s5k4aa_set_noise(&sd->gspca_dev, 0);
354 PDEBUG(D_V4L2, "Configuring camera for VGA mode");
356 for (i = 0; i < ARRAY_SIZE(VGA_s5k4aa); i++) {
357 switch (VGA_s5k4aa[i][0]) {
359 err = m5602_write_bridge(sd,
365 data[0] = VGA_s5k4aa[i][2];
366 err = m5602_write_sensor(sd,
372 data[0] = VGA_s5k4aa[i][2];
373 data[1] = VGA_s5k4aa[i][3];
374 err = m5602_write_sensor(sd,
380 err("Invalid stream command, exiting init");
384 err = s5k4aa_set_noise(&sd->gspca_dev, 1);
392 err = s5k4aa_set_exposure(&sd->gspca_dev,
393 sensor_settings[EXPOSURE_IDX]);
397 err = s5k4aa_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
401 err = s5k4aa_set_brightness(&sd->gspca_dev,
402 sensor_settings[BRIGHTNESS_IDX]);
406 err = s5k4aa_set_noise(&sd->gspca_dev, sensor_settings[NOISE_SUPP_IDX]);
410 err = s5k4aa_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
414 return s5k4aa_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
417 int s5k4aa_init(struct sd *sd)
421 for (i = 0; i < ARRAY_SIZE(init_s5k4aa) && !err; i++) {
422 u8 data[2] = {0x00, 0x00};
424 switch (init_s5k4aa[i][0]) {
426 err = m5602_write_bridge(sd,
432 data[0] = init_s5k4aa[i][2];
433 err = m5602_write_sensor(sd,
434 init_s5k4aa[i][1], data, 1);
438 data[0] = init_s5k4aa[i][2];
439 data[1] = init_s5k4aa[i][3];
440 err = m5602_write_sensor(sd,
441 init_s5k4aa[i][1], data, 2);
444 info("Invalid stream command, exiting init");
450 s5k4aa_dump_registers(sd);
455 static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
457 struct sd *sd = (struct sd *) gspca_dev;
458 s32 *sensor_settings = sd->sensor_priv;
460 *val = sensor_settings[EXPOSURE_IDX];
461 PDEBUG(D_V4L2, "Read exposure %d", *val);
466 static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
468 struct sd *sd = (struct sd *) gspca_dev;
469 s32 *sensor_settings = sd->sensor_priv;
470 u8 data = S5K4AA_PAGE_MAP_2;
473 sensor_settings[EXPOSURE_IDX] = val;
474 PDEBUG(D_V4L2, "Set exposure to %d", val);
475 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
478 data = (val >> 8) & 0xff;
479 err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
483 err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
488 static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
490 struct sd *sd = (struct sd *) gspca_dev;
491 s32 *sensor_settings = sd->sensor_priv;
493 *val = sensor_settings[VFLIP_IDX];
494 PDEBUG(D_V4L2, "Read vertical flip %d", *val);
499 static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
501 struct sd *sd = (struct sd *) gspca_dev;
502 s32 *sensor_settings = sd->sensor_priv;
503 u8 data = S5K4AA_PAGE_MAP_2;
506 sensor_settings[VFLIP_IDX] = val;
508 PDEBUG(D_V4L2, "Set vertical flip to %d", val);
509 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
513 err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
517 if (dmi_check_system(s5k4aa_vflip_dmi_table))
520 data = ((data & ~S5K4AA_RM_V_FLIP) | ((val & 0x01) << 7));
521 err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
525 err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
532 err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
536 static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
538 struct sd *sd = (struct sd *) gspca_dev;
539 s32 *sensor_settings = sd->sensor_priv;
541 *val = sensor_settings[HFLIP_IDX];
542 PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
547 static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
549 struct sd *sd = (struct sd *) gspca_dev;
550 s32 *sensor_settings = sd->sensor_priv;
551 u8 data = S5K4AA_PAGE_MAP_2;
554 sensor_settings[HFLIP_IDX] = val;
556 PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
557 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
561 err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
565 if (dmi_check_system(s5k4aa_vflip_dmi_table))
568 data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6));
569 err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
573 err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
580 err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
584 static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
586 struct sd *sd = (struct sd *) gspca_dev;
587 s32 *sensor_settings = sd->sensor_priv;
589 *val = sensor_settings[GAIN_IDX];
590 PDEBUG(D_V4L2, "Read gain %d", *val);
594 static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
596 struct sd *sd = (struct sd *) gspca_dev;
597 s32 *sensor_settings = sd->sensor_priv;
598 u8 data = S5K4AA_PAGE_MAP_2;
601 sensor_settings[GAIN_IDX] = val;
603 PDEBUG(D_V4L2, "Set gain to %d", val);
604 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
609 err = m5602_write_sensor(sd, S5K4AA_GAIN, &data, 1);
614 static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
616 struct sd *sd = (struct sd *) gspca_dev;
617 s32 *sensor_settings = sd->sensor_priv;
619 *val = sensor_settings[BRIGHTNESS_IDX];
620 PDEBUG(D_V4L2, "Read brightness %d", *val);
624 static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
626 struct sd *sd = (struct sd *) gspca_dev;
627 s32 *sensor_settings = sd->sensor_priv;
628 u8 data = S5K4AA_PAGE_MAP_2;
631 sensor_settings[BRIGHTNESS_IDX] = val;
633 PDEBUG(D_V4L2, "Set brightness to %d", val);
634 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
639 return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1);
642 static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val)
644 struct sd *sd = (struct sd *) gspca_dev;
645 s32 *sensor_settings = sd->sensor_priv;
647 *val = sensor_settings[NOISE_SUPP_IDX];
648 PDEBUG(D_V4L2, "Read noise %d", *val);
652 static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val)
654 struct sd *sd = (struct sd *) gspca_dev;
655 s32 *sensor_settings = sd->sensor_priv;
656 u8 data = S5K4AA_PAGE_MAP_2;
659 sensor_settings[NOISE_SUPP_IDX] = val;
661 PDEBUG(D_V4L2, "Set noise to %d", val);
662 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
667 return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1);
670 void s5k4aa_disconnect(struct sd *sd)
673 kfree(sd->sensor_priv);
676 static void s5k4aa_dump_registers(struct sd *sd)
680 m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
681 for (page = 0; page < 16; page++) {
682 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
683 info("Dumping the s5k4aa register state for page 0x%x", page);
684 for (address = 0; address <= 0xff; address++) {
686 m5602_read_sensor(sd, address, &value, 1);
687 info("register 0x%x contains 0x%x",
691 info("s5k4aa register state dump complete");
693 for (page = 0; page < 16; page++) {
694 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
695 info("Probing for which registers that are "
696 "read/write for page 0x%x", page);
697 for (address = 0; address <= 0xff; address++) {
698 u8 old_value, ctrl_value, test_value = 0xff;
700 m5602_read_sensor(sd, address, &old_value, 1);
701 m5602_write_sensor(sd, address, &test_value, 1);
702 m5602_read_sensor(sd, address, &ctrl_value, 1);
704 if (ctrl_value == test_value)
705 info("register 0x%x is writeable", address);
707 info("register 0x%x is read only", address);
709 /* Restore original value */
710 m5602_write_sensor(sd, address, &old_value, 1);
713 info("Read/write register probing complete");
714 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);