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 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
21 #include "m5602_s5k4aa.h"
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);
38 struct dmi_system_id s5k4aa_vflip_dmi_table[] = {
42 DMI_MATCH(DMI_SYS_VENDOR, "BRUNENIT"),
43 DMI_MATCH(DMI_PRODUCT_NAME, "BRUNENIT"),
44 DMI_MATCH(DMI_BOARD_VERSION, "00030D0000000001")
47 .ident = "Fujitsu-Siemens Amilo Xa 2528",
49 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
50 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xa 2528")
53 .ident = "Fujitsu-Siemens Amilo Xi 2428",
55 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
56 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2428")
59 .ident = "Fujitsu-Siemens Amilo Xi 2528",
61 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
62 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2528")
65 .ident = "Fujitsu-Siemens Amilo Xi 2550",
67 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
68 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550")
71 .ident = "Fujitsu-Siemens Amilo Pa 2548",
73 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
74 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 2548")
77 .ident = "Fujitsu-Siemens Amilo Pi 2530",
79 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
80 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 2530")
85 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
86 DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
87 DMI_MATCH(DMI_BIOS_DATE, "12/02/2008")
92 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
93 DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
94 DMI_MATCH(DMI_BIOS_DATE, "07/26/2007")
99 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
100 DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
101 DMI_MATCH(DMI_BIOS_DATE, "07/19/2007")
104 .ident = "MSI GX700/GX705/EX700",
106 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
107 DMI_MATCH(DMI_PRODUCT_NAME, "GX700/GX705/EX700")
112 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
113 DMI_MATCH(DMI_PRODUCT_NAME, "MS-1717X")
116 .ident = "Lenovo Y300",
118 DMI_MATCH(DMI_SYS_VENDOR, "L3000 Y300"),
119 DMI_MATCH(DMI_PRODUCT_NAME, "Y300")
125 static struct v4l2_pix_format s5k4aa_modes[] = {
134 .colorspace = V4L2_COLORSPACE_SRGB,
144 .bytesperline = 1280,
145 .colorspace = V4L2_COLORSPACE_SRGB,
150 static const struct ctrl s5k4aa_ctrls[] = {
154 .id = V4L2_CID_VFLIP,
155 .type = V4L2_CTRL_TYPE_BOOLEAN,
156 .name = "vertical flip",
162 .set = s5k4aa_set_vflip,
163 .get = s5k4aa_get_vflip
168 .id = V4L2_CID_HFLIP,
169 .type = V4L2_CTRL_TYPE_BOOLEAN,
170 .name = "horizontal flip",
176 .set = s5k4aa_set_hflip,
177 .get = s5k4aa_get_hflip
183 .type = V4L2_CTRL_TYPE_INTEGER,
188 .default_value = S5K4AA_DEFAULT_GAIN,
189 .flags = V4L2_CTRL_FLAG_SLIDER
191 .set = s5k4aa_set_gain,
192 .get = s5k4aa_get_gain
194 #define EXPOSURE_IDX 3
197 .id = V4L2_CID_EXPOSURE,
198 .type = V4L2_CTRL_TYPE_INTEGER,
203 .default_value = 0x100,
204 .flags = V4L2_CTRL_FLAG_SLIDER
206 .set = s5k4aa_set_exposure,
207 .get = s5k4aa_get_exposure
209 #define NOISE_SUPP_IDX 4
212 .id = V4L2_CID_PRIVATE_BASE,
213 .type = V4L2_CTRL_TYPE_BOOLEAN,
214 .name = "Noise suppression (smoothing)",
220 .set = s5k4aa_set_noise,
221 .get = s5k4aa_get_noise
223 #define BRIGHTNESS_IDX 5
226 .id = V4L2_CID_BRIGHTNESS,
227 .type = V4L2_CTRL_TYPE_INTEGER,
228 .name = "Brightness",
232 .default_value = S5K4AA_DEFAULT_BRIGHTNESS,
234 .set = s5k4aa_set_brightness,
235 .get = s5k4aa_get_brightness
240 static void s5k4aa_dump_registers(struct sd *sd);
242 int s5k4aa_probe(struct sd *sd)
244 u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
245 const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75};
247 s32 *sensor_settings;
250 if (force_sensor == S5K4AA_SENSOR) {
251 pr_info("Forcing a %s sensor\n", s5k4aa.name);
254 /* If we want to force another sensor, don't try to probe this
259 PDEBUG(D_PROBE, "Probing for a s5k4aa sensor");
261 /* Preinit the sensor */
262 for (i = 0; i < ARRAY_SIZE(preinit_s5k4aa) && !err; i++) {
263 u8 data[2] = {0x00, 0x00};
265 switch (preinit_s5k4aa[i][0]) {
267 err = m5602_write_bridge(sd,
268 preinit_s5k4aa[i][1],
269 preinit_s5k4aa[i][2]);
273 data[0] = preinit_s5k4aa[i][2];
274 err = m5602_write_sensor(sd,
275 preinit_s5k4aa[i][1],
280 data[0] = preinit_s5k4aa[i][2];
281 data[1] = preinit_s5k4aa[i][3];
282 err = m5602_write_sensor(sd,
283 preinit_s5k4aa[i][1],
287 pr_info("Invalid stream command, exiting init\n");
292 /* Test some registers, but we don't know their exact meaning yet */
293 if (m5602_read_sensor(sd, 0x00, prod_id, 2))
295 if (m5602_read_sensor(sd, 0x02, prod_id+2, 2))
297 if (m5602_read_sensor(sd, 0x04, prod_id+4, 2))
300 if (memcmp(prod_id, expected_prod_id, sizeof(prod_id)))
303 pr_info("Detected a s5k4aa sensor\n");
306 sensor_settings = kmalloc(
307 ARRAY_SIZE(s5k4aa_ctrls) * sizeof(s32), GFP_KERNEL);
308 if (!sensor_settings)
311 sd->gspca_dev.cam.cam_mode = s5k4aa_modes;
312 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes);
313 sd->desc->ctrls = s5k4aa_ctrls;
314 sd->desc->nctrls = ARRAY_SIZE(s5k4aa_ctrls);
316 for (i = 0; i < ARRAY_SIZE(s5k4aa_ctrls); i++)
317 sensor_settings[i] = s5k4aa_ctrls[i].qctrl.default_value;
318 sd->sensor_priv = sensor_settings;
323 int s5k4aa_start(struct sd *sd)
327 struct cam *cam = &sd->gspca_dev.cam;
328 s32 *sensor_settings = sd->sensor_priv;
330 switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) {
332 PDEBUG(D_V4L2, "Configuring camera for SXGA mode");
334 for (i = 0; i < ARRAY_SIZE(SXGA_s5k4aa); i++) {
335 switch (SXGA_s5k4aa[i][0]) {
337 err = m5602_write_bridge(sd,
343 data[0] = SXGA_s5k4aa[i][2];
344 err = m5602_write_sensor(sd,
350 data[0] = SXGA_s5k4aa[i][2];
351 data[1] = SXGA_s5k4aa[i][3];
352 err = m5602_write_sensor(sd,
358 pr_err("Invalid stream command, exiting init\n");
362 err = s5k4aa_set_noise(&sd->gspca_dev, 0);
368 PDEBUG(D_V4L2, "Configuring camera for VGA mode");
370 for (i = 0; i < ARRAY_SIZE(VGA_s5k4aa); i++) {
371 switch (VGA_s5k4aa[i][0]) {
373 err = m5602_write_bridge(sd,
379 data[0] = VGA_s5k4aa[i][2];
380 err = m5602_write_sensor(sd,
386 data[0] = VGA_s5k4aa[i][2];
387 data[1] = VGA_s5k4aa[i][3];
388 err = m5602_write_sensor(sd,
394 pr_err("Invalid stream command, exiting init\n");
398 err = s5k4aa_set_noise(&sd->gspca_dev, 1);
406 err = s5k4aa_set_exposure(&sd->gspca_dev,
407 sensor_settings[EXPOSURE_IDX]);
411 err = s5k4aa_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
415 err = s5k4aa_set_brightness(&sd->gspca_dev,
416 sensor_settings[BRIGHTNESS_IDX]);
420 err = s5k4aa_set_noise(&sd->gspca_dev, sensor_settings[NOISE_SUPP_IDX]);
424 err = s5k4aa_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
428 return s5k4aa_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
431 int s5k4aa_init(struct sd *sd)
435 for (i = 0; i < ARRAY_SIZE(init_s5k4aa) && !err; i++) {
436 u8 data[2] = {0x00, 0x00};
438 switch (init_s5k4aa[i][0]) {
440 err = m5602_write_bridge(sd,
446 data[0] = init_s5k4aa[i][2];
447 err = m5602_write_sensor(sd,
448 init_s5k4aa[i][1], data, 1);
452 data[0] = init_s5k4aa[i][2];
453 data[1] = init_s5k4aa[i][3];
454 err = m5602_write_sensor(sd,
455 init_s5k4aa[i][1], data, 2);
458 pr_info("Invalid stream command, exiting init\n");
464 s5k4aa_dump_registers(sd);
469 static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
471 struct sd *sd = (struct sd *) gspca_dev;
472 s32 *sensor_settings = sd->sensor_priv;
474 *val = sensor_settings[EXPOSURE_IDX];
475 PDEBUG(D_V4L2, "Read exposure %d", *val);
480 static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
482 struct sd *sd = (struct sd *) gspca_dev;
483 s32 *sensor_settings = sd->sensor_priv;
484 u8 data = S5K4AA_PAGE_MAP_2;
487 sensor_settings[EXPOSURE_IDX] = val;
488 PDEBUG(D_V4L2, "Set exposure to %d", val);
489 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
492 data = (val >> 8) & 0xff;
493 err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
497 err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
502 static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
504 struct sd *sd = (struct sd *) gspca_dev;
505 s32 *sensor_settings = sd->sensor_priv;
507 *val = sensor_settings[VFLIP_IDX];
508 PDEBUG(D_V4L2, "Read vertical flip %d", *val);
513 static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
515 struct sd *sd = (struct sd *) gspca_dev;
516 s32 *sensor_settings = sd->sensor_priv;
517 u8 data = S5K4AA_PAGE_MAP_2;
520 sensor_settings[VFLIP_IDX] = val;
522 PDEBUG(D_V4L2, "Set vertical flip to %d", val);
523 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
527 err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
531 if (dmi_check_system(s5k4aa_vflip_dmi_table))
534 data = ((data & ~S5K4AA_RM_V_FLIP) | ((val & 0x01) << 7));
535 err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
539 err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
546 err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
550 static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
552 struct sd *sd = (struct sd *) gspca_dev;
553 s32 *sensor_settings = sd->sensor_priv;
555 *val = sensor_settings[HFLIP_IDX];
556 PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
561 static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
563 struct sd *sd = (struct sd *) gspca_dev;
564 s32 *sensor_settings = sd->sensor_priv;
565 u8 data = S5K4AA_PAGE_MAP_2;
568 sensor_settings[HFLIP_IDX] = val;
570 PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
571 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
575 err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
579 if (dmi_check_system(s5k4aa_vflip_dmi_table))
582 data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6));
583 err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
587 err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
594 err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
598 static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
600 struct sd *sd = (struct sd *) gspca_dev;
601 s32 *sensor_settings = sd->sensor_priv;
603 *val = sensor_settings[GAIN_IDX];
604 PDEBUG(D_V4L2, "Read gain %d", *val);
608 static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
610 struct sd *sd = (struct sd *) gspca_dev;
611 s32 *sensor_settings = sd->sensor_priv;
612 u8 data = S5K4AA_PAGE_MAP_2;
615 sensor_settings[GAIN_IDX] = val;
617 PDEBUG(D_V4L2, "Set gain to %d", val);
618 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
623 err = m5602_write_sensor(sd, S5K4AA_GAIN, &data, 1);
628 static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
630 struct sd *sd = (struct sd *) gspca_dev;
631 s32 *sensor_settings = sd->sensor_priv;
633 *val = sensor_settings[BRIGHTNESS_IDX];
634 PDEBUG(D_V4L2, "Read brightness %d", *val);
638 static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
640 struct sd *sd = (struct sd *) gspca_dev;
641 s32 *sensor_settings = sd->sensor_priv;
642 u8 data = S5K4AA_PAGE_MAP_2;
645 sensor_settings[BRIGHTNESS_IDX] = val;
647 PDEBUG(D_V4L2, "Set brightness to %d", val);
648 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
653 return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1);
656 static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val)
658 struct sd *sd = (struct sd *) gspca_dev;
659 s32 *sensor_settings = sd->sensor_priv;
661 *val = sensor_settings[NOISE_SUPP_IDX];
662 PDEBUG(D_V4L2, "Read noise %d", *val);
666 static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val)
668 struct sd *sd = (struct sd *) gspca_dev;
669 s32 *sensor_settings = sd->sensor_priv;
670 u8 data = S5K4AA_PAGE_MAP_2;
673 sensor_settings[NOISE_SUPP_IDX] = val;
675 PDEBUG(D_V4L2, "Set noise to %d", val);
676 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
681 return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1);
684 void s5k4aa_disconnect(struct sd *sd)
687 kfree(sd->sensor_priv);
690 static void s5k4aa_dump_registers(struct sd *sd)
694 m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
695 for (page = 0; page < 16; page++) {
696 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
697 pr_info("Dumping the s5k4aa register state for page 0x%x\n",
699 for (address = 0; address <= 0xff; address++) {
701 m5602_read_sensor(sd, address, &value, 1);
702 pr_info("register 0x%x contains 0x%x\n",
706 pr_info("s5k4aa register state dump complete\n");
708 for (page = 0; page < 16; page++) {
709 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
710 pr_info("Probing for which registers that are read/write for page 0x%x\n",
712 for (address = 0; address <= 0xff; address++) {
713 u8 old_value, ctrl_value, test_value = 0xff;
715 m5602_read_sensor(sd, address, &old_value, 1);
716 m5602_write_sensor(sd, address, &test_value, 1);
717 m5602_read_sensor(sd, address, &ctrl_value, 1);
719 if (ctrl_value == test_value)
720 pr_info("register 0x%x is writeable\n",
723 pr_info("register 0x%x is read only\n",
726 /* Restore original value */
727 m5602_write_sensor(sd, address, &old_value, 1);
730 pr_info("Read/write register probing complete\n");
731 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);