📄 qc-vv6410.c
字号:
} } } if (!IS_850(qc)) { STV_SET_CHECK(0x1443, sd->subsample ? 0x10 : 0x20); /* Scan rate */ STV_SET_CHECK(0x1446,1); STV_SETW_CHECK(0x15C1,600); /* ISO size, 0x380|orig:600 */ STV_SET_CHECK(0x1680,0x14); /* X ctrl */ } for (i=0; i<SIZE(vv_init); i++) { I2C_SET_CHECK(vv_init[i][0], vv_init[i][1]); if (i<2) if ((r = qc_i2c_wait(qc))<0) goto fail; } if (!sd->compress) { /* Disable compression */ STV_SET_CHECK(0x1443, sd->subsample ? 0x00 : 0x10); /* Scan rate: Larger -> slower */ STV_SETW_CHECK(0x15C1, 1023); /* ISO-Size */ STV_SET_CHECK(0x15C3, 1); /* Y control */ sd->width = 356; sd->height = 292; if (qc->settings.subsample) { //FIXME:subsampling (still) doesn't work yet cols=250; rows=160; sd->width = 180; sd->height = 148; I2C_SET_CHECK(VV6410_SETUP0, BIT(7)|BIT(6)|BIT(1)|BIT(0)); /* Subsampled timing mode */ } } I2C_SET_CHECK(VV6410_XOFFSETH, x >> 8); I2C_SET_CHECK(VV6410_XOFFSETL, x & 0xFF); I2C_SET_CHECK(VV6410_YOFFSETH, y >> 8); I2C_SET_CHECK(VV6410_YOFFSETL, y & 0xFF); I2C_SET_CHECK(VV6410_LINELENGTHH, (cols-1) >> 8); I2C_SET_CHECK(VV6410_LINELENGTHL, (cols-1) & 0xFF); I2C_SET_CHECK(VV6410_FIELDLENGTHH, (rows-1) >> 8); I2C_SET_CHECK(VV6410_FIELDLENGTHL, (rows-1) & 0xFF); sd->maxwidth = sd->width; sd->maxheight = sd->height; return 0;/* }}} */ } else {#endif/* {{{ [fold] Initialization without compression support */ if (sd->compress) return -EINVAL; if (sd->subsample) { sd->maxwidth = 180; sd->maxheight = 148; } else { sd->maxwidth = 356; sd->maxheight = 292; }#if QCEGA_MODE{int line_length = mode?250:416;//415; if (mode) { sd->subsample=1; // quater. sd->width = 180; sd->height = 148; } else { sd->subsample=0; sd->width = 356; sd->height = 292; } STV_SET_CHECK(STV_REG23, 5); // was 5. if (!IS_850(qc)) { /* logitech quickcam web has 0x850 as idProduct */ STV_SET_CHECK(0x1446, 1); } STV_SET_CHECK(STV_SCAN_RATE, 0x00); STV_SET_CHECK(0x1423, 0x04); STV_SET_CHECK(STV_REG00, 0x1b); // 0x0b I2C_SET_CHECK(VV6410_CONTROL,0x04); // reset to defaults if ((r = qc_i2c_wait(qc))<0) goto fail; // CIF or QCIF and sleep. if (IS_850(qc)) { I2C_SET_CHECK(VV6410_CONTROL,(mode?0xa2:0x02)); } else { I2C_SET_CHECK(VV6410_CONTROL,(mode?0xc2:0x02)); } if ((r = qc_i2c_wait(qc))<0) goto fail; I2C_SET_CHECK(VV6410_GAIN,0xfb); if ((r = qc_i2c_wait(qc))<0) goto fail; STV_SET_CHECK(STV_REG04, 0x07); STV_SET_CHECK(STV_REG03, 0x45); /* set window size */ if ((r=vv6410_set_window(qc,0,0,48,64)) < 0) { PRINTK(KERN_ERR, "vv6410_set_window failed"); goto fail; } /* EXPERIMENTAL */ /* * line length default is 415 so it's the value we use to * calculate values for registers 0x20-0x21 * Ref. DS Pag. 67 */ I2C_SET_CHECK(0x20,mode? ((line_length-23)>>8):((line_length-51)>>8)); I2C_SET_CHECK(0x21,mode?((line_length-23)&0xff):((line_length-51)&0xff)); I2C_SET_CHECK(0x22,mode?0x00:0x01); //usb_quickcam_i2c_add(&i2cbuff,0x23,mode?0x9e:0x3e); I2C_SET_CHECK(0x23,mode?158:318&0xff); I2C_SET_CHECK(0x24,0xfa); // clock divisor. I2C_SET_CHECK(0x25,0x01); if ((r = qc_i2c_wait(qc))<0) goto fail; /* if (isaweb(dev)) { //EXPERIMENTAL: dark/black pixel cancellation usb_quickcam_i2c_add(&i2cbuff,0x3e,0x01); usb_quickcam_i2c_add(&i2cbuff,0x72,0x01); if (usb_quickcam_i2c_send(dev,&i2cbuff,VV6410_ADDR) < 0) { printk(KERN_ERR "usb_control_msg dark/black pixel failed"); goto error; } } */ STV_SET_CHECK(STV_REG01, 0xb7); STV_SET_CHECK(STV_REG02, 0xa7); // setup I2C_SET_CHECK(0x11,0x18); // 0x18 or Jochen 0x40 I2C_SET_CHECK(0x14,0x55); // was 0x55 I2C_SET_CHECK(0x15,0x10); // 0x10 or Jochen:0x00 I2C_SET_CHECK(0x16,0x81); // Pre clock dividor. I2C_SET_CHECK(0x17,0x18); // they are reserved. I2C_SET_CHECK(0x18,0x00); I2C_SET_CHECK(0x77,0x5e); I2C_SET_CHECK(0x78,0x04);// 0x04 or Jochen:0x00 if (IS_850(qc)) { I2C_SET_CHECK(0x79,0x11);//audio init } if ((r = qc_i2c_wait(qc))<0) goto fail; STV_SETW_CHECK(STV_ISO_SIZE, IS_850(qc)?1023:600); // 0x380|orig:600 STV_SET_CHECK(STV_Y_CTRL, 1); STV_SET_CHECK(STV_SCAN_RATE, mode?0x00:0x10); if (!IS_850(qc)) { /* logitech quickam web has 0x0850 as idProduct */ STV_SET_CHECK(STV_X_CTRL, 0x14); }}#else STV_SET_CHECK(0x0423,0x05); /* Unknown register, 0x04 or 0x05 */ STV_SET_CHECK(0x1423,0x04); /* Unknown register, 0x04 or 0x05 */ STV_SET_CHECK(0x1443,0x00); /* Scan rate */ STV_SET_CHECK(0x1500,0x1B); /* 0x0B */ STV_SET_CHECK(0x1501,0xB7); STV_SET_CHECK(0x1502,0xA7); STV_SET_CHECK(0x1503,0x45); STV_SET_CHECK(0x1504,0x07); STV_SET_CHECK(0x15C3,1); /* Y ctrl */ if (IS_850(qc)) { STV_SET_CHECK(0x1443, sd->subsample ? 0x20 : 0x10); /* Scan rate */ STV_SETW_CHECK(0x15C1,1023); /* ISO size, 0x380|orig:600 */ } else { STV_SET_CHECK(0x1443, sd->subsample ? 0x10 : 0x20); /* Scan rate */ STV_SET_CHECK(0x1446,1); STV_SETW_CHECK(0x15C1,600); /* ISO size, 0x380|orig:600 */ STV_SET_CHECK(0x1680,0x14); /* X ctrl */ } I2C_SET_CHECK(0x10,0x04); /* Control register: reset to defaults */ if ((r = qc_i2c_wait(qc))<0) goto fail; I2C_SET_CHECK(0x10,sd->subsample ? 0xC2 : 0x02);/* Control register: CIF or QCIF and sleep */ if ((r = qc_i2c_wait(qc))<0) goto fail; I2C_SET_CHECK(0x11,0x18); /* 0x18 or Jochen 0x40 */ I2C_SET_CHECK(0x14,0x55); I2C_SET_CHECK(0x15,0x10); /* 0x10 or Jochen:0x00 */ I2C_SET_CHECK(0x16,0x81); /* Pre clock dividor. */ I2C_SET_CHECK(0x17,0x18); /* they are reserved. */ I2C_SET_CHECK(0x18,0x00); I2C_SET_CHECK(0x24,0xFB); /* Set gain value */ I2C_SET_CHECK(0x25,0x01); /* Clock divisor value */ I2C_SET_CHECK(0x77,0x5E); I2C_SET_CHECK(0x78,0x04); /* 0x04 or Jochen:0x00 */ if (IS_850(qc)) { I2C_SET_CHECK(0x3E,0x01); /* EXPERIMENTAL: dark/black pixel cancellation */ I2C_SET_CHECK(0x72,0x01); } if ((r = qc_i2c_wait(qc))<0) goto fail;#endif return 0;/* }}} */#if COMPRESS }#endiffail: return r;}/* }}} *//* {{{ [fold] vv6410_set_exposure() */static int vv6410_set_exposure(struct quickcam *qc, unsigned int val){ struct qc_sensor_data *sd = &qc->sensor_data; static const unsigned int linelength = 415; /* For CIF */ unsigned int fine; unsigned int coarse; int r; val = (val*val >> 14) + val/4; if (sd->exposure==val) return 0; sd->exposure = val; fine = val % linelength; coarse = val / linelength; if (coarse>=512) coarse = 512; if (qcdebug&QC_DEBUGLOGIC) PDEBUG("vv6410_set_exposure %d (%i,%i)",val,coarse,fine); I2C_SET_CHECK(VV6410_FINEH, fine >> 8); I2C_SET_CHECK(VV6410_FINEL, fine & 0xFF); I2C_SET_CHECK(VV6410_COARSEH, coarse >> 8); I2C_SET_CHECK(VV6410_COARSEL, coarse & 0xFF);fail: return r;}/* }}} *//* {{{ [fold] vv6410_set_gains() */static int vv6410_set_gains(struct quickcam *qc, unsigned int hue, unsigned int sat, unsigned int val){ static const int maxgain = 13; /* Absolute maximum is 14, recommended is 12 */ struct qc_sensor_data *sd = &qc->sensor_data; unsigned int gain; int r; if (qcdebug&QC_DEBUGLOGIC) PDEBUG("vv6410_set_gains %d %d %d", hue, sat, val); gain = val / 256; gain >>= 4; if (gain > maxgain) gain = maxgain; if (sd->rgain==gain) return 0; sd->rgain = gain; r = qc_i2c_set(qc, VV6410_ANALOGGAIN, 0xF0 | gain); return r;}/* }}} *//* {{{ [fold] vv6410_set_levels() */static int vv6410_set_levels(struct quickcam *qc, unsigned int exp, unsigned int gain, unsigned int hue, unsigned int sat){ int r; if ((r = vv6410_set_exposure(qc, exp))<0) goto fail; vv6410_set_gains(qc, hue, sat, gain);fail: return r;}/* }}} *//* {{{ [fold] struct qc_sensor qc_sensor_vv6410 */const struct qc_sensor qc_sensor_vv6410 = { name: "VV6410", manufacturer: "ST Microelectronics", init: vv6410_init, start: vv6410_start, stop: vv6410_stop, set_size: vv6410_set_size, set_levels: vv6410_set_levels, /* Exposure and gain control information */ autoexposure: FALSE, adapt_gainlow: 40000, adapt_gainhigh: 65535, /* Information needed to access the sensor via I2C */ reg23: 5, i2c_addr: VV6410_ADDR, /* Identification information used for auto-detection */ id_reg: VV6410_DEVICEH, id: 0x19, length_id: 1,};/* }}} *//* End of file */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -