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_s_ctrl(struct v4l2_ctrl
*ctrl
);
24 static void s5k4aa_dump_registers(struct sd
*sd
);
26 static const struct v4l2_ctrl_ops s5k4aa_ctrl_ops
= {
27 .s_ctrl
= s5k4aa_s_ctrl
,
32 struct dmi_system_id s5k4aa_vflip_dmi_table
[] = {
36 DMI_MATCH(DMI_SYS_VENDOR
, "BRUNENIT"),
37 DMI_MATCH(DMI_PRODUCT_NAME
, "BRUNENIT"),
38 DMI_MATCH(DMI_BOARD_VERSION
, "00030D0000000001")
41 .ident
= "Fujitsu-Siemens Amilo Xa 2528",
43 DMI_MATCH(DMI_SYS_VENDOR
, "FUJITSU SIEMENS"),
44 DMI_MATCH(DMI_PRODUCT_NAME
, "AMILO Xa 2528")
47 .ident
= "Fujitsu-Siemens Amilo Xi 2428",
49 DMI_MATCH(DMI_SYS_VENDOR
, "FUJITSU SIEMENS"),
50 DMI_MATCH(DMI_PRODUCT_NAME
, "AMILO Xi 2428")
53 .ident
= "Fujitsu-Siemens Amilo Xi 2528",
55 DMI_MATCH(DMI_SYS_VENDOR
, "FUJITSU SIEMENS"),
56 DMI_MATCH(DMI_PRODUCT_NAME
, "AMILO Xi 2528")
59 .ident
= "Fujitsu-Siemens Amilo Xi 2550",
61 DMI_MATCH(DMI_SYS_VENDOR
, "FUJITSU SIEMENS"),
62 DMI_MATCH(DMI_PRODUCT_NAME
, "AMILO Xi 2550")
65 .ident
= "Fujitsu-Siemens Amilo Pa 2548",
67 DMI_MATCH(DMI_SYS_VENDOR
, "FUJITSU SIEMENS"),
68 DMI_MATCH(DMI_PRODUCT_NAME
, "AMILO Pa 2548")
71 .ident
= "Fujitsu-Siemens Amilo Pi 2530",
73 DMI_MATCH(DMI_SYS_VENDOR
, "FUJITSU SIEMENS"),
74 DMI_MATCH(DMI_PRODUCT_NAME
, "AMILO Pi 2530")
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")
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")
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")
98 .ident
= "MSI GX700/GX705/EX700",
100 DMI_MATCH(DMI_SYS_VENDOR
, "Micro-Star International"),
101 DMI_MATCH(DMI_PRODUCT_NAME
, "GX700/GX705/EX700")
106 DMI_MATCH(DMI_SYS_VENDOR
, "Micro-Star International"),
107 DMI_MATCH(DMI_PRODUCT_NAME
, "MS-1717X")
110 .ident
= "Lenovo Y300",
112 DMI_MATCH(DMI_SYS_VENDOR
, "L3000 Y300"),
113 DMI_MATCH(DMI_PRODUCT_NAME
, "Y300")
119 static struct v4l2_pix_format s5k4aa_modes
[] = {
128 .colorspace
= V4L2_COLORSPACE_SRGB
,
138 .bytesperline
= 1280,
139 .colorspace
= V4L2_COLORSPACE_SRGB
,
144 int s5k4aa_probe(struct sd
*sd
)
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
;
152 if (force_sensor
== S5K4AA_SENSOR
) {
153 pr_info("Forcing a %s sensor\n", s5k4aa
.name
);
156 /* If we want to force another sensor, don't try to probe this
161 PDEBUG(D_PROBE
, "Probing for a s5k4aa sensor");
163 /* Preinit the sensor */
164 for (i
= 0; i
< ARRAY_SIZE(preinit_s5k4aa
) && !err
; i
++) {
165 u8 data
[2] = {0x00, 0x00};
167 switch (preinit_s5k4aa
[i
][0]) {
169 err
= m5602_write_bridge(sd
,
170 preinit_s5k4aa
[i
][1],
171 preinit_s5k4aa
[i
][2]);
175 data
[0] = preinit_s5k4aa
[i
][2];
176 err
= m5602_write_sensor(sd
,
177 preinit_s5k4aa
[i
][1],
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],
189 pr_info("Invalid stream command, exiting init\n");
194 /* Test some registers, but we don't know their exact meaning yet */
195 if (m5602_read_sensor(sd
, 0x00, prod_id
, 2))
197 if (m5602_read_sensor(sd
, 0x02, prod_id
+2, 2))
199 if (m5602_read_sensor(sd
, 0x04, prod_id
+4, 2))
202 if (memcmp(prod_id
, expected_prod_id
, sizeof(prod_id
)))
205 pr_info("Detected a s5k4aa sensor\n");
208 sd
->gspca_dev
.cam
.cam_mode
= s5k4aa_modes
;
209 sd
->gspca_dev
.cam
.nmodes
= ARRAY_SIZE(s5k4aa_modes
);
214 int s5k4aa_start(struct sd
*sd
)
218 struct cam
*cam
= &sd
->gspca_dev
.cam
;
219 struct gspca_dev
*gspca_dev
= (struct gspca_dev
*)sd
;
221 switch (cam
->cam_mode
[sd
->gspca_dev
.curr_mode
].width
) {
223 PDEBUG(D_CONF
, "Configuring camera for SXGA mode");
225 for (i
= 0; i
< ARRAY_SIZE(SXGA_s5k4aa
); i
++) {
226 switch (SXGA_s5k4aa
[i
][0]) {
228 err
= m5602_write_bridge(sd
,
234 data
[0] = SXGA_s5k4aa
[i
][2];
235 err
= m5602_write_sensor(sd
,
241 data
[0] = SXGA_s5k4aa
[i
][2];
242 data
[1] = SXGA_s5k4aa
[i
][3];
243 err
= m5602_write_sensor(sd
,
249 pr_err("Invalid stream command, exiting init\n");
256 PDEBUG(D_CONF
, "Configuring camera for VGA mode");
258 for (i
= 0; i
< ARRAY_SIZE(VGA_s5k4aa
); i
++) {
259 switch (VGA_s5k4aa
[i
][0]) {
261 err
= m5602_write_bridge(sd
,
267 data
[0] = VGA_s5k4aa
[i
][2];
268 err
= m5602_write_sensor(sd
,
274 data
[0] = VGA_s5k4aa
[i
][2];
275 data
[1] = VGA_s5k4aa
[i
][3];
276 err
= m5602_write_sensor(sd
,
282 pr_err("Invalid stream command, exiting init\n");
294 int s5k4aa_init(struct sd
*sd
)
298 for (i
= 0; i
< ARRAY_SIZE(init_s5k4aa
) && !err
; i
++) {
299 u8 data
[2] = {0x00, 0x00};
301 switch (init_s5k4aa
[i
][0]) {
303 err
= m5602_write_bridge(sd
,
309 data
[0] = init_s5k4aa
[i
][2];
310 err
= m5602_write_sensor(sd
,
311 init_s5k4aa
[i
][1], data
, 1);
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);
321 pr_info("Invalid stream command, exiting init\n");
327 s5k4aa_dump_registers(sd
);
332 int s5k4aa_init_controls(struct sd
*sd
)
334 struct v4l2_ctrl_handler
*hdl
= &sd
->gspca_dev
.ctrl_handler
;
336 sd
->gspca_dev
.vdev
.ctrl_handler
= hdl
;
337 v4l2_ctrl_handler_init(hdl
, 6);
339 v4l2_ctrl_new_std(hdl
, &s5k4aa_ctrl_ops
, V4L2_CID_BRIGHTNESS
,
340 0, 0x1f, 1, S5K4AA_DEFAULT_BRIGHTNESS
);
342 v4l2_ctrl_new_std(hdl
, &s5k4aa_ctrl_ops
, V4L2_CID_EXPOSURE
,
343 13, 0xfff, 1, 0x100);
345 v4l2_ctrl_new_std(hdl
, &s5k4aa_ctrl_ops
, V4L2_CID_GAIN
,
346 0, 127, 1, S5K4AA_DEFAULT_GAIN
);
348 v4l2_ctrl_new_std(hdl
, &s5k4aa_ctrl_ops
, V4L2_CID_SHARPNESS
,
351 sd
->hflip
= v4l2_ctrl_new_std(hdl
, &s5k4aa_ctrl_ops
, V4L2_CID_HFLIP
,
353 sd
->vflip
= v4l2_ctrl_new_std(hdl
, &s5k4aa_ctrl_ops
, V4L2_CID_VFLIP
,
357 pr_err("Could not initialize controls\n");
361 v4l2_ctrl_cluster(2, &sd
->hflip
);
366 static int s5k4aa_set_exposure(struct gspca_dev
*gspca_dev
, __s32 val
)
368 struct sd
*sd
= (struct sd
*) gspca_dev
;
369 u8 data
= S5K4AA_PAGE_MAP_2
;
372 PDEBUG(D_CONF
, "Set exposure to %d", val
);
373 err
= m5602_write_sensor(sd
, S5K4AA_PAGE_MAP
, &data
, 1);
376 data
= (val
>> 8) & 0xff;
377 err
= m5602_write_sensor(sd
, S5K4AA_EXPOSURE_HI
, &data
, 1);
381 err
= m5602_write_sensor(sd
, S5K4AA_EXPOSURE_LO
, &data
, 1);
386 static int s5k4aa_set_hvflip(struct gspca_dev
*gspca_dev
)
388 struct sd
*sd
= (struct sd
*) gspca_dev
;
389 u8 data
= S5K4AA_PAGE_MAP_2
;
391 int hflip
= sd
->hflip
->val
;
392 int vflip
= sd
->vflip
->val
;
394 PDEBUG(D_CONF
, "Set hvflip %d %d", hflip
, vflip
);
395 err
= m5602_write_sensor(sd
, S5K4AA_PAGE_MAP
, &data
, 1);
399 err
= m5602_read_sensor(sd
, S5K4AA_READ_MODE
, &data
, 1);
403 if (dmi_check_system(s5k4aa_vflip_dmi_table
)) {
408 data
= (data
& 0x7f) | (vflip
<< 7) | (hflip
<< 6);
409 err
= m5602_write_sensor(sd
, S5K4AA_READ_MODE
, &data
, 1);
413 err
= m5602_read_sensor(sd
, S5K4AA_COLSTART_LO
, &data
, 1);
420 err
= m5602_write_sensor(sd
, S5K4AA_COLSTART_LO
, &data
, 1);
424 err
= m5602_read_sensor(sd
, S5K4AA_ROWSTART_LO
, &data
, 1);
431 err
= m5602_write_sensor(sd
, S5K4AA_ROWSTART_LO
, &data
, 1);
438 static int s5k4aa_set_gain(struct gspca_dev
*gspca_dev
, __s32 val
)
440 struct sd
*sd
= (struct sd
*) gspca_dev
;
441 u8 data
= S5K4AA_PAGE_MAP_2
;
444 PDEBUG(D_CONF
, "Set gain to %d", val
);
445 err
= m5602_write_sensor(sd
, S5K4AA_PAGE_MAP
, &data
, 1);
450 err
= m5602_write_sensor(sd
, S5K4AA_GAIN
, &data
, 1);
455 static int s5k4aa_set_brightness(struct gspca_dev
*gspca_dev
, __s32 val
)
457 struct sd
*sd
= (struct sd
*) gspca_dev
;
458 u8 data
= S5K4AA_PAGE_MAP_2
;
461 PDEBUG(D_CONF
, "Set brightness to %d", val
);
462 err
= m5602_write_sensor(sd
, S5K4AA_PAGE_MAP
, &data
, 1);
467 return m5602_write_sensor(sd
, S5K4AA_BRIGHTNESS
, &data
, 1);
470 static int s5k4aa_set_noise(struct gspca_dev
*gspca_dev
, __s32 val
)
472 struct sd
*sd
= (struct sd
*) gspca_dev
;
473 u8 data
= S5K4AA_PAGE_MAP_2
;
476 PDEBUG(D_CONF
, "Set noise to %d", val
);
477 err
= m5602_write_sensor(sd
, S5K4AA_PAGE_MAP
, &data
, 1);
482 return m5602_write_sensor(sd
, S5K4AA_NOISE_SUPP
, &data
, 1);
485 static int s5k4aa_s_ctrl(struct v4l2_ctrl
*ctrl
)
487 struct gspca_dev
*gspca_dev
=
488 container_of(ctrl
->handler
, struct gspca_dev
, ctrl_handler
);
491 if (!gspca_dev
->streaming
)
495 case V4L2_CID_BRIGHTNESS
:
496 err
= s5k4aa_set_brightness(gspca_dev
, ctrl
->val
);
498 case V4L2_CID_EXPOSURE
:
499 err
= s5k4aa_set_exposure(gspca_dev
, ctrl
->val
);
502 err
= s5k4aa_set_gain(gspca_dev
, ctrl
->val
);
504 case V4L2_CID_SHARPNESS
:
505 err
= s5k4aa_set_noise(gspca_dev
, ctrl
->val
);
508 err
= s5k4aa_set_hvflip(gspca_dev
);
517 void s5k4aa_disconnect(struct sd
*sd
)
522 static void s5k4aa_dump_registers(struct sd
*sd
)
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",
531 for (address
= 0; address
<= 0xff; address
++) {
533 m5602_read_sensor(sd
, address
, &value
, 1);
534 pr_info("register 0x%x contains 0x%x\n",
538 pr_info("s5k4aa register state dump complete\n");
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",
544 for (address
= 0; address
<= 0xff; address
++) {
545 u8 old_value
, ctrl_value
, test_value
= 0xff;
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);
551 if (ctrl_value
== test_value
)
552 pr_info("register 0x%x is writeable\n",
555 pr_info("register 0x%x is read only\n",
558 /* Restore original value */
559 m5602_write_sensor(sd
, address
, &old_value
, 1);
562 pr_info("Read/write register probing complete\n");
563 m5602_write_sensor(sd
, S5K4AA_PAGE_MAP
, &old_page
, 1);