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