ov519.c
来自「trident tm5600的linux驱动」· C语言 代码 · 共 2,231 行 · 第 1/4 页
C
2,231 行
* the same register settings as the OV8610, since they are very similar. */static int ov8xx0_configure(struct sd *sd){ int rc; PDEBUG(D_PROBE, "starting ov8xx0 configuration"); /* Detect sensor (sub)type */ rc = i2c_r(sd, OV7610_REG_COM_I); if (rc < 0) { PDEBUG(D_ERR, "Error detecting sensor type"); return -1; } if ((rc & 3) == 1) { sd->sensor = SEN_OV8610; } else { PDEBUG(D_ERR, "Unknown image sensor version: %d", rc & 3); return -1; } /* Set sensor-specific vars *//* sd->sif = 0; already done */ return 0;}/* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses * the same register settings as the OV7610, since they are very similar. */static int ov7xx0_configure(struct sd *sd){ int rc, high, low; PDEBUG(D_PROBE, "starting OV7xx0 configuration"); /* Detect sensor (sub)type */ rc = i2c_r(sd, OV7610_REG_COM_I); /* add OV7670 here * it appears to be wrongly detected as a 7610 by default */ if (rc < 0) { PDEBUG(D_ERR, "Error detecting sensor type"); return -1; } if ((rc & 3) == 3) { /* quick hack to make OV7670s work */ high = i2c_r(sd, 0x0a); low = i2c_r(sd, 0x0b); /* info("%x, %x", high, low); */ if (high == 0x76 && low == 0x73) { PDEBUG(D_PROBE, "Sensor is an OV7670"); sd->sensor = SEN_OV7670; } else { PDEBUG(D_PROBE, "Sensor is an OV7610"); sd->sensor = SEN_OV7610; } } else if ((rc & 3) == 1) { /* I don't know what's different about the 76BE yet. */ if (i2c_r(sd, 0x15) & 1) PDEBUG(D_PROBE, "Sensor is an OV7620AE"); else PDEBUG(D_PROBE, "Sensor is an OV76BE"); /* OV511+ will return all zero isoc data unless we * configure the sensor as a 7620. Someone needs to * find the exact reg. setting that causes this. */ sd->sensor = SEN_OV76BE; } else if ((rc & 3) == 0) { /* try to read product id registers */ high = i2c_r(sd, 0x0a); if (high < 0) { PDEBUG(D_ERR, "Error detecting camera chip PID"); return high; } low = i2c_r(sd, 0x0b); if (low < 0) { PDEBUG(D_ERR, "Error detecting camera chip VER"); return low; } if (high == 0x76) { switch (low) { case 0x30: PDEBUG(D_PROBE, "Sensor is an OV7630/OV7635"); PDEBUG(D_ERR, "7630 is not supported by this driver"); return -1; case 0x40: PDEBUG(D_PROBE, "Sensor is an OV7645"); sd->sensor = SEN_OV7640; /* FIXME */ break; case 0x45: PDEBUG(D_PROBE, "Sensor is an OV7645B"); sd->sensor = SEN_OV7640; /* FIXME */ break; case 0x48: PDEBUG(D_PROBE, "Sensor is an OV7648"); sd->sensor = SEN_OV7640; /* FIXME */ break; default: PDEBUG(D_PROBE, "Unknown sensor: 0x76%x", low); return -1; } } else { PDEBUG(D_PROBE, "Sensor is an OV7620"); sd->sensor = SEN_OV7620; } } else { PDEBUG(D_ERR, "Unknown image sensor version: %d", rc & 3); return -1; } /* Set sensor-specific vars *//* sd->sif = 0; already done */ return 0;}/* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */static int ov6xx0_configure(struct sd *sd){ int rc; PDEBUG(D_PROBE, "starting OV6xx0 configuration"); /* Detect sensor (sub)type */ rc = i2c_r(sd, OV7610_REG_COM_I); if (rc < 0) { PDEBUG(D_ERR, "Error detecting sensor type"); return -1; } /* Ugh. The first two bits are the version bits, but * the entire register value must be used. I guess OVT * underestimated how many variants they would make. */ switch (rc) { case 0x00: sd->sensor = SEN_OV6630; PDEBUG(D_ERR, "WARNING: Sensor is an OV66308. Your camera may have"); PDEBUG(D_ERR, "been misdetected in previous driver versions."); break; case 0x01: sd->sensor = SEN_OV6620; break; case 0x02: sd->sensor = SEN_OV6630; PDEBUG(D_PROBE, "Sensor is an OV66308AE"); break; case 0x03: sd->sensor = SEN_OV6630; PDEBUG(D_PROBE, "Sensor is an OV66308AF"); break; case 0x90: sd->sensor = SEN_OV6630; PDEBUG(D_ERR, "WARNING: Sensor is an OV66307. Your camera may have"); PDEBUG(D_ERR, "been misdetected in previous driver versions."); break; default: PDEBUG(D_ERR, "FATAL: Unknown sensor version: 0x%02x", rc); return -1; } /* Set sensor-specific vars */ sd->sif = 1; return 0;}/* Turns on or off the LED. Only has an effect with OV511+/OV518(+)/OV519 */static void ov51x_led_control(struct sd *sd, int on){/* PDEBUG(D_STREAM, "LED (%s)", on ? "on" : "off"); */ reg_w_mask(sd, OV519_GPIO_DATA_OUT0, !on, 1); /* 0 / 1 */}/* this function is called at probe time */static int sd_config(struct gspca_dev *gspca_dev, const struct usb_device_id *id){ struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; static const struct ov_regvals init_519[] = { { 0x5a, 0x6d }, /* EnableSystem */ { 0x53, 0x9b }, { 0x54, 0xff }, /* set bit2 to enable jpeg */ { 0x5d, 0x03 }, { 0x49, 0x01 }, { 0x48, 0x00 }, /* Set LED pin to output mode. Bit 4 must be cleared or sensor * detection will fail. This deserves further investigation. */ { OV519_GPIO_IO_CTRL0, 0xee }, { 0x51, 0x0f }, /* SetUsbInit */ { 0x51, 0x00 }, { 0x22, 0x00 }, /* windows reads 0x55 at this point*/ }; if (write_regvals(sd, init_519, ARRAY_SIZE(init_519))) goto error; ov51x_led_control(sd, 0); /* turn LED off */ /* Test for 76xx */ if (ov51x_set_slave_ids(sd, OV7xx0_SID) < 0) goto error; /* The OV519 must be more aggressive about sensor detection since * I2C write will never fail if the sensor is not present. We have * to try to initialize the sensor to detect its presence */ if (init_ov_sensor(sd) >= 0) { if (ov7xx0_configure(sd) < 0) { PDEBUG(D_ERR, "Failed to configure OV7xx0"); goto error; } } else { /* Test for 6xx0 */ if (ov51x_set_slave_ids(sd, OV6xx0_SID) < 0) goto error; if (init_ov_sensor(sd) >= 0) { if (ov6xx0_configure(sd) < 0) { PDEBUG(D_ERR, "Failed to configure OV6xx0"); goto error; } } else { /* Test for 8xx0 */ if (ov51x_set_slave_ids(sd, OV8xx0_SID) < 0) goto error; if (init_ov_sensor(sd) < 0) { PDEBUG(D_ERR, "Can't determine sensor slave IDs"); goto error; } if (ov8xx0_configure(sd) < 0) { PDEBUG(D_ERR, "Failed to configure OV8xx0 sensor"); goto error; } } } cam = &gspca_dev->cam; cam->epaddr = OV511_ENDPOINT_ADDRESS; if (!sd->sif) { cam->cam_mode = vga_mode; cam->nmodes = ARRAY_SIZE(vga_mode); } else { cam->cam_mode = sif_mode; cam->nmodes = ARRAY_SIZE(sif_mode); } sd->brightness = BRIGHTNESS_DEF; sd->contrast = CONTRAST_DEF; sd->colors = COLOR_DEF; sd->hflip = HFLIP_DEF; sd->vflip = VFLIP_DEF; if (sd->sensor != SEN_OV7670) gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX); return 0;error: PDEBUG(D_ERR, "OV519 Config failed"); return -EBUSY;}/* this function is called at probe and resume time */static int sd_init(struct gspca_dev *gspca_dev){ struct sd *sd = (struct sd *) gspca_dev; /* initialize the sensor */ switch (sd->sensor) { case SEN_OV6620: if (write_i2c_regvals(sd, norm_6x20, ARRAY_SIZE(norm_6x20))) return -EIO; break; case SEN_OV6630: if (write_i2c_regvals(sd, norm_6x30, ARRAY_SIZE(norm_6x30))) return -EIO; break; default:/* case SEN_OV7610: *//* case SEN_OV76BE: */ if (write_i2c_regvals(sd, norm_7610, ARRAY_SIZE(norm_7610))) return -EIO; break; case SEN_OV7620: if (write_i2c_regvals(sd, norm_7620, ARRAY_SIZE(norm_7620))) return -EIO; break; case SEN_OV7640: if (write_i2c_regvals(sd, norm_7640, ARRAY_SIZE(norm_7640))) return -EIO; break; case SEN_OV7670: if (write_i2c_regvals(sd, norm_7670, ARRAY_SIZE(norm_7670))) return -EIO; break; case SEN_OV8610: if (write_i2c_regvals(sd, norm_8610, ARRAY_SIZE(norm_8610))) return -EIO; break; } return 0;}/* Sets up the OV519 with the given image parameters * * OV519 needs a completely different approach, until we can figure out what * the individual registers do. * * Do not put any sensor-specific code in here (including I2C I/O functions) */static int ov519_mode_init_regs(struct sd *sd){ static const struct ov_regvals mode_init_519_ov7670[] = { { 0x5d, 0x03 }, /* Turn off suspend mode */ { 0x53, 0x9f }, /* was 9b in 1.65-1.08 */ { 0x54, 0x0f }, /* bit2 (jpeg enable) */ { 0xa2, 0x20 }, /* a2-a5 are undocumented */ { 0xa3, 0x18 }, { 0xa4, 0x04 }, { 0xa5, 0x28 }, { 0x37, 0x00 }, /* SetUsbInit */ { 0x55, 0x02 }, /* 4.096 Mhz audio clock */ /* Enable both fields, YUV Input, disable defect comp (why?) */ { 0x20, 0x0c }, { 0x21, 0x38 }, { 0x22, 0x1d }, { 0x17, 0x50 }, /* undocumented */ { 0x37, 0x00 }, /* undocumented */ { 0x40, 0xff }, /* I2C timeout counter */ { 0x46, 0x00 }, /* I2C clock prescaler */ { 0x59, 0x04 }, /* new from windrv 090403 */ { 0xff, 0x00 }, /* undocumented */ /* windows reads 0x55 at this point, why? */ }; static const struct ov_regvals mode_init_519[] = { { 0x5d, 0x03 }, /* Turn off suspend mode */ { 0x53, 0x9f }, /* was 9b in 1.65-1.08 */ { 0x54, 0x0f }, /* bit2 (jpeg enable) */ { 0xa2, 0x20 }, /* a2-a5 are undocumented */ { 0xa3, 0x18 }, { 0xa4, 0x04 }, { 0xa5, 0x28 }, { 0x37, 0x00 }, /* SetUsbInit */ { 0x55, 0x02 }, /* 4.096 Mhz audio clock */ /* Enable both fields, YUV Input, disable defect comp (why?) */ { 0x22, 0x1d }, { 0x17, 0x50 }, /* undocumented */ { 0x37, 0x00 }, /* undocumented */ { 0x40, 0xff }, /* I2C timeout counter */ { 0x46, 0x00 }, /* I2C clock prescaler */ { 0x59, 0x04 }, /* new from windrv 090403 */ { 0xff, 0x00 }, /* undocumented */ /* windows reads 0x55 at this point, why? */ }; /******** Set the mode ********/ if (sd->sensor != SEN_OV7670) { if (write_regvals(sd, mode_init_519, ARRAY_SIZE(mode_init_519))) return -EIO; if (sd->sensor == SEN_OV7640) { /* Select 8-bit input mode */ reg_w_mask(sd, OV519_CAM_DFR, 0x10, 0x10); } } else { if (write_regvals(sd, mode_init_519_ov7670, ARRAY_SIZE(mode_init_519_ov7670))) return -EIO; } reg_w(sd, OV519_CAM_H_SIZE, sd->gspca_dev.width >> 4); reg_w(sd, OV519_CAM_V_SIZE, sd->gspca_dev.height >> 3); reg_w(sd, OV519_CAM_X_OFFSETL, 0x00); reg_w(sd, OV519_CAM_X_OFFSETH, 0x00); reg_w(sd, OV519_CAM_Y_OFFSETL, 0x00); reg_w(sd, OV519_CAM_Y_OFFSETH, 0x00); reg_w(sd, OV519_CAM_DIVIDER, 0x00); reg_w(sd, OV519_CAM_FORMAT, 0x03); /* YUV422 */ reg_w(sd, 0x26, 0x00); /* Undocumented */ /******** Set the framerate ********/ if (frame_rate > 0) sd->frame_rate = frame_rate;/* FIXME: These are only valid at the max resolution. */ sd->clockdiv = 0; switch (sd->sensor) { case SEN_OV7640: switch (sd->frame_rate) {/*fixme: default was 30 fps */ case 30: reg_w(sd, 0xa4, 0x0c); reg_w(sd, 0x23, 0xff); break; case 25: reg_w(sd, 0xa4, 0x0c); reg_w(sd, 0x23, 0x1f); break; case 20: reg_w(sd, 0xa4, 0x0c); reg_w(sd, 0x23, 0x1b); break; default:/* case 15: */ reg_w(sd, 0xa4, 0x04); reg_w(sd, 0x23, 0xff); sd->clockdiv = 1; break; case 10: reg_w(sd, 0xa4, 0x04); reg_w(sd, 0x23, 0x1f); sd->clockdiv = 1; break; case 5: reg_w(sd, 0xa4, 0x04); reg_w(sd, 0x23, 0x1b); sd->clockdiv = 1; break; } break; case SEN_OV8610: switch (sd->frame_rate) { default: /* 15 fps *//* case 15: */ reg_w(sd, 0xa4, 0x06); reg_w(sd, 0x23, 0xff); break; case 10: reg_w(sd, 0xa4, 0x06); reg_w(sd, 0x23, 0x1f); break; case 5: reg_w(sd, 0xa4, 0x06); reg_w(sd, 0x23, 0x1b); break; } break; case SEN_OV7670: /* guesses, based on 7640 */ PDEBUG(D_STREAM, "Setting framerate to %d fps", (sd->frame_rate == 0) ? 15 : sd->frame_rate); reg_w(sd, 0xa4, 0x10); switch (sd->frame_rate) { case 30: reg_w(sd, 0x23, 0xff); break; case 20: reg_w(sd, 0x23, 0x1b); break; default:/* case 15: */ reg_w(sd, 0x23, 0xff); sd->clockdiv = 1; break; } break; } return 0;}static int mode_init_ov_sensor_regs(struct sd *sd){ struct gspca_dev *gspca_dev; int qvga; gspca_dev = &sd->gspca_dev; qvga = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; /******** Mode (VGA/QVGA) and sensor specific regs ********/ switch (sd->sensor) { case SEN_OV8610: /* For OV8610 qvga means qsvga */ i2c_w_mask(sd, OV7610_REG_COM_C, qvga ? (1 << 5) : 0, 1 << 5);#if 0 /* FIXME: Does this improve the image quality or frame rate? */ i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20); i2c_w(sd, 0x24, 0x10); i2c_w(sd, 0x25, qvga ? 0x40 : 0x8a); i2c_w(sd, 0x2f, qvga ? 0x30 : 0xb0); i2c_w(sd, 0x35, qvga ? 0x1c : 0x9c);#endif break; case SEN_OV7610: i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);#if 0 /* FIXME: Does this improve the image quality or frame rate? */ i2c_w_mask(sd, 0x28, qvga?0x00:0x20, 0x20); i2c_w(sd, 0x24, 0x10); i2c_w(sd, 0x25, qvga?0x40:0x8a); i2c_w(sd, 0x2f, qvga?0x30:0xb0); i2c_w(sd, 0x35, qvga?0x1c:0x9c);#endif break; case SEN_OV7620:/* i2c_w(sd, 0x2b, 0x00); */ i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20); i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20); i2c_w(sd, 0x24, qvga ? 0x20 : 0x3a); i2c_w(sd, 0x25, qvga ? 0x30 : 0x60); i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40); i2c_w_mask(sd, 0x67, qvga ? 0xf0 : 0x90, 0xf0); i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20); break; case SEN_OV76BE:/* i2c_w(sd, 0x2b, 0x00); */ i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);#if 0 /* FIXME: Enable this once 7620AE uses 7620 initial settings */ i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20); i2c_w(sd, 0x24, qvga ? 0x20 : 0x3a); i2c_w(sd, 0x25, qvga ? 0x30 : 0x60); i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40); i2c_w_mask(sd, 0x67, qvga ? 0xb0 : 0x90, 0xf0); i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20);#endif break; case SEN_OV7640:/* i2c_w(sd, 0x2b, 0x00); */ i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20); i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20);/* i2c_w(sd, 0x24, qvga ? 0x20 : 0x3a); *//* i2c_w(sd, 0x25, qvga ? 0x30 : 0x60); *//* i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40); *//* i2c_w_mask(sd, 0x67, qvga ? 0xf0 : 0x90, 0xf0); *//* i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20); */ break; case SEN_OV7670: /* set COM7_FMT_VGA or COM7_FMT_QVGA * do we need to set anything else? * HSTART etc are set in set_ov_sensor_window itself */ i2c_w_mask(sd, OV7670_REG_COM7, qvga ? OV7670_COM7_FMT_QVGA : OV7670_COM7_FMT_VGA, OV7670_COM7_FMT_MASK); break; case SEN_OV6620: case SEN_OV6630: i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20); break; default: return -EINVAL; } /******** Palette-specific regs ********/ if (sd->sensor == SEN_OV7610 || sd->sensor == SEN_OV76BE) { /* not valid on the OV6620/OV7620/6630? */ i2c_w_mask(sd, 0x0e, 0x00, 0x40); } /* The OV518 needs special treatment. Although both the OV518 * and the OV6630 support a 16-bit video bus, only the 8 bit Y * bus is actually used. The UV bus is tied to ground. * Therefore, the OV6630 needs to be in 8-bit multiplexed
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?