?? ov511.c
字號:
goto error; } } return 0;error: err("i2c write: error %d", rc); 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 ov51x_i2c_read(). Note that this function * always succeeds regardless of whether the sensor is present and working. */static int ov518_i2c_read_internal(struct usb_device *dev, unsigned char reg){ int rc, value; /* 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, OV518_REG_I2C_CONTROL, 0x03); if (rc < 0) goto error; /* Initiate 2-byte read cycle */ rc = ov511_reg_write(dev, OV518_REG_I2C_CONTROL, 0x05); if (rc < 0) goto error; value = ov511_reg_read(dev, OV511_REG_I2C_DATA_PORT); PDEBUG(5, "0x%02X:0x%02X", reg, value); return value;error: err("ov518 i2c read: error %d", rc); return rc;}/* NOTE: Do not call this function directly! * returns: negative is error, pos or zero is data */static int ov511_i2c_read_internal(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, "0x%02X:0x%02X", reg, value); /* This is needed to make ov51x_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;}/* returns: negative is error, pos or zero is data */static int ov51x_i2c_read(struct usb_ov511 *ov511, unsigned char reg){ int rc; struct usb_device *dev = ov511->dev; down(&ov511->i2c_lock); if (dev->descriptor.idProduct == PROD_OV518 || dev->descriptor.idProduct == PROD_OV518PLUS) rc = ov518_i2c_read_internal(dev, reg); else rc = ov511_i2c_read_internal(dev, reg); up(&ov511->i2c_lock); return rc;}static int ov51x_i2c_write(struct usb_ov511 *ov511, unsigned char reg, unsigned char value){ int rc; struct usb_device *dev = ov511->dev; down(&ov511->i2c_lock); if (dev->descriptor.idProduct == PROD_OV518 || dev->descriptor.idProduct == PROD_OV518PLUS) rc = ov518_i2c_write_internal(dev, reg, value); else rc = ov511_i2c_write_internal(dev, reg, value); up(&ov511->i2c_lock); return rc;}/* Do not call this function directly! */static int ov51x_i2c_write_mask_internal(struct usb_device *dev, unsigned char reg, unsigned char value, unsigned char mask){ int rc; unsigned char oldval, newval; if (mask == 0xff) { newval = value; } else { if (dev->descriptor.idProduct == PROD_OV518 || dev->descriptor.idProduct == PROD_OV518PLUS) rc = ov518_i2c_read_internal(dev, reg); else rc = ov511_i2c_read_internal(dev, 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 (dev->descriptor.idProduct == PROD_OV518 || dev->descriptor.idProduct == PROD_OV518PLUS) return (ov518_i2c_write_internal(dev, reg, newval)); else return (ov511_i2c_write_internal(dev, 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 ov51x_i2c_write_mask(struct usb_ov511 *ov511, unsigned char reg, unsigned char value, unsigned char mask){ int rc; struct usb_device *dev = ov511->dev; down(&ov511->i2c_lock); rc = ov51x_i2c_write_mask_internal(dev, reg, value, mask); up(&ov511->i2c_lock); return rc;}/* Write to a specific I2C slave ID and register, using the specified mask */static int ov51x_i2c_write_slave(struct usb_ov511 *ov511, unsigned char slave, unsigned char reg, unsigned char value, unsigned char mask){ int rc = 0; struct usb_device *dev = ov511->dev; down(&ov511->i2c_lock); /* Set new slave IDs */ if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, slave) < 0) { rc = -EIO; goto out; } if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, slave + 1) < 0) { rc = -EIO; goto out; } rc = ov51x_i2c_write_mask_internal(dev, reg, value, mask); /* Don't bail out yet if error; IDs must be restored */ /* Restore primary IDs */ slave = ov511->primary_i2c_slave; if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, slave) < 0) { rc = -EIO; goto out; } if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, slave + 1) < 0) { rc = -EIO; goto out; }out: up(&ov511->i2c_lock); return rc;}/* Read from a specific I2C slave ID and register */static int ov51x_i2c_read_slave(struct usb_ov511 *ov511, unsigned char slave, unsigned char reg){ int rc; struct usb_device *dev = ov511->dev; down(&ov511->i2c_lock); /* Set new slave IDs */ if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, slave) < 0) { rc = -EIO; goto out; } if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, slave + 1) < 0) { rc = -EIO; goto out; } if (dev->descriptor.idProduct == PROD_OV518 || dev->descriptor.idProduct == PROD_OV518PLUS) rc = ov518_i2c_read_internal(dev, reg); else rc = ov511_i2c_read_internal(dev, reg); /* Don't bail out yet if error; IDs must be restored */ /* Restore primary IDs */ slave = ov511->primary_i2c_slave; if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, slave) < 0) { rc = -EIO; goto out; } if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, slave + 1) < 0) { rc = -EIO; goto out; }out: up(&ov511->i2c_lock); return rc;}static int ov511_write_regvals(struct usb_ov511 *ov511, struct ov511_regvals * pRegvals){ int rc; struct usb_device *dev = ov511->dev; 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 = ov51x_i2c_write(ov511, 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_ov511 *ov511, int reg1, int regn){ int i; int rc; for (i = reg1; i <= regn; i++) { rc = ov51x_i2c_read(ov511, i); info("OV7610[0x%X] = 0x%X", i, rc); }}static void ov51x_dump_i2c_regs(struct usb_ov511 *ov511){ info("I2C REGS"); ov511_dump_i2c_range(ov511, 0x00, 0x7C);}static 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); info("OV511[0x%X] = 0x%X", i, rc); }}static void ov511_dump_regs(struct usb_device *dev){ info("CAMERA INTERFACE REGS"); ov511_dump_reg_range(dev, 0x10, 0x1f); info("DRAM INTERFACE REGS"); ov511_dump_reg_range(dev, 0x20, 0x23); info("ISO FIFO REGS"); ov511_dump_reg_range(dev, 0x30, 0x31); info("PIO REGS"); ov511_dump_reg_range(dev, 0x38, 0x39); ov511_dump_reg_range(dev, 0x3e, 0x3e); info("I2C REGS"); ov511_dump_reg_range(dev, 0x40, 0x49); info("SYSTEM CONTROL REGS"); ov511_dump_reg_range(dev, 0x50, 0x55); ov511_dump_reg_range(dev, 0x5e, 0x5f); info("OmniCE REGS"); ov511_dump_reg_range(dev, 0x70, 0x79); /* NOTE: Quantization tables are not readable. You will get the value * in reg. 0x79 for every table register */ ov511_dump_reg_range(dev, 0x80, 0x9f); ov511_dump_reg_range(dev, 0xa0, 0xbf);}#endif/********************************************************************** * * Kernel I2C Interface * **********************************************************************//* For as-yet unimplemented I2C interface */static void call_i2c_clients(struct usb_ov511 *ov511, unsigned int cmd, void *arg){ /* Do nothing */}/*****************************************************************************/static int ov511_reset(struct usb_ov511 *ov511, unsigned char reset_type){ int rc; /* Setting bit 0 not allowed on 518/518Plus */ if (ov511->bridge == BRG_OV518 || ov511->bridge == BRG_OV518PLUS) reset_type &= 0xfe; PDEBUG(4, "Reset: type=0x%X", reset_type); rc = ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, reset_type); rc = ov511_reg_write(ov511->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_ov511 *ov511){ PDEBUG(4, "stopping"); ov511->stopped = 1; if (ov511->bridge == BRG_OV518 || ov511->bridge == BRG_OV518PLUS) return (ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, 0x3a)); else return (ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, 0x3d));}/* Restarts OV511 after ov511_stop() is called. Has no effect if it is not * actually stopped (for performance). */static inline int ov511_restart(struct usb_ov511 *ov511){ if (ov511->stopped) { PDEBUG(4, "restarting"); ov511->stopped = 0; /* Reinitialize the stream */ if (ov511->bridge == BRG_OV518 || ov511->bridge == BRG_OV518PLUS) ov511_reg_write(ov511->dev, 0x2f, 0x80); return (ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, 0x00)); } return 0;}/* Resets the hardware snapshot button */static void ov51x_clear_snapshot(struct usb_ov511 *ov511){ if (ov511->bridge == BRG_OV511 || ov511->bridge == BRG_OV511PLUS) { ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x01); ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x03); ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x01); } else if (ov511->bridge == BRG_OV518 || ov511->bridge == BRG_OV518PLUS) { warn("snapshot reset not supported yet on OV518(+)"); } else { err("clear snap: invalid bridge type"); } }/* Checks the status of the snapshot button. Returns 1 if it was pressed since * it was last cleared, and zero in all other cases (including errors) */static int ov51x_check_snapshot(struct usb_ov511 *ov511){ int ret, status = 0; if (ov511->bridge == BRG_OV511 || ov511->bridge == BRG_OV511PLUS) { ret = ov511_reg_read(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT); if (ret < 0) { err("Error checking snspshot status (%d)", ret); } else if (ret & 0x08) { status = 1; } } else if (ov511->bridge == BRG_OV518 || ov511->bridge == BRG_OV518PLUS) { warn("snapshot check not supported yet on OV518(+)"); } else { err("check snap: invalid bridge type"); } return status;}/* Sets I2C read and write slave IDs. Returns <0 for error */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -