1/* 2 * Driver for the s5k4aa sensor 3 * 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> 7 * 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 12 * 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. 16 * 17 */ 18 19#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 20 21#include "m5602_s5k4aa.h" 22 23static int s5k4aa_s_ctrl(struct v4l2_ctrl *ctrl); 24static void s5k4aa_dump_registers(struct sd *sd); 25 26static const struct v4l2_ctrl_ops s5k4aa_ctrl_ops = { 27 .s_ctrl = s5k4aa_s_ctrl, 28}; 29 30static 31 const 32 struct dmi_system_id s5k4aa_vflip_dmi_table[] = { 33 { 34 .ident = "BRUNEINIT", 35 .matches = { 36 DMI_MATCH(DMI_SYS_VENDOR, "BRUNENIT"), 37 DMI_MATCH(DMI_PRODUCT_NAME, "BRUNENIT"), 38 DMI_MATCH(DMI_BOARD_VERSION, "00030D0000000001") 39 } 40 }, { 41 .ident = "Fujitsu-Siemens Amilo Xa 2528", 42 .matches = { 43 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 44 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xa 2528") 45 } 46 }, { 47 .ident = "Fujitsu-Siemens Amilo Xi 2428", 48 .matches = { 49 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 50 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2428") 51 } 52 }, { 53 .ident = "Fujitsu-Siemens Amilo Xi 2528", 54 .matches = { 55 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 56 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2528") 57 } 58 }, { 59 .ident = "Fujitsu-Siemens Amilo Xi 2550", 60 .matches = { 61 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 62 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550") 63 } 64 }, { 65 .ident = "Fujitsu-Siemens Amilo Pa 2548", 66 .matches = { 67 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 68 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 2548") 69 } 70 }, { 71 .ident = "Fujitsu-Siemens Amilo Pi 2530", 72 .matches = { 73 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 74 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 2530") 75 } 76 }, { 77 .ident = "MSI GX700", 78 .matches = { 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") 82 } 83 }, { 84 .ident = "MSI GX700", 85 .matches = { 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") 89 } 90 }, { 91 .ident = "MSI GX700", 92 .matches = { 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") 96 } 97 }, { 98 .ident = "MSI GX700/GX705/EX700", 99 .matches = { 100 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), 101 DMI_MATCH(DMI_PRODUCT_NAME, "GX700/GX705/EX700") 102 } 103 }, { 104 .ident = "MSI L735", 105 .matches = { 106 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), 107 DMI_MATCH(DMI_PRODUCT_NAME, "MS-1717X") 108 } 109 }, { 110 .ident = "Lenovo Y300", 111 .matches = { 112 DMI_MATCH(DMI_SYS_VENDOR, "L3000 Y300"), 113 DMI_MATCH(DMI_PRODUCT_NAME, "Y300") 114 } 115 }, 116 { } 117}; 118 119static struct v4l2_pix_format s5k4aa_modes[] = { 120 { 121 640, 122 480, 123 V4L2_PIX_FMT_SBGGR8, 124 V4L2_FIELD_NONE, 125 .sizeimage = 126 640 * 480, 127 .bytesperline = 640, 128 .colorspace = V4L2_COLORSPACE_SRGB, 129 .priv = 0 130 }, 131 { 132 1280, 133 1024, 134 V4L2_PIX_FMT_SBGGR8, 135 V4L2_FIELD_NONE, 136 .sizeimage = 137 1280 * 1024, 138 .bytesperline = 1280, 139 .colorspace = V4L2_COLORSPACE_SRGB, 140 .priv = 0 141 } 142}; 143 144int s5k4aa_probe(struct sd *sd) 145{ 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; 149 int i, err = 0; 150 151 if (force_sensor) { 152 if (force_sensor == S5K4AA_SENSOR) { 153 pr_info("Forcing a %s sensor\n", s5k4aa.name); 154 goto sensor_found; 155 } 156 /* If we want to force another sensor, don't try to probe this 157 * one */ 158 return -ENODEV; 159 } 160 161 PDEBUG(D_PROBE, "Probing for a s5k4aa sensor"); 162 163 /* Preinit the sensor */ 164 for (i = 0; i < ARRAY_SIZE(preinit_s5k4aa) && !err; i++) { 165 u8 data[2] = {0x00, 0x00}; 166 167 switch (preinit_s5k4aa[i][0]) { 168 case BRIDGE: 169 err = m5602_write_bridge(sd, 170 preinit_s5k4aa[i][1], 171 preinit_s5k4aa[i][2]); 172 break; 173 174 case SENSOR: 175 data[0] = preinit_s5k4aa[i][2]; 176 err = m5602_write_sensor(sd, 177 preinit_s5k4aa[i][1], 178 data, 1); 179 break; 180 181 case SENSOR_LONG: 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], 186 data, 2); 187 break; 188 default: 189 pr_info("Invalid stream command, exiting init\n"); 190 return -EINVAL; 191 } 192 } 193 194 /* Test some registers, but we don't know their exact meaning yet */ 195 if (m5602_read_sensor(sd, 0x00, prod_id, 2)) 196 return -ENODEV; 197 if (m5602_read_sensor(sd, 0x02, prod_id+2, 2)) 198 return -ENODEV; 199 if (m5602_read_sensor(sd, 0x04, prod_id+4, 2)) 200 return -ENODEV; 201 202 if (memcmp(prod_id, expected_prod_id, sizeof(prod_id))) 203 return -ENODEV; 204 else 205 pr_info("Detected a s5k4aa sensor\n"); 206 207sensor_found: 208 sd->gspca_dev.cam.cam_mode = s5k4aa_modes; 209 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes); 210 211 return 0; 212} 213 214int s5k4aa_start(struct sd *sd) 215{ 216 int i, err = 0; 217 u8 data[2]; 218 struct cam *cam = &sd->gspca_dev.cam; 219 struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; 220 221 switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) { 222 case 1280: 223 PDEBUG(D_CONF, "Configuring camera for SXGA mode"); 224 225 for (i = 0; i < ARRAY_SIZE(SXGA_s5k4aa); i++) { 226 switch (SXGA_s5k4aa[i][0]) { 227 case BRIDGE: 228 err = m5602_write_bridge(sd, 229 SXGA_s5k4aa[i][1], 230 SXGA_s5k4aa[i][2]); 231 break; 232 233 case SENSOR: 234 data[0] = SXGA_s5k4aa[i][2]; 235 err = m5602_write_sensor(sd, 236 SXGA_s5k4aa[i][1], 237 data, 1); 238 break; 239 240 case SENSOR_LONG: 241 data[0] = SXGA_s5k4aa[i][2]; 242 data[1] = SXGA_s5k4aa[i][3]; 243 err = m5602_write_sensor(sd, 244 SXGA_s5k4aa[i][1], 245 data, 2); 246 break; 247 248 default: 249 pr_err("Invalid stream command, exiting init\n"); 250 return -EINVAL; 251 } 252 } 253 break; 254 255 case 640: 256 PDEBUG(D_CONF, "Configuring camera for VGA mode"); 257 258 for (i = 0; i < ARRAY_SIZE(VGA_s5k4aa); i++) { 259 switch (VGA_s5k4aa[i][0]) { 260 case BRIDGE: 261 err = m5602_write_bridge(sd, 262 VGA_s5k4aa[i][1], 263 VGA_s5k4aa[i][2]); 264 break; 265 266 case SENSOR: 267 data[0] = VGA_s5k4aa[i][2]; 268 err = m5602_write_sensor(sd, 269 VGA_s5k4aa[i][1], 270 data, 1); 271 break; 272 273 case SENSOR_LONG: 274 data[0] = VGA_s5k4aa[i][2]; 275 data[1] = VGA_s5k4aa[i][3]; 276 err = m5602_write_sensor(sd, 277 VGA_s5k4aa[i][1], 278 data, 2); 279 break; 280 281 default: 282 pr_err("Invalid stream command, exiting init\n"); 283 return -EINVAL; 284 } 285 } 286 break; 287 } 288 if (err < 0) 289 return err; 290 291 return 0; 292} 293 294int s5k4aa_init(struct sd *sd) 295{ 296 int i, err = 0; 297 298 for (i = 0; i < ARRAY_SIZE(init_s5k4aa) && !err; i++) { 299 u8 data[2] = {0x00, 0x00}; 300 301 switch (init_s5k4aa[i][0]) { 302 case BRIDGE: 303 err = m5602_write_bridge(sd, 304 init_s5k4aa[i][1], 305 init_s5k4aa[i][2]); 306 break; 307 308 case SENSOR: 309 data[0] = init_s5k4aa[i][2]; 310 err = m5602_write_sensor(sd, 311 init_s5k4aa[i][1], data, 1); 312 break; 313 314 case SENSOR_LONG: 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); 319 break; 320 default: 321 pr_info("Invalid stream command, exiting init\n"); 322 return -EINVAL; 323 } 324 } 325 326 if (dump_sensor) 327 s5k4aa_dump_registers(sd); 328 329 return err; 330} 331 332int s5k4aa_init_controls(struct sd *sd) 333{ 334 struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler; 335 336 sd->gspca_dev.vdev.ctrl_handler = hdl; 337 v4l2_ctrl_handler_init(hdl, 6); 338 339 v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_BRIGHTNESS, 340 0, 0x1f, 1, S5K4AA_DEFAULT_BRIGHTNESS); 341 342 v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_EXPOSURE, 343 13, 0xfff, 1, 0x100); 344 345 v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_GAIN, 346 0, 127, 1, S5K4AA_DEFAULT_GAIN); 347 348 v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_SHARPNESS, 349 0, 1, 1, 1); 350 351 sd->hflip = v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_HFLIP, 352 0, 1, 1, 0); 353 sd->vflip = v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_VFLIP, 354 0, 1, 1, 0); 355 356 if (hdl->error) { 357 pr_err("Could not initialize controls\n"); 358 return hdl->error; 359 } 360 361 v4l2_ctrl_cluster(2, &sd->hflip); 362 363 return 0; 364} 365 366static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val) 367{ 368 struct sd *sd = (struct sd *) gspca_dev; 369 u8 data = S5K4AA_PAGE_MAP_2; 370 int err; 371 372 PDEBUG(D_CONF, "Set exposure to %d", val); 373 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); 374 if (err < 0) 375 return err; 376 data = (val >> 8) & 0xff; 377 err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1); 378 if (err < 0) 379 return err; 380 data = val & 0xff; 381 err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1); 382 383 return err; 384} 385 386static int s5k4aa_set_hvflip(struct gspca_dev *gspca_dev) 387{ 388 struct sd *sd = (struct sd *) gspca_dev; 389 u8 data = S5K4AA_PAGE_MAP_2; 390 int err; 391 int hflip = sd->hflip->val; 392 int vflip = sd->vflip->val; 393 394 PDEBUG(D_CONF, "Set hvflip %d %d", hflip, vflip); 395 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); 396 if (err < 0) 397 return err; 398 399 err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1); 400 if (err < 0) 401 return err; 402 403 if (dmi_check_system(s5k4aa_vflip_dmi_table)) { 404 hflip = !hflip; 405 vflip = !vflip; 406 } 407 408 data = (data & 0x7f) | (vflip << 7) | (hflip << 6); 409 err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1); 410 if (err < 0) 411 return err; 412 413 err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); 414 if (err < 0) 415 return err; 416 if (hflip) 417 data &= 0xfe; 418 else 419 data |= 0x01; 420 err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); 421 if (err < 0) 422 return err; 423 424 err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); 425 if (err < 0) 426 return err; 427 if (vflip) 428 data &= 0xfe; 429 else 430 data |= 0x01; 431 err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); 432 if (err < 0) 433 return err; 434 435 return 0; 436} 437 438static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val) 439{ 440 struct sd *sd = (struct sd *) gspca_dev; 441 u8 data = S5K4AA_PAGE_MAP_2; 442 int err; 443 444 PDEBUG(D_CONF, "Set gain to %d", val); 445 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); 446 if (err < 0) 447 return err; 448 449 data = val & 0xff; 450 err = m5602_write_sensor(sd, S5K4AA_GAIN, &data, 1); 451 452 return err; 453} 454 455static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val) 456{ 457 struct sd *sd = (struct sd *) gspca_dev; 458 u8 data = S5K4AA_PAGE_MAP_2; 459 int err; 460 461 PDEBUG(D_CONF, "Set brightness to %d", val); 462 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); 463 if (err < 0) 464 return err; 465 466 data = val & 0xff; 467 return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1); 468} 469 470static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val) 471{ 472 struct sd *sd = (struct sd *) gspca_dev; 473 u8 data = S5K4AA_PAGE_MAP_2; 474 int err; 475 476 PDEBUG(D_CONF, "Set noise to %d", val); 477 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); 478 if (err < 0) 479 return err; 480 481 data = val & 0x01; 482 return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1); 483} 484 485static int s5k4aa_s_ctrl(struct v4l2_ctrl *ctrl) 486{ 487 struct gspca_dev *gspca_dev = 488 container_of(ctrl->handler, struct gspca_dev, ctrl_handler); 489 int err; 490 491 if (!gspca_dev->streaming) 492 return 0; 493 494 switch (ctrl->id) { 495 case V4L2_CID_BRIGHTNESS: 496 err = s5k4aa_set_brightness(gspca_dev, ctrl->val); 497 break; 498 case V4L2_CID_EXPOSURE: 499 err = s5k4aa_set_exposure(gspca_dev, ctrl->val); 500 break; 501 case V4L2_CID_GAIN: 502 err = s5k4aa_set_gain(gspca_dev, ctrl->val); 503 break; 504 case V4L2_CID_SHARPNESS: 505 err = s5k4aa_set_noise(gspca_dev, ctrl->val); 506 break; 507 case V4L2_CID_HFLIP: 508 err = s5k4aa_set_hvflip(gspca_dev); 509 break; 510 default: 511 return -EINVAL; 512 } 513 514 return err; 515} 516 517void s5k4aa_disconnect(struct sd *sd) 518{ 519 sd->sensor = NULL; 520} 521 522static void s5k4aa_dump_registers(struct sd *sd) 523{ 524 int address; 525 u8 page, old_page; 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", 530 page); 531 for (address = 0; address <= 0xff; address++) { 532 u8 value = 0; 533 m5602_read_sensor(sd, address, &value, 1); 534 pr_info("register 0x%x contains 0x%x\n", 535 address, value); 536 } 537 } 538 pr_info("s5k4aa register state dump complete\n"); 539 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", 543 page); 544 for (address = 0; address <= 0xff; address++) { 545 u8 old_value, ctrl_value, test_value = 0xff; 546 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); 550 551 if (ctrl_value == test_value) 552 pr_info("register 0x%x is writeable\n", 553 address); 554 else 555 pr_info("register 0x%x is read only\n", 556 address); 557 558 /* Restore original value */ 559 m5602_write_sensor(sd, address, &old_value, 1); 560 } 561 } 562 pr_info("Read/write register probing complete\n"); 563 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1); 564} 565