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);