linux/drivers/media/usb/gspca/m5602/m5602_po1030.c
<<
>>
Prefs
   1/*
   2 * Driver for the po1030 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_po1030.h"
  22
  23static int po1030_s_ctrl(struct v4l2_ctrl *ctrl);
  24static void po1030_dump_registers(struct sd *sd);
  25
  26static const unsigned char preinit_po1030[][3] = {
  27        {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
  28        {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
  29        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
  30        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
  31        {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
  32        {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00},
  33        {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
  34        {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
  35        {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
  36        {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
  37        {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
  38        {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
  39        {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02},
  40
  41        {SENSOR, PO1030_AUTOCTRL2, PO1030_SENSOR_RESET | (1 << 2)},
  42
  43        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
  44        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
  45        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
  46        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
  47        {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
  48        {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
  49        {BRIDGE, M5602_XB_GPIO_DAT, 0x00}
  50};
  51
  52static const unsigned char init_po1030[][3] = {
  53        {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
  54        {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
  55        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
  56        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
  57        {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
  58        {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00},
  59        {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
  60
  61        {SENSOR, PO1030_AUTOCTRL2, PO1030_SENSOR_RESET | (1 << 2)},
  62
  63        {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
  64        {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
  65        {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
  66        {BRIDGE, M5602_XB_GPIO_EN_L, 0x00},
  67        {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
  68        {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02},
  69        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
  70        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
  71        {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
  72        {BRIDGE, M5602_XB_GPIO_DAT, 0x00},
  73
  74        {SENSOR, PO1030_AUTOCTRL2, 0x04},
  75
  76        {SENSOR, PO1030_OUTFORMCTRL2, PO1030_RAW_RGB_BAYER},
  77        {SENSOR, PO1030_AUTOCTRL1, PO1030_WEIGHT_WIN_2X},
  78
  79        {SENSOR, PO1030_CONTROL2, 0x03},
  80        {SENSOR, 0x21, 0x90},
  81        {SENSOR, PO1030_YTARGET, 0x60},
  82        {SENSOR, 0x59, 0x13},
  83        {SENSOR, PO1030_OUTFORMCTRL1, PO1030_HREF_ENABLE},
  84        {SENSOR, PO1030_EDGE_ENH_OFF, 0x00},
  85        {SENSOR, PO1030_EGA, 0x80},
  86        {SENSOR, 0x78, 0x14},
  87        {SENSOR, 0x6f, 0x01},
  88        {SENSOR, PO1030_GLOBALGAINMAX, 0x14},
  89        {SENSOR, PO1030_Cb_U_GAIN, 0x38},
  90        {SENSOR, PO1030_Cr_V_GAIN, 0x38},
  91        {SENSOR, PO1030_CONTROL1, PO1030_SHUTTER_MODE |
  92                                  PO1030_AUTO_SUBSAMPLING |
  93                                  PO1030_FRAME_EQUAL},
  94        {SENSOR, PO1030_GC0, 0x10},
  95        {SENSOR, PO1030_GC1, 0x20},
  96        {SENSOR, PO1030_GC2, 0x40},
  97        {SENSOR, PO1030_GC3, 0x60},
  98        {SENSOR, PO1030_GC4, 0x80},
  99        {SENSOR, PO1030_GC5, 0xa0},
 100        {SENSOR, PO1030_GC6, 0xc0},
 101        {SENSOR, PO1030_GC7, 0xff},
 102
 103        /* Set the width to 751 */
 104        {SENSOR, PO1030_FRAMEWIDTH_H, 0x02},
 105        {SENSOR, PO1030_FRAMEWIDTH_L, 0xef},
 106
 107        /* Set the height to 540 */
 108        {SENSOR, PO1030_FRAMEHEIGHT_H, 0x02},
 109        {SENSOR, PO1030_FRAMEHEIGHT_L, 0x1c},
 110
 111        /* Set the x window to 1 */
 112        {SENSOR, PO1030_WINDOWX_H, 0x00},
 113        {SENSOR, PO1030_WINDOWX_L, 0x01},
 114
 115        /* Set the y window to 1 */
 116        {SENSOR, PO1030_WINDOWY_H, 0x00},
 117        {SENSOR, PO1030_WINDOWY_L, 0x01},
 118
 119        /* with a very low lighted environment increase the exposure but
 120         * decrease the FPS (Frame Per Second) */
 121        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
 122        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
 123
 124        {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
 125        {BRIDGE, M5602_XB_GPIO_DAT, 0x00},
 126        {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
 127        {BRIDGE, M5602_XB_GPIO_EN_L, 0x00},
 128};
 129
 130static struct v4l2_pix_format po1030_modes[] = {
 131        {
 132                640,
 133                480,
 134                V4L2_PIX_FMT_SBGGR8,
 135                V4L2_FIELD_NONE,
 136                .sizeimage = 640 * 480,
 137                .bytesperline = 640,
 138                .colorspace = V4L2_COLORSPACE_SRGB,
 139                .priv = 2
 140        }
 141};
 142
 143static const struct v4l2_ctrl_ops po1030_ctrl_ops = {
 144        .s_ctrl = po1030_s_ctrl,
 145};
 146
 147static const struct v4l2_ctrl_config po1030_greenbal_cfg = {
 148        .ops    = &po1030_ctrl_ops,
 149        .id     = M5602_V4L2_CID_GREEN_BALANCE,
 150        .name   = "Green Balance",
 151        .type   = V4L2_CTRL_TYPE_INTEGER,
 152        .min    = 0,
 153        .max    = 255,
 154        .step   = 1,
 155        .def    = PO1030_GREEN_GAIN_DEFAULT,
 156        .flags  = V4L2_CTRL_FLAG_SLIDER,
 157};
 158
 159int po1030_probe(struct sd *sd)
 160{
 161        u8 dev_id_h = 0, i;
 162        struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
 163
 164        if (force_sensor) {
 165                if (force_sensor == PO1030_SENSOR) {
 166                        pr_info("Forcing a %s sensor\n", po1030.name);
 167                        goto sensor_found;
 168                }
 169                /* If we want to force another sensor, don't try to probe this
 170                 * one */
 171                return -ENODEV;
 172        }
 173
 174        gspca_dbg(gspca_dev, D_PROBE, "Probing for a po1030 sensor\n");
 175
 176        /* Run the pre-init to actually probe the unit */
 177        for (i = 0; i < ARRAY_SIZE(preinit_po1030); i++) {
 178                u8 data = preinit_po1030[i][2];
 179                if (preinit_po1030[i][0] == SENSOR)
 180                        m5602_write_sensor(sd,
 181                                preinit_po1030[i][1], &data, 1);
 182                else
 183                        m5602_write_bridge(sd, preinit_po1030[i][1], data);
 184        }
 185
 186        if (m5602_read_sensor(sd, PO1030_DEVID_H, &dev_id_h, 1))
 187                return -ENODEV;
 188
 189        if (dev_id_h == 0x30) {
 190                pr_info("Detected a po1030 sensor\n");
 191                goto sensor_found;
 192        }
 193        return -ENODEV;
 194
 195sensor_found:
 196        sd->gspca_dev.cam.cam_mode = po1030_modes;
 197        sd->gspca_dev.cam.nmodes = ARRAY_SIZE(po1030_modes);
 198
 199        return 0;
 200}
 201
 202int po1030_init(struct sd *sd)
 203{
 204        int i, err = 0;
 205
 206        /* Init the sensor */
 207        for (i = 0; i < ARRAY_SIZE(init_po1030) && !err; i++) {
 208                u8 data[2] = {0x00, 0x00};
 209
 210                switch (init_po1030[i][0]) {
 211                case BRIDGE:
 212                        err = m5602_write_bridge(sd,
 213                                init_po1030[i][1],
 214                                init_po1030[i][2]);
 215                        break;
 216
 217                case SENSOR:
 218                        data[0] = init_po1030[i][2];
 219                        err = m5602_write_sensor(sd,
 220                                init_po1030[i][1], data, 1);
 221                        break;
 222
 223                default:
 224                        pr_info("Invalid stream command, exiting init\n");
 225                        return -EINVAL;
 226                }
 227        }
 228        if (err < 0)
 229                return err;
 230
 231        if (dump_sensor)
 232                po1030_dump_registers(sd);
 233
 234        return 0;
 235}
 236
 237int po1030_init_controls(struct sd *sd)
 238{
 239        struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
 240
 241        sd->gspca_dev.vdev.ctrl_handler = hdl;
 242        v4l2_ctrl_handler_init(hdl, 9);
 243
 244        sd->auto_white_bal = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops,
 245                                               V4L2_CID_AUTO_WHITE_BALANCE,
 246                                               0, 1, 1, 0);
 247        sd->green_bal = v4l2_ctrl_new_custom(hdl, &po1030_greenbal_cfg, NULL);
 248        sd->red_bal = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops,
 249                                        V4L2_CID_RED_BALANCE, 0, 255, 1,
 250                                        PO1030_RED_GAIN_DEFAULT);
 251        sd->blue_bal = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops,
 252                                        V4L2_CID_BLUE_BALANCE, 0, 255, 1,
 253                                        PO1030_BLUE_GAIN_DEFAULT);
 254
 255        sd->autoexpo = v4l2_ctrl_new_std_menu(hdl, &po1030_ctrl_ops,
 256                          V4L2_CID_EXPOSURE_AUTO, 1, 0, V4L2_EXPOSURE_MANUAL);
 257        sd->expo = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_EXPOSURE,
 258                          0, 0x2ff, 1, PO1030_EXPOSURE_DEFAULT);
 259
 260        sd->gain = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_GAIN, 0,
 261                                     0x4f, 1, PO1030_GLOBAL_GAIN_DEFAULT);
 262
 263        sd->hflip = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_HFLIP,
 264                                      0, 1, 1, 0);
 265        sd->vflip = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_VFLIP,
 266                                      0, 1, 1, 0);
 267
 268        if (hdl->error) {
 269                pr_err("Could not initialize controls\n");
 270                return hdl->error;
 271        }
 272
 273        v4l2_ctrl_auto_cluster(4, &sd->auto_white_bal, 0, false);
 274        v4l2_ctrl_auto_cluster(2, &sd->autoexpo, 0, false);
 275        v4l2_ctrl_cluster(2, &sd->hflip);
 276
 277        return 0;
 278}
 279
 280int po1030_start(struct sd *sd)
 281{
 282        struct cam *cam = &sd->gspca_dev.cam;
 283        int i, err = 0;
 284        int width = cam->cam_mode[sd->gspca_dev.curr_mode].width;
 285        int height = cam->cam_mode[sd->gspca_dev.curr_mode].height;
 286        int ver_offs = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
 287        u8 data;
 288
 289        switch (width) {
 290        case 320:
 291                data = PO1030_SUBSAMPLING;
 292                err = m5602_write_sensor(sd, PO1030_CONTROL3, &data, 1);
 293                if (err < 0)
 294                        return err;
 295
 296                data = ((width + 3) >> 8) & 0xff;
 297                err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_H, &data, 1);
 298                if (err < 0)
 299                        return err;
 300
 301                data = (width + 3) & 0xff;
 302                err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_L, &data, 1);
 303                if (err < 0)
 304                        return err;
 305
 306                data = ((height + 1) >> 8) & 0xff;
 307                err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_H, &data, 1);
 308                if (err < 0)
 309                        return err;
 310
 311                data = (height + 1) & 0xff;
 312                err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_L, &data, 1);
 313
 314                height += 6;
 315                width -= 1;
 316                break;
 317
 318        case 640:
 319                data = 0;
 320                err = m5602_write_sensor(sd, PO1030_CONTROL3, &data, 1);
 321                if (err < 0)
 322                        return err;
 323
 324                data = ((width + 7) >> 8) & 0xff;
 325                err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_H, &data, 1);
 326                if (err < 0)
 327                        return err;
 328
 329                data = (width + 7) & 0xff;
 330                err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_L, &data, 1);
 331                if (err < 0)
 332                        return err;
 333
 334                data = ((height + 3) >> 8) & 0xff;
 335                err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_H, &data, 1);
 336                if (err < 0)
 337                        return err;
 338
 339                data = (height + 3) & 0xff;
 340                err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_L, &data, 1);
 341
 342                height += 12;
 343                width -= 2;
 344                break;
 345        }
 346        err = m5602_write_bridge(sd, M5602_XB_SENSOR_TYPE, 0x0c);
 347        if (err < 0)
 348                return err;
 349
 350        err = m5602_write_bridge(sd, M5602_XB_LINE_OF_FRAME_H, 0x81);
 351        if (err < 0)
 352                return err;
 353
 354        err = m5602_write_bridge(sd, M5602_XB_PIX_OF_LINE_H, 0x82);
 355        if (err < 0)
 356                return err;
 357
 358        err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0x01);
 359        if (err < 0)
 360                return err;
 361
 362        err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA,
 363                                 ((ver_offs >> 8) & 0xff));
 364        if (err < 0)
 365                return err;
 366
 367        err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (ver_offs & 0xff));
 368        if (err < 0)
 369                return err;
 370
 371        for (i = 0; i < 2 && !err; i++)
 372                err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
 373        if (err < 0)
 374                return err;
 375
 376        err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height >> 8) & 0xff);
 377        if (err < 0)
 378                return err;
 379
 380        err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height & 0xff));
 381        if (err < 0)
 382                return err;
 383
 384        for (i = 0; i < 2 && !err; i++)
 385                err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
 386
 387        for (i = 0; i < 2 && !err; i++)
 388                err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
 389
 390        for (i = 0; i < 2 && !err; i++)
 391                err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, 0);
 392        if (err < 0)
 393                return err;
 394
 395        err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, (width >> 8) & 0xff);
 396        if (err < 0)
 397                return err;
 398
 399        err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, (width & 0xff));
 400        if (err < 0)
 401                return err;
 402
 403        err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
 404        return err;
 405}
 406
 407static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
 408{
 409        struct sd *sd = (struct sd *) gspca_dev;
 410        u8 i2c_data;
 411        int err;
 412
 413        gspca_dbg(gspca_dev, D_CONF, "Set exposure to %d\n", val & 0xffff);
 414
 415        i2c_data = ((val & 0xff00) >> 8);
 416        gspca_dbg(gspca_dev, D_CONF, "Set exposure to high byte to 0x%x\n",
 417                  i2c_data);
 418
 419        err = m5602_write_sensor(sd, PO1030_INTEGLINES_H,
 420                                  &i2c_data, 1);
 421        if (err < 0)
 422                return err;
 423
 424        i2c_data = (val & 0xff);
 425        gspca_dbg(gspca_dev, D_CONF, "Set exposure to low byte to 0x%x\n",
 426                  i2c_data);
 427        err = m5602_write_sensor(sd, PO1030_INTEGLINES_M,
 428                                  &i2c_data, 1);
 429
 430        return err;
 431}
 432
 433static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val)
 434{
 435        struct sd *sd = (struct sd *) gspca_dev;
 436        u8 i2c_data;
 437        int err;
 438
 439        i2c_data = val & 0xff;
 440        gspca_dbg(gspca_dev, D_CONF, "Set global gain to %d\n", i2c_data);
 441        err = m5602_write_sensor(sd, PO1030_GLOBALGAIN,
 442                                 &i2c_data, 1);
 443        return err;
 444}
 445
 446static int po1030_set_hvflip(struct gspca_dev *gspca_dev)
 447{
 448        struct sd *sd = (struct sd *) gspca_dev;
 449        u8 i2c_data;
 450        int err;
 451
 452        gspca_dbg(gspca_dev, D_CONF, "Set hvflip %d %d\n",
 453                  sd->hflip->val, sd->vflip->val);
 454        err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1);
 455        if (err < 0)
 456                return err;
 457
 458        i2c_data = (0x3f & i2c_data) | (sd->hflip->val << 7) |
 459                   (sd->vflip->val << 6);
 460
 461        err = m5602_write_sensor(sd, PO1030_CONTROL2,
 462                                 &i2c_data, 1);
 463
 464        return err;
 465}
 466
 467static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
 468{
 469        struct sd *sd = (struct sd *) gspca_dev;
 470        u8 i2c_data;
 471        int err;
 472
 473        i2c_data = val & 0xff;
 474        gspca_dbg(gspca_dev, D_CONF, "Set red gain to %d\n", i2c_data);
 475        err = m5602_write_sensor(sd, PO1030_RED_GAIN,
 476                                  &i2c_data, 1);
 477        return err;
 478}
 479
 480static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
 481{
 482        struct sd *sd = (struct sd *) gspca_dev;
 483        u8 i2c_data;
 484        int err;
 485
 486        i2c_data = val & 0xff;
 487        gspca_dbg(gspca_dev, D_CONF, "Set blue gain to %d\n", i2c_data);
 488        err = m5602_write_sensor(sd, PO1030_BLUE_GAIN,
 489                                  &i2c_data, 1);
 490
 491        return err;
 492}
 493
 494static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val)
 495{
 496        struct sd *sd = (struct sd *) gspca_dev;
 497        u8 i2c_data;
 498        int err;
 499
 500        i2c_data = val & 0xff;
 501        gspca_dbg(gspca_dev, D_CONF, "Set green gain to %d\n", i2c_data);
 502
 503        err = m5602_write_sensor(sd, PO1030_GREEN_1_GAIN,
 504                           &i2c_data, 1);
 505        if (err < 0)
 506                return err;
 507
 508        return m5602_write_sensor(sd, PO1030_GREEN_2_GAIN,
 509                                 &i2c_data, 1);
 510}
 511
 512static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev,
 513                                         __s32 val)
 514{
 515        struct sd *sd = (struct sd *) gspca_dev;
 516        u8 i2c_data;
 517        int err;
 518
 519        err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
 520        if (err < 0)
 521                return err;
 522
 523        gspca_dbg(gspca_dev, D_CONF, "Set auto white balance to %d\n", val);
 524        i2c_data = (i2c_data & 0xfe) | (val & 0x01);
 525        err = m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
 526        return err;
 527}
 528
 529static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev,
 530                                    __s32 val)
 531{
 532        struct sd *sd = (struct sd *) gspca_dev;
 533        u8 i2c_data;
 534        int err;
 535
 536        err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
 537        if (err < 0)
 538                return err;
 539
 540        gspca_dbg(gspca_dev, D_CONF, "Set auto exposure to %d\n", val);
 541        val = (val == V4L2_EXPOSURE_AUTO);
 542        i2c_data = (i2c_data & 0xfd) | ((val & 0x01) << 1);
 543        return m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
 544}
 545
 546void po1030_disconnect(struct sd *sd)
 547{
 548        sd->sensor = NULL;
 549}
 550
 551static int po1030_s_ctrl(struct v4l2_ctrl *ctrl)
 552{
 553        struct gspca_dev *gspca_dev =
 554                container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
 555        struct sd *sd = (struct sd *) gspca_dev;
 556        int err;
 557
 558        if (!gspca_dev->streaming)
 559                return 0;
 560
 561        switch (ctrl->id) {
 562        case V4L2_CID_AUTO_WHITE_BALANCE:
 563                err = po1030_set_auto_white_balance(gspca_dev, ctrl->val);
 564                if (err || ctrl->val)
 565                        return err;
 566                err = po1030_set_green_balance(gspca_dev, sd->green_bal->val);
 567                if (err)
 568                        return err;
 569                err = po1030_set_red_balance(gspca_dev, sd->red_bal->val);
 570                if (err)
 571                        return err;
 572                err = po1030_set_blue_balance(gspca_dev, sd->blue_bal->val);
 573                break;
 574        case V4L2_CID_EXPOSURE_AUTO:
 575                err = po1030_set_auto_exposure(gspca_dev, ctrl->val);
 576                if (err || ctrl->val == V4L2_EXPOSURE_AUTO)
 577                        return err;
 578                err = po1030_set_exposure(gspca_dev, sd->expo->val);
 579                break;
 580        case V4L2_CID_GAIN:
 581                err = po1030_set_gain(gspca_dev, ctrl->val);
 582                break;
 583        case V4L2_CID_HFLIP:
 584                err = po1030_set_hvflip(gspca_dev);
 585                break;
 586        default:
 587                return -EINVAL;
 588        }
 589
 590        return err;
 591}
 592
 593static void po1030_dump_registers(struct sd *sd)
 594{
 595        int address;
 596        u8 value = 0;
 597
 598        pr_info("Dumping the po1030 sensor core registers\n");
 599        for (address = 0; address < 0x7f; address++) {
 600                m5602_read_sensor(sd, address, &value, 1);
 601                pr_info("register 0x%x contains 0x%x\n", address, value);
 602        }
 603
 604        pr_info("po1030 register state dump complete\n");
 605
 606        pr_info("Probing for which registers that are read/write\n");
 607        for (address = 0; address < 0xff; address++) {
 608                u8 old_value, ctrl_value;
 609                u8 test_value[2] = {0xff, 0xff};
 610
 611                m5602_read_sensor(sd, address, &old_value, 1);
 612                m5602_write_sensor(sd, address, test_value, 1);
 613                m5602_read_sensor(sd, address, &ctrl_value, 1);
 614
 615                if (ctrl_value == test_value[0])
 616                        pr_info("register 0x%x is writeable\n", address);
 617                else
 618                        pr_info("register 0x%x is read only\n", address);
 619
 620                /* Restore original value */
 621                m5602_write_sensor(sd, address, &old_value, 1);
 622        }
 623}
 624