linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.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 * Copyright (c) 2008 Chia-I Wu
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License as published by
  10 * the Free Software Foundation; either version 2 of the License, or
  11 * (at your option) any later version.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU General Public License
  19 * along with this program; if not, write to the Free Software
  20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  21 *
  22 * P/N 861037:      Sensor HDCS1000        ASIC STV0600
  23 * P/N 861050-0010: Sensor HDCS1000        ASIC STV0600
  24 * P/N 861050-0020: Sensor Photobit PB100  ASIC STV0600-1 - QuickCam Express
  25 * P/N 861055:      Sensor ST VV6410       ASIC STV0610   - LEGO cam
  26 * P/N 861075-0040: Sensor HDCS1000        ASIC
  27 * P/N 961179-0700: Sensor ST VV6410       ASIC STV0602   - Dexxa WebCam USB
  28 * P/N 861040-0000: Sensor ST VV6410       ASIC STV0610   - QuickCam Web
  29 */
  30
  31#include "stv06xx_hdcs.h"
  32
  33static const struct ctrl hdcs1x00_ctrl[] = {
  34        {
  35                {
  36                        .id             = V4L2_CID_EXPOSURE,
  37                        .type           = V4L2_CTRL_TYPE_INTEGER,
  38                        .name           = "exposure",
  39                        .minimum        = 0x00,
  40                        .maximum        = 0xff,
  41                        .step           = 0x1,
  42                        .default_value  = HDCS_DEFAULT_EXPOSURE,
  43                        .flags          = V4L2_CTRL_FLAG_SLIDER
  44                },
  45                .set = hdcs_set_exposure,
  46                .get = hdcs_get_exposure
  47        }, {
  48                {
  49                        .id             = V4L2_CID_GAIN,
  50                        .type           = V4L2_CTRL_TYPE_INTEGER,
  51                        .name           = "gain",
  52                        .minimum        = 0x00,
  53                        .maximum        = 0xff,
  54                        .step           = 0x1,
  55                        .default_value  = HDCS_DEFAULT_GAIN,
  56                        .flags          = V4L2_CTRL_FLAG_SLIDER
  57                },
  58                .set = hdcs_set_gain,
  59                .get = hdcs_get_gain
  60        }
  61};
  62
  63static struct v4l2_pix_format hdcs1x00_mode[] = {
  64        {
  65                HDCS_1X00_DEF_WIDTH,
  66                HDCS_1X00_DEF_HEIGHT,
  67                V4L2_PIX_FMT_SGRBG8,
  68                V4L2_FIELD_NONE,
  69                .sizeimage =
  70                        HDCS_1X00_DEF_WIDTH * HDCS_1X00_DEF_HEIGHT,
  71                .bytesperline = HDCS_1X00_DEF_WIDTH,
  72                .colorspace = V4L2_COLORSPACE_SRGB,
  73                .priv = 1
  74        }
  75};
  76
  77static const struct ctrl hdcs1020_ctrl[] = {
  78        {
  79                {
  80                        .id             = V4L2_CID_EXPOSURE,
  81                        .type           = V4L2_CTRL_TYPE_INTEGER,
  82                        .name           = "exposure",
  83                        .minimum        = 0x00,
  84                        .maximum        = 0xffff,
  85                        .step           = 0x1,
  86                        .default_value  = HDCS_DEFAULT_EXPOSURE,
  87                        .flags          = V4L2_CTRL_FLAG_SLIDER
  88                },
  89                .set = hdcs_set_exposure,
  90                .get = hdcs_get_exposure
  91        }, {
  92                {
  93                        .id             = V4L2_CID_GAIN,
  94                        .type           = V4L2_CTRL_TYPE_INTEGER,
  95                        .name           = "gain",
  96                        .minimum        = 0x00,
  97                        .maximum        = 0xff,
  98                        .step           = 0x1,
  99                        .default_value  = HDCS_DEFAULT_GAIN,
 100                        .flags          = V4L2_CTRL_FLAG_SLIDER
 101                },
 102                .set = hdcs_set_gain,
 103                .get = hdcs_get_gain
 104        }
 105};
 106
 107static struct v4l2_pix_format hdcs1020_mode[] = {
 108        {
 109                HDCS_1020_DEF_WIDTH,
 110                HDCS_1020_DEF_HEIGHT,
 111                V4L2_PIX_FMT_SGRBG8,
 112                V4L2_FIELD_NONE,
 113                .sizeimage =
 114                        HDCS_1020_DEF_WIDTH * HDCS_1020_DEF_HEIGHT,
 115                .bytesperline = HDCS_1020_DEF_WIDTH,
 116                .colorspace = V4L2_COLORSPACE_SRGB,
 117                .priv = 1
 118        }
 119};
 120
 121enum hdcs_power_state {
 122        HDCS_STATE_SLEEP,
 123        HDCS_STATE_IDLE,
 124        HDCS_STATE_RUN
 125};
 126
 127/* no lock? */
 128struct hdcs {
 129        enum hdcs_power_state state;
 130        int w, h;
 131
 132        /* visible area of the sensor array */
 133        struct {
 134                int left, top;
 135                int width, height;
 136                int border;
 137        } array;
 138
 139        struct {
 140                /* Column timing overhead */
 141                u8 cto;
 142                /* Column processing overhead */
 143                u8 cpo;
 144                /* Row sample period constant */
 145                u16 rs;
 146                /* Exposure reset duration */
 147                u16 er;
 148        } exp;
 149
 150        int psmp;
 151        u8 exp_cache, gain_cache;
 152};
 153
 154static int hdcs_reg_write_seq(struct sd *sd, u8 reg, u8 *vals, u8 len)
 155{
 156        u8 regs[I2C_MAX_BYTES * 2];
 157        int i;
 158
 159        if (unlikely((len <= 0) || (len >= I2C_MAX_BYTES) ||
 160                     (reg + len > 0xff)))
 161                return -EINVAL;
 162
 163        for (i = 0; i < len; i++) {
 164                regs[2 * i] = reg;
 165                regs[2 * i + 1] = vals[i];
 166                /* All addresses are shifted left one bit as bit 0 toggles r/w */
 167                reg += 2;
 168        }
 169
 170        return stv06xx_write_sensor_bytes(sd, regs, len);
 171}
 172
 173static int hdcs_set_state(struct sd *sd, enum hdcs_power_state state)
 174{
 175        struct hdcs *hdcs = sd->sensor_priv;
 176        u8 val;
 177        int ret;
 178
 179        if (hdcs->state == state)
 180                return 0;
 181
 182        /* we need to go idle before running or sleeping */
 183        if (hdcs->state != HDCS_STATE_IDLE) {
 184                ret = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), 0);
 185                if (ret)
 186                        return ret;
 187        }
 188
 189        hdcs->state = HDCS_STATE_IDLE;
 190
 191        if (state == HDCS_STATE_IDLE)
 192                return 0;
 193
 194        switch (state) {
 195        case HDCS_STATE_SLEEP:
 196                val = HDCS_SLEEP_MODE;
 197                break;
 198
 199        case HDCS_STATE_RUN:
 200                val = HDCS_RUN_ENABLE;
 201                break;
 202
 203        default:
 204                return -EINVAL;
 205        }
 206
 207        ret = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), val);
 208
 209        /* Update the state if the write succeeded */
 210        if (!ret)
 211                hdcs->state = state;
 212
 213        return ret;
 214}
 215
 216static int hdcs_reset(struct sd *sd)
 217{
 218        struct hdcs *hdcs = sd->sensor_priv;
 219        int err;
 220
 221        err = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), 1);
 222        if (err < 0)
 223                return err;
 224
 225        err = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), 0);
 226        if (err < 0)
 227                hdcs->state = HDCS_STATE_IDLE;
 228
 229        return err;
 230}
 231
 232static int hdcs_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
 233{
 234        struct sd *sd = (struct sd *) gspca_dev;
 235        struct hdcs *hdcs = sd->sensor_priv;
 236
 237        *val = hdcs->exp_cache;
 238
 239        return 0;
 240}
 241
 242static int hdcs_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
 243{
 244        struct sd *sd = (struct sd *) gspca_dev;
 245        struct hdcs *hdcs = sd->sensor_priv;
 246        int rowexp, srowexp;
 247        int max_srowexp;
 248        /* Column time period */
 249        int ct;
 250        /* Column processing period */
 251        int cp;
 252        /* Row processing period */
 253        int rp;
 254        /* Minimum number of column timing periods
 255           within the column processing period */
 256        int mnct;
 257        int cycles, err;
 258        u8 exp[14];
 259
 260        val &= 0xff;
 261        hdcs->exp_cache = val;
 262
 263        cycles = val * HDCS_CLK_FREQ_MHZ * 257;
 264
 265        ct = hdcs->exp.cto + hdcs->psmp + (HDCS_ADC_START_SIG_DUR + 2);
 266        cp = hdcs->exp.cto + (hdcs->w * ct / 2);
 267
 268        /* the cycles one row takes */
 269        rp = hdcs->exp.rs + cp;
 270
 271        rowexp = cycles / rp;
 272
 273        /* the remaining cycles */
 274        cycles -= rowexp * rp;
 275
 276        /* calculate sub-row exposure */
 277        if (IS_1020(sd)) {
 278                /* see HDCS-1020 datasheet 3.5.6.4, p. 63 */
 279                srowexp = hdcs->w - (cycles + hdcs->exp.er + 13) / ct;
 280
 281                mnct = (hdcs->exp.er + 12 + ct - 1) / ct;
 282                max_srowexp = hdcs->w - mnct;
 283        } else {
 284                /* see HDCS-1000 datasheet 3.4.5.5, p. 61 */
 285                srowexp = cp - hdcs->exp.er - 6 - cycles;
 286
 287                mnct = (hdcs->exp.er + 5 + ct - 1) / ct;
 288                max_srowexp = cp - mnct * ct - 1;
 289        }
 290
 291        if (srowexp < 0)
 292                srowexp = 0;
 293        else if (srowexp > max_srowexp)
 294                srowexp = max_srowexp;
 295
 296        if (IS_1020(sd)) {
 297                exp[0] = HDCS20_CONTROL;
 298                exp[1] = 0x00;          /* Stop streaming */
 299                exp[2] = HDCS_ROWEXPL;
 300                exp[3] = rowexp & 0xff;
 301                exp[4] = HDCS_ROWEXPH;
 302                exp[5] = rowexp >> 8;
 303                exp[6] = HDCS20_SROWEXP;
 304                exp[7] = (srowexp >> 2) & 0xff;
 305                exp[8] = HDCS20_ERROR;
 306                exp[9] = 0x10;          /* Clear exposure error flag*/
 307                exp[10] = HDCS20_CONTROL;
 308                exp[11] = 0x04;         /* Restart streaming */
 309                err = stv06xx_write_sensor_bytes(sd, exp, 6);
 310        } else {
 311                exp[0] = HDCS00_CONTROL;
 312                exp[1] = 0x00;         /* Stop streaming */
 313                exp[2] = HDCS_ROWEXPL;
 314                exp[3] = rowexp & 0xff;
 315                exp[4] = HDCS_ROWEXPH;
 316                exp[5] = rowexp >> 8;
 317                exp[6] = HDCS00_SROWEXPL;
 318                exp[7] = srowexp & 0xff;
 319                exp[8] = HDCS00_SROWEXPH;
 320                exp[9] = srowexp >> 8;
 321                exp[10] = HDCS_STATUS;
 322                exp[11] = 0x10;         /* Clear exposure error flag*/
 323                exp[12] = HDCS00_CONTROL;
 324                exp[13] = 0x04;         /* Restart streaming */
 325                err = stv06xx_write_sensor_bytes(sd, exp, 7);
 326                if (err < 0)
 327                        return err;
 328        }
 329        PDEBUG(D_V4L2, "Writing exposure %d, rowexp %d, srowexp %d",
 330               val, rowexp, srowexp);
 331        return err;
 332}
 333
 334static int hdcs_set_gains(struct sd *sd, u8 g)
 335{
 336        struct hdcs *hdcs = sd->sensor_priv;
 337        int err;
 338        u8 gains[4];
 339
 340        hdcs->gain_cache = g;
 341
 342        /* the voltage gain Av = (1 + 19 * val / 127) * (1 + bit7) */
 343        if (g > 127)
 344                g = 0x80 | (g / 2);
 345
 346        gains[0] = g;
 347        gains[1] = g;
 348        gains[2] = g;
 349        gains[3] = g;
 350
 351        err = hdcs_reg_write_seq(sd, HDCS_ERECPGA, gains, 4);
 352                return err;
 353}
 354
 355static int hdcs_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
 356{
 357        struct sd *sd = (struct sd *) gspca_dev;
 358        struct hdcs *hdcs = sd->sensor_priv;
 359
 360        *val = hdcs->gain_cache;
 361
 362        return 0;
 363}
 364
 365static int hdcs_set_gain(struct gspca_dev *gspca_dev, __s32 val)
 366{
 367        PDEBUG(D_V4L2, "Writing gain %d", val);
 368        return hdcs_set_gains((struct sd *) gspca_dev,
 369                               val & 0xff);
 370}
 371
 372static int hdcs_set_size(struct sd *sd,
 373                unsigned int width, unsigned int height)
 374{
 375        struct hdcs *hdcs = sd->sensor_priv;
 376        u8 win[4];
 377        unsigned int x, y;
 378        int err;
 379
 380        /* must be multiple of 4 */
 381        width = (width + 3) & ~0x3;
 382        height = (height + 3) & ~0x3;
 383
 384        if (width > hdcs->array.width)
 385                width = hdcs->array.width;
 386
 387        if (IS_1020(sd)) {
 388                /* the borders are also invalid */
 389                if (height + 2 * hdcs->array.border + HDCS_1020_BOTTOM_Y_SKIP
 390                                  > hdcs->array.height)
 391                        height = hdcs->array.height - 2 * hdcs->array.border -
 392                                HDCS_1020_BOTTOM_Y_SKIP;
 393
 394                y = (hdcs->array.height - HDCS_1020_BOTTOM_Y_SKIP - height) / 2
 395                                + hdcs->array.top;
 396        } else {
 397                if (height > hdcs->array.height)
 398                        height = hdcs->array.height;
 399
 400                y = hdcs->array.top + (hdcs->array.height - height) / 2;
 401        }
 402
 403        x = hdcs->array.left + (hdcs->array.width - width) / 2;
 404
 405        win[0] = y / 4;
 406        win[1] = x / 4;
 407        win[2] = (y + height) / 4 - 1;
 408        win[3] = (x + width) / 4 - 1;
 409
 410        err = hdcs_reg_write_seq(sd, HDCS_FWROW, win, 4);
 411        if (err < 0)
 412                return err;
 413
 414        /* Update the current width and height */
 415        hdcs->w = width;
 416        hdcs->h = height;
 417        return err;
 418}
 419
 420static int hdcs_probe_1x00(struct sd *sd)
 421{
 422        struct hdcs *hdcs;
 423        u16 sensor;
 424        int ret;
 425
 426        ret = stv06xx_read_sensor(sd, HDCS_IDENT, &sensor);
 427        if (ret < 0 || sensor != 0x08)
 428                return -ENODEV;
 429
 430        info("HDCS-1000/1100 sensor detected");
 431
 432        sd->gspca_dev.cam.cam_mode = hdcs1x00_mode;
 433        sd->gspca_dev.cam.nmodes = ARRAY_SIZE(hdcs1x00_mode);
 434        sd->desc.ctrls = hdcs1x00_ctrl;
 435        sd->desc.nctrls = ARRAY_SIZE(hdcs1x00_ctrl);
 436
 437        hdcs = kmalloc(sizeof(struct hdcs), GFP_KERNEL);
 438        if (!hdcs)
 439                return -ENOMEM;
 440
 441        hdcs->array.left = 8;
 442        hdcs->array.top = 8;
 443        hdcs->array.width = HDCS_1X00_DEF_WIDTH;
 444        hdcs->array.height = HDCS_1X00_DEF_HEIGHT;
 445        hdcs->array.border = 4;
 446
 447        hdcs->exp.cto = 4;
 448        hdcs->exp.cpo = 2;
 449        hdcs->exp.rs = 186;
 450        hdcs->exp.er = 100;
 451
 452        /*
 453         * Frame rate on HDCS-1000 with STV600 depends on PSMP:
 454         *  4 = doesn't work at all
 455         *  5 = 7.8 fps,
 456         *  6 = 6.9 fps,
 457         *  8 = 6.3 fps,
 458         * 10 = 5.5 fps,
 459         * 15 = 4.4 fps,
 460         * 31 = 2.8 fps
 461         *
 462         * Frame rate on HDCS-1000 with STV602 depends on PSMP:
 463         * 15 = doesn't work at all
 464         * 18 = doesn't work at all
 465         * 19 = 7.3 fps
 466         * 20 = 7.4 fps
 467         * 21 = 7.4 fps
 468         * 22 = 7.4 fps
 469         * 24 = 6.3 fps
 470         * 30 = 5.4 fps
 471         */
 472        hdcs->psmp = (sd->bridge == BRIDGE_STV602) ? 20 : 5;
 473
 474        sd->sensor_priv = hdcs;
 475
 476        return 0;
 477}
 478
 479static int hdcs_probe_1020(struct sd *sd)
 480{
 481        struct hdcs *hdcs;
 482        u16 sensor;
 483        int ret;
 484
 485        ret = stv06xx_read_sensor(sd, HDCS_IDENT, &sensor);
 486        if (ret < 0 || sensor != 0x10)
 487                return -ENODEV;
 488
 489        info("HDCS-1020 sensor detected");
 490
 491        sd->gspca_dev.cam.cam_mode = hdcs1020_mode;
 492        sd->gspca_dev.cam.nmodes = ARRAY_SIZE(hdcs1020_mode);
 493        sd->desc.ctrls = hdcs1020_ctrl;
 494        sd->desc.nctrls = ARRAY_SIZE(hdcs1020_ctrl);
 495
 496        hdcs = kmalloc(sizeof(struct hdcs), GFP_KERNEL);
 497        if (!hdcs)
 498                return -ENOMEM;
 499
 500        /*
 501         * From Andrey's test image: looks like HDCS-1020 upper-left
 502         * visible pixel is at 24,8 (y maybe even smaller?) and lower-right
 503         * visible pixel at 375,299 (x maybe even larger?)
 504         */
 505        hdcs->array.left = 24;
 506        hdcs->array.top  = 4;
 507        hdcs->array.width = HDCS_1020_DEF_WIDTH;
 508        hdcs->array.height = 304;
 509        hdcs->array.border = 4;
 510
 511        hdcs->psmp = 6;
 512
 513        hdcs->exp.cto = 3;
 514        hdcs->exp.cpo = 3;
 515        hdcs->exp.rs = 155;
 516        hdcs->exp.er = 96;
 517
 518        sd->sensor_priv = hdcs;
 519
 520        return 0;
 521}
 522
 523static int hdcs_start(struct sd *sd)
 524{
 525        PDEBUG(D_STREAM, "Starting stream");
 526
 527        return hdcs_set_state(sd, HDCS_STATE_RUN);
 528}
 529
 530static int hdcs_stop(struct sd *sd)
 531{
 532        PDEBUG(D_STREAM, "Halting stream");
 533
 534        return hdcs_set_state(sd, HDCS_STATE_SLEEP);
 535}
 536
 537static void hdcs_disconnect(struct sd *sd)
 538{
 539        PDEBUG(D_PROBE, "Disconnecting the sensor");
 540        kfree(sd->sensor_priv);
 541}
 542
 543static int hdcs_init(struct sd *sd)
 544{
 545        struct hdcs *hdcs = sd->sensor_priv;
 546        int i, err = 0;
 547
 548        /* Set the STV0602AA in STV0600 emulation mode */
 549        if (sd->bridge == BRIDGE_STV602)
 550                stv06xx_write_bridge(sd, STV_STV0600_EMULATION, 1);
 551
 552        /* Execute the bridge init */
 553        for (i = 0; i < ARRAY_SIZE(stv_bridge_init) && !err; i++) {
 554                err = stv06xx_write_bridge(sd, stv_bridge_init[i][0],
 555                                           stv_bridge_init[i][1]);
 556        }
 557        if (err < 0)
 558                return err;
 559
 560        /* sensor soft reset */
 561        hdcs_reset(sd);
 562
 563        /* Execute the sensor init */
 564        for (i = 0; i < ARRAY_SIZE(stv_sensor_init) && !err; i++) {
 565                err = stv06xx_write_sensor(sd, stv_sensor_init[i][0],
 566                                             stv_sensor_init[i][1]);
 567        }
 568        if (err < 0)
 569                return err;
 570
 571        /* Enable continous frame capture, bit 2: stop when frame complete */
 572        err = stv06xx_write_sensor(sd, HDCS_REG_CONFIG(sd), BIT(3));
 573        if (err < 0)
 574                return err;
 575
 576        /* Set PGA sample duration
 577        (was 0x7E for the STV602, but caused slow framerate with HDCS-1020) */
 578        if (IS_1020(sd))
 579                err = stv06xx_write_sensor(sd, HDCS_TCTRL,
 580                                (HDCS_ADC_START_SIG_DUR << 6) | hdcs->psmp);
 581        else
 582                err = stv06xx_write_sensor(sd, HDCS_TCTRL,
 583                                (HDCS_ADC_START_SIG_DUR << 5) | hdcs->psmp);
 584        if (err < 0)
 585                return err;
 586
 587        err = hdcs_set_gains(sd, HDCS_DEFAULT_GAIN);
 588        if (err < 0)
 589                return err;
 590
 591        err = hdcs_set_size(sd, hdcs->array.width, hdcs->array.height);
 592        if (err < 0)
 593                return err;
 594
 595        err = hdcs_set_exposure(&sd->gspca_dev, HDCS_DEFAULT_EXPOSURE);
 596        return err;
 597}
 598
 599static int hdcs_dump(struct sd *sd)
 600{
 601        u16 reg, val;
 602
 603        info("Dumping sensor registers:");
 604
 605        for (reg = HDCS_IDENT; reg <= HDCS_ROWEXPH; reg++) {
 606                stv06xx_read_sensor(sd, reg, &val);
 607                info("reg 0x%02x = 0x%02x", reg, val);
 608        }
 609        return 0;
 610}
 611