linux/drivers/media/usb/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#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  32
  33#include "stv06xx_hdcs.h"
  34
  35static struct v4l2_pix_format hdcs1x00_mode[] = {
  36        {
  37                HDCS_1X00_DEF_WIDTH,
  38                HDCS_1X00_DEF_HEIGHT,
  39                V4L2_PIX_FMT_SGRBG8,
  40                V4L2_FIELD_NONE,
  41                .sizeimage =
  42                        HDCS_1X00_DEF_WIDTH * HDCS_1X00_DEF_HEIGHT,
  43                .bytesperline = HDCS_1X00_DEF_WIDTH,
  44                .colorspace = V4L2_COLORSPACE_SRGB,
  45                .priv = 1
  46        }
  47};
  48
  49static struct v4l2_pix_format hdcs1020_mode[] = {
  50        {
  51                HDCS_1020_DEF_WIDTH,
  52                HDCS_1020_DEF_HEIGHT,
  53                V4L2_PIX_FMT_SGRBG8,
  54                V4L2_FIELD_NONE,
  55                .sizeimage =
  56                        HDCS_1020_DEF_WIDTH * HDCS_1020_DEF_HEIGHT,
  57                .bytesperline = HDCS_1020_DEF_WIDTH,
  58                .colorspace = V4L2_COLORSPACE_SRGB,
  59                .priv = 1
  60        }
  61};
  62
  63enum hdcs_power_state {
  64        HDCS_STATE_SLEEP,
  65        HDCS_STATE_IDLE,
  66        HDCS_STATE_RUN
  67};
  68
  69/* no lock? */
  70struct hdcs {
  71        enum hdcs_power_state state;
  72        int w, h;
  73
  74        /* visible area of the sensor array */
  75        struct {
  76                int left, top;
  77                int width, height;
  78                int border;
  79        } array;
  80
  81        struct {
  82                /* Column timing overhead */
  83                u8 cto;
  84                /* Column processing overhead */
  85                u8 cpo;
  86                /* Row sample period constant */
  87                u16 rs;
  88                /* Exposure reset duration */
  89                u16 er;
  90        } exp;
  91
  92        int psmp;
  93};
  94
  95static int hdcs_reg_write_seq(struct sd *sd, u8 reg, u8 *vals, u8 len)
  96{
  97        u8 regs[I2C_MAX_BYTES * 2];
  98        int i;
  99
 100        if (unlikely((len <= 0) || (len >= I2C_MAX_BYTES) ||
 101                     (reg + len > 0xff)))
 102                return -EINVAL;
 103
 104        for (i = 0; i < len; i++) {
 105                regs[2 * i] = reg;
 106                regs[2 * i + 1] = vals[i];
 107                /* All addresses are shifted left one bit
 108                 * as bit 0 toggles r/w */
 109                reg += 2;
 110        }
 111
 112        return stv06xx_write_sensor_bytes(sd, regs, len);
 113}
 114
 115static int hdcs_set_state(struct sd *sd, enum hdcs_power_state state)
 116{
 117        struct hdcs *hdcs = sd->sensor_priv;
 118        u8 val;
 119        int ret;
 120
 121        if (hdcs->state == state)
 122                return 0;
 123
 124        /* we need to go idle before running or sleeping */
 125        if (hdcs->state != HDCS_STATE_IDLE) {
 126                ret = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), 0);
 127                if (ret)
 128                        return ret;
 129        }
 130
 131        hdcs->state = HDCS_STATE_IDLE;
 132
 133        if (state == HDCS_STATE_IDLE)
 134                return 0;
 135
 136        switch (state) {
 137        case HDCS_STATE_SLEEP:
 138                val = HDCS_SLEEP_MODE;
 139                break;
 140
 141        case HDCS_STATE_RUN:
 142                val = HDCS_RUN_ENABLE;
 143                break;
 144
 145        default:
 146                return -EINVAL;
 147        }
 148
 149        ret = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), val);
 150
 151        /* Update the state if the write succeeded */
 152        if (!ret)
 153                hdcs->state = state;
 154
 155        return ret;
 156}
 157
 158static int hdcs_reset(struct sd *sd)
 159{
 160        struct hdcs *hdcs = sd->sensor_priv;
 161        int err;
 162
 163        err = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), 1);
 164        if (err < 0)
 165                return err;
 166
 167        err = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), 0);
 168        if (err < 0)
 169                hdcs->state = HDCS_STATE_IDLE;
 170
 171        return err;
 172}
 173
 174static int hdcs_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
 175{
 176        struct sd *sd = (struct sd *) gspca_dev;
 177        struct hdcs *hdcs = sd->sensor_priv;
 178        int rowexp, srowexp;
 179        int max_srowexp;
 180        /* Column time period */
 181        int ct;
 182        /* Column processing period */
 183        int cp;
 184        /* Row processing period */
 185        int rp;
 186        /* Minimum number of column timing periods
 187           within the column processing period */
 188        int mnct;
 189        int cycles, err;
 190        u8 exp[14];
 191
 192        cycles = val * HDCS_CLK_FREQ_MHZ * 257;
 193
 194        ct = hdcs->exp.cto + hdcs->psmp + (HDCS_ADC_START_SIG_DUR + 2);
 195        cp = hdcs->exp.cto + (hdcs->w * ct / 2);
 196
 197        /* the cycles one row takes */
 198        rp = hdcs->exp.rs + cp;
 199
 200        rowexp = cycles / rp;
 201
 202        /* the remaining cycles */
 203        cycles -= rowexp * rp;
 204
 205        /* calculate sub-row exposure */
 206        if (IS_1020(sd)) {
 207                /* see HDCS-1020 datasheet 3.5.6.4, p. 63 */
 208                srowexp = hdcs->w - (cycles + hdcs->exp.er + 13) / ct;
 209
 210                mnct = (hdcs->exp.er + 12 + ct - 1) / ct;
 211                max_srowexp = hdcs->w - mnct;
 212        } else {
 213                /* see HDCS-1000 datasheet 3.4.5.5, p. 61 */
 214                srowexp = cp - hdcs->exp.er - 6 - cycles;
 215
 216                mnct = (hdcs->exp.er + 5 + ct - 1) / ct;
 217                max_srowexp = cp - mnct * ct - 1;
 218        }
 219
 220        if (srowexp < 0)
 221                srowexp = 0;
 222        else if (srowexp > max_srowexp)
 223                srowexp = max_srowexp;
 224
 225        if (IS_1020(sd)) {
 226                exp[0] = HDCS20_CONTROL;
 227                exp[1] = 0x00;          /* Stop streaming */
 228                exp[2] = HDCS_ROWEXPL;
 229                exp[3] = rowexp & 0xff;
 230                exp[4] = HDCS_ROWEXPH;
 231                exp[5] = rowexp >> 8;
 232                exp[6] = HDCS20_SROWEXP;
 233                exp[7] = (srowexp >> 2) & 0xff;
 234                exp[8] = HDCS20_ERROR;
 235                exp[9] = 0x10;          /* Clear exposure error flag*/
 236                exp[10] = HDCS20_CONTROL;
 237                exp[11] = 0x04;         /* Restart streaming */
 238                err = stv06xx_write_sensor_bytes(sd, exp, 6);
 239        } else {
 240                exp[0] = HDCS00_CONTROL;
 241                exp[1] = 0x00;         /* Stop streaming */
 242                exp[2] = HDCS_ROWEXPL;
 243                exp[3] = rowexp & 0xff;
 244                exp[4] = HDCS_ROWEXPH;
 245                exp[5] = rowexp >> 8;
 246                exp[6] = HDCS00_SROWEXPL;
 247                exp[7] = srowexp & 0xff;
 248                exp[8] = HDCS00_SROWEXPH;
 249                exp[9] = srowexp >> 8;
 250                exp[10] = HDCS_STATUS;
 251                exp[11] = 0x10;         /* Clear exposure error flag*/
 252                exp[12] = HDCS00_CONTROL;
 253                exp[13] = 0x04;         /* Restart streaming */
 254                err = stv06xx_write_sensor_bytes(sd, exp, 7);
 255                if (err < 0)
 256                        return err;
 257        }
 258        PDEBUG(D_CONF, "Writing exposure %d, rowexp %d, srowexp %d",
 259               val, rowexp, srowexp);
 260        return err;
 261}
 262
 263static int hdcs_set_gains(struct sd *sd, u8 g)
 264{
 265        int err;
 266        u8 gains[4];
 267
 268        /* the voltage gain Av = (1 + 19 * val / 127) * (1 + bit7) */
 269        if (g > 127)
 270                g = 0x80 | (g / 2);
 271
 272        gains[0] = g;
 273        gains[1] = g;
 274        gains[2] = g;
 275        gains[3] = g;
 276
 277        err = hdcs_reg_write_seq(sd, HDCS_ERECPGA, gains, 4);
 278        return err;
 279}
 280
 281static int hdcs_set_gain(struct gspca_dev *gspca_dev, __s32 val)
 282{
 283        PDEBUG(D_CONF, "Writing gain %d", val);
 284        return hdcs_set_gains((struct sd *) gspca_dev,
 285                               val & 0xff);
 286}
 287
 288static int hdcs_set_size(struct sd *sd,
 289                unsigned int width, unsigned int height)
 290{
 291        struct hdcs *hdcs = sd->sensor_priv;
 292        u8 win[4];
 293        unsigned int x, y;
 294        int err;
 295
 296        /* must be multiple of 4 */
 297        width = (width + 3) & ~0x3;
 298        height = (height + 3) & ~0x3;
 299
 300        if (width > hdcs->array.width)
 301                width = hdcs->array.width;
 302
 303        if (IS_1020(sd)) {
 304                /* the borders are also invalid */
 305                if (height + 2 * hdcs->array.border + HDCS_1020_BOTTOM_Y_SKIP
 306                                  > hdcs->array.height)
 307                        height = hdcs->array.height - 2 * hdcs->array.border -
 308                                HDCS_1020_BOTTOM_Y_SKIP;
 309
 310                y = (hdcs->array.height - HDCS_1020_BOTTOM_Y_SKIP - height) / 2
 311                                + hdcs->array.top;
 312        } else {
 313                if (height > hdcs->array.height)
 314                        height = hdcs->array.height;
 315
 316                y = hdcs->array.top + (hdcs->array.height - height) / 2;
 317        }
 318
 319        x = hdcs->array.left + (hdcs->array.width - width) / 2;
 320
 321        win[0] = y / 4;
 322        win[1] = x / 4;
 323        win[2] = (y + height) / 4 - 1;
 324        win[3] = (x + width) / 4 - 1;
 325
 326        err = hdcs_reg_write_seq(sd, HDCS_FWROW, win, 4);
 327        if (err < 0)
 328                return err;
 329
 330        /* Update the current width and height */
 331        hdcs->w = width;
 332        hdcs->h = height;
 333        return err;
 334}
 335
 336static int hdcs_s_ctrl(struct v4l2_ctrl *ctrl)
 337{
 338        struct gspca_dev *gspca_dev =
 339                container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
 340        int err = -EINVAL;
 341
 342        switch (ctrl->id) {
 343        case V4L2_CID_GAIN:
 344                err = hdcs_set_gain(gspca_dev, ctrl->val);
 345                break;
 346        case V4L2_CID_EXPOSURE:
 347                err = hdcs_set_exposure(gspca_dev, ctrl->val);
 348                break;
 349        }
 350        return err;
 351}
 352
 353static const struct v4l2_ctrl_ops hdcs_ctrl_ops = {
 354        .s_ctrl = hdcs_s_ctrl,
 355};
 356
 357static int hdcs_init_controls(struct sd *sd)
 358{
 359        struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
 360
 361        v4l2_ctrl_handler_init(hdl, 2);
 362        v4l2_ctrl_new_std(hdl, &hdcs_ctrl_ops,
 363                        V4L2_CID_EXPOSURE, 0, 0xff, 1, HDCS_DEFAULT_EXPOSURE);
 364        v4l2_ctrl_new_std(hdl, &hdcs_ctrl_ops,
 365                        V4L2_CID_GAIN, 0, 0xff, 1, HDCS_DEFAULT_GAIN);
 366        return hdl->error;
 367}
 368
 369static int hdcs_probe_1x00(struct sd *sd)
 370{
 371        struct hdcs *hdcs;
 372        u16 sensor;
 373        int ret;
 374
 375        ret = stv06xx_read_sensor(sd, HDCS_IDENT, &sensor);
 376        if (ret < 0 || sensor != 0x08)
 377                return -ENODEV;
 378
 379        pr_info("HDCS-1000/1100 sensor detected\n");
 380
 381        sd->gspca_dev.cam.cam_mode = hdcs1x00_mode;
 382        sd->gspca_dev.cam.nmodes = ARRAY_SIZE(hdcs1x00_mode);
 383
 384        hdcs = kmalloc(sizeof(struct hdcs), GFP_KERNEL);
 385        if (!hdcs)
 386                return -ENOMEM;
 387
 388        hdcs->array.left = 8;
 389        hdcs->array.top = 8;
 390        hdcs->array.width = HDCS_1X00_DEF_WIDTH;
 391        hdcs->array.height = HDCS_1X00_DEF_HEIGHT;
 392        hdcs->array.border = 4;
 393
 394        hdcs->exp.cto = 4;
 395        hdcs->exp.cpo = 2;
 396        hdcs->exp.rs = 186;
 397        hdcs->exp.er = 100;
 398
 399        /*
 400         * Frame rate on HDCS-1000 with STV600 depends on PSMP:
 401         *  4 = doesn't work at all
 402         *  5 = 7.8 fps,
 403         *  6 = 6.9 fps,
 404         *  8 = 6.3 fps,
 405         * 10 = 5.5 fps,
 406         * 15 = 4.4 fps,
 407         * 31 = 2.8 fps
 408         *
 409         * Frame rate on HDCS-1000 with STV602 depends on PSMP:
 410         * 15 = doesn't work at all
 411         * 18 = doesn't work at all
 412         * 19 = 7.3 fps
 413         * 20 = 7.4 fps
 414         * 21 = 7.4 fps
 415         * 22 = 7.4 fps
 416         * 24 = 6.3 fps
 417         * 30 = 5.4 fps
 418         */
 419        hdcs->psmp = (sd->bridge == BRIDGE_STV602) ? 20 : 5;
 420
 421        sd->sensor_priv = hdcs;
 422
 423        return 0;
 424}
 425
 426static int hdcs_probe_1020(struct sd *sd)
 427{
 428        struct hdcs *hdcs;
 429        u16 sensor;
 430        int ret;
 431
 432        ret = stv06xx_read_sensor(sd, HDCS_IDENT, &sensor);
 433        if (ret < 0 || sensor != 0x10)
 434                return -ENODEV;
 435
 436        pr_info("HDCS-1020 sensor detected\n");
 437
 438        sd->gspca_dev.cam.cam_mode = hdcs1020_mode;
 439        sd->gspca_dev.cam.nmodes = ARRAY_SIZE(hdcs1020_mode);
 440
 441        hdcs = kmalloc(sizeof(struct hdcs), GFP_KERNEL);
 442        if (!hdcs)
 443                return -ENOMEM;
 444
 445        /*
 446         * From Andrey's test image: looks like HDCS-1020 upper-left
 447         * visible pixel is at 24,8 (y maybe even smaller?) and lower-right
 448         * visible pixel at 375,299 (x maybe even larger?)
 449         */
 450        hdcs->array.left = 24;
 451        hdcs->array.top  = 4;
 452        hdcs->array.width = HDCS_1020_DEF_WIDTH;
 453        hdcs->array.height = 304;
 454        hdcs->array.border = 4;
 455
 456        hdcs->psmp = 6;
 457
 458        hdcs->exp.cto = 3;
 459        hdcs->exp.cpo = 3;
 460        hdcs->exp.rs = 155;
 461        hdcs->exp.er = 96;
 462
 463        sd->sensor_priv = hdcs;
 464
 465        return 0;
 466}
 467
 468static int hdcs_start(struct sd *sd)
 469{
 470        struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
 471
 472        PDEBUG(D_STREAM, "Starting stream");
 473
 474        return hdcs_set_state(sd, HDCS_STATE_RUN);
 475}
 476
 477static int hdcs_stop(struct sd *sd)
 478{
 479        struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
 480
 481        PDEBUG(D_STREAM, "Halting stream");
 482
 483        return hdcs_set_state(sd, HDCS_STATE_SLEEP);
 484}
 485
 486static int hdcs_init(struct sd *sd)
 487{
 488        struct hdcs *hdcs = sd->sensor_priv;
 489        int i, err = 0;
 490
 491        /* Set the STV0602AA in STV0600 emulation mode */
 492        if (sd->bridge == BRIDGE_STV602)
 493                stv06xx_write_bridge(sd, STV_STV0600_EMULATION, 1);
 494
 495        /* Execute the bridge init */
 496        for (i = 0; i < ARRAY_SIZE(stv_bridge_init) && !err; i++) {
 497                err = stv06xx_write_bridge(sd, stv_bridge_init[i][0],
 498                                           stv_bridge_init[i][1]);
 499        }
 500        if (err < 0)
 501                return err;
 502
 503        /* sensor soft reset */
 504        hdcs_reset(sd);
 505
 506        /* Execute the sensor init */
 507        for (i = 0; i < ARRAY_SIZE(stv_sensor_init) && !err; i++) {
 508                err = stv06xx_write_sensor(sd, stv_sensor_init[i][0],
 509                                             stv_sensor_init[i][1]);
 510        }
 511        if (err < 0)
 512                return err;
 513
 514        /* Enable continuous frame capture, bit 2: stop when frame complete */
 515        err = stv06xx_write_sensor(sd, HDCS_REG_CONFIG(sd), BIT(3));
 516        if (err < 0)
 517                return err;
 518
 519        /* Set PGA sample duration
 520        (was 0x7E for the STV602, but caused slow framerate with HDCS-1020) */
 521        if (IS_1020(sd))
 522                err = stv06xx_write_sensor(sd, HDCS_TCTRL,
 523                                (HDCS_ADC_START_SIG_DUR << 6) | hdcs->psmp);
 524        else
 525                err = stv06xx_write_sensor(sd, HDCS_TCTRL,
 526                                (HDCS_ADC_START_SIG_DUR << 5) | hdcs->psmp);
 527        if (err < 0)
 528                return err;
 529
 530        return hdcs_set_size(sd, hdcs->array.width, hdcs->array.height);
 531}
 532
 533static int hdcs_dump(struct sd *sd)
 534{
 535        u16 reg, val;
 536
 537        pr_info("Dumping sensor registers:\n");
 538
 539        for (reg = HDCS_IDENT; reg <= HDCS_ROWEXPH; reg++) {
 540                stv06xx_read_sensor(sd, reg, &val);
 541                pr_info("reg 0x%02x = 0x%02x\n", reg, val);
 542        }
 543        return 0;
 544}
 545