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