⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ov511.c

📁 用于ARM S3C44B0/S3C4510嵌入式系统的ov511驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
		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 + -