📄 ov511.c
字号:
if (rc < 0) return rc; } reg++; } return 0;}static intov51x_reset(struct usb_ov511 *ov, unsigned char reset_type){ int rc; /* Setting bit 0 not allowed on 518/518Plus */ if (ov->bclass == BCL_OV518) reset_type &= 0xfe; PDEBUG(4, "Reset: type=0x%02X", reset_type); rc = reg_w(ov, R51x_SYS_RESET, reset_type); rc = reg_w(ov, R51x_SYS_RESET, 0); if (rc < 0) err("reset: command failed"); return rc;}/********************************************************************** * * Low-level I2C I/O functions * **********************************************************************//* NOTE: Do not call this function directly! * The OV518 I2C I/O procedure is different, hence, this function. * This is normally only called from i2c_w(). Note that this function * always succeeds regardless of whether the sensor is present and working. */static intov518_i2c_write_internal(struct usb_ov511 *ov, unsigned char reg, unsigned char value){ int rc; PDEBUG(5, "0x%02X:0x%02X", reg, value); /* Select camera register */ rc = reg_w(ov, R51x_I2C_SADDR_3, reg); if (rc < 0) return rc; /* Write "value" to I2C data port of OV511 */ rc = reg_w(ov, R51x_I2C_DATA, value); if (rc < 0) return rc; /* Initiate 3-byte write cycle */ rc = reg_w(ov, R518_I2C_CTL, 0x01); if (rc < 0) return rc; return 0;}/* NOTE: Do not call this function directly! */static intov511_i2c_write_internal(struct usb_ov511 *ov, unsigned char reg, unsigned char value){ int rc, retries; PDEBUG(5, "0x%02X:0x%02X", reg, value); /* Three byte write cycle */ for (retries = OV511_I2C_RETRIES; ; ) { /* Select camera register */ rc = reg_w(ov, R51x_I2C_SADDR_3, reg); if (rc < 0) break; /* Write "value" to I2C data port of OV511 */ rc = reg_w(ov, R51x_I2C_DATA, value); if (rc < 0) break; /* Initiate 3-byte write cycle */ rc = reg_w(ov, R511_I2C_CTL, 0x01); if (rc < 0) break; /* Retry until idle */ do rc = reg_r(ov, R511_I2C_CTL); while (rc > 0 && ((rc&1) == 0)); if (rc < 0) break; /* Ack? */ if ((rc&2) == 0) { rc = 0; break; }#if 0 /* I2C abort */ reg_w(ov, R511_I2C_CTL, 0x10);#endif if (--retries < 0) { err("i2c write retries exhausted"); rc = -1; break; } } return rc;}/* NOTE: Do not call this function directly! * The OV518 I2C I/O procedure is different, hence, this function. * This is normally only called from i2c_r(). Note that this function * always succeeds regardless of whether the sensor is present and working. */static intov518_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg){ int rc, value; /* Select camera register */ rc = reg_w(ov, R51x_I2C_SADDR_2, reg); if (rc < 0) return rc; /* Initiate 2-byte write cycle */ rc = reg_w(ov, R518_I2C_CTL, 0x03); if (rc < 0) return rc; /* Initiate 2-byte read cycle */ rc = reg_w(ov, R518_I2C_CTL, 0x05); if (rc < 0) return rc; value = reg_r(ov, R51x_I2C_DATA); PDEBUG(5, "0x%02X:0x%02X", reg, value); return value;}/* NOTE: Do not call this function directly! * returns: negative is error, pos or zero is data */static intov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg){ int rc, value, retries; /* Two byte write cycle */ for (retries = OV511_I2C_RETRIES; ; ) { /* Select camera register */ rc = reg_w(ov, R51x_I2C_SADDR_2, reg); if (rc < 0) return rc; /* Initiate 2-byte write cycle */ rc = reg_w(ov, R511_I2C_CTL, 0x03); if (rc < 0) return rc; /* Retry until idle */ do rc = reg_r(ov, R511_I2C_CTL); while (rc > 0 && ((rc&1) == 0)); if (rc < 0) return rc; if ((rc&2) == 0) /* Ack? */ break; /* I2C abort */ reg_w(ov, R511_I2C_CTL, 0x10); if (--retries < 0) { err("i2c write retries exhausted"); return -1; } } /* Two byte read cycle */ for (retries = OV511_I2C_RETRIES; ; ) { /* Initiate 2-byte read cycle */ rc = reg_w(ov, R511_I2C_CTL, 0x05); if (rc < 0) return rc; /* Retry until idle */ do rc = reg_r(ov, R511_I2C_CTL); while (rc > 0 && ((rc&1) == 0)); if (rc < 0) return rc; if ((rc&2) == 0) /* Ack? */ break; /* I2C abort */ rc = reg_w(ov, R511_I2C_CTL, 0x10); if (rc < 0) return rc; if (--retries < 0) { err("i2c read retries exhausted"); return -1; } } value = reg_r(ov, R51x_I2C_DATA); PDEBUG(5, "0x%02X:0x%02X", reg, value); /* This is needed to make i2c_w() work */ rc = reg_w(ov, R511_I2C_CTL, 0x05); if (rc < 0) return rc; return value;}/* returns: negative is error, pos or zero is data */static inti2c_r(struct usb_ov511 *ov, unsigned char reg){ int rc; down(&ov->i2c_lock); if (ov->bclass == BCL_OV518) rc = ov518_i2c_read_internal(ov, reg); else rc = ov511_i2c_read_internal(ov, reg); up(&ov->i2c_lock); return rc;}static inti2c_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value){ int rc; down(&ov->i2c_lock); if (ov->bclass == BCL_OV518) rc = ov518_i2c_write_internal(ov, reg, value); else rc = ov511_i2c_write_internal(ov, reg, value); up(&ov->i2c_lock); return rc;}/* Do not call this function directly! */static intov51x_i2c_write_mask_internal(struct usb_ov511 *ov, unsigned char reg, unsigned char value, unsigned char mask){ int rc; unsigned char oldval, newval; if (mask == 0xff) { newval = value; } else { if (ov->bclass == BCL_OV518) rc = ov518_i2c_read_internal(ov, reg); else rc = ov511_i2c_read_internal(ov, reg); if (rc < 0) return rc; oldval = (unsigned char) rc; oldval &= (~mask); /* Clear the masked bits */ value &= mask; /* Enforce mask on value */ newval = oldval | value; /* Set the desired bits */ } if (ov->bclass == BCL_OV518) return (ov518_i2c_write_internal(ov, reg, newval)); else return (ov511_i2c_write_internal(ov, reg, newval));}/* Writes bits at positions specified by mask to an I2C reg. Bits that are in * the same position as 1's in "mask" are cleared and set to "value". Bits * that are in the same position as 0's in "mask" are preserved, regardless * of their respective state in "value". */static inti2c_w_mask(struct usb_ov511 *ov, unsigned char reg, unsigned char value, unsigned char mask){ int rc; down(&ov->i2c_lock); rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask); up(&ov->i2c_lock); return rc;}/* Set the read and write slave IDs. The "slave" argument is the write slave, * and the read slave will be set to (slave + 1). ov->i2c_lock should be held * when calling this. This should not be called from outside the i2c I/O * functions. */static inti2c_set_slave_internal(struct usb_ov511 *ov, unsigned char slave){ int rc; rc = reg_w(ov, R51x_I2C_W_SID, slave); if (rc < 0) return rc; rc = reg_w(ov, R51x_I2C_R_SID, slave + 1); if (rc < 0) return rc; return 0;}/* Write to a specific I2C slave ID and register, using the specified mask */static inti2c_w_slave(struct usb_ov511 *ov, unsigned char slave, unsigned char reg, unsigned char value, unsigned char mask){ int rc = 0; down(&ov->i2c_lock); /* Set new slave IDs */ rc = i2c_set_slave_internal(ov, slave); if (rc < 0) goto out; rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask);out: /* Restore primary IDs */ if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0) err("Couldn't restore primary I2C slave"); up(&ov->i2c_lock); return rc;}/* Read from a specific I2C slave ID and register */static inti2c_r_slave(struct usb_ov511 *ov, unsigned char slave, unsigned char reg){ int rc; down(&ov->i2c_lock); /* Set new slave IDs */ rc = i2c_set_slave_internal(ov, slave); if (rc < 0) goto out; if (ov->bclass == BCL_OV518) rc = ov518_i2c_read_internal(ov, reg); else rc = ov511_i2c_read_internal(ov, reg);out: /* Restore primary IDs */ if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0) err("Couldn't restore primary I2C slave"); up(&ov->i2c_lock); return rc;}/* Sets I2C read and write slave IDs. Returns <0 for error */static intov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid){ int rc; down(&ov->i2c_lock); rc = i2c_set_slave_internal(ov, sid); if (rc < 0) goto out; // FIXME: Is this actually necessary? rc = ov51x_reset(ov, OV511_RESET_NOREGS);out: up(&ov->i2c_lock); return rc;}static intwrite_regvals(struct usb_ov511 *ov, struct ov511_regvals * pRegvals){ int rc; while (pRegvals->bus != OV511_DONE_BUS) { if (pRegvals->bus == OV511_REG_BUS) { if ((rc = reg_w(ov, pRegvals->reg, pRegvals->val)) < 0) return rc; } else if (pRegvals->bus == OV511_I2C_BUS) { if ((rc = i2c_w(ov, pRegvals->reg, pRegvals->val)) < 0) return rc; } else { err("Bad regval array"); return -1; } pRegvals++; } return 0;}#ifdef OV511_DEBUGstatic voiddump_i2c_range(struct usb_ov511 *ov, int reg1, int regn){ int i, rc; for (i = reg1; i <= regn; i++) { rc = i2c_r(ov, i); info("Sensor[0x%02X] = 0x%02X", i, rc); }}static voiddump_i2c_regs(struct usb_ov511 *ov){ info("I2C REGS"); dump_i2c_range(ov, 0x00, 0x7C);}static voiddump_reg_range(struct usb_ov511 *ov, int reg1, int regn){ int i, rc; for (i = reg1; i <= regn; i++) { rc = reg_r(ov, i); info("OV511[0x%02X] = 0x%02X", i, rc); }}static voidov511_dump_regs(struct usb_ov511 *ov){ info("CAMERA INTERFACE REGS"); dump_reg_range(ov, 0x10, 0x1f); info("DRAM INTERFACE REGS"); dump_reg_range(ov, 0x20, 0x23); info("ISO FIFO REGS"); dump_reg_range(ov, 0x30, 0x31); info("PIO REGS"); dump_reg_range(ov, 0x38, 0x39); dump_reg_range(ov, 0x3e, 0x3e); info("I2C REGS"); dump_reg_range(ov, 0x40, 0x49); info("SYSTEM CONTROL REGS"); dump_reg_range(ov, 0x50, 0x55); dump_reg_range(ov, 0x5e, 0x5f); info("OmniCE REGS"); dump_reg_range(ov, 0x70, 0x79); /* NOTE: Quantization tables are not readable. You will get the value * in reg. 0x79 for every table register */ dump_reg_range(ov, 0x80, 0x9f); dump_reg_range(ov, 0xa0, 0xbf);}static voidov518_dump_regs(struct usb_ov511 *ov){ info("VIDEO MODE REGS"); dump_reg_range(ov, 0x20, 0x2f); info("DATA PUMP AND SNAPSHOT REGS"); dump_reg_range(ov, 0x30, 0x3f); info("I2C REGS"); dump_reg_range(ov, 0x40, 0x4f); info("SYSTEM CONTROL AND VENDOR REGS"); dump_reg_range(ov, 0x50, 0x5f); info("60 - 6F"); dump_reg_range(ov, 0x60, 0x6f); info("70 - 7F"); dump_reg_range(ov, 0x70, 0x7f); info("Y QUANTIZATION TABLE"); dump_reg_range(ov, 0x80, 0x8f); info("UV QUANTIZATION TABLE"); dump_reg_range(ov, 0x90, 0x9f); info("A0 - BF"); dump_reg_range(ov, 0xa0, 0xbf); info("CBR"); dump_reg_range(ov, 0xc0, 0xcf);}#endif/*****************************************************************************//* Temporarily stops OV511 from functioning. Must do this before changing * registers while the camera is streaming */static inline intov51x_stop(struct usb_ov511 *ov){ PDEBUG(4, "stopping"); ov->stopped = 1; if (ov->bclass == BCL_OV518) return (reg_w_mask(ov, R51x_SYS_RESET, 0x3a, 0x3a)); else return (reg_w(ov, R51x_SYS_RESET, 0x3d));}/* Restarts OV511 after ov511_stop() is called. Has no effect if it is not * actually stopped (for performance). */static inline intov51x_restart(struct usb_ov511 *ov){ if (ov->stopped) { PDEBUG(4, "restarting"); ov->stopped = 0; /* Reinitialize the stream */ if (ov->bclass == BCL_OV518) reg_w(ov, 0x2f, 0x80); return (reg_w(ov, R51x_SYS_RESET, 0x00)); } return 0;}/* Sleeps until no frames are active. Returns !0 if got signal */static intov51x_wait_frames_inactive(struct usb_ov511 *ov){ return wait_event_interruptible(ov->wq, ov->curframe < 0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -