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 2428",
53 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
54 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2428")
57 .ident = "Fujitsu-Siemens Amilo Xi 2528",
59 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
60 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2528")
63 .ident = "Fujitsu-Siemens Amilo Xi 2550",
65 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
66 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550")
69 .ident = "Fujitsu-Siemens Amilo Pa 2548",
71 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
72 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 2548")
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")
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")
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")
96 .ident = "MSI GX700/GX705/EX700",
98 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
99 DMI_MATCH(DMI_PRODUCT_NAME, "GX700/GX705/EX700")
104 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
105 DMI_MATCH(DMI_PRODUCT_NAME, "MS-1717X")
108 .ident = "Lenovo Y300",
110 DMI_MATCH(DMI_SYS_VENDOR, "L3000 Y300"),
111 DMI_MATCH(DMI_PRODUCT_NAME, "Y300")
117 static struct v4l2_pix_format s5k4aa_modes[] = {
126 .colorspace = V4L2_COLORSPACE_SRGB,
136 .bytesperline = 1280,
137 .colorspace = V4L2_COLORSPACE_SRGB,
142 static const struct ctrl s5k4aa_ctrls[] = {
146 .id = V4L2_CID_VFLIP,
147 .type = V4L2_CTRL_TYPE_BOOLEAN,
148 .name = "vertical flip",
154 .set = s5k4aa_set_vflip,
155 .get = s5k4aa_get_vflip
160 .id = V4L2_CID_HFLIP,
161 .type = V4L2_CTRL_TYPE_BOOLEAN,
162 .name = "horizontal flip",
168 .set = s5k4aa_set_hflip,
169 .get = s5k4aa_get_hflip
175 .type = V4L2_CTRL_TYPE_INTEGER,
180 .default_value = S5K4AA_DEFAULT_GAIN,
181 .flags = V4L2_CTRL_FLAG_SLIDER
183 .set = s5k4aa_set_gain,
184 .get = s5k4aa_get_gain
186 #define EXPOSURE_IDX 3
189 .id = V4L2_CID_EXPOSURE,
190 .type = V4L2_CTRL_TYPE_INTEGER,
195 .default_value = 0x100,
196 .flags = V4L2_CTRL_FLAG_SLIDER
198 .set = s5k4aa_set_exposure,
199 .get = s5k4aa_get_exposure
201 #define NOISE_SUPP_IDX 4
204 .id = V4L2_CID_PRIVATE_BASE,
205 .type = V4L2_CTRL_TYPE_BOOLEAN,
206 .name = "Noise suppression (smoothing)",
212 .set = s5k4aa_set_noise,
213 .get = s5k4aa_get_noise
215 #define BRIGHTNESS_IDX 5
218 .id = V4L2_CID_BRIGHTNESS,
219 .type = V4L2_CTRL_TYPE_INTEGER,
220 .name = "Brightness",
224 .default_value = S5K4AA_DEFAULT_BRIGHTNESS,
226 .set = s5k4aa_set_brightness,
227 .get = s5k4aa_get_brightness
232 static void s5k4aa_dump_registers(struct sd *sd);
234 int s5k4aa_probe(struct sd *sd)
236 u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
237 const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75};
239 s32 *sensor_settings;
242 if (force_sensor == S5K4AA_SENSOR) {
243 info("Forcing a %s sensor", s5k4aa.name);
246 /* If we want to force another sensor, don't try to probe this
251 PDEBUG(D_PROBE, "Probing for a s5k4aa sensor");
253 /* Preinit the sensor */
254 for (i = 0; i < ARRAY_SIZE(preinit_s5k4aa) && !err; i++) {
255 u8 data[2] = {0x00, 0x00};
257 switch (preinit_s5k4aa[i][0]) {
259 err = m5602_write_bridge(sd,
260 preinit_s5k4aa[i][1],
261 preinit_s5k4aa[i][2]);
265 data[0] = preinit_s5k4aa[i][2];
266 err = m5602_write_sensor(sd,
267 preinit_s5k4aa[i][1],
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],
279 info("Invalid stream command, exiting init");
284 /* Test some registers, but we don't know their exact meaning yet */
285 if (m5602_read_sensor(sd, 0x00, prod_id, 2))
287 if (m5602_read_sensor(sd, 0x02, prod_id+2, 2))
289 if (m5602_read_sensor(sd, 0x04, prod_id+4, 2))
292 if (memcmp(prod_id, expected_prod_id, sizeof(prod_id)))
295 info("Detected a s5k4aa sensor");
298 sensor_settings = kmalloc(
299 ARRAY_SIZE(s5k4aa_ctrls) * sizeof(s32), GFP_KERNEL);
300 if (!sensor_settings)
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);
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;
315 int s5k4aa_start(struct sd *sd)
319 struct cam *cam = &sd->gspca_dev.cam;
320 s32 *sensor_settings = sd->sensor_priv;
322 switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) {
324 PDEBUG(D_V4L2, "Configuring camera for SXGA mode");
326 for (i = 0; i < ARRAY_SIZE(SXGA_s5k4aa); i++) {
327 switch (SXGA_s5k4aa[i][0]) {
329 err = m5602_write_bridge(sd,
335 data[0] = SXGA_s5k4aa[i][2];
336 err = m5602_write_sensor(sd,
342 data[0] = SXGA_s5k4aa[i][2];
343 data[1] = SXGA_s5k4aa[i][3];
344 err = m5602_write_sensor(sd,
350 err("Invalid stream command, exiting init");
354 err = s5k4aa_set_noise(&sd->gspca_dev, 0);
360 PDEBUG(D_V4L2, "Configuring camera for VGA mode");
362 for (i = 0; i < ARRAY_SIZE(VGA_s5k4aa); i++) {
363 switch (VGA_s5k4aa[i][0]) {
365 err = m5602_write_bridge(sd,
371 data[0] = VGA_s5k4aa[i][2];
372 err = m5602_write_sensor(sd,
378 data[0] = VGA_s5k4aa[i][2];
379 data[1] = VGA_s5k4aa[i][3];
380 err = m5602_write_sensor(sd,
386 err("Invalid stream command, exiting init");
390 err = s5k4aa_set_noise(&sd->gspca_dev, 1);
398 err = s5k4aa_set_exposure(&sd->gspca_dev,
399 sensor_settings[EXPOSURE_IDX]);
403 err = s5k4aa_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
407 err = s5k4aa_set_brightness(&sd->gspca_dev,
408 sensor_settings[BRIGHTNESS_IDX]);
412 err = s5k4aa_set_noise(&sd->gspca_dev, sensor_settings[NOISE_SUPP_IDX]);
416 err = s5k4aa_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
420 return s5k4aa_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
423 int s5k4aa_init(struct sd *sd)
427 for (i = 0; i < ARRAY_SIZE(init_s5k4aa) && !err; i++) {
428 u8 data[2] = {0x00, 0x00};
430 switch (init_s5k4aa[i][0]) {
432 err = m5602_write_bridge(sd,
438 data[0] = init_s5k4aa[i][2];
439 err = m5602_write_sensor(sd,
440 init_s5k4aa[i][1], data, 1);
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);
450 info("Invalid stream command, exiting init");
456 s5k4aa_dump_registers(sd);
461 static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
463 struct sd *sd = (struct sd *) gspca_dev;
464 s32 *sensor_settings = sd->sensor_priv;
466 *val = sensor_settings[EXPOSURE_IDX];
467 PDEBUG(D_V4L2, "Read exposure %d", *val);
472 static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
474 struct sd *sd = (struct sd *) gspca_dev;
475 s32 *sensor_settings = sd->sensor_priv;
476 u8 data = S5K4AA_PAGE_MAP_2;
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);
484 data = (val >> 8) & 0xff;
485 err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
489 err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
494 static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
496 struct sd *sd = (struct sd *) gspca_dev;
497 s32 *sensor_settings = sd->sensor_priv;
499 *val = sensor_settings[VFLIP_IDX];
500 PDEBUG(D_V4L2, "Read vertical flip %d", *val);
505 static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
507 struct sd *sd = (struct sd *) gspca_dev;
508 s32 *sensor_settings = sd->sensor_priv;
509 u8 data = S5K4AA_PAGE_MAP_2;
512 sensor_settings[VFLIP_IDX] = val;
514 PDEBUG(D_V4L2, "Set vertical flip to %d", val);
515 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
519 err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
523 if (dmi_check_system(s5k4aa_vflip_dmi_table))
526 data = ((data & ~S5K4AA_RM_V_FLIP) | ((val & 0x01) << 7));
527 err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
531 err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
538 err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
542 static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
544 struct sd *sd = (struct sd *) gspca_dev;
545 s32 *sensor_settings = sd->sensor_priv;
547 *val = sensor_settings[HFLIP_IDX];
548 PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
553 static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
555 struct sd *sd = (struct sd *) gspca_dev;
556 s32 *sensor_settings = sd->sensor_priv;
557 u8 data = S5K4AA_PAGE_MAP_2;
560 sensor_settings[HFLIP_IDX] = val;
562 PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
563 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
567 err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
571 if (dmi_check_system(s5k4aa_vflip_dmi_table))
574 data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6));
575 err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
579 err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
586 err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
590 static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
592 struct sd *sd = (struct sd *) gspca_dev;
593 s32 *sensor_settings = sd->sensor_priv;
595 *val = sensor_settings[GAIN_IDX];
596 PDEBUG(D_V4L2, "Read gain %d", *val);
600 static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
602 struct sd *sd = (struct sd *) gspca_dev;
603 s32 *sensor_settings = sd->sensor_priv;
604 u8 data = S5K4AA_PAGE_MAP_2;
607 sensor_settings[GAIN_IDX] = val;
609 PDEBUG(D_V4L2, "Set gain to %d", val);
610 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
615 err = m5602_write_sensor(sd, S5K4AA_GAIN, &data, 1);
620 static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
622 struct sd *sd = (struct sd *) gspca_dev;
623 s32 *sensor_settings = sd->sensor_priv;
625 *val = sensor_settings[BRIGHTNESS_IDX];
626 PDEBUG(D_V4L2, "Read brightness %d", *val);
630 static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
632 struct sd *sd = (struct sd *) gspca_dev;
633 s32 *sensor_settings = sd->sensor_priv;
634 u8 data = S5K4AA_PAGE_MAP_2;
637 sensor_settings[BRIGHTNESS_IDX] = val;
639 PDEBUG(D_V4L2, "Set brightness to %d", val);
640 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
645 return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1);
648 static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val)
650 struct sd *sd = (struct sd *) gspca_dev;
651 s32 *sensor_settings = sd->sensor_priv;
653 *val = sensor_settings[NOISE_SUPP_IDX];
654 PDEBUG(D_V4L2, "Read noise %d", *val);
658 static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val)
660 struct sd *sd = (struct sd *) gspca_dev;
661 s32 *sensor_settings = sd->sensor_priv;
662 u8 data = S5K4AA_PAGE_MAP_2;
665 sensor_settings[NOISE_SUPP_IDX] = val;
667 PDEBUG(D_V4L2, "Set noise to %d", val);
668 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
673 return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1);
676 void s5k4aa_disconnect(struct sd *sd)
679 kfree(sd->sensor_priv);
682 static void s5k4aa_dump_registers(struct sd *sd)
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++) {
692 m5602_read_sensor(sd, address, &value, 1);
693 info("register 0x%x contains 0x%x",
697 info("s5k4aa register state dump complete");
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;
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);
710 if (ctrl_value == test_value)
711 info("register 0x%x is writeable", address);
713 info("register 0x%x is read only", address);
715 /* Restore original value */
716 m5602_write_sensor(sd, address, &old_value, 1);
719 info("Read/write register probing complete");
720 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);