📄 ov511.c
字号:
PDEBUG(5, "reg read: 0x%02X:0x%02X", reg, buffer[0]); if (rc < 0) { err("reg read: error %d", rc); return rc; } else { return buffer[0]; }}static int ov511_i2c_write(struct usb_device *dev, unsigned char reg, unsigned char value){ int rc, retries; PDEBUG(5, "i2c write: 0x%02X:0x%02X", reg, value); /* Three byte write cycle */ for (retries = OV511_I2C_RETRIES; ; ) { /* Select camera register */ rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_3_BYTE, reg); if (rc < 0) goto error; /* Write "value" to I2C data port of OV511 */ rc = ov511_reg_write(dev, OV511_REG_I2C_DATA_PORT, value); if (rc < 0) goto error; /* Initiate 3-byte write cycle */ rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x01); if (rc < 0) goto error; do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL); while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */ if (rc < 0) goto error; if ((rc&2) == 0) /* Ack? */ break;#if 0 /* I2C abort */ ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10);#endif if (--retries < 0) { err("i2c write retries exhausted"); rc = -1; goto error; } } return 0;error: err("i2c write: error %d", rc); return rc;}/* returns: negative is error, pos or zero is data */static int ov511_i2c_read(struct usb_device *dev, unsigned char reg){ int rc, value, retries; /* Two byte write cycle */ for (retries = OV511_I2C_RETRIES; ; ) { /* Select camera register */ rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_2_BYTE, reg); if (rc < 0) goto error; /* Initiate 2-byte write cycle */ rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x03); if (rc < 0) goto error; do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL); while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */ if (rc < 0) goto error; if ((rc&2) == 0) /* Ack? */ break; /* I2C abort */ ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10); if (--retries < 0) { err("i2c write retries exhausted"); rc = -1; goto error; } } /* Two byte read cycle */ for (retries = OV511_I2C_RETRIES; ; ) { /* Initiate 2-byte read cycle */ rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05); if (rc < 0) goto error; do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL); while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */ if (rc < 0) goto error; if ((rc&2) == 0) /* Ack? */ break; /* I2C abort */ rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10); if (rc < 0) goto error; if (--retries < 0) { err("i2c read retries exhausted"); rc = -1; goto error; } } value = ov511_reg_read(dev, OV511_REG_I2C_DATA_PORT); PDEBUG(5, "i2c read: 0x%02X:0x%02X", reg, value); /* This is needed to make ov511_i2c_write() work */ rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05); if (rc < 0) goto error; return value;error: err("i2c read: error %d", rc); return rc;}static int ov511_write_regvals(struct usb_device *dev, struct ov511_regvals * pRegvals){ int rc; while (pRegvals->bus != OV511_DONE_BUS) { if (pRegvals->bus == OV511_REG_BUS) { if ((rc = ov511_reg_write(dev, pRegvals->reg, pRegvals->val)) < 0) goto error; } else if (pRegvals->bus == OV511_I2C_BUS) { if ((rc = ov511_i2c_write(dev, pRegvals->reg, pRegvals->val)) < 0) goto error; } else { err("Bad regval array"); rc = -1; goto error; } pRegvals++; } return 0;error: err("write regvals: error %d", rc); return rc;}#ifdef OV511_DEBUG static void ov511_dump_i2c_range(struct usb_device *dev, int reg1, int regn){ int i; int rc; for(i = reg1; i <= regn; i++) { rc = ov511_i2c_read(dev, i); PDEBUG(1, "OV7610[0x%X] = 0x%X", i, rc); }}static void ov511_dump_i2c_regs(struct usb_device *dev){ PDEBUG(3, "I2C REGS"); ov511_dump_i2c_range(dev, 0x00, 0x7C);}#if 0static void ov511_dump_reg_range(struct usb_device *dev, int reg1, int regn){ int i; int rc; for(i = reg1; i <= regn; i++) { rc = ov511_reg_read(dev, i); PDEBUG(1, "OV511[0x%X] = 0x%X", i, rc); }}static void ov511_dump_regs(struct usb_device *dev){ PDEBUG(1, "CAMERA INTERFACE REGS"); ov511_dump_reg_range(dev, 0x10, 0x1f); PDEBUG(1, "DRAM INTERFACE REGS"); ov511_dump_reg_range(dev, 0x20, 0x23); PDEBUG(1, "ISO FIFO REGS"); ov511_dump_reg_range(dev, 0x30, 0x31); PDEBUG(1, "PIO REGS"); ov511_dump_reg_range(dev, 0x38, 0x39); ov511_dump_reg_range(dev, 0x3e, 0x3e); PDEBUG(1, "I2C REGS"); ov511_dump_reg_range(dev, 0x40, 0x49); PDEBUG(1, "SYSTEM CONTROL REGS"); ov511_dump_reg_range(dev, 0x50, 0x55); ov511_dump_reg_range(dev, 0x5e, 0x5f); PDEBUG(1, "OmniCE REGS"); ov511_dump_reg_range(dev, 0x70, 0x79); ov511_dump_reg_range(dev, 0x80, 0x9f); ov511_dump_reg_range(dev, 0xa0, 0xbf);}#endif#endifstatic int ov511_reset(struct usb_device *dev, unsigned char reset_type){ int rc; PDEBUG(4, "Reset: type=0x%X", reset_type); rc = ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, reset_type); rc = ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0); if (rc < 0) err("reset: command failed"); return rc;}/* Temporarily stops OV511 from functioning. Must do this before changing * registers while the camera is streaming */static inline int ov511_stop(struct usb_device *dev){ PDEBUG(4, "stopping"); return (ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0x3d));}/* Restarts OV511 after ov511_stop() is called */static inline int ov511_restart(struct usb_device *dev){ PDEBUG(4, "restarting"); return (ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0x00));}static int ov511_set_packet_size(struct usb_ov511 *ov511, int size){ int alt, mult; if (ov511_stop(ov511->dev) < 0) return -EIO; mult = size >> 5; if (ov511->bridge == BRG_OV511) { if (size == 0) alt = OV511_ALT_SIZE_0; else if (size == 257) alt = OV511_ALT_SIZE_257; else if (size == 513) alt = OV511_ALT_SIZE_513; else if (size == 769) alt = OV511_ALT_SIZE_769; else if (size == 993) alt = OV511_ALT_SIZE_993; else { err("Set packet size: invalid size (%d)", size); return -EINVAL; } } else if (ov511->bridge == BRG_OV511PLUS) { if (size == 0) alt = OV511PLUS_ALT_SIZE_0; else if (size == 33) alt = OV511PLUS_ALT_SIZE_33; else if (size == 129) alt = OV511PLUS_ALT_SIZE_129; else if (size == 257) alt = OV511PLUS_ALT_SIZE_257; else if (size == 385) alt = OV511PLUS_ALT_SIZE_385; else if (size == 513) alt = OV511PLUS_ALT_SIZE_513; else if (size == 769) alt = OV511PLUS_ALT_SIZE_769; else if (size == 961) alt = OV511PLUS_ALT_SIZE_961; else { err("Set packet size: invalid size (%d)", size); return -EINVAL; } } else { err("Set packet size: Invalid bridge type"); return -EINVAL; } PDEBUG(3, "set packet size: %d, mult=%d, alt=%d", size, mult, alt); if (ov511_reg_write(ov511->dev, OV511_REG_FIFO_PACKET_SIZE, mult) < 0) return -ENOMEM; if (usb_set_interface(ov511->dev, ov511->iface, alt) < 0) { err("Set packet size: set interface error"); return -EBUSY; } // FIXME - Should we only reset the FIFO? if (ov511_reset(ov511->dev, OV511_RESET_NOREGS) < 0) return -ENOMEM; ov511->packet_size = size; if (ov511_restart(ov511->dev) < 0) return -EIO; return 0;}static inline intov7610_set_picture(struct usb_ov511 *ov511, struct video_picture *p){ int ret; struct usb_device *dev = ov511->dev; PDEBUG(4, "ov511_set_picture"); if (ov511_stop(dev) < 0) return -EIO; ov511->contrast = p->contrast; ov511->brightness = p->brightness; ov511->colour = p->colour; ov511->hue = p->hue; ov511->whiteness = p->whiteness; if ((ret = ov511_i2c_read(dev, OV7610_REG_COM_B)) < 0) return -EIO;#if 0 /* disable auto adjust mode */ if (ov511_i2c_write(dev, OV7610_REG_COM_B, ret & 0xfe) < 0) return -EIO;#endif if (ov511->sensor == SEN_OV7610 || ov511->sensor == SEN_OV7620AE || ov511->sensor == SEN_OV6620) if (ov511_i2c_write(dev, OV7610_REG_SAT, p->colour >> 8) < 0) return -EIO; if (ov511->sensor == SEN_OV7610 || ov511->sensor == SEN_OV6620) { if (ov511_i2c_write(dev, OV7610_REG_CNT, p->contrast >> 8) < 0) return -EIO; if (ov511_i2c_write(dev, OV7610_REG_RED, 0xFF - (p->hue >> 8)) < 0) return -EIO; if (ov511_i2c_write(dev, OV7610_REG_BLUE, p->hue >> 8) < 0) return -EIO; if (ov511_i2c_write(dev, OV7610_REG_BRT, p->brightness >> 8) < 0) return -EIO; } else if ((ov511->sensor == SEN_OV7620) || (ov511->sensor == SEN_OV7620AE)) {#if 0 int cur_sat, new_sat, tmp; cur_sat = ov511_i2c_read(dev, OV7610_REG_BLUE); tmp = (p->hue >> 8) - cur_sat; new_sat = (tmp < 0) ? (-tmp) | 0x80 : tmp; PDEBUG(1, "cur=%d target=%d diff=%d", cur_sat, p->hue >> 8, tmp); if (ov511_i2c_write(dev, OV7610_REG_BLUE, new_sat) < 0) return -EIO; // DEBUG_CODE PDEBUG(1, "hue=%d", ov511_i2c_read(dev, OV7610_REG_BLUE)); #endif } if (ov511_restart(dev) < 0) return -EIO; return 0;}static inline intov7610_get_picture(struct usb_ov511 *ov511, struct video_picture *p){ int ret; struct usb_device *dev = ov511->dev; PDEBUG(4, "ov511_get_picture"); if (ov511_stop(dev) < 0) return -EIO; if ((ret = ov511_i2c_read(dev, OV7610_REG_SAT)) < 0) return -EIO; p->colour = ret << 8; if ((ret = ov511_i2c_read(dev, OV7610_REG_CNT)) < 0) return -EIO; p->contrast = ret << 8; if ((ret = ov511_i2c_read(dev, OV7610_REG_BRT)) < 0) return -EIO; p->brightness = ret << 8; /* This may not be the best way to do it */ if ((ret = ov511_i2c_read(dev, OV7610_REG_BLUE)) < 0) return -EIO; p->hue = ret << 8; p->whiteness = 105 << 8; /* Can we get these from frame[0]? -claudio? */ p->depth = ov511->frame[0].depth; p->palette = ov511->frame[0].format; if (ov511_restart(dev) < 0) return -EIO; return 0;}/* Returns number of bits per pixel (regardless of where they are located; planar or * not), or zero for unsupported format. */static int ov511_get_depth(int palette){ switch (palette) { case VIDEO_PALETTE_GREY: return 8; case VIDEO_PALETTE_RGB565: return 16; case VIDEO_PALETTE_RGB24: return 24; case VIDEO_PALETTE_YUV422: return 16; case VIDEO_PALETTE_YUYV: return 16; case VIDEO_PALETTE_YUV420: return 24; case VIDEO_PALETTE_YUV422P: return 24; /* Planar */ default: return 0; /* Invalid format */ }}/* LNCNT values fixed by Lawrence Glaister <lg@jfm.bc.ca> */static struct mode_list mlist[] = { /* W H C PXCNT LNCNT PXDIV LNDIV M420 COMA COML */ { 640, 480, 0, 0x4f, 0x3b, 0x00, 0x00, 0x03, 0x24, 0x9e }, { 640, 480, 1, 0x4f, 0x3b, 0x00, 0x00, 0x03, 0x24, 0x9e }, { 320, 240, 0, 0x27, 0x1d, 0x00, 0x00, 0x03, 0x04, 0x1e }, { 320, 240, 1, 0x27, 0x1d, 0x00, 0x00, 0x03, 0x04, 0x1e }, { 352, 288, 0, 0x2b, 0x25, 0x00, 0x00, 0x03, 0x04, 0x1e }, { 352, 288, 1, 0x2b, 0x25, 0x00, 0x00, 0x03, 0x04, 0x1e }, { 384, 288, 0, 0x2f, 0x25, 0x00, 0x00, 0x03, 0x04, 0x1e }, { 384, 288, 1, 0x2f, 0x25, 0x00, 0x00, 0x03, 0x04, 0x1e }, { 448, 336, 0, 0x37, 0x29, 0x00, 0x00, 0x03, 0x04, 0x1e }, { 448, 336, 1, 0x37, 0x29, 0x00, 0x00, 0x03, 0x04, 0x1e }, { 176, 144, 0, 0x15, 0x12, 0x00, 0x00, 0x03, 0x04, 0x1e }, { 176, 144, 1, 0x15, 0x12, 0x00, 0x00, 0x03, 0x04, 0x1e }, { 160, 120, 0, 0x13, 0x0e, 0x00, 0x00, 0x03, 0x04, 0x1e }, { 160, 120, 1, 0x13, 0x0e, 0x00, 0x00, 0x03, 0x04, 0x1e }, { 0, 0 }};static intov511_mode_init_regs(struct usb_ov511 *ov511, int width, int height, int mode, int sub_flag){ int i; struct usb_device *dev = ov511->dev; int hwsbase, hwebase, vwsbase, vwebase, hwsize, vwsize; int hwscale = 0, vwscale = 0; PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d", width, height, mode, sub_flag); if (ov511_stop(ov511->dev) < 0) return -EIO; /* Dumppix only works with RGB24 */ if (dumppix && (mode != VIDEO_PALETTE_RGB24)) { err("dumppix only supported with RGB 24"); return -EINVAL; } if (mode == VIDEO_PALETTE_GREY) { ov511_reg_write(dev, 0x16, 0x00); if (ov511->sensor == SEN_OV7610 || ov511->sensor == SEN_OV7620AE) { /* these aren't valid on the OV6620/OV7620 */ ov511_i2c_write(dev, 0x0e, 0x44); } ov511_i2c_write(dev, 0x13, autoadjust ? 0x21 : 0x20); /* For snapshot */ ov511_reg_write(dev, 0x1e, 0x00); ov511_reg_write(dev, 0x1f, 0x01); } else { ov511_reg_write(dev, 0x16, 0x01); if (ov511->sensor == SEN_OV7610 || ov511->sensor == SEN_OV7620AE) { /* not valid on the OV6620/OV7620 */ ov511_i2c_write(dev, 0x0e, 0x04); } ov511_i2c_write(dev, 0x13, autoadjust ? 0x01 : 0x00); /* For snapshot */ ov511_reg_write(dev, 0x1e, 0x01); ov511_reg_write(dev, 0x1f, 0x03); } /* The different sensor ICs handle setting up of window differently */ switch (ov511->sensor) { case SEN_OV7610: case SEN_OV7620AE: hwsbase = 0x38; hwebase = 0x3a; vwsbase = vwebase = 0x05; break; case SEN_OV6620: hwsbase = 0x38; hwebase = 0x3a; vwsbase = 0x05; vwebase = 0x06; break; case SEN_OV7620: hwsbase = 0x2c; hwebase = 0x2d; vwsbase = vwebase = 0x05; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -