linux/drivers/media/usb/gspca/m5602/m5602_mt9m111.c
<<
>>
Prefs
   1/*
   2 * Driver for the mt9m111 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_mt9m111.h"
  22
  23static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
  24static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
  25static int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
  26static int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
  27static int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
  28static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val);
  29static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev,
  30                                         __s32 val);
  31static int mt9m111_get_auto_white_balance(struct gspca_dev *gspca_dev,
  32                                          __s32 *val);
  33static int mt9m111_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val);
  34static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val);
  35static int mt9m111_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
  36static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
  37static int mt9m111_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
  38static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
  39
  40static struct v4l2_pix_format mt9m111_modes[] = {
  41        {
  42                640,
  43                480,
  44                V4L2_PIX_FMT_SBGGR8,
  45                V4L2_FIELD_NONE,
  46                .sizeimage = 640 * 480,
  47                .bytesperline = 640,
  48                .colorspace = V4L2_COLORSPACE_SRGB,
  49                .priv = 0
  50        }
  51};
  52
  53static const struct ctrl mt9m111_ctrls[] = {
  54#define VFLIP_IDX 0
  55        {
  56                {
  57                        .id             = V4L2_CID_VFLIP,
  58                        .type           = V4L2_CTRL_TYPE_BOOLEAN,
  59                        .name           = "vertical flip",
  60                        .minimum        = 0,
  61                        .maximum        = 1,
  62                        .step           = 1,
  63                        .default_value  = 0
  64                },
  65                .set = mt9m111_set_vflip,
  66                .get = mt9m111_get_vflip
  67        },
  68#define HFLIP_IDX 1
  69        {
  70                {
  71                        .id             = V4L2_CID_HFLIP,
  72                        .type           = V4L2_CTRL_TYPE_BOOLEAN,
  73                        .name           = "horizontal flip",
  74                        .minimum        = 0,
  75                        .maximum        = 1,
  76                        .step           = 1,
  77                        .default_value  = 0
  78                },
  79                .set = mt9m111_set_hflip,
  80                .get = mt9m111_get_hflip
  81        },
  82#define GAIN_IDX 2
  83        {
  84                {
  85                        .id             = V4L2_CID_GAIN,
  86                        .type           = V4L2_CTRL_TYPE_INTEGER,
  87                        .name           = "gain",
  88                        .minimum        = 0,
  89                        .maximum        = (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2,
  90                        .step           = 1,
  91                        .default_value  = MT9M111_DEFAULT_GAIN,
  92                        .flags          = V4L2_CTRL_FLAG_SLIDER
  93                },
  94                .set = mt9m111_set_gain,
  95                .get = mt9m111_get_gain
  96        },
  97#define AUTO_WHITE_BALANCE_IDX 3
  98        {
  99                {
 100                        .id             = V4L2_CID_AUTO_WHITE_BALANCE,
 101                        .type           = V4L2_CTRL_TYPE_BOOLEAN,
 102                        .name           = "auto white balance",
 103                        .minimum        = 0,
 104                        .maximum        = 1,
 105                        .step           = 1,
 106                        .default_value  = 0,
 107                },
 108                .set = mt9m111_set_auto_white_balance,
 109                .get = mt9m111_get_auto_white_balance
 110        },
 111#define GREEN_BALANCE_IDX 4
 112        {
 113                {
 114                        .id             = M5602_V4L2_CID_GREEN_BALANCE,
 115                        .type           = V4L2_CTRL_TYPE_INTEGER,
 116                        .name           = "green balance",
 117                        .minimum        = 0x00,
 118                        .maximum        = 0x7ff,
 119                        .step           = 0x1,
 120                        .default_value  = MT9M111_GREEN_GAIN_DEFAULT,
 121                        .flags          = V4L2_CTRL_FLAG_SLIDER
 122                },
 123                .set = mt9m111_set_green_balance,
 124                .get = mt9m111_get_green_balance
 125        },
 126#define BLUE_BALANCE_IDX 5
 127        {
 128                {
 129                        .id             = V4L2_CID_BLUE_BALANCE,
 130                        .type           = V4L2_CTRL_TYPE_INTEGER,
 131                        .name           = "blue balance",
 132                        .minimum        = 0x00,
 133                        .maximum        = 0x7ff,
 134                        .step           = 0x1,
 135                        .default_value  = MT9M111_BLUE_GAIN_DEFAULT,
 136                        .flags          = V4L2_CTRL_FLAG_SLIDER
 137                },
 138                .set = mt9m111_set_blue_balance,
 139                .get = mt9m111_get_blue_balance
 140        },
 141#define RED_BALANCE_IDX 5
 142        {
 143                {
 144                        .id             = V4L2_CID_RED_BALANCE,
 145                        .type           = V4L2_CTRL_TYPE_INTEGER,
 146                        .name           = "red balance",
 147                        .minimum        = 0x00,
 148                        .maximum        = 0x7ff,
 149                        .step           = 0x1,
 150                        .default_value  = MT9M111_RED_GAIN_DEFAULT,
 151                        .flags          = V4L2_CTRL_FLAG_SLIDER
 152                },
 153                .set = mt9m111_set_red_balance,
 154                .get = mt9m111_get_red_balance
 155        },
 156};
 157
 158static void mt9m111_dump_registers(struct sd *sd);
 159
 160int mt9m111_probe(struct sd *sd)
 161{
 162        u8 data[2] = {0x00, 0x00};
 163        int i;
 164        s32 *sensor_settings;
 165
 166        if (force_sensor) {
 167                if (force_sensor == MT9M111_SENSOR) {
 168                        pr_info("Forcing a %s sensor\n", mt9m111.name);
 169                        goto sensor_found;
 170                }
 171                /* If we want to force another sensor, don't try to probe this
 172                 * one */
 173                return -ENODEV;
 174        }
 175
 176        PDEBUG(D_PROBE, "Probing for a mt9m111 sensor");
 177
 178        /* Do the preinit */
 179        for (i = 0; i < ARRAY_SIZE(preinit_mt9m111); i++) {
 180                if (preinit_mt9m111[i][0] == BRIDGE) {
 181                        m5602_write_bridge(sd,
 182                                preinit_mt9m111[i][1],
 183                                preinit_mt9m111[i][2]);
 184                } else {
 185                        data[0] = preinit_mt9m111[i][2];
 186                        data[1] = preinit_mt9m111[i][3];
 187                        m5602_write_sensor(sd,
 188                                preinit_mt9m111[i][1], data, 2);
 189                }
 190        }
 191
 192        if (m5602_read_sensor(sd, MT9M111_SC_CHIPVER, data, 2))
 193                return -ENODEV;
 194
 195        if ((data[0] == 0x14) && (data[1] == 0x3a)) {
 196                pr_info("Detected a mt9m111 sensor\n");
 197                goto sensor_found;
 198        }
 199
 200        return -ENODEV;
 201
 202sensor_found:
 203        sensor_settings = kmalloc(ARRAY_SIZE(mt9m111_ctrls) * sizeof(s32),
 204                                  GFP_KERNEL);
 205        if (!sensor_settings)
 206                return -ENOMEM;
 207
 208        sd->gspca_dev.cam.cam_mode = mt9m111_modes;
 209        sd->gspca_dev.cam.nmodes = ARRAY_SIZE(mt9m111_modes);
 210        sd->desc->ctrls = mt9m111_ctrls;
 211        sd->desc->nctrls = ARRAY_SIZE(mt9m111_ctrls);
 212
 213        for (i = 0; i < ARRAY_SIZE(mt9m111_ctrls); i++)
 214                sensor_settings[i] = mt9m111_ctrls[i].qctrl.default_value;
 215        sd->sensor_priv = sensor_settings;
 216
 217        return 0;
 218}
 219
 220int mt9m111_init(struct sd *sd)
 221{
 222        int i, err = 0;
 223        s32 *sensor_settings = sd->sensor_priv;
 224
 225        /* Init the sensor */
 226        for (i = 0; i < ARRAY_SIZE(init_mt9m111) && !err; i++) {
 227                u8 data[2];
 228
 229                if (init_mt9m111[i][0] == BRIDGE) {
 230                        err = m5602_write_bridge(sd,
 231                                init_mt9m111[i][1],
 232                                init_mt9m111[i][2]);
 233                } else {
 234                        data[0] = init_mt9m111[i][2];
 235                        data[1] = init_mt9m111[i][3];
 236                        err = m5602_write_sensor(sd,
 237                                init_mt9m111[i][1], data, 2);
 238                }
 239        }
 240
 241        if (dump_sensor)
 242                mt9m111_dump_registers(sd);
 243
 244        err = mt9m111_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
 245        if (err < 0)
 246                return err;
 247
 248        err = mt9m111_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
 249        if (err < 0)
 250                return err;
 251
 252        err = mt9m111_set_green_balance(&sd->gspca_dev,
 253                                         sensor_settings[GREEN_BALANCE_IDX]);
 254        if (err < 0)
 255                return err;
 256
 257        err = mt9m111_set_blue_balance(&sd->gspca_dev,
 258                                         sensor_settings[BLUE_BALANCE_IDX]);
 259        if (err < 0)
 260                return err;
 261
 262        err = mt9m111_set_red_balance(&sd->gspca_dev,
 263                                        sensor_settings[RED_BALANCE_IDX]);
 264        if (err < 0)
 265                return err;
 266
 267        return mt9m111_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
 268}
 269
 270int mt9m111_start(struct sd *sd)
 271{
 272        int i, err = 0;
 273        u8 data[2];
 274        struct cam *cam = &sd->gspca_dev.cam;
 275        s32 *sensor_settings = sd->sensor_priv;
 276
 277        int width = cam->cam_mode[sd->gspca_dev.curr_mode].width - 1;
 278        int height = cam->cam_mode[sd->gspca_dev.curr_mode].height;
 279
 280        for (i = 0; i < ARRAY_SIZE(start_mt9m111) && !err; i++) {
 281                if (start_mt9m111[i][0] == BRIDGE) {
 282                        err = m5602_write_bridge(sd,
 283                                start_mt9m111[i][1],
 284                                start_mt9m111[i][2]);
 285                } else {
 286                        data[0] = start_mt9m111[i][2];
 287                        data[1] = start_mt9m111[i][3];
 288                        err = m5602_write_sensor(sd,
 289                                start_mt9m111[i][1], data, 2);
 290                }
 291        }
 292        if (err < 0)
 293                return err;
 294
 295        err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height >> 8) & 0xff);
 296        if (err < 0)
 297                return err;
 298
 299        err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height & 0xff));
 300        if (err < 0)
 301                return err;
 302
 303        for (i = 0; i < 2 && !err; i++)
 304                err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
 305        if (err < 0)
 306                return err;
 307
 308        err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
 309        if (err < 0)
 310                return err;
 311
 312        err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 2);
 313        if (err < 0)
 314                return err;
 315
 316        for (i = 0; i < 2 && !err; i++)
 317                err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, 0);
 318        if (err < 0)
 319                return err;
 320
 321        err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
 322                                 (width >> 8) & 0xff);
 323        if (err < 0)
 324                return err;
 325
 326        err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, width & 0xff);
 327        if (err < 0)
 328                return err;
 329
 330        err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
 331        if (err < 0)
 332                return err;
 333
 334        switch (width) {
 335        case 640:
 336                PDEBUG(D_V4L2, "Configuring camera for VGA mode");
 337                data[0] = MT9M111_RMB_OVER_SIZED;
 338                data[1] = MT9M111_RMB_ROW_SKIP_2X |
 339                          MT9M111_RMB_COLUMN_SKIP_2X |
 340                          (sensor_settings[VFLIP_IDX] << 0) |
 341                          (sensor_settings[HFLIP_IDX] << 1);
 342
 343                err = m5602_write_sensor(sd,
 344                                         MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
 345                break;
 346
 347        case 320:
 348                PDEBUG(D_V4L2, "Configuring camera for QVGA mode");
 349                data[0] = MT9M111_RMB_OVER_SIZED;
 350                data[1] = MT9M111_RMB_ROW_SKIP_4X |
 351                                MT9M111_RMB_COLUMN_SKIP_4X |
 352                                (sensor_settings[VFLIP_IDX] << 0) |
 353                                (sensor_settings[HFLIP_IDX] << 1);
 354                err = m5602_write_sensor(sd,
 355                                         MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
 356                break;
 357        }
 358        return err;
 359}
 360
 361void mt9m111_disconnect(struct sd *sd)
 362{
 363        sd->sensor = NULL;
 364        kfree(sd->sensor_priv);
 365}
 366
 367static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
 368{
 369        struct sd *sd = (struct sd *) gspca_dev;
 370        s32 *sensor_settings = sd->sensor_priv;
 371
 372        *val = sensor_settings[VFLIP_IDX];
 373        PDEBUG(D_V4L2, "Read vertical flip %d", *val);
 374
 375        return 0;
 376}
 377
 378static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
 379{
 380        int err;
 381        u8 data[2] = {0x00, 0x00};
 382        struct sd *sd = (struct sd *) gspca_dev;
 383        s32 *sensor_settings = sd->sensor_priv;
 384
 385        PDEBUG(D_V4L2, "Set vertical flip to %d", val);
 386
 387        sensor_settings[VFLIP_IDX] = val;
 388
 389        /* The mt9m111 is flipped by default */
 390        val = !val;
 391
 392        /* Set the correct page map */
 393        err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
 394        if (err < 0)
 395                return err;
 396
 397        err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
 398        if (err < 0)
 399                return err;
 400
 401        data[1] = (data[1] & 0xfe) | val;
 402        err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
 403                                   data, 2);
 404        return err;
 405}
 406
 407static int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
 408{
 409        struct sd *sd = (struct sd *) gspca_dev;
 410        s32 *sensor_settings = sd->sensor_priv;
 411
 412        *val = sensor_settings[HFLIP_IDX];
 413        PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
 414
 415        return 0;
 416}
 417
 418static int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
 419{
 420        int err;
 421        u8 data[2] = {0x00, 0x00};
 422        struct sd *sd = (struct sd *) gspca_dev;
 423        s32 *sensor_settings = sd->sensor_priv;
 424
 425        PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
 426
 427        sensor_settings[HFLIP_IDX] = val;
 428
 429        /* The mt9m111 is flipped by default */
 430        val = !val;
 431
 432        /* Set the correct page map */
 433        err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
 434        if (err < 0)
 435                return err;
 436
 437        err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
 438        if (err < 0)
 439                return err;
 440
 441        data[1] = (data[1] & 0xfd) | ((val << 1) & 0x02);
 442        err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
 443                                        data, 2);
 444        return err;
 445}
 446
 447static int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
 448{
 449        struct sd *sd = (struct sd *) gspca_dev;
 450        s32 *sensor_settings = sd->sensor_priv;
 451
 452        *val = sensor_settings[GAIN_IDX];
 453        PDEBUG(D_V4L2, "Read gain %d", *val);
 454
 455        return 0;
 456}
 457
 458static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev,
 459                                          __s32 val)
 460{
 461        struct sd *sd = (struct sd *) gspca_dev;
 462        s32 *sensor_settings = sd->sensor_priv;
 463        int err;
 464        u8 data[2];
 465
 466        err = m5602_read_sensor(sd, MT9M111_CP_OPERATING_MODE_CTL, data, 2);
 467        if (err < 0)
 468                return err;
 469
 470        sensor_settings[AUTO_WHITE_BALANCE_IDX] = val & 0x01;
 471        data[1] = ((data[1] & 0xfd) | ((val & 0x01) << 1));
 472
 473        err = m5602_write_sensor(sd, MT9M111_CP_OPERATING_MODE_CTL, data, 2);
 474
 475        PDEBUG(D_V4L2, "Set auto white balance %d", val);
 476        return err;
 477}
 478
 479static int mt9m111_get_auto_white_balance(struct gspca_dev *gspca_dev,
 480                                          __s32 *val) {
 481        struct sd *sd = (struct sd *) gspca_dev;
 482        s32 *sensor_settings = sd->sensor_priv;
 483
 484        *val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
 485        PDEBUG(D_V4L2, "Read auto white balance %d", *val);
 486        return 0;
 487}
 488
 489static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
 490{
 491        int err, tmp;
 492        u8 data[2] = {0x00, 0x00};
 493        struct sd *sd = (struct sd *) gspca_dev;
 494        s32 *sensor_settings = sd->sensor_priv;
 495
 496        sensor_settings[GAIN_IDX] = val;
 497
 498        /* Set the correct page map */
 499        err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
 500        if (err < 0)
 501                return err;
 502
 503        if (val >= INITIAL_MAX_GAIN * 2 * 2 * 2)
 504                return -EINVAL;
 505
 506        if ((val >= INITIAL_MAX_GAIN * 2 * 2) &&
 507            (val < (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2))
 508                tmp = (1 << 10) | (val << 9) |
 509                                (val << 8) | (val / 8);
 510        else if ((val >= INITIAL_MAX_GAIN * 2) &&
 511                 (val <  INITIAL_MAX_GAIN * 2 * 2))
 512                tmp = (1 << 9) | (1 << 8) | (val / 4);
 513        else if ((val >= INITIAL_MAX_GAIN) &&
 514                 (val < INITIAL_MAX_GAIN * 2))
 515                tmp = (1 << 8) | (val / 2);
 516        else
 517                tmp = val;
 518
 519        data[1] = (tmp & 0xff);
 520        data[0] = (tmp & 0xff00) >> 8;
 521        PDEBUG(D_V4L2, "tmp=%d, data[1]=%d, data[0]=%d", tmp,
 522               data[1], data[0]);
 523
 524        err = m5602_write_sensor(sd, MT9M111_SC_GLOBAL_GAIN,
 525                                   data, 2);
 526
 527        return err;
 528}
 529
 530static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val)
 531{
 532        int err;
 533        u8 data[2];
 534        struct sd *sd = (struct sd *) gspca_dev;
 535        s32 *sensor_settings = sd->sensor_priv;
 536
 537        sensor_settings[GREEN_BALANCE_IDX] = val;
 538        data[1] = (val & 0xff);
 539        data[0] = (val & 0xff00) >> 8;
 540
 541        PDEBUG(D_V4L2, "Set green balance %d", val);
 542        err = m5602_write_sensor(sd, MT9M111_SC_GREEN_1_GAIN,
 543                                 data, 2);
 544        if (err < 0)
 545                return err;
 546
 547        return m5602_write_sensor(sd, MT9M111_SC_GREEN_2_GAIN,
 548                                  data, 2);
 549}
 550
 551static int mt9m111_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val)
 552{
 553        struct sd *sd = (struct sd *) gspca_dev;
 554        s32 *sensor_settings = sd->sensor_priv;
 555
 556        *val = sensor_settings[GREEN_BALANCE_IDX];
 557        PDEBUG(D_V4L2, "Read green balance %d", *val);
 558        return 0;
 559}
 560
 561static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
 562{
 563        u8 data[2];
 564        struct sd *sd = (struct sd *) gspca_dev;
 565        s32 *sensor_settings = sd->sensor_priv;
 566
 567        sensor_settings[BLUE_BALANCE_IDX] = val;
 568        data[1] = (val & 0xff);
 569        data[0] = (val & 0xff00) >> 8;
 570
 571        PDEBUG(D_V4L2, "Set blue balance %d", val);
 572
 573        return m5602_write_sensor(sd, MT9M111_SC_BLUE_GAIN,
 574                                  data, 2);
 575}
 576
 577static int mt9m111_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
 578{
 579        struct sd *sd = (struct sd *) gspca_dev;
 580        s32 *sensor_settings = sd->sensor_priv;
 581
 582        *val = sensor_settings[BLUE_BALANCE_IDX];
 583        PDEBUG(D_V4L2, "Read blue balance %d", *val);
 584        return 0;
 585}
 586
 587static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
 588{
 589        u8 data[2];
 590        struct sd *sd = (struct sd *) gspca_dev;
 591        s32 *sensor_settings = sd->sensor_priv;
 592
 593        sensor_settings[RED_BALANCE_IDX] = val;
 594        data[1] = (val & 0xff);
 595        data[0] = (val & 0xff00) >> 8;
 596
 597        PDEBUG(D_V4L2, "Set red balance %d", val);
 598
 599        return m5602_write_sensor(sd, MT9M111_SC_RED_GAIN,
 600                                  data, 2);
 601}
 602
 603static int mt9m111_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
 604{
 605        struct sd *sd = (struct sd *) gspca_dev;
 606        s32 *sensor_settings = sd->sensor_priv;
 607
 608        *val = sensor_settings[RED_BALANCE_IDX];
 609        PDEBUG(D_V4L2, "Read red balance %d", *val);
 610        return 0;
 611}
 612
 613static void mt9m111_dump_registers(struct sd *sd)
 614{
 615        u8 address, value[2] = {0x00, 0x00};
 616
 617        pr_info("Dumping the mt9m111 register state\n");
 618
 619        pr_info("Dumping the mt9m111 sensor core registers\n");
 620        value[1] = MT9M111_SENSOR_CORE;
 621        m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
 622        for (address = 0; address < 0xff; address++) {
 623                m5602_read_sensor(sd, address, value, 2);
 624                pr_info("register 0x%x contains 0x%x%x\n",
 625                        address, value[0], value[1]);
 626        }
 627
 628        pr_info("Dumping the mt9m111 color pipeline registers\n");
 629        value[1] = MT9M111_COLORPIPE;
 630        m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
 631        for (address = 0; address < 0xff; address++) {
 632                m5602_read_sensor(sd, address, value, 2);
 633                pr_info("register 0x%x contains 0x%x%x\n",
 634                        address, value[0], value[1]);
 635        }
 636
 637        pr_info("Dumping the mt9m111 camera control registers\n");
 638        value[1] = MT9M111_CAMERA_CONTROL;
 639        m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
 640        for (address = 0; address < 0xff; address++) {
 641                m5602_read_sensor(sd, address, value, 2);
 642                pr_info("register 0x%x contains 0x%x%x\n",
 643                        address, value[0], value[1]);
 644        }
 645
 646        pr_info("mt9m111 register state dump complete\n");
 647}
 648