linux/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher
   3 *                    Mark Cave-Ayland, Carlo E Prelz, Dick Streefland
   4 * Copyright (c) 2002, 2003 Tuukka Toivonen
   5 * Copyright (c) 2008 Erik Andrén
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License as published by
   9 * the Free Software Foundation; either version 2 of the License, or
  10 * (at your option) any later version.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program; if not, write to the Free Software
  19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  20 *
  21 * P/N 861037:      Sensor HDCS1000        ASIC STV0600
  22 * P/N 861050-0010: Sensor HDCS1000        ASIC STV0600
  23 * P/N 861050-0020: Sensor Photobit PB100  ASIC STV0600-1 - QuickCam Express
  24 * P/N 861055:      Sensor ST VV6410       ASIC STV0610   - LEGO cam
  25 * P/N 861075-0040: Sensor HDCS1000        ASIC
  26 * P/N 961179-0700: Sensor ST VV6410       ASIC STV0602   - Dexxa WebCam USB
  27 * P/N 861040-0000: Sensor ST VV6410       ASIC STV0610   - QuickCam Web
  28 */
  29
  30/*
  31 * The spec file for the PB-0100 suggests the following for best quality
  32 * images after the sensor has been reset :
  33 *
  34 * PB_ADCGAINL      = R60 = 0x03 (3 dec)      : sets low reference of ADC
  35                                                to produce good black level
  36 * PB_PREADCTRL     = R32 = 0x1400 (5120 dec) : Enables global gain changes
  37                                                through R53
  38 * PB_ADCMINGAIN    = R52 = 0x10 (16 dec)     : Sets the minimum gain for
  39                                                auto-exposure
  40 * PB_ADCGLOBALGAIN = R53 = 0x10 (16 dec)     : Sets the global gain
  41 * PB_EXPGAIN       = R14 = 0x11 (17 dec)     : Sets the auto-exposure value
  42 * PB_UPDATEINT     = R23 = 0x02 (2 dec)      : Sets the speed on
  43                                                auto-exposure routine
  44 * PB_CFILLIN       = R5  = 0x0E (14 dec)     : Sets the frame rate
  45 */
  46
  47#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  48
  49#include "stv06xx_pb0100.h"
  50
  51static const struct ctrl pb0100_ctrl[] = {
  52#define GAIN_IDX 0
  53        {
  54                {
  55                        .id             = V4L2_CID_GAIN,
  56                        .type           = V4L2_CTRL_TYPE_INTEGER,
  57                        .name           = "Gain",
  58                        .minimum        = 0,
  59                        .maximum        = 255,
  60                        .step           = 1,
  61                        .default_value  = 128
  62                },
  63                .set = pb0100_set_gain,
  64                .get = pb0100_get_gain
  65        },
  66#define RED_BALANCE_IDX 1
  67        {
  68                {
  69                        .id             = V4L2_CID_RED_BALANCE,
  70                        .type           = V4L2_CTRL_TYPE_INTEGER,
  71                        .name           = "Red Balance",
  72                        .minimum        = -255,
  73                        .maximum        = 255,
  74                        .step           = 1,
  75                        .default_value  = 0
  76                },
  77                .set = pb0100_set_red_balance,
  78                .get = pb0100_get_red_balance
  79        },
  80#define BLUE_BALANCE_IDX 2
  81        {
  82                {
  83                        .id             = V4L2_CID_BLUE_BALANCE,
  84                        .type           = V4L2_CTRL_TYPE_INTEGER,
  85                        .name           = "Blue Balance",
  86                        .minimum        = -255,
  87                        .maximum        = 255,
  88                        .step           = 1,
  89                        .default_value  = 0
  90                },
  91                .set = pb0100_set_blue_balance,
  92                .get = pb0100_get_blue_balance
  93        },
  94#define EXPOSURE_IDX 3
  95        {
  96                {
  97                        .id             = V4L2_CID_EXPOSURE,
  98                        .type           = V4L2_CTRL_TYPE_INTEGER,
  99                        .name           = "Exposure",
 100                        .minimum        = 0,
 101                        .maximum        = 511,
 102                        .step           = 1,
 103                        .default_value  = 12
 104                },
 105                .set = pb0100_set_exposure,
 106                .get = pb0100_get_exposure
 107        },
 108#define AUTOGAIN_IDX 4
 109        {
 110                {
 111                        .id             = V4L2_CID_AUTOGAIN,
 112                        .type           = V4L2_CTRL_TYPE_BOOLEAN,
 113                        .name           = "Automatic Gain and Exposure",
 114                        .minimum        = 0,
 115                        .maximum        = 1,
 116                        .step           = 1,
 117                        .default_value  = 1
 118                },
 119                .set = pb0100_set_autogain,
 120                .get = pb0100_get_autogain
 121        },
 122#define AUTOGAIN_TARGET_IDX 5
 123        {
 124                {
 125                        .id             = V4L2_CTRL_CLASS_USER + 0x1000,
 126                        .type           = V4L2_CTRL_TYPE_INTEGER,
 127                        .name           = "Automatic Gain Target",
 128                        .minimum        = 0,
 129                        .maximum        = 255,
 130                        .step           = 1,
 131                        .default_value  = 128
 132                },
 133                .set = pb0100_set_autogain_target,
 134                .get = pb0100_get_autogain_target
 135        },
 136#define NATURAL_IDX 6
 137        {
 138                {
 139                        .id             = V4L2_CTRL_CLASS_USER + 0x1001,
 140                        .type           = V4L2_CTRL_TYPE_BOOLEAN,
 141                        .name           = "Natural Light Source",
 142                        .minimum        = 0,
 143                        .maximum        = 1,
 144                        .step           = 1,
 145                        .default_value  = 1
 146                },
 147                .set = pb0100_set_natural,
 148                .get = pb0100_get_natural
 149        }
 150};
 151
 152static struct v4l2_pix_format pb0100_mode[] = {
 153/* low res / subsample modes disabled as they are only half res horizontal,
 154   halving the vertical resolution does not seem to work */
 155        {
 156                320,
 157                240,
 158                V4L2_PIX_FMT_SGRBG8,
 159                V4L2_FIELD_NONE,
 160                .sizeimage = 320 * 240,
 161                .bytesperline = 320,
 162                .colorspace = V4L2_COLORSPACE_SRGB,
 163                .priv = PB0100_CROP_TO_VGA
 164        },
 165        {
 166                352,
 167                288,
 168                V4L2_PIX_FMT_SGRBG8,
 169                V4L2_FIELD_NONE,
 170                .sizeimage = 352 * 288,
 171                .bytesperline = 352,
 172                .colorspace = V4L2_COLORSPACE_SRGB,
 173                .priv = 0
 174        }
 175};
 176
 177static int pb0100_probe(struct sd *sd)
 178{
 179        u16 sensor;
 180        int i, err;
 181        s32 *sensor_settings;
 182
 183        err = stv06xx_read_sensor(sd, PB_IDENT, &sensor);
 184
 185        if (err < 0)
 186                return -ENODEV;
 187
 188        if ((sensor >> 8) == 0x64) {
 189                sensor_settings = kmalloc(
 190                                ARRAY_SIZE(pb0100_ctrl) * sizeof(s32),
 191                                GFP_KERNEL);
 192                if (!sensor_settings)
 193                        return -ENOMEM;
 194
 195                pr_info("Photobit pb0100 sensor detected\n");
 196
 197                sd->gspca_dev.cam.cam_mode = pb0100_mode;
 198                sd->gspca_dev.cam.nmodes = ARRAY_SIZE(pb0100_mode);
 199                sd->desc.ctrls = pb0100_ctrl;
 200                sd->desc.nctrls = ARRAY_SIZE(pb0100_ctrl);
 201                for (i = 0; i < sd->desc.nctrls; i++)
 202                        sensor_settings[i] = pb0100_ctrl[i].qctrl.default_value;
 203                sd->sensor_priv = sensor_settings;
 204
 205                return 0;
 206        }
 207
 208        return -ENODEV;
 209}
 210
 211static int pb0100_start(struct sd *sd)
 212{
 213        int err, packet_size, max_packet_size;
 214        struct usb_host_interface *alt;
 215        struct usb_interface *intf;
 216        struct cam *cam = &sd->gspca_dev.cam;
 217        s32 *sensor_settings = sd->sensor_priv;
 218        u32 mode = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
 219
 220        intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
 221        alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
 222        if (!alt)
 223                return -ENODEV;
 224        packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
 225
 226        /* If we don't have enough bandwidth use a lower framerate */
 227        max_packet_size = sd->sensor->max_packet_size[sd->gspca_dev.curr_mode];
 228        if (packet_size < max_packet_size)
 229                stv06xx_write_sensor(sd, PB_ROWSPEED, BIT(4)|BIT(3)|BIT(1));
 230        else
 231                stv06xx_write_sensor(sd, PB_ROWSPEED, BIT(5)|BIT(3)|BIT(1));
 232
 233        /* Setup sensor window */
 234        if (mode & PB0100_CROP_TO_VGA) {
 235                stv06xx_write_sensor(sd, PB_RSTART, 30);
 236                stv06xx_write_sensor(sd, PB_CSTART, 20);
 237                stv06xx_write_sensor(sd, PB_RWSIZE, 240 - 1);
 238                stv06xx_write_sensor(sd, PB_CWSIZE, 320 - 1);
 239        } else {
 240                stv06xx_write_sensor(sd, PB_RSTART, 8);
 241                stv06xx_write_sensor(sd, PB_CSTART, 4);
 242                stv06xx_write_sensor(sd, PB_RWSIZE, 288 - 1);
 243                stv06xx_write_sensor(sd, PB_CWSIZE, 352 - 1);
 244        }
 245
 246        if (mode & PB0100_SUBSAMPLE) {
 247                stv06xx_write_bridge(sd, STV_Y_CTRL, 0x02); /* Wrong, FIXME */
 248                stv06xx_write_bridge(sd, STV_X_CTRL, 0x06);
 249
 250                stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x10);
 251        } else {
 252                stv06xx_write_bridge(sd, STV_Y_CTRL, 0x01);
 253                stv06xx_write_bridge(sd, STV_X_CTRL, 0x0a);
 254                /* larger -> slower */
 255                stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x20);
 256        }
 257
 258        /* set_gain also sets red and blue balance */
 259        pb0100_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
 260        pb0100_set_exposure(&sd->gspca_dev, sensor_settings[EXPOSURE_IDX]);
 261        pb0100_set_autogain_target(&sd->gspca_dev,
 262                                   sensor_settings[AUTOGAIN_TARGET_IDX]);
 263        pb0100_set_autogain(&sd->gspca_dev, sensor_settings[AUTOGAIN_IDX]);
 264
 265        err = stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3)|BIT(1));
 266        PDEBUG(D_STREAM, "Started stream, status: %d", err);
 267
 268        return (err < 0) ? err : 0;
 269}
 270
 271static int pb0100_stop(struct sd *sd)
 272{
 273        int err;
 274
 275        err = stv06xx_write_sensor(sd, PB_ABORTFRAME, 1);
 276
 277        if (err < 0)
 278                goto out;
 279
 280        /* Set bit 1 to zero */
 281        err = stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3));
 282
 283        PDEBUG(D_STREAM, "Halting stream");
 284out:
 285        return (err < 0) ? err : 0;
 286}
 287
 288static void pb0100_disconnect(struct sd *sd)
 289{
 290        sd->sensor = NULL;
 291        kfree(sd->sensor_priv);
 292}
 293
 294/* FIXME: Sort the init commands out and put them into tables,
 295          this is only for getting the camera to work */
 296/* FIXME: No error handling for now,
 297          add this once the init has been converted to proper tables */
 298static int pb0100_init(struct sd *sd)
 299{
 300        stv06xx_write_bridge(sd, STV_REG00, 1);
 301        stv06xx_write_bridge(sd, STV_SCAN_RATE, 0);
 302
 303        /* Reset sensor */
 304        stv06xx_write_sensor(sd, PB_RESET, 1);
 305        stv06xx_write_sensor(sd, PB_RESET, 0);
 306
 307        /* Disable chip */
 308        stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3));
 309
 310        /* Gain stuff...*/
 311        stv06xx_write_sensor(sd, PB_PREADCTRL, BIT(12)|BIT(10)|BIT(6));
 312        stv06xx_write_sensor(sd, PB_ADCGLOBALGAIN, 12);
 313
 314        /* Set up auto-exposure */
 315        /* ADC VREF_HI new setting for a transition
 316          from the Expose1 to the Expose2 setting */
 317        stv06xx_write_sensor(sd, PB_R28, 12);
 318        /* gain max for autoexposure */
 319        stv06xx_write_sensor(sd, PB_ADCMAXGAIN, 180);
 320        /* gain min for autoexposure  */
 321        stv06xx_write_sensor(sd, PB_ADCMINGAIN, 12);
 322        /* Maximum frame integration time (programmed into R8)
 323           allowed for auto-exposure routine */
 324        stv06xx_write_sensor(sd, PB_R54, 3);
 325        /* Minimum frame integration time (programmed into R8)
 326           allowed for auto-exposure routine */
 327        stv06xx_write_sensor(sd, PB_R55, 0);
 328        stv06xx_write_sensor(sd, PB_UPDATEINT, 1);
 329        /* R15  Expose0 (maximum that auto-exposure may use) */
 330        stv06xx_write_sensor(sd, PB_R15, 800);
 331        /* R17  Expose2 (minimum that auto-exposure may use) */
 332        stv06xx_write_sensor(sd, PB_R17, 10);
 333
 334        stv06xx_write_sensor(sd, PB_EXPGAIN, 0);
 335
 336        /* 0x14 */
 337        stv06xx_write_sensor(sd, PB_VOFFSET, 0);
 338        /* 0x0D */
 339        stv06xx_write_sensor(sd, PB_ADCGAINH, 11);
 340        /* Set black level (important!) */
 341        stv06xx_write_sensor(sd, PB_ADCGAINL, 0);
 342
 343        /* ??? */
 344        stv06xx_write_bridge(sd, STV_REG00, 0x11);
 345        stv06xx_write_bridge(sd, STV_REG03, 0x45);
 346        stv06xx_write_bridge(sd, STV_REG04, 0x07);
 347
 348        /* Scan/timing for the sensor */
 349        stv06xx_write_sensor(sd, PB_ROWSPEED, BIT(4)|BIT(3)|BIT(1));
 350        stv06xx_write_sensor(sd, PB_CFILLIN, 14);
 351        stv06xx_write_sensor(sd, PB_VBL, 0);
 352        stv06xx_write_sensor(sd, PB_FINTTIME, 0);
 353        stv06xx_write_sensor(sd, PB_RINTTIME, 123);
 354
 355        stv06xx_write_bridge(sd, STV_REG01, 0xc2);
 356        stv06xx_write_bridge(sd, STV_REG02, 0xb0);
 357        return 0;
 358}
 359
 360static int pb0100_dump(struct sd *sd)
 361{
 362        return 0;
 363}
 364
 365static int pb0100_get_gain(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[GAIN_IDX];
 371
 372        return 0;
 373}
 374
 375static int pb0100_set_gain(struct gspca_dev *gspca_dev, __s32 val)
 376{
 377        int err;
 378        struct sd *sd = (struct sd *) gspca_dev;
 379        s32 *sensor_settings = sd->sensor_priv;
 380
 381        if (sensor_settings[AUTOGAIN_IDX])
 382                return -EBUSY;
 383
 384        sensor_settings[GAIN_IDX] = val;
 385        err = stv06xx_write_sensor(sd, PB_G1GAIN, val);
 386        if (!err)
 387                err = stv06xx_write_sensor(sd, PB_G2GAIN, val);
 388        PDEBUG(D_V4L2, "Set green gain to %d, status: %d", val, err);
 389
 390        if (!err)
 391                err = pb0100_set_red_balance(gspca_dev,
 392                                             sensor_settings[RED_BALANCE_IDX]);
 393        if (!err)
 394                err = pb0100_set_blue_balance(gspca_dev,
 395                                            sensor_settings[BLUE_BALANCE_IDX]);
 396
 397        return err;
 398}
 399
 400static int pb0100_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
 401{
 402        struct sd *sd = (struct sd *) gspca_dev;
 403        s32 *sensor_settings = sd->sensor_priv;
 404
 405        *val = sensor_settings[RED_BALANCE_IDX];
 406
 407        return 0;
 408}
 409
 410static int pb0100_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
 411{
 412        int err;
 413        struct sd *sd = (struct sd *) gspca_dev;
 414        s32 *sensor_settings = sd->sensor_priv;
 415
 416        if (sensor_settings[AUTOGAIN_IDX])
 417                return -EBUSY;
 418
 419        sensor_settings[RED_BALANCE_IDX] = val;
 420        val += sensor_settings[GAIN_IDX];
 421        if (val < 0)
 422                val = 0;
 423        else if (val > 255)
 424                val = 255;
 425
 426        err = stv06xx_write_sensor(sd, PB_RGAIN, val);
 427        PDEBUG(D_V4L2, "Set red gain to %d, status: %d", val, err);
 428
 429        return err;
 430}
 431
 432static int pb0100_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
 433{
 434        struct sd *sd = (struct sd *) gspca_dev;
 435        s32 *sensor_settings = sd->sensor_priv;
 436
 437        *val = sensor_settings[BLUE_BALANCE_IDX];
 438
 439        return 0;
 440}
 441
 442static int pb0100_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
 443{
 444        int err;
 445        struct sd *sd = (struct sd *) gspca_dev;
 446        s32 *sensor_settings = sd->sensor_priv;
 447
 448        if (sensor_settings[AUTOGAIN_IDX])
 449                return -EBUSY;
 450
 451        sensor_settings[BLUE_BALANCE_IDX] = val;
 452        val += sensor_settings[GAIN_IDX];
 453        if (val < 0)
 454                val = 0;
 455        else if (val > 255)
 456                val = 255;
 457
 458        err = stv06xx_write_sensor(sd, PB_BGAIN, val);
 459        PDEBUG(D_V4L2, "Set blue gain to %d, status: %d", val, err);
 460
 461        return err;
 462}
 463
 464static int pb0100_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
 465{
 466        struct sd *sd = (struct sd *) gspca_dev;
 467        s32 *sensor_settings = sd->sensor_priv;
 468
 469        *val = sensor_settings[EXPOSURE_IDX];
 470
 471        return 0;
 472}
 473
 474static int pb0100_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
 475{
 476        int err;
 477        struct sd *sd = (struct sd *) gspca_dev;
 478        s32 *sensor_settings = sd->sensor_priv;
 479
 480        if (sensor_settings[AUTOGAIN_IDX])
 481                return -EBUSY;
 482
 483        sensor_settings[EXPOSURE_IDX] = val;
 484        err = stv06xx_write_sensor(sd, PB_RINTTIME, val);
 485        PDEBUG(D_V4L2, "Set exposure to %d, status: %d", val, err);
 486
 487        return err;
 488}
 489
 490static int pb0100_get_autogain(struct gspca_dev *gspca_dev, __s32 *val)
 491{
 492        struct sd *sd = (struct sd *) gspca_dev;
 493        s32 *sensor_settings = sd->sensor_priv;
 494
 495        *val = sensor_settings[AUTOGAIN_IDX];
 496
 497        return 0;
 498}
 499
 500static int pb0100_set_autogain(struct gspca_dev *gspca_dev, __s32 val)
 501{
 502        int err;
 503        struct sd *sd = (struct sd *) gspca_dev;
 504        s32 *sensor_settings = sd->sensor_priv;
 505
 506        sensor_settings[AUTOGAIN_IDX] = val;
 507        if (sensor_settings[AUTOGAIN_IDX]) {
 508                if (sensor_settings[NATURAL_IDX])
 509                        val = BIT(6)|BIT(4)|BIT(0);
 510                else
 511                        val = BIT(4)|BIT(0);
 512        } else
 513                val = 0;
 514
 515        err = stv06xx_write_sensor(sd, PB_EXPGAIN, val);
 516        PDEBUG(D_V4L2, "Set autogain to %d (natural: %d), status: %d",
 517               sensor_settings[AUTOGAIN_IDX], sensor_settings[NATURAL_IDX],
 518               err);
 519
 520        return err;
 521}
 522
 523static int pb0100_get_autogain_target(struct gspca_dev *gspca_dev, __s32 *val)
 524{
 525        struct sd *sd = (struct sd *) gspca_dev;
 526        s32 *sensor_settings = sd->sensor_priv;
 527
 528        *val = sensor_settings[AUTOGAIN_TARGET_IDX];
 529
 530        return 0;
 531}
 532
 533static int pb0100_set_autogain_target(struct gspca_dev *gspca_dev, __s32 val)
 534{
 535        int err, totalpixels, brightpixels, darkpixels;
 536        struct sd *sd = (struct sd *) gspca_dev;
 537        s32 *sensor_settings = sd->sensor_priv;
 538
 539        sensor_settings[AUTOGAIN_TARGET_IDX] = val;
 540
 541        /* Number of pixels counted by the sensor when subsampling the pixels.
 542         * Slightly larger than the real value to avoid oscillation */
 543        totalpixels = gspca_dev->width * gspca_dev->height;
 544        totalpixels = totalpixels/(8*8) + totalpixels/(64*64);
 545
 546        brightpixels = (totalpixels * val) >> 8;
 547        darkpixels   = totalpixels - brightpixels;
 548        err = stv06xx_write_sensor(sd, PB_R21, brightpixels);
 549        if (!err)
 550                err = stv06xx_write_sensor(sd, PB_R22, darkpixels);
 551
 552        PDEBUG(D_V4L2, "Set autogain target to %d, status: %d", val, err);
 553
 554        return err;
 555}
 556
 557static int pb0100_get_natural(struct gspca_dev *gspca_dev, __s32 *val)
 558{
 559        struct sd *sd = (struct sd *) gspca_dev;
 560        s32 *sensor_settings = sd->sensor_priv;
 561
 562        *val = sensor_settings[NATURAL_IDX];
 563
 564        return 0;
 565}
 566
 567static int pb0100_set_natural(struct gspca_dev *gspca_dev, __s32 val)
 568{
 569        struct sd *sd = (struct sd *) gspca_dev;
 570        s32 *sensor_settings = sd->sensor_priv;
 571
 572        sensor_settings[NATURAL_IDX] = val;
 573
 574        return pb0100_set_autogain(gspca_dev, sensor_settings[AUTOGAIN_IDX]);
 575}
 576