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")
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 static const struct ctrl s5k4aa_ctrls
[] = {
148 .id
= V4L2_CID_VFLIP
,
149 .type
= V4L2_CTRL_TYPE_BOOLEAN
,
150 .name
= "vertical flip",
156 .set
= s5k4aa_set_vflip
,
157 .get
= s5k4aa_get_vflip
162 .id
= V4L2_CID_HFLIP
,
163 .type
= V4L2_CTRL_TYPE_BOOLEAN
,
164 .name
= "horizontal flip",
170 .set
= s5k4aa_set_hflip
,
171 .get
= s5k4aa_get_hflip
177 .type
= V4L2_CTRL_TYPE_INTEGER
,
182 .default_value
= S5K4AA_DEFAULT_GAIN
,
183 .flags
= V4L2_CTRL_FLAG_SLIDER
185 .set
= s5k4aa_set_gain
,
186 .get
= s5k4aa_get_gain
188 #define EXPOSURE_IDX 3
191 .id
= V4L2_CID_EXPOSURE
,
192 .type
= V4L2_CTRL_TYPE_INTEGER
,
197 .default_value
= 0x100,
198 .flags
= V4L2_CTRL_FLAG_SLIDER
200 .set
= s5k4aa_set_exposure
,
201 .get
= s5k4aa_get_exposure
203 #define NOISE_SUPP_IDX 4
206 .id
= V4L2_CID_PRIVATE_BASE
,
207 .type
= V4L2_CTRL_TYPE_BOOLEAN
,
208 .name
= "Noise suppression (smoothing)",
214 .set
= s5k4aa_set_noise
,
215 .get
= s5k4aa_get_noise
217 #define BRIGHTNESS_IDX 5
220 .id
= V4L2_CID_BRIGHTNESS
,
221 .type
= V4L2_CTRL_TYPE_INTEGER
,
222 .name
= "Brightness",
226 .default_value
= S5K4AA_DEFAULT_BRIGHTNESS
,
228 .set
= s5k4aa_set_brightness
,
229 .get
= s5k4aa_get_brightness
234 static void s5k4aa_dump_registers(struct sd
*sd
);
236 int s5k4aa_probe(struct sd
*sd
)
238 u8 prod_id
[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
239 const u8 expected_prod_id
[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75};
241 s32
*sensor_settings
;
244 if (force_sensor
== S5K4AA_SENSOR
) {
245 pr_info("Forcing a %s sensor\n", s5k4aa
.name
);
248 /* If we want to force another sensor, don't try to probe this
253 PDEBUG(D_PROBE
, "Probing for a s5k4aa sensor");
255 /* Preinit the sensor */
256 for (i
= 0; i
< ARRAY_SIZE(preinit_s5k4aa
) && !err
; i
++) {
257 u8 data
[2] = {0x00, 0x00};
259 switch (preinit_s5k4aa
[i
][0]) {
261 err
= m5602_write_bridge(sd
,
262 preinit_s5k4aa
[i
][1],
263 preinit_s5k4aa
[i
][2]);
267 data
[0] = preinit_s5k4aa
[i
][2];
268 err
= m5602_write_sensor(sd
,
269 preinit_s5k4aa
[i
][1],
274 data
[0] = preinit_s5k4aa
[i
][2];
275 data
[1] = preinit_s5k4aa
[i
][3];
276 err
= m5602_write_sensor(sd
,
277 preinit_s5k4aa
[i
][1],
281 pr_info("Invalid stream command, exiting init\n");
286 /* Test some registers, but we don't know their exact meaning yet */
287 if (m5602_read_sensor(sd
, 0x00, prod_id
, 2))
289 if (m5602_read_sensor(sd
, 0x02, prod_id
+2, 2))
291 if (m5602_read_sensor(sd
, 0x04, prod_id
+4, 2))
294 if (memcmp(prod_id
, expected_prod_id
, sizeof(prod_id
)))
297 pr_info("Detected a s5k4aa sensor\n");
300 sensor_settings
= kmalloc(
301 ARRAY_SIZE(s5k4aa_ctrls
) * sizeof(s32
), GFP_KERNEL
);
302 if (!sensor_settings
)
305 sd
->gspca_dev
.cam
.cam_mode
= s5k4aa_modes
;
306 sd
->gspca_dev
.cam
.nmodes
= ARRAY_SIZE(s5k4aa_modes
);
307 sd
->desc
->ctrls
= s5k4aa_ctrls
;
308 sd
->desc
->nctrls
= ARRAY_SIZE(s5k4aa_ctrls
);
310 for (i
= 0; i
< ARRAY_SIZE(s5k4aa_ctrls
); i
++)
311 sensor_settings
[i
] = s5k4aa_ctrls
[i
].qctrl
.default_value
;
312 sd
->sensor_priv
= sensor_settings
;
317 int s5k4aa_start(struct sd
*sd
)
321 struct cam
*cam
= &sd
->gspca_dev
.cam
;
322 s32
*sensor_settings
= sd
->sensor_priv
;
324 switch (cam
->cam_mode
[sd
->gspca_dev
.curr_mode
].width
) {
326 PDEBUG(D_V4L2
, "Configuring camera for SXGA mode");
328 for (i
= 0; i
< ARRAY_SIZE(SXGA_s5k4aa
); i
++) {
329 switch (SXGA_s5k4aa
[i
][0]) {
331 err
= m5602_write_bridge(sd
,
337 data
[0] = SXGA_s5k4aa
[i
][2];
338 err
= m5602_write_sensor(sd
,
344 data
[0] = SXGA_s5k4aa
[i
][2];
345 data
[1] = SXGA_s5k4aa
[i
][3];
346 err
= m5602_write_sensor(sd
,
352 pr_err("Invalid stream command, exiting init\n");
356 err
= s5k4aa_set_noise(&sd
->gspca_dev
, 0);
362 PDEBUG(D_V4L2
, "Configuring camera for VGA mode");
364 for (i
= 0; i
< ARRAY_SIZE(VGA_s5k4aa
); i
++) {
365 switch (VGA_s5k4aa
[i
][0]) {
367 err
= m5602_write_bridge(sd
,
373 data
[0] = VGA_s5k4aa
[i
][2];
374 err
= m5602_write_sensor(sd
,
380 data
[0] = VGA_s5k4aa
[i
][2];
381 data
[1] = VGA_s5k4aa
[i
][3];
382 err
= m5602_write_sensor(sd
,
388 pr_err("Invalid stream command, exiting init\n");
392 err
= s5k4aa_set_noise(&sd
->gspca_dev
, 1);
400 err
= s5k4aa_set_exposure(&sd
->gspca_dev
,
401 sensor_settings
[EXPOSURE_IDX
]);
405 err
= s5k4aa_set_gain(&sd
->gspca_dev
, sensor_settings
[GAIN_IDX
]);
409 err
= s5k4aa_set_brightness(&sd
->gspca_dev
,
410 sensor_settings
[BRIGHTNESS_IDX
]);
414 err
= s5k4aa_set_noise(&sd
->gspca_dev
, sensor_settings
[NOISE_SUPP_IDX
]);
418 err
= s5k4aa_set_vflip(&sd
->gspca_dev
, sensor_settings
[VFLIP_IDX
]);
422 return s5k4aa_set_hflip(&sd
->gspca_dev
, sensor_settings
[HFLIP_IDX
]);
425 int s5k4aa_init(struct sd
*sd
)
429 for (i
= 0; i
< ARRAY_SIZE(init_s5k4aa
) && !err
; i
++) {
430 u8 data
[2] = {0x00, 0x00};
432 switch (init_s5k4aa
[i
][0]) {
434 err
= m5602_write_bridge(sd
,
440 data
[0] = init_s5k4aa
[i
][2];
441 err
= m5602_write_sensor(sd
,
442 init_s5k4aa
[i
][1], data
, 1);
446 data
[0] = init_s5k4aa
[i
][2];
447 data
[1] = init_s5k4aa
[i
][3];
448 err
= m5602_write_sensor(sd
,
449 init_s5k4aa
[i
][1], data
, 2);
452 pr_info("Invalid stream command, exiting init\n");
458 s5k4aa_dump_registers(sd
);
463 static int s5k4aa_get_exposure(struct gspca_dev
*gspca_dev
, __s32
*val
)
465 struct sd
*sd
= (struct sd
*) gspca_dev
;
466 s32
*sensor_settings
= sd
->sensor_priv
;
468 *val
= sensor_settings
[EXPOSURE_IDX
];
469 PDEBUG(D_V4L2
, "Read exposure %d", *val
);
474 static int s5k4aa_set_exposure(struct gspca_dev
*gspca_dev
, __s32 val
)
476 struct sd
*sd
= (struct sd
*) gspca_dev
;
477 s32
*sensor_settings
= sd
->sensor_priv
;
478 u8 data
= S5K4AA_PAGE_MAP_2
;
481 sensor_settings
[EXPOSURE_IDX
] = val
;
482 PDEBUG(D_V4L2
, "Set exposure to %d", val
);
483 err
= m5602_write_sensor(sd
, S5K4AA_PAGE_MAP
, &data
, 1);
486 data
= (val
>> 8) & 0xff;
487 err
= m5602_write_sensor(sd
, S5K4AA_EXPOSURE_HI
, &data
, 1);
491 err
= m5602_write_sensor(sd
, S5K4AA_EXPOSURE_LO
, &data
, 1);
496 static int s5k4aa_get_vflip(struct gspca_dev
*gspca_dev
, __s32
*val
)
498 struct sd
*sd
= (struct sd
*) gspca_dev
;
499 s32
*sensor_settings
= sd
->sensor_priv
;
501 *val
= sensor_settings
[VFLIP_IDX
];
502 PDEBUG(D_V4L2
, "Read vertical flip %d", *val
);
507 static int s5k4aa_set_vflip(struct gspca_dev
*gspca_dev
, __s32 val
)
509 struct sd
*sd
= (struct sd
*) gspca_dev
;
510 s32
*sensor_settings
= sd
->sensor_priv
;
511 u8 data
= S5K4AA_PAGE_MAP_2
;
514 sensor_settings
[VFLIP_IDX
] = val
;
516 PDEBUG(D_V4L2
, "Set vertical flip to %d", val
);
517 err
= m5602_write_sensor(sd
, S5K4AA_PAGE_MAP
, &data
, 1);
521 err
= m5602_read_sensor(sd
, S5K4AA_READ_MODE
, &data
, 1);
525 if (dmi_check_system(s5k4aa_vflip_dmi_table
))
528 data
= ((data
& ~S5K4AA_RM_V_FLIP
) | ((val
& 0x01) << 7));
529 err
= m5602_write_sensor(sd
, S5K4AA_READ_MODE
, &data
, 1);
533 err
= m5602_read_sensor(sd
, S5K4AA_ROWSTART_LO
, &data
, 1);
540 err
= m5602_write_sensor(sd
, S5K4AA_ROWSTART_LO
, &data
, 1);
544 static int s5k4aa_get_hflip(struct gspca_dev
*gspca_dev
, __s32
*val
)
546 struct sd
*sd
= (struct sd
*) gspca_dev
;
547 s32
*sensor_settings
= sd
->sensor_priv
;
549 *val
= sensor_settings
[HFLIP_IDX
];
550 PDEBUG(D_V4L2
, "Read horizontal flip %d", *val
);
555 static int s5k4aa_set_hflip(struct gspca_dev
*gspca_dev
, __s32 val
)
557 struct sd
*sd
= (struct sd
*) gspca_dev
;
558 s32
*sensor_settings
= sd
->sensor_priv
;
559 u8 data
= S5K4AA_PAGE_MAP_2
;
562 sensor_settings
[HFLIP_IDX
] = val
;
564 PDEBUG(D_V4L2
, "Set horizontal flip to %d", val
);
565 err
= m5602_write_sensor(sd
, S5K4AA_PAGE_MAP
, &data
, 1);
569 err
= m5602_read_sensor(sd
, S5K4AA_READ_MODE
, &data
, 1);
573 if (dmi_check_system(s5k4aa_vflip_dmi_table
))
576 data
= ((data
& ~S5K4AA_RM_H_FLIP
) | ((val
& 0x01) << 6));
577 err
= m5602_write_sensor(sd
, S5K4AA_READ_MODE
, &data
, 1);
581 err
= m5602_read_sensor(sd
, S5K4AA_COLSTART_LO
, &data
, 1);
588 err
= m5602_write_sensor(sd
, S5K4AA_COLSTART_LO
, &data
, 1);
592 static int s5k4aa_get_gain(struct gspca_dev
*gspca_dev
, __s32
*val
)
594 struct sd
*sd
= (struct sd
*) gspca_dev
;
595 s32
*sensor_settings
= sd
->sensor_priv
;
597 *val
= sensor_settings
[GAIN_IDX
];
598 PDEBUG(D_V4L2
, "Read gain %d", *val
);
602 static int s5k4aa_set_gain(struct gspca_dev
*gspca_dev
, __s32 val
)
604 struct sd
*sd
= (struct sd
*) gspca_dev
;
605 s32
*sensor_settings
= sd
->sensor_priv
;
606 u8 data
= S5K4AA_PAGE_MAP_2
;
609 sensor_settings
[GAIN_IDX
] = val
;
611 PDEBUG(D_V4L2
, "Set gain to %d", val
);
612 err
= m5602_write_sensor(sd
, S5K4AA_PAGE_MAP
, &data
, 1);
617 err
= m5602_write_sensor(sd
, S5K4AA_GAIN
, &data
, 1);
622 static int s5k4aa_get_brightness(struct gspca_dev
*gspca_dev
, __s32
*val
)
624 struct sd
*sd
= (struct sd
*) gspca_dev
;
625 s32
*sensor_settings
= sd
->sensor_priv
;
627 *val
= sensor_settings
[BRIGHTNESS_IDX
];
628 PDEBUG(D_V4L2
, "Read brightness %d", *val
);
632 static int s5k4aa_set_brightness(struct gspca_dev
*gspca_dev
, __s32 val
)
634 struct sd
*sd
= (struct sd
*) gspca_dev
;
635 s32
*sensor_settings
= sd
->sensor_priv
;
636 u8 data
= S5K4AA_PAGE_MAP_2
;
639 sensor_settings
[BRIGHTNESS_IDX
] = val
;
641 PDEBUG(D_V4L2
, "Set brightness to %d", val
);
642 err
= m5602_write_sensor(sd
, S5K4AA_PAGE_MAP
, &data
, 1);
647 return m5602_write_sensor(sd
, S5K4AA_BRIGHTNESS
, &data
, 1);
650 static int s5k4aa_get_noise(struct gspca_dev
*gspca_dev
, __s32
*val
)
652 struct sd
*sd
= (struct sd
*) gspca_dev
;
653 s32
*sensor_settings
= sd
->sensor_priv
;
655 *val
= sensor_settings
[NOISE_SUPP_IDX
];
656 PDEBUG(D_V4L2
, "Read noise %d", *val
);
660 static int s5k4aa_set_noise(struct gspca_dev
*gspca_dev
, __s32 val
)
662 struct sd
*sd
= (struct sd
*) gspca_dev
;
663 s32
*sensor_settings
= sd
->sensor_priv
;
664 u8 data
= S5K4AA_PAGE_MAP_2
;
667 sensor_settings
[NOISE_SUPP_IDX
] = val
;
669 PDEBUG(D_V4L2
, "Set noise to %d", val
);
670 err
= m5602_write_sensor(sd
, S5K4AA_PAGE_MAP
, &data
, 1);
675 return m5602_write_sensor(sd
, S5K4AA_NOISE_SUPP
, &data
, 1);
678 void s5k4aa_disconnect(struct sd
*sd
)
681 kfree(sd
->sensor_priv
);
684 static void s5k4aa_dump_registers(struct sd
*sd
)
688 m5602_read_sensor(sd
, S5K4AA_PAGE_MAP
, &old_page
, 1);
689 for (page
= 0; page
< 16; page
++) {
690 m5602_write_sensor(sd
, S5K4AA_PAGE_MAP
, &page
, 1);
691 pr_info("Dumping the s5k4aa register state for page 0x%x\n",
693 for (address
= 0; address
<= 0xff; address
++) {
695 m5602_read_sensor(sd
, address
, &value
, 1);
696 pr_info("register 0x%x contains 0x%x\n",
700 pr_info("s5k4aa register state dump complete\n");
702 for (page
= 0; page
< 16; page
++) {
703 m5602_write_sensor(sd
, S5K4AA_PAGE_MAP
, &page
, 1);
704 pr_info("Probing for which registers that are read/write for page 0x%x\n",
706 for (address
= 0; address
<= 0xff; address
++) {
707 u8 old_value
, ctrl_value
, test_value
= 0xff;
709 m5602_read_sensor(sd
, address
, &old_value
, 1);
710 m5602_write_sensor(sd
, address
, &test_value
, 1);
711 m5602_read_sensor(sd
, address
, &ctrl_value
, 1);
713 if (ctrl_value
== test_value
)
714 pr_info("register 0x%x is writeable\n",
717 pr_info("register 0x%x is read only\n",
720 /* Restore original value */
721 m5602_write_sensor(sd
, address
, &old_value
, 1);
724 pr_info("Read/write register probing complete\n");
725 m5602_write_sensor(sd
, S5K4AA_PAGE_MAP
, &old_page
, 1);