📄 ov511.c
字号:
reg++;
}
return 0;
}
static int
ov51x_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 int
ov518_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 int
ov511_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) 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, R511_I2C_CTL, 0x01);
if (rc < 0) return rc;
do rc = reg_r(ov, R511_I2C_CTL);
while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */
if (rc < 0) return rc;
if ((rc&2) == 0) /* Ack? */
break;
#if 0
/* I2C abort */
reg_w(ov, R511_I2C_CTL, 0x10);
#endif
if (--retries < 0) {
err("i2c write retries exhausted");
return -1;
}
}
return 0;
}
/* 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 int
ov518_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 int
ov511_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;
do rc = reg_r(ov, R511_I2C_CTL);
while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */
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;
do rc = reg_r(ov, R511_I2C_CTL);
while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */
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 int
i2c_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 int
i2c_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 int
ov51x_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 int
i2c_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 inline int
i2c_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 int
i2c_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 int
i2c_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 int
ov51x_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);
if (rc < 0) goto out;
out:
up(&ov->i2c_lock);
return rc;
}
static int
write_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_DEBUG
static void
dump_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 void
dump_i2c_regs(struct usb_ov511 *ov)
{
info("I2C REGS");
dump_i2c_range(ov, 0x00, 0x7C);
}
static void
dump_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 void
ov511_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 void
ov518_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 int
ov51x_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 int
ov51x_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;
}
/* Resets the hardware snapshot button */
static void
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -