📄 ov511.c
字号:
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; }#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) /* 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; }#endif /* defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) */ /* 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; int 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; int rc; for (i = reg1; i <= regn; i++) { rc = reg_r(ov, i); info("OV511[0x%02X] = 0x%02X", i, rc); } } /* FIXME: Should there be an OV518 version of this? */ 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); }#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 ov51x_clear_snapshot(struct usb_ov511 *ov) { if (ov->bclass == BCL_OV511) { reg_w(ov, R51x_SYS_SNAP, 0x01); reg_w(ov, R51x_SYS_SNAP, 0x03); reg_w(ov, R51x_SYS_SNAP, 0x01); } else if (ov->bclass == BCL_OV518) { warn("snapshot reset not supported yet on OV518(+)"); } else { err("clear snap: invalid bridge type"); } }#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) /* 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 *ov) { int ret, status = 0; if (ov->bclass == BCL_OV511) { ret = reg_r(ov, R51x_SYS_SNAP); if (ret < 0) { err("Error checking snspshot status (%d)", ret); } else if (ret & 0x08) { status = 1; } } else if (ov->bclass == BCL_OV518) { warn("snapshot check not supported yet on OV518(+)"); } else { err("check snap: invalid bridge type"); } return status; }#endif /* This does an initial reset of an OmniVision sensor and ensures that I2C * is synchronized. Returns <0 for failure. */ static int init_ov_sensor(struct usb_ov511 *ov) { int i, success; /* Reset the sensor */ if (i2c_w(ov, 0x12, 0x80) < 0) return -EIO; /* Wait for it to initialize */ schedule_timeout (1 + 150 * HZ / 1000); for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) { if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) && (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) { success = 1; continue; } /* Reset the sensor */ if (i2c_w(ov, 0x12, 0x80) < 0) return -EIO; /* Wait for it to initialize */ schedule_timeout(1 + 150 * HZ / 1000); /* Dummy read to sync I2C */ if (i2c_r(ov, 0x00) < 0) return -EIO; } if (!success) return -EIO; PDEBUG(1, "I2C synced in %d attempt(s)", i); return 0; } static int ov511_set_packet_size(struct usb_ov511 *ov, int size) { int alt, mult; if (ov51x_stop(ov) < 0) return -EIO; mult = size >> 5; printk("We are in ov511_set_packet_size size = %d\n", size); if (ov->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 (ov->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, "%d, mult=%d, alt=%d", size, mult, alt); if (reg_w(ov, R51x_FIFO_PSIZE, mult) < 0) return -EIO; if (usb_set_interface(ov->dev, ov->iface, alt) < 0) { err("Set packet size: set interface error"); return -EBUSY; } if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0) return -EIO; ov->packet_size = size; if (ov51x_restart(ov) < 0) return -EIO; return 0; } /* Note: Unlike the OV511/OV511+, the size argument does NOT include the * optional packet number byte. The actual size *is* stored in ov->packet_size, * though. */ static int ov518_set_packet_size(struct usb_ov511 *ov, int size) { int alt; if (ov51x_stop(ov) < 0) return -EIO; if (ov->bclass == BCL_OV518) { if (size == 0) alt = OV518_ALT_SIZE_0; else if (size == 128) alt = OV518_ALT_SIZE_128; else if (size == 256) alt = OV518_ALT_SIZE_256; else if (size == 384) alt = OV518_ALT_SIZE_384; else if (size == 512) alt = OV518_ALT_SIZE_512; else if (size == 640) alt = OV518_ALT_SIZE_640; else if (size == 768) alt = OV518_ALT_SIZE_768; else if (size == 896) alt = OV518_ALT_SIZE_896; else { err("Set packet size: invalid size (%d)", size); return -EINVAL; } } else { err("Set packet size: Invalid bridge type"); return -EINVAL; } PDEBUG(3, "%d, alt=%d", size, alt); ov->packet_size = size; if (size > 0) { /* Program ISO FIFO size reg (packet number isn't included) */ ov518_reg_w32(ov, 0x30, size, 2); if (ov->packet_numbering) ++ov->packet_size; } if (usb_set_interface(ov->dev, ov->iface, alt) < 0) { err("Set packet size: set interface error"); return -EBUSY; } /* Initialize the stream */ if (reg_w(ov, 0x2f, 0x80) < 0) return -EIO; if (ov51x_restart(ov) < 0) return -EIO; if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0) return -EIO; return 0; } /* Upload compression params and quantization tables. Returns 0 for success. */ static int ov511_init_compression(struct usb_ov511 *ov) { int rc = 0; if (!ov->compress_inited) { reg_w(ov, 0x70, phy); reg_w(ov, 0x71, phuv); reg_w(ov, 0x72, pvy); reg_w(ov, 0x73, pvuv); reg_w(ov, 0x74, qhy); reg_w(ov, 0x75, qhuv); reg_w(ov, 0x76, qvy); reg_w(ov, 0x77, qvuv); if (ov511_upload_quan_tables(ov) < 0) { err("Error uploading quantization tables"); rc = -EIO; goto out; } } ov->compress_inited = 1; out: return rc; } /* Upload compression params and quantization tables. Returns 0 for success. */ static int ov518_init_compression(struct usb_ov511 *ov) { int rc = 0; if (!ov->compress_inited) { if (ov518_upload_quan_tables(ov) < 0) { err("Error uploading quantization tables"); rc = -EIO; goto out;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -