linux/drivers/media/usb/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
  51struct pb0100_ctrls {
  52        struct { /* one big happy control cluster... */
  53                struct v4l2_ctrl *autogain;
  54                struct v4l2_ctrl *gain;
  55                struct v4l2_ctrl *exposure;
  56                struct v4l2_ctrl *red;
  57                struct v4l2_ctrl *blue;
  58                struct v4l2_ctrl *natural;
  59        };
  60        struct v4l2_ctrl *target;
  61};
  62
  63static struct v4l2_pix_format pb0100_mode[] = {
  64/* low res / subsample modes disabled as they are only half res horizontal,
  65   halving the vertical resolution does not seem to work */
  66        {
  67                320,
  68                240,
  69                V4L2_PIX_FMT_SGRBG8,
  70                V4L2_FIELD_NONE,
  71                .sizeimage = 320 * 240,
  72                .bytesperline = 320,
  73                .colorspace = V4L2_COLORSPACE_SRGB,
  74                .priv = PB0100_CROP_TO_VGA
  75        },
  76        {
  77                352,
  78                288,
  79                V4L2_PIX_FMT_SGRBG8,
  80                V4L2_FIELD_NONE,
  81                .sizeimage = 352 * 288,
  82                .bytesperline = 352,
  83                .colorspace = V4L2_COLORSPACE_SRGB,
  84                .priv = 0
  85        }
  86};
  87
  88static int pb0100_s_ctrl(struct v4l2_ctrl *ctrl)
  89{
  90        struct gspca_dev *gspca_dev =
  91                container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
  92        struct sd *sd = (struct sd *)gspca_dev;
  93        struct pb0100_ctrls *ctrls = sd->sensor_priv;
  94        int err = -EINVAL;
  95
  96        switch (ctrl->id) {
  97        case V4L2_CID_AUTOGAIN:
  98                err = pb0100_set_autogain(gspca_dev, ctrl->val);
  99                if (err)
 100                        break;
 101                if (ctrl->val)
 102                        break;
 103                err = pb0100_set_gain(gspca_dev, ctrls->gain->val);
 104                if (err)
 105                        break;
 106                err = pb0100_set_exposure(gspca_dev, ctrls->exposure->val);
 107                break;
 108        case V4L2_CTRL_CLASS_USER + 0x1001:
 109                err = pb0100_set_autogain_target(gspca_dev, ctrl->val);
 110                break;
 111        }
 112        return err;
 113}
 114
 115static const struct v4l2_ctrl_ops pb0100_ctrl_ops = {
 116        .s_ctrl = pb0100_s_ctrl,
 117};
 118
 119static int pb0100_init_controls(struct sd *sd)
 120{
 121        struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
 122        struct pb0100_ctrls *ctrls;
 123        static const struct v4l2_ctrl_config autogain_target = {
 124                .ops = &pb0100_ctrl_ops,
 125                .id = V4L2_CTRL_CLASS_USER + 0x1000,
 126                .type = V4L2_CTRL_TYPE_INTEGER,
 127                .name = "Automatic Gain Target",
 128                .max = 255,
 129                .step = 1,
 130                .def = 128,
 131        };
 132        static const struct v4l2_ctrl_config natural_light = {
 133                .ops = &pb0100_ctrl_ops,
 134                .id = V4L2_CTRL_CLASS_USER + 0x1001,
 135                .type = V4L2_CTRL_TYPE_BOOLEAN,
 136                .name = "Natural Light Source",
 137                .max = 1,
 138                .step = 1,
 139                .def = 1,
 140        };
 141
 142        ctrls = kzalloc(sizeof(*ctrls), GFP_KERNEL);
 143        if (!ctrls)
 144                return -ENOMEM;
 145
 146        v4l2_ctrl_handler_init(hdl, 6);
 147        ctrls->autogain = v4l2_ctrl_new_std(hdl, &pb0100_ctrl_ops,
 148                        V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
 149        ctrls->exposure = v4l2_ctrl_new_std(hdl, &pb0100_ctrl_ops,
 150                        V4L2_CID_EXPOSURE, 0, 511, 1, 12);
 151        ctrls->gain = v4l2_ctrl_new_std(hdl, &pb0100_ctrl_ops,
 152                        V4L2_CID_GAIN, 0, 255, 1, 128);
 153        ctrls->red = v4l2_ctrl_new_std(hdl, &pb0100_ctrl_ops,
 154                        V4L2_CID_RED_BALANCE, -255, 255, 1, 0);
 155        ctrls->blue = v4l2_ctrl_new_std(hdl, &pb0100_ctrl_ops,
 156                        V4L2_CID_BLUE_BALANCE, -255, 255, 1, 0);
 157        ctrls->natural = v4l2_ctrl_new_custom(hdl, &natural_light, NULL);
 158        ctrls->target = v4l2_ctrl_new_custom(hdl, &autogain_target, NULL);
 159        if (hdl->error) {
 160                kfree(ctrls);
 161                return hdl->error;
 162        }
 163        sd->sensor_priv = ctrls;
 164        v4l2_ctrl_auto_cluster(5, &ctrls->autogain, 0, false);
 165        return 0;
 166}
 167
 168static int pb0100_probe(struct sd *sd)
 169{
 170        u16 sensor;
 171        int err;
 172
 173        err = stv06xx_read_sensor(sd, PB_IDENT, &sensor);
 174
 175        if (err < 0)
 176                return -ENODEV;
 177        if ((sensor >> 8) != 0x64)
 178                return -ENODEV;
 179
 180        pr_info("Photobit pb0100 sensor detected\n");
 181
 182        sd->gspca_dev.cam.cam_mode = pb0100_mode;
 183        sd->gspca_dev.cam.nmodes = ARRAY_SIZE(pb0100_mode);
 184
 185        return 0;
 186}
 187
 188static int pb0100_start(struct sd *sd)
 189{
 190        int err, packet_size, max_packet_size;
 191        struct usb_host_interface *alt;
 192        struct usb_interface *intf;
 193        struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
 194        struct cam *cam = &sd->gspca_dev.cam;
 195        u32 mode = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
 196
 197        intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
 198        alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
 199        if (!alt)
 200                return -ENODEV;
 201        packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
 202
 203        /* If we don't have enough bandwidth use a lower framerate */
 204        max_packet_size = sd->sensor->max_packet_size[sd->gspca_dev.curr_mode];
 205        if (packet_size < max_packet_size)
 206                stv06xx_write_sensor(sd, PB_ROWSPEED, BIT(4)|BIT(3)|BIT(1));
 207        else
 208                stv06xx_write_sensor(sd, PB_ROWSPEED, BIT(5)|BIT(3)|BIT(1));
 209
 210        /* Setup sensor window */
 211        if (mode & PB0100_CROP_TO_VGA) {
 212                stv06xx_write_sensor(sd, PB_RSTART, 30);
 213                stv06xx_write_sensor(sd, PB_CSTART, 20);
 214                stv06xx_write_sensor(sd, PB_RWSIZE, 240 - 1);
 215                stv06xx_write_sensor(sd, PB_CWSIZE, 320 - 1);
 216        } else {
 217                stv06xx_write_sensor(sd, PB_RSTART, 8);
 218                stv06xx_write_sensor(sd, PB_CSTART, 4);
 219                stv06xx_write_sensor(sd, PB_RWSIZE, 288 - 1);
 220                stv06xx_write_sensor(sd, PB_CWSIZE, 352 - 1);
 221        }
 222
 223        if (mode & PB0100_SUBSAMPLE) {
 224                stv06xx_write_bridge(sd, STV_Y_CTRL, 0x02); /* Wrong, FIXME */
 225                stv06xx_write_bridge(sd, STV_X_CTRL, 0x06);
 226
 227                stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x10);
 228        } else {
 229                stv06xx_write_bridge(sd, STV_Y_CTRL, 0x01);
 230                stv06xx_write_bridge(sd, STV_X_CTRL, 0x0a);
 231                /* larger -> slower */
 232                stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x20);
 233        }
 234
 235        err = stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3)|BIT(1));
 236        PDEBUG(D_STREAM, "Started stream, status: %d", err);
 237
 238        return (err < 0) ? err : 0;
 239}
 240
 241static int pb0100_stop(struct sd *sd)
 242{
 243        struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
 244        int err;
 245
 246        err = stv06xx_write_sensor(sd, PB_ABORTFRAME, 1);
 247
 248        if (err < 0)
 249                goto out;
 250
 251        /* Set bit 1 to zero */
 252        err = stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3));
 253
 254        PDEBUG(D_STREAM, "Halting stream");
 255out:
 256        return (err < 0) ? err : 0;
 257}
 258
 259/* FIXME: Sort the init commands out and put them into tables,
 260          this is only for getting the camera to work */
 261/* FIXME: No error handling for now,
 262          add this once the init has been converted to proper tables */
 263static int pb0100_init(struct sd *sd)
 264{
 265        stv06xx_write_bridge(sd, STV_REG00, 1);
 266        stv06xx_write_bridge(sd, STV_SCAN_RATE, 0);
 267
 268        /* Reset sensor */
 269        stv06xx_write_sensor(sd, PB_RESET, 1);
 270        stv06xx_write_sensor(sd, PB_RESET, 0);
 271
 272        /* Disable chip */
 273        stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3));
 274
 275        /* Gain stuff...*/
 276        stv06xx_write_sensor(sd, PB_PREADCTRL, BIT(12)|BIT(10)|BIT(6));
 277        stv06xx_write_sensor(sd, PB_ADCGLOBALGAIN, 12);
 278
 279        /* Set up auto-exposure */
 280        /* ADC VREF_HI new setting for a transition
 281          from the Expose1 to the Expose2 setting */
 282        stv06xx_write_sensor(sd, PB_R28, 12);
 283        /* gain max for autoexposure */
 284        stv06xx_write_sensor(sd, PB_ADCMAXGAIN, 180);
 285        /* gain min for autoexposure  */
 286        stv06xx_write_sensor(sd, PB_ADCMINGAIN, 12);
 287        /* Maximum frame integration time (programmed into R8)
 288           allowed for auto-exposure routine */
 289        stv06xx_write_sensor(sd, PB_R54, 3);
 290        /* Minimum frame integration time (programmed into R8)
 291           allowed for auto-exposure routine */
 292        stv06xx_write_sensor(sd, PB_R55, 0);
 293        stv06xx_write_sensor(sd, PB_UPDATEINT, 1);
 294        /* R15  Expose0 (maximum that auto-exposure may use) */
 295        stv06xx_write_sensor(sd, PB_R15, 800);
 296        /* R17  Expose2 (minimum that auto-exposure may use) */
 297        stv06xx_write_sensor(sd, PB_R17, 10);
 298
 299        stv06xx_write_sensor(sd, PB_EXPGAIN, 0);
 300
 301        /* 0x14 */
 302        stv06xx_write_sensor(sd, PB_VOFFSET, 0);
 303        /* 0x0D */
 304        stv06xx_write_sensor(sd, PB_ADCGAINH, 11);
 305        /* Set black level (important!) */
 306        stv06xx_write_sensor(sd, PB_ADCGAINL, 0);
 307
 308        /* ??? */
 309        stv06xx_write_bridge(sd, STV_REG00, 0x11);
 310        stv06xx_write_bridge(sd, STV_REG03, 0x45);
 311        stv06xx_write_bridge(sd, STV_REG04, 0x07);
 312
 313        /* Scan/timing for the sensor */
 314        stv06xx_write_sensor(sd, PB_ROWSPEED, BIT(4)|BIT(3)|BIT(1));
 315        stv06xx_write_sensor(sd, PB_CFILLIN, 14);
 316        stv06xx_write_sensor(sd, PB_VBL, 0);
 317        stv06xx_write_sensor(sd, PB_FINTTIME, 0);
 318        stv06xx_write_sensor(sd, PB_RINTTIME, 123);
 319
 320        stv06xx_write_bridge(sd, STV_REG01, 0xc2);
 321        stv06xx_write_bridge(sd, STV_REG02, 0xb0);
 322        return 0;
 323}
 324
 325static int pb0100_dump(struct sd *sd)
 326{
 327        return 0;
 328}
 329
 330static int pb0100_set_gain(struct gspca_dev *gspca_dev, __s32 val)
 331{
 332        int err;
 333        struct sd *sd = (struct sd *) gspca_dev;
 334        struct pb0100_ctrls *ctrls = sd->sensor_priv;
 335
 336        err = stv06xx_write_sensor(sd, PB_G1GAIN, val);
 337        if (!err)
 338                err = stv06xx_write_sensor(sd, PB_G2GAIN, val);
 339        PDEBUG(D_CONF, "Set green gain to %d, status: %d", val, err);
 340
 341        if (!err)
 342                err = pb0100_set_red_balance(gspca_dev, ctrls->red->val);
 343        if (!err)
 344                err = pb0100_set_blue_balance(gspca_dev, ctrls->blue->val);
 345
 346        return err;
 347}
 348
 349static int pb0100_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
 350{
 351        int err;
 352        struct sd *sd = (struct sd *) gspca_dev;
 353        struct pb0100_ctrls *ctrls = sd->sensor_priv;
 354
 355        val += ctrls->gain->val;
 356        if (val < 0)
 357                val = 0;
 358        else if (val > 255)
 359                val = 255;
 360
 361        err = stv06xx_write_sensor(sd, PB_RGAIN, val);
 362        PDEBUG(D_CONF, "Set red gain to %d, status: %d", val, err);
 363
 364        return err;
 365}
 366
 367static int pb0100_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
 368{
 369        int err;
 370        struct sd *sd = (struct sd *) gspca_dev;
 371        struct pb0100_ctrls *ctrls = sd->sensor_priv;
 372
 373        val += ctrls->gain->val;
 374        if (val < 0)
 375                val = 0;
 376        else if (val > 255)
 377                val = 255;
 378
 379        err = stv06xx_write_sensor(sd, PB_BGAIN, val);
 380        PDEBUG(D_CONF, "Set blue gain to %d, status: %d", val, err);
 381
 382        return err;
 383}
 384
 385static int pb0100_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
 386{
 387        struct sd *sd = (struct sd *) gspca_dev;
 388        int err;
 389
 390        err = stv06xx_write_sensor(sd, PB_RINTTIME, val);
 391        PDEBUG(D_CONF, "Set exposure to %d, status: %d", val, err);
 392
 393        return err;
 394}
 395
 396static int pb0100_set_autogain(struct gspca_dev *gspca_dev, __s32 val)
 397{
 398        int err;
 399        struct sd *sd = (struct sd *) gspca_dev;
 400        struct pb0100_ctrls *ctrls = sd->sensor_priv;
 401
 402        if (val) {
 403                if (ctrls->natural->val)
 404                        val = BIT(6)|BIT(4)|BIT(0);
 405                else
 406                        val = BIT(4)|BIT(0);
 407        } else
 408                val = 0;
 409
 410        err = stv06xx_write_sensor(sd, PB_EXPGAIN, val);
 411        PDEBUG(D_CONF, "Set autogain to %d (natural: %d), status: %d",
 412               val, ctrls->natural->val, err);
 413
 414        return err;
 415}
 416
 417static int pb0100_set_autogain_target(struct gspca_dev *gspca_dev, __s32 val)
 418{
 419        int err, totalpixels, brightpixels, darkpixels;
 420        struct sd *sd = (struct sd *) gspca_dev;
 421
 422        /* Number of pixels counted by the sensor when subsampling the pixels.
 423         * Slightly larger than the real value to avoid oscillation */
 424        totalpixels = gspca_dev->pixfmt.width * gspca_dev->pixfmt.height;
 425        totalpixels = totalpixels/(8*8) + totalpixels/(64*64);
 426
 427        brightpixels = (totalpixels * val) >> 8;
 428        darkpixels   = totalpixels - brightpixels;
 429        err = stv06xx_write_sensor(sd, PB_R21, brightpixels);
 430        if (!err)
 431                err = stv06xx_write_sensor(sd, PB_R22, darkpixels);
 432
 433        PDEBUG(D_CONF, "Set autogain target to %d, status: %d", val, err);
 434
 435        return err;
 436}
 437