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 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); 35 36 static 37 const 38 struct dmi_system_id s5k4aa_vflip_dmi_table[] = { 39 { 40 .ident = "BRUNEINIT", 41 .matches = { 42 DMI_MATCH(DMI_SYS_VENDOR, "BRUNENIT"), 43 DMI_MATCH(DMI_PRODUCT_NAME, "BRUNENIT"), 44 DMI_MATCH(DMI_BOARD_VERSION, "00030D0000000001") 45 } 46 }, { 47 .ident = "Fujitsu-Siemens Amilo Xa 2528", 48 .matches = { 49 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 50 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xa 2528") 51 } 52 }, { 53 .ident = "Fujitsu-Siemens Amilo Xi 2428", 54 .matches = { 55 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 56 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2428") 57 } 58 }, { 59 .ident = "Fujitsu-Siemens Amilo Xi 2528", 60 .matches = { 61 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 62 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2528") 63 } 64 }, { 65 .ident = "Fujitsu-Siemens Amilo Xi 2550", 66 .matches = { 67 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 68 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550") 69 } 70 }, { 71 .ident = "Fujitsu-Siemens Amilo Pa 2548", 72 .matches = { 73 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 74 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 2548") 75 } 76 }, { 77 .ident = "Fujitsu-Siemens Amilo Pi 2530", 78 .matches = { 79 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 80 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 2530") 81 } 82 }, { 83 .ident = "MSI GX700", 84 .matches = { 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") 88 } 89 }, { 90 .ident = "MSI GX700", 91 .matches = { 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") 95 } 96 }, { 97 .ident = "MSI GX700", 98 .matches = { 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") 102 } 103 }, { 104 .ident = "MSI GX700/GX705/EX700", 105 .matches = { 106 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), 107 DMI_MATCH(DMI_PRODUCT_NAME, "GX700/GX705/EX700") 108 } 109 }, { 110 .ident = "MSI L735", 111 .matches = { 112 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), 113 DMI_MATCH(DMI_PRODUCT_NAME, "MS-1717X") 114 } 115 }, { 116 .ident = "Lenovo Y300", 117 .matches = { 118 DMI_MATCH(DMI_SYS_VENDOR, "L3000 Y300"), 119 DMI_MATCH(DMI_PRODUCT_NAME, "Y300") 120 } 121 }, 122 { } 123 }; 124 125 static struct v4l2_pix_format s5k4aa_modes[] = { 126 { 127 640, 128 480, 129 V4L2_PIX_FMT_SBGGR8, 130 V4L2_FIELD_NONE, 131 .sizeimage = 132 640 * 480, 133 .bytesperline = 640, 134 .colorspace = V4L2_COLORSPACE_SRGB, 135 .priv = 0 136 }, 137 { 138 1280, 139 1024, 140 V4L2_PIX_FMT_SBGGR8, 141 V4L2_FIELD_NONE, 142 .sizeimage = 143 1280 * 1024, 144 .bytesperline = 1280, 145 .colorspace = V4L2_COLORSPACE_SRGB, 146 .priv = 0 147 } 148 }; 149 150 static const struct ctrl s5k4aa_ctrls[] = { 151 #define VFLIP_IDX 0 152 { 153 { 154 .id = V4L2_CID_VFLIP, 155 .type = V4L2_CTRL_TYPE_BOOLEAN, 156 .name = "vertical flip", 157 .minimum = 0, 158 .maximum = 1, 159 .step = 1, 160 .default_value = 0 161 }, 162 .set = s5k4aa_set_vflip, 163 .get = s5k4aa_get_vflip 164 }, 165 #define HFLIP_IDX 1 166 { 167 { 168 .id = V4L2_CID_HFLIP, 169 .type = V4L2_CTRL_TYPE_BOOLEAN, 170 .name = "horizontal flip", 171 .minimum = 0, 172 .maximum = 1, 173 .step = 1, 174 .default_value = 0 175 }, 176 .set = s5k4aa_set_hflip, 177 .get = s5k4aa_get_hflip 178 }, 179 #define GAIN_IDX 2 180 { 181 { 182 .id = V4L2_CID_GAIN, 183 .type = V4L2_CTRL_TYPE_INTEGER, 184 .name = "Gain", 185 .minimum = 0, 186 .maximum = 127, 187 .step = 1, 188 .default_value = S5K4AA_DEFAULT_GAIN, 189 .flags = V4L2_CTRL_FLAG_SLIDER 190 }, 191 .set = s5k4aa_set_gain, 192 .get = s5k4aa_get_gain 193 }, 194 #define EXPOSURE_IDX 3 195 { 196 { 197 .id = V4L2_CID_EXPOSURE, 198 .type = V4L2_CTRL_TYPE_INTEGER, 199 .name = "Exposure", 200 .minimum = 13, 201 .maximum = 0xfff, 202 .step = 1, 203 .default_value = 0x100, 204 .flags = V4L2_CTRL_FLAG_SLIDER 205 }, 206 .set = s5k4aa_set_exposure, 207 .get = s5k4aa_get_exposure 208 }, 209 #define NOISE_SUPP_IDX 4 210 { 211 { 212 .id = V4L2_CID_PRIVATE_BASE, 213 .type = V4L2_CTRL_TYPE_BOOLEAN, 214 .name = "Noise suppression (smoothing)", 215 .minimum = 0, 216 .maximum = 1, 217 .step = 1, 218 .default_value = 1, 219 }, 220 .set = s5k4aa_set_noise, 221 .get = s5k4aa_get_noise 222 }, 223 #define BRIGHTNESS_IDX 5 224 { 225 { 226 .id = V4L2_CID_BRIGHTNESS, 227 .type = V4L2_CTRL_TYPE_INTEGER, 228 .name = "Brightness", 229 .minimum = 0, 230 .maximum = 0x1f, 231 .step = 1, 232 .default_value = S5K4AA_DEFAULT_BRIGHTNESS, 233 }, 234 .set = s5k4aa_set_brightness, 235 .get = s5k4aa_get_brightness 236 }, 237 238 }; 239 240 static void s5k4aa_dump_registers(struct sd *sd); 241 242 int s5k4aa_probe(struct sd *sd) 243 { 244 u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 245 const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75}; 246 int i, err = 0; 247 s32 *sensor_settings; 248 249 if (force_sensor) { 250 if (force_sensor == S5K4AA_SENSOR) { 251 pr_info("Forcing a %s sensor\n", s5k4aa.name); 252 goto sensor_found; 253 } 254 /* If we want to force another sensor, don't try to probe this 255 * one */ 256 return -ENODEV; 257 } 258 259 PDEBUG(D_PROBE, "Probing for a s5k4aa sensor"); 260 261 /* Preinit the sensor */ 262 for (i = 0; i < ARRAY_SIZE(preinit_s5k4aa) && !err; i++) { 263 u8 data[2] = {0x00, 0x00}; 264 265 switch (preinit_s5k4aa[i][0]) { 266 case BRIDGE: 267 err = m5602_write_bridge(sd, 268 preinit_s5k4aa[i][1], 269 preinit_s5k4aa[i][2]); 270 break; 271 272 case SENSOR: 273 data[0] = preinit_s5k4aa[i][2]; 274 err = m5602_write_sensor(sd, 275 preinit_s5k4aa[i][1], 276 data, 1); 277 break; 278 279 case SENSOR_LONG: 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], 284 data, 2); 285 break; 286 default: 287 pr_info("Invalid stream command, exiting init\n"); 288 return -EINVAL; 289 } 290 } 291 292 /* Test some registers, but we don't know their exact meaning yet */ 293 if (m5602_read_sensor(sd, 0x00, prod_id, 2)) 294 return -ENODEV; 295 if (m5602_read_sensor(sd, 0x02, prod_id+2, 2)) 296 return -ENODEV; 297 if (m5602_read_sensor(sd, 0x04, prod_id+4, 2)) 298 return -ENODEV; 299 300 if (memcmp(prod_id, expected_prod_id, sizeof(prod_id))) 301 return -ENODEV; 302 else 303 pr_info("Detected a s5k4aa sensor\n"); 304 305 sensor_found: 306 sensor_settings = kmalloc( 307 ARRAY_SIZE(s5k4aa_ctrls) * sizeof(s32), GFP_KERNEL); 308 if (!sensor_settings) 309 return -ENOMEM; 310 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); 315 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; 319 320 return 0; 321 } 322 323 int s5k4aa_start(struct sd *sd) 324 { 325 int i, err = 0; 326 u8 data[2]; 327 struct cam *cam = &sd->gspca_dev.cam; 328 s32 *sensor_settings = sd->sensor_priv; 329 330 switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) { 331 case 1280: 332 PDEBUG(D_V4L2, "Configuring camera for SXGA mode"); 333 334 for (i = 0; i < ARRAY_SIZE(SXGA_s5k4aa); i++) { 335 switch (SXGA_s5k4aa[i][0]) { 336 case BRIDGE: 337 err = m5602_write_bridge(sd, 338 SXGA_s5k4aa[i][1], 339 SXGA_s5k4aa[i][2]); 340 break; 341 342 case SENSOR: 343 data[0] = SXGA_s5k4aa[i][2]; 344 err = m5602_write_sensor(sd, 345 SXGA_s5k4aa[i][1], 346 data, 1); 347 break; 348 349 case SENSOR_LONG: 350 data[0] = SXGA_s5k4aa[i][2]; 351 data[1] = SXGA_s5k4aa[i][3]; 352 err = m5602_write_sensor(sd, 353 SXGA_s5k4aa[i][1], 354 data, 2); 355 break; 356 357 default: 358 pr_err("Invalid stream command, exiting init\n"); 359 return -EINVAL; 360 } 361 } 362 err = s5k4aa_set_noise(&sd->gspca_dev, 0); 363 if (err < 0) 364 return err; 365 break; 366 367 case 640: 368 PDEBUG(D_V4L2, "Configuring camera for VGA mode"); 369 370 for (i = 0; i < ARRAY_SIZE(VGA_s5k4aa); i++) { 371 switch (VGA_s5k4aa[i][0]) { 372 case BRIDGE: 373 err = m5602_write_bridge(sd, 374 VGA_s5k4aa[i][1], 375 VGA_s5k4aa[i][2]); 376 break; 377 378 case SENSOR: 379 data[0] = VGA_s5k4aa[i][2]; 380 err = m5602_write_sensor(sd, 381 VGA_s5k4aa[i][1], 382 data, 1); 383 break; 384 385 case SENSOR_LONG: 386 data[0] = VGA_s5k4aa[i][2]; 387 data[1] = VGA_s5k4aa[i][3]; 388 err = m5602_write_sensor(sd, 389 VGA_s5k4aa[i][1], 390 data, 2); 391 break; 392 393 default: 394 pr_err("Invalid stream command, exiting init\n"); 395 return -EINVAL; 396 } 397 } 398 err = s5k4aa_set_noise(&sd->gspca_dev, 1); 399 if (err < 0) 400 return err; 401 break; 402 } 403 if (err < 0) 404 return err; 405 406 err = s5k4aa_set_exposure(&sd->gspca_dev, 407 sensor_settings[EXPOSURE_IDX]); 408 if (err < 0) 409 return err; 410 411 err = s5k4aa_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); 412 if (err < 0) 413 return err; 414 415 err = s5k4aa_set_brightness(&sd->gspca_dev, 416 sensor_settings[BRIGHTNESS_IDX]); 417 if (err < 0) 418 return err; 419 420 err = s5k4aa_set_noise(&sd->gspca_dev, sensor_settings[NOISE_SUPP_IDX]); 421 if (err < 0) 422 return err; 423 424 err = s5k4aa_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]); 425 if (err < 0) 426 return err; 427 428 return s5k4aa_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]); 429 } 430 431 int s5k4aa_init(struct sd *sd) 432 { 433 int i, err = 0; 434 435 for (i = 0; i < ARRAY_SIZE(init_s5k4aa) && !err; i++) { 436 u8 data[2] = {0x00, 0x00}; 437 438 switch (init_s5k4aa[i][0]) { 439 case BRIDGE: 440 err = m5602_write_bridge(sd, 441 init_s5k4aa[i][1], 442 init_s5k4aa[i][2]); 443 break; 444 445 case SENSOR: 446 data[0] = init_s5k4aa[i][2]; 447 err = m5602_write_sensor(sd, 448 init_s5k4aa[i][1], data, 1); 449 break; 450 451 case SENSOR_LONG: 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); 456 break; 457 default: 458 pr_info("Invalid stream command, exiting init\n"); 459 return -EINVAL; 460 } 461 } 462 463 if (dump_sensor) 464 s5k4aa_dump_registers(sd); 465 466 return err; 467 } 468 469 static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) 470 { 471 struct sd *sd = (struct sd *) gspca_dev; 472 s32 *sensor_settings = sd->sensor_priv; 473 474 *val = sensor_settings[EXPOSURE_IDX]; 475 PDEBUG(D_V4L2, "Read exposure %d", *val); 476 477 return 0; 478 } 479 480 static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val) 481 { 482 struct sd *sd = (struct sd *) gspca_dev; 483 s32 *sensor_settings = sd->sensor_priv; 484 u8 data = S5K4AA_PAGE_MAP_2; 485 int err; 486 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); 490 if (err < 0) 491 return err; 492 data = (val >> 8) & 0xff; 493 err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1); 494 if (err < 0) 495 return err; 496 data = val & 0xff; 497 err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1); 498 499 return err; 500 } 501 502 static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) 503 { 504 struct sd *sd = (struct sd *) gspca_dev; 505 s32 *sensor_settings = sd->sensor_priv; 506 507 *val = sensor_settings[VFLIP_IDX]; 508 PDEBUG(D_V4L2, "Read vertical flip %d", *val); 509 510 return 0; 511 } 512 513 static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val) 514 { 515 struct sd *sd = (struct sd *) gspca_dev; 516 s32 *sensor_settings = sd->sensor_priv; 517 u8 data = S5K4AA_PAGE_MAP_2; 518 int err; 519 520 sensor_settings[VFLIP_IDX] = val; 521 522 PDEBUG(D_V4L2, "Set vertical flip to %d", val); 523 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); 524 if (err < 0) 525 return err; 526 527 err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1); 528 if (err < 0) 529 return err; 530 531 if (dmi_check_system(s5k4aa_vflip_dmi_table)) 532 val = !val; 533 534 data = ((data & ~S5K4AA_RM_V_FLIP) | ((val & 0x01) << 7)); 535 err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1); 536 if (err < 0) 537 return err; 538 539 err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); 540 if (err < 0) 541 return err; 542 if (val) 543 data &= 0xfe; 544 else 545 data |= 0x01; 546 err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); 547 return err; 548 } 549 550 static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) 551 { 552 struct sd *sd = (struct sd *) gspca_dev; 553 s32 *sensor_settings = sd->sensor_priv; 554 555 *val = sensor_settings[HFLIP_IDX]; 556 PDEBUG(D_V4L2, "Read horizontal flip %d", *val); 557 558 return 0; 559 } 560 561 static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val) 562 { 563 struct sd *sd = (struct sd *) gspca_dev; 564 s32 *sensor_settings = sd->sensor_priv; 565 u8 data = S5K4AA_PAGE_MAP_2; 566 int err; 567 568 sensor_settings[HFLIP_IDX] = val; 569 570 PDEBUG(D_V4L2, "Set horizontal flip to %d", val); 571 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); 572 if (err < 0) 573 return err; 574 575 err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1); 576 if (err < 0) 577 return err; 578 579 if (dmi_check_system(s5k4aa_vflip_dmi_table)) 580 val = !val; 581 582 data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6)); 583 err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1); 584 if (err < 0) 585 return err; 586 587 err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); 588 if (err < 0) 589 return err; 590 if (val) 591 data &= 0xfe; 592 else 593 data |= 0x01; 594 err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); 595 return err; 596 } 597 598 static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val) 599 { 600 struct sd *sd = (struct sd *) gspca_dev; 601 s32 *sensor_settings = sd->sensor_priv; 602 603 *val = sensor_settings[GAIN_IDX]; 604 PDEBUG(D_V4L2, "Read gain %d", *val); 605 return 0; 606 } 607 608 static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val) 609 { 610 struct sd *sd = (struct sd *) gspca_dev; 611 s32 *sensor_settings = sd->sensor_priv; 612 u8 data = S5K4AA_PAGE_MAP_2; 613 int err; 614 615 sensor_settings[GAIN_IDX] = val; 616 617 PDEBUG(D_V4L2, "Set gain to %d", val); 618 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); 619 if (err < 0) 620 return err; 621 622 data = val & 0xff; 623 err = m5602_write_sensor(sd, S5K4AA_GAIN, &data, 1); 624 625 return err; 626 } 627 628 static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val) 629 { 630 struct sd *sd = (struct sd *) gspca_dev; 631 s32 *sensor_settings = sd->sensor_priv; 632 633 *val = sensor_settings[BRIGHTNESS_IDX]; 634 PDEBUG(D_V4L2, "Read brightness %d", *val); 635 return 0; 636 } 637 638 static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val) 639 { 640 struct sd *sd = (struct sd *) gspca_dev; 641 s32 *sensor_settings = sd->sensor_priv; 642 u8 data = S5K4AA_PAGE_MAP_2; 643 int err; 644 645 sensor_settings[BRIGHTNESS_IDX] = val; 646 647 PDEBUG(D_V4L2, "Set brightness to %d", val); 648 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); 649 if (err < 0) 650 return err; 651 652 data = val & 0xff; 653 return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1); 654 } 655 656 static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val) 657 { 658 struct sd *sd = (struct sd *) gspca_dev; 659 s32 *sensor_settings = sd->sensor_priv; 660 661 *val = sensor_settings[NOISE_SUPP_IDX]; 662 PDEBUG(D_V4L2, "Read noise %d", *val); 663 return 0; 664 } 665 666 static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val) 667 { 668 struct sd *sd = (struct sd *) gspca_dev; 669 s32 *sensor_settings = sd->sensor_priv; 670 u8 data = S5K4AA_PAGE_MAP_2; 671 int err; 672 673 sensor_settings[NOISE_SUPP_IDX] = val; 674 675 PDEBUG(D_V4L2, "Set noise to %d", val); 676 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); 677 if (err < 0) 678 return err; 679 680 data = val & 0x01; 681 return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1); 682 } 683 684 void s5k4aa_disconnect(struct sd *sd) 685 { 686 sd->sensor = NULL; 687 kfree(sd->sensor_priv); 688 } 689 690 static void s5k4aa_dump_registers(struct sd *sd) 691 { 692 int address; 693 u8 page, old_page; 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", 698 page); 699 for (address = 0; address <= 0xff; address++) { 700 u8 value = 0; 701 m5602_read_sensor(sd, address, &value, 1); 702 pr_info("register 0x%x contains 0x%x\n", 703 address, value); 704 } 705 } 706 pr_info("s5k4aa register state dump complete\n"); 707 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", 711 page); 712 for (address = 0; address <= 0xff; address++) { 713 u8 old_value, ctrl_value, test_value = 0xff; 714 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); 718 719 if (ctrl_value == test_value) 720 pr_info("register 0x%x is writeable\n", 721 address); 722 else 723 pr_info("register 0x%x is read only\n", 724 address); 725 726 /* Restore original value */ 727 m5602_write_sensor(sd, address, &old_value, 1); 728 } 729 } 730 pr_info("Read/write register probing complete\n"); 731 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1); 732 } 733