linux/drivers/media/video/gspca/m5602/m5602_ov7660.c
<<
>>
Prefs
   1/*
   2 * Driver for the ov7660 sensor
   3 *
   4 * Copyright (C) 2009 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_ov7660.h"
  20
  21static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
  22static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val);
  23static int ov7660_get_auto_white_balance(struct gspca_dev *gspca_dev,
  24                                         __s32 *val);
  25static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev,
  26                                         __s32 val);
  27static int ov7660_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val);
  28static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val);
  29static int ov7660_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val);
  30static int ov7660_set_auto_exposure(struct gspca_dev *gspca_dev, __s32 val);
  31static int ov7660_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
  32static int ov7660_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
  33static int ov7660_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
  34static int ov7660_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
  35
  36const static struct ctrl ov7660_ctrls[] = {
  37#define GAIN_IDX 1
  38        {
  39                {
  40                        .id             = V4L2_CID_GAIN,
  41                        .type           = V4L2_CTRL_TYPE_INTEGER,
  42                        .name           = "gain",
  43                        .minimum        = 0x00,
  44                        .maximum        = 0xff,
  45                        .step           = 0x1,
  46                        .default_value  = OV7660_DEFAULT_GAIN,
  47                        .flags          = V4L2_CTRL_FLAG_SLIDER
  48                },
  49                .set = ov7660_set_gain,
  50                .get = ov7660_get_gain
  51        },
  52#define BLUE_BALANCE_IDX 2
  53#define RED_BALANCE_IDX 3
  54#define AUTO_WHITE_BALANCE_IDX 4
  55        {
  56                {
  57                        .id             = V4L2_CID_AUTO_WHITE_BALANCE,
  58                        .type           = V4L2_CTRL_TYPE_BOOLEAN,
  59                        .name           = "auto white balance",
  60                        .minimum        = 0,
  61                        .maximum        = 1,
  62                        .step           = 1,
  63                        .default_value  = 1
  64                },
  65                .set = ov7660_set_auto_white_balance,
  66                .get = ov7660_get_auto_white_balance
  67        },
  68#define AUTO_GAIN_CTRL_IDX 5
  69        {
  70                {
  71                        .id             = V4L2_CID_AUTOGAIN,
  72                        .type           = V4L2_CTRL_TYPE_BOOLEAN,
  73                        .name           = "auto gain control",
  74                        .minimum        = 0,
  75                        .maximum        = 1,
  76                        .step           = 1,
  77                        .default_value  = 1
  78                },
  79                .set = ov7660_set_auto_gain,
  80                .get = ov7660_get_auto_gain
  81        },
  82#define AUTO_EXPOSURE_IDX 6
  83        {
  84                {
  85                        .id             = V4L2_CID_EXPOSURE_AUTO,
  86                        .type           = V4L2_CTRL_TYPE_BOOLEAN,
  87                        .name           = "auto exposure",
  88                        .minimum        = 0,
  89                        .maximum        = 1,
  90                        .step           = 1,
  91                        .default_value  = 1
  92                },
  93                .set = ov7660_set_auto_exposure,
  94                .get = ov7660_get_auto_exposure
  95        },
  96#define HFLIP_IDX 7
  97        {
  98                {
  99                        .id             = V4L2_CID_HFLIP,
 100                        .type           = V4L2_CTRL_TYPE_BOOLEAN,
 101                        .name           = "horizontal flip",
 102                        .minimum        = 0,
 103                        .maximum        = 1,
 104                        .step           = 1,
 105                        .default_value  = 0
 106                },
 107                .set = ov7660_set_hflip,
 108                .get = ov7660_get_hflip
 109        },
 110#define VFLIP_IDX 8
 111        {
 112                {
 113                        .id             = V4L2_CID_VFLIP,
 114                        .type           = V4L2_CTRL_TYPE_BOOLEAN,
 115                        .name           = "vertical flip",
 116                        .minimum        = 0,
 117                        .maximum        = 1,
 118                        .step           = 1,
 119                        .default_value  = 0
 120                },
 121                .set = ov7660_set_vflip,
 122                .get = ov7660_get_vflip
 123        },
 124
 125};
 126
 127static struct v4l2_pix_format ov7660_modes[] = {
 128        {
 129                640,
 130                480,
 131                V4L2_PIX_FMT_SBGGR8,
 132                V4L2_FIELD_NONE,
 133                .sizeimage =
 134                        640 * 480,
 135                .bytesperline = 640,
 136                .colorspace = V4L2_COLORSPACE_SRGB,
 137                .priv = 0
 138        }
 139};
 140
 141static void ov7660_dump_registers(struct sd *sd);
 142
 143int ov7660_probe(struct sd *sd)
 144{
 145        int err = 0, i;
 146        u8 prod_id = 0, ver_id = 0;
 147
 148        s32 *sensor_settings;
 149
 150        if (force_sensor) {
 151                if (force_sensor == OV7660_SENSOR) {
 152                        info("Forcing an %s sensor", ov7660.name);
 153                        goto sensor_found;
 154                }
 155                /* If we want to force another sensor,
 156                don't try to probe this one */
 157                return -ENODEV;
 158        }
 159
 160        /* Do the preinit */
 161        for (i = 0; i < ARRAY_SIZE(preinit_ov7660) && !err; i++) {
 162                u8 data[2];
 163
 164                if (preinit_ov7660[i][0] == BRIDGE) {
 165                        err = m5602_write_bridge(sd,
 166                                preinit_ov7660[i][1],
 167                                preinit_ov7660[i][2]);
 168                } else {
 169                        data[0] = preinit_ov7660[i][2];
 170                        err = m5602_write_sensor(sd,
 171                                preinit_ov7660[i][1], data, 1);
 172                }
 173        }
 174        if (err < 0)
 175                return err;
 176
 177        if (m5602_read_sensor(sd, OV7660_PID, &prod_id, 1))
 178                return -ENODEV;
 179
 180        if (m5602_read_sensor(sd, OV7660_VER, &ver_id, 1))
 181                return -ENODEV;
 182
 183        info("Sensor reported 0x%x%x", prod_id, ver_id);
 184
 185        if ((prod_id == 0x76) && (ver_id == 0x60)) {
 186                info("Detected a ov7660 sensor");
 187                goto sensor_found;
 188        }
 189        return -ENODEV;
 190
 191sensor_found:
 192        sensor_settings = kmalloc(
 193                ARRAY_SIZE(ov7660_ctrls) * sizeof(s32), GFP_KERNEL);
 194        if (!sensor_settings)
 195                return -ENOMEM;
 196
 197        sd->gspca_dev.cam.cam_mode = ov7660_modes;
 198        sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov7660_modes);
 199        sd->desc->ctrls = ov7660_ctrls;
 200        sd->desc->nctrls = ARRAY_SIZE(ov7660_ctrls);
 201
 202        for (i = 0; i < ARRAY_SIZE(ov7660_ctrls); i++)
 203                sensor_settings[i] = ov7660_ctrls[i].qctrl.default_value;
 204        sd->sensor_priv = sensor_settings;
 205
 206        return 0;
 207}
 208
 209int ov7660_init(struct sd *sd)
 210{
 211        int i, err = 0;
 212        s32 *sensor_settings = sd->sensor_priv;
 213
 214        /* Init the sensor */
 215        for (i = 0; i < ARRAY_SIZE(init_ov7660); i++) {
 216                u8 data[2];
 217
 218                if (init_ov7660[i][0] == BRIDGE) {
 219                        err = m5602_write_bridge(sd,
 220                                init_ov7660[i][1],
 221                                init_ov7660[i][2]);
 222                } else {
 223                        data[0] = init_ov7660[i][2];
 224                        err = m5602_write_sensor(sd,
 225                                init_ov7660[i][1], data, 1);
 226                }
 227        }
 228
 229        if (dump_sensor)
 230                ov7660_dump_registers(sd);
 231
 232        err = ov7660_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
 233        if (err < 0)
 234                return err;
 235
 236        err = ov7660_set_auto_white_balance(&sd->gspca_dev,
 237                sensor_settings[AUTO_WHITE_BALANCE_IDX]);
 238        if (err < 0)
 239                return err;
 240
 241        err = ov7660_set_auto_gain(&sd->gspca_dev,
 242                sensor_settings[AUTO_GAIN_CTRL_IDX]);
 243        if (err < 0)
 244                return err;
 245
 246        err = ov7660_set_auto_exposure(&sd->gspca_dev,
 247                sensor_settings[AUTO_EXPOSURE_IDX]);
 248        if (err < 0)
 249                return err;
 250        err = ov7660_set_hflip(&sd->gspca_dev,
 251                sensor_settings[HFLIP_IDX]);
 252        if (err < 0)
 253                return err;
 254
 255        err = ov7660_set_vflip(&sd->gspca_dev,
 256                sensor_settings[VFLIP_IDX]);
 257
 258        return err;
 259}
 260
 261int ov7660_start(struct sd *sd)
 262{
 263        return 0;
 264}
 265
 266int ov7660_stop(struct sd *sd)
 267{
 268        return 0;
 269}
 270
 271void ov7660_disconnect(struct sd *sd)
 272{
 273        ov7660_stop(sd);
 274
 275        sd->sensor = NULL;
 276        kfree(sd->sensor_priv);
 277}
 278
 279static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
 280{
 281        struct sd *sd = (struct sd *) gspca_dev;
 282        s32 *sensor_settings = sd->sensor_priv;
 283
 284        *val = sensor_settings[GAIN_IDX];
 285        PDEBUG(D_V4L2, "Read gain %d", *val);
 286        return 0;
 287}
 288
 289static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val)
 290{
 291        int err;
 292        u8 i2c_data;
 293        struct sd *sd = (struct sd *) gspca_dev;
 294        s32 *sensor_settings = sd->sensor_priv;
 295
 296        PDEBUG(D_V4L2, "Setting gain to %d", val);
 297
 298        sensor_settings[GAIN_IDX] = val;
 299
 300        err = m5602_write_sensor(sd, OV7660_GAIN, &i2c_data, 1);
 301        return err;
 302}
 303
 304
 305static int ov7660_get_auto_white_balance(struct gspca_dev *gspca_dev,
 306                                         __s32 *val)
 307{
 308        struct sd *sd = (struct sd *) gspca_dev;
 309        s32 *sensor_settings = sd->sensor_priv;
 310
 311        *val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
 312        return 0;
 313}
 314
 315static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev,
 316                                         __s32 val)
 317{
 318        int err;
 319        u8 i2c_data;
 320        struct sd *sd = (struct sd *) gspca_dev;
 321        s32 *sensor_settings = sd->sensor_priv;
 322
 323        PDEBUG(D_V4L2, "Set auto white balance to %d", val);
 324
 325        sensor_settings[AUTO_WHITE_BALANCE_IDX] = val;
 326        err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
 327        if (err < 0)
 328                return err;
 329
 330        i2c_data = ((i2c_data & 0xfd) | ((val & 0x01) << 1));
 331        err = m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1);
 332
 333        return err;
 334}
 335
 336static int ov7660_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
 337{
 338        struct sd *sd = (struct sd *) gspca_dev;
 339        s32 *sensor_settings = sd->sensor_priv;
 340
 341        *val = sensor_settings[AUTO_GAIN_CTRL_IDX];
 342        PDEBUG(D_V4L2, "Read auto gain control %d", *val);
 343        return 0;
 344}
 345
 346static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
 347{
 348        int err;
 349        u8 i2c_data;
 350        struct sd *sd = (struct sd *) gspca_dev;
 351        s32 *sensor_settings = sd->sensor_priv;
 352
 353        PDEBUG(D_V4L2, "Set auto gain control to %d", val);
 354
 355        sensor_settings[AUTO_GAIN_CTRL_IDX] = val;
 356        err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
 357        if (err < 0)
 358                return err;
 359
 360        i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2));
 361
 362        return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1);
 363}
 364
 365static int ov7660_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val)
 366{
 367        struct sd *sd = (struct sd *) gspca_dev;
 368        s32 *sensor_settings = sd->sensor_priv;
 369
 370        *val = sensor_settings[AUTO_EXPOSURE_IDX];
 371        PDEBUG(D_V4L2, "Read auto exposure control %d", *val);
 372        return 0;
 373}
 374
 375static int ov7660_set_auto_exposure(struct gspca_dev *gspca_dev,
 376                                    __s32 val)
 377{
 378        int err;
 379        u8 i2c_data;
 380        struct sd *sd = (struct sd *) gspca_dev;
 381        s32 *sensor_settings = sd->sensor_priv;
 382
 383        PDEBUG(D_V4L2, "Set auto exposure control to %d", val);
 384
 385        sensor_settings[AUTO_EXPOSURE_IDX] = val;
 386        err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
 387        if (err < 0)
 388                return err;
 389
 390        i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0));
 391
 392        return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1);
 393}
 394
 395static int ov7660_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
 396{
 397        struct sd *sd = (struct sd *) gspca_dev;
 398        s32 *sensor_settings = sd->sensor_priv;
 399
 400        *val = sensor_settings[HFLIP_IDX];
 401        PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
 402        return 0;
 403}
 404
 405static int ov7660_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
 406{
 407        int err;
 408        u8 i2c_data;
 409        struct sd *sd = (struct sd *) gspca_dev;
 410        s32 *sensor_settings = sd->sensor_priv;
 411
 412        PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
 413
 414        sensor_settings[HFLIP_IDX] = val;
 415
 416        i2c_data = ((val & 0x01) << 5) |
 417                (sensor_settings[VFLIP_IDX] << 4);
 418
 419        err = m5602_write_sensor(sd, OV7660_MVFP, &i2c_data, 1);
 420
 421        return err;
 422}
 423
 424static int ov7660_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
 425{
 426        struct sd *sd = (struct sd *) gspca_dev;
 427        s32 *sensor_settings = sd->sensor_priv;
 428
 429        *val = sensor_settings[VFLIP_IDX];
 430        PDEBUG(D_V4L2, "Read vertical flip %d", *val);
 431
 432        return 0;
 433}
 434
 435static int ov7660_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
 436{
 437        int err;
 438        u8 i2c_data;
 439        struct sd *sd = (struct sd *) gspca_dev;
 440        s32 *sensor_settings = sd->sensor_priv;
 441
 442        PDEBUG(D_V4L2, "Set vertical flip to %d", val);
 443        sensor_settings[VFLIP_IDX] = val;
 444
 445        i2c_data = ((val & 0x01) << 4) | (sensor_settings[VFLIP_IDX] << 5);
 446        err = m5602_write_sensor(sd, OV7660_MVFP, &i2c_data, 1);
 447        if (err < 0)
 448                return err;
 449
 450        /* When vflip is toggled we need to readjust the bridge hsync/vsync */
 451        if (gspca_dev->streaming)
 452                err = ov7660_start(sd);
 453
 454        return err;
 455}
 456
 457static void ov7660_dump_registers(struct sd *sd)
 458{
 459        int address;
 460        info("Dumping the ov7660 register state");
 461        for (address = 0; address < 0xa9; address++) {
 462                u8 value;
 463                m5602_read_sensor(sd, address, &value, 1);
 464                info("register 0x%x contains 0x%x",
 465                     address, value);
 466        }
 467
 468        info("ov7660 register state dump complete");
 469
 470        info("Probing for which registers that are read/write");
 471        for (address = 0; address < 0xff; address++) {
 472                u8 old_value, ctrl_value;
 473                u8 test_value[2] = {0xff, 0xff};
 474
 475                m5602_read_sensor(sd, address, &old_value, 1);
 476                m5602_write_sensor(sd, address, test_value, 1);
 477                m5602_read_sensor(sd, address, &ctrl_value, 1);
 478
 479                if (ctrl_value == test_value[0])
 480                        info("register 0x%x is writeable", address);
 481                else
 482                        info("register 0x%x is read only", address);
 483
 484                /* Restore original value */
 485                m5602_write_sensor(sd, address, &old_value, 1);
 486        }
 487}
 488
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.