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