ov519.c

来自「trident tm5600的linux驱动」· C语言 代码 · 共 2,231 行 · 第 1/4 页

C
2,231
字号
	{ OV7670_REG_HSTOP, 0x01 },	{ OV7670_REG_HREF, 0xb6 },	{ OV7670_REG_VSTART, 0x02 },	{ OV7670_REG_VSTOP, 0x7a },	{ OV7670_REG_VREF, 0x0a },	{ OV7670_REG_COM3, 0 },	{ OV7670_REG_COM14, 0 },/* Mystery scaling numbers */	{ 0x70, 0x3a },	{ 0x71, 0x35 },	{ 0x72, 0x11 },	{ 0x73, 0xf0 },	{ 0xa2, 0x02 },/*	{ OV7670_REG_COM10, 0x0 }, *//* Gamma curve values */	{ 0x7a, 0x20 },	{ 0x7b, 0x10 },	{ 0x7c, 0x1e },	{ 0x7d, 0x35 },	{ 0x7e, 0x5a },	{ 0x7f, 0x69 },	{ 0x80, 0x76 },	{ 0x81, 0x80 },	{ 0x82, 0x88 },	{ 0x83, 0x8f },	{ 0x84, 0x96 },	{ 0x85, 0xa3 },	{ 0x86, 0xaf },	{ 0x87, 0xc4 },	{ 0x88, 0xd7 },	{ 0x89, 0xe8 },/* AGC and AEC parameters.  Note we start by disabling those features,   then turn them only after tweaking the values. */	{ OV7670_REG_COM8, OV7670_COM8_FASTAEC			 | OV7670_COM8_AECSTEP			 | OV7670_COM8_BFILT },	{ OV7670_REG_GAIN, 0 },	{ OV7670_REG_AECH, 0 },	{ OV7670_REG_COM4, 0x40 }, /* magic reserved bit */	{ OV7670_REG_COM9, 0x18 }, /* 4x gain + magic rsvd bit */	{ OV7670_REG_BD50MAX, 0x05 },	{ OV7670_REG_BD60MAX, 0x07 },	{ OV7670_REG_AEW, 0x95 },	{ OV7670_REG_AEB, 0x33 },	{ OV7670_REG_VPT, 0xe3 },	{ OV7670_REG_HAECC1, 0x78 },	{ OV7670_REG_HAECC2, 0x68 },	{ 0xa1, 0x03 }, /* magic */	{ OV7670_REG_HAECC3, 0xd8 },	{ OV7670_REG_HAECC4, 0xd8 },	{ OV7670_REG_HAECC5, 0xf0 },	{ OV7670_REG_HAECC6, 0x90 },	{ OV7670_REG_HAECC7, 0x94 },	{ OV7670_REG_COM8, OV7670_COM8_FASTAEC			| OV7670_COM8_AECSTEP			| OV7670_COM8_BFILT			| OV7670_COM8_AGC			| OV7670_COM8_AEC },/* Almost all of these are magic "reserved" values.  */	{ OV7670_REG_COM5, 0x61 },	{ OV7670_REG_COM6, 0x4b },	{ 0x16, 0x02 },	{ OV7670_REG_MVFP, 0x07 },	{ 0x21, 0x02 },	{ 0x22, 0x91 },	{ 0x29, 0x07 },	{ 0x33, 0x0b },	{ 0x35, 0x0b },	{ 0x37, 0x1d },	{ 0x38, 0x71 },	{ 0x39, 0x2a },	{ OV7670_REG_COM12, 0x78 },	{ 0x4d, 0x40 },	{ 0x4e, 0x20 },	{ OV7670_REG_GFIX, 0 },	{ 0x6b, 0x4a },	{ 0x74, 0x10 },	{ 0x8d, 0x4f },	{ 0x8e, 0 },	{ 0x8f, 0 },	{ 0x90, 0 },	{ 0x91, 0 },	{ 0x96, 0 },	{ 0x9a, 0 },	{ 0xb0, 0x84 },	{ 0xb1, 0x0c },	{ 0xb2, 0x0e },	{ 0xb3, 0x82 },	{ 0xb8, 0x0a },/* More reserved magic, some of which tweaks white balance */	{ 0x43, 0x0a },	{ 0x44, 0xf0 },	{ 0x45, 0x34 },	{ 0x46, 0x58 },	{ 0x47, 0x28 },	{ 0x48, 0x3a },	{ 0x59, 0x88 },	{ 0x5a, 0x88 },	{ 0x5b, 0x44 },	{ 0x5c, 0x67 },	{ 0x5d, 0x49 },	{ 0x5e, 0x0e },	{ 0x6c, 0x0a },	{ 0x6d, 0x55 },	{ 0x6e, 0x11 },	{ 0x6f, 0x9f },					/* "9e for advance AWB" */	{ 0x6a, 0x40 },	{ OV7670_REG_BLUE, 0x40 },	{ OV7670_REG_RED, 0x60 },	{ OV7670_REG_COM8, OV7670_COM8_FASTAEC			| OV7670_COM8_AECSTEP			| OV7670_COM8_BFILT			| OV7670_COM8_AGC			| OV7670_COM8_AEC			| OV7670_COM8_AWB },/* Matrix coefficients */	{ 0x4f, 0x80 },	{ 0x50, 0x80 },	{ 0x51, 0 },	{ 0x52, 0x22 },	{ 0x53, 0x5e },	{ 0x54, 0x80 },	{ 0x58, 0x9e },	{ OV7670_REG_COM16, OV7670_COM16_AWBGAIN },	{ OV7670_REG_EDGE, 0 },	{ 0x75, 0x05 },	{ 0x76, 0xe1 },	{ 0x4c, 0 },	{ 0x77, 0x01 },	{ OV7670_REG_COM13, OV7670_COM13_GAMMA			  | OV7670_COM13_UVSAT			  | 2},		/* was 3 */	{ 0x4b, 0x09 },	{ 0xc9, 0x60 },	{ OV7670_REG_COM16, 0x38 },	{ 0x56, 0x40 },	{ 0x34, 0x11 },	{ OV7670_REG_COM11, OV7670_COM11_EXP|OV7670_COM11_HZAUTO },	{ 0xa4, 0x88 },	{ 0x96, 0 },	{ 0x97, 0x30 },	{ 0x98, 0x20 },	{ 0x99, 0x30 },	{ 0x9a, 0x84 },	{ 0x9b, 0x29 },	{ 0x9c, 0x03 },	{ 0x9d, 0x4c },	{ 0x9e, 0x3f },	{ 0x78, 0x04 },/* Extra-weird stuff.  Some sort of multiplexor register */	{ 0x79, 0x01 },	{ 0xc8, 0xf0 },	{ 0x79, 0x0f },	{ 0xc8, 0x00 },	{ 0x79, 0x10 },	{ 0xc8, 0x7e },	{ 0x79, 0x0a },	{ 0xc8, 0x80 },	{ 0x79, 0x0b },	{ 0xc8, 0x01 },	{ 0x79, 0x0c },	{ 0xc8, 0x0f },	{ 0x79, 0x0d },	{ 0xc8, 0x20 },	{ 0x79, 0x09 },	{ 0xc8, 0x80 },	{ 0x79, 0x02 },	{ 0xc8, 0xc0 },	{ 0x79, 0x03 },	{ 0xc8, 0x40 },	{ 0x79, 0x05 },	{ 0xc8, 0x30 },	{ 0x79, 0x26 },};static const struct ov_i2c_regvals norm_8610[] = {	{ 0x12, 0x80 },	{ 0x00, 0x00 },	{ 0x01, 0x80 },	{ 0x02, 0x80 },	{ 0x03, 0xc0 },	{ 0x04, 0x30 },	{ 0x05, 0x30 }, /* was 0x10, new from windrv 090403 */	{ 0x06, 0x70 }, /* was 0x80, new from windrv 090403 */	{ 0x0a, 0x86 },	{ 0x0b, 0xb0 },	{ 0x0c, 0x20 },	{ 0x0d, 0x20 },	{ 0x11, 0x01 },	{ 0x12, 0x25 },	{ 0x13, 0x01 },	{ 0x14, 0x04 },	{ 0x15, 0x01 }, /* Lin and Win think different about UV order */	{ 0x16, 0x03 },	{ 0x17, 0x38 }, /* was 0x2f, new from windrv 090403 */	{ 0x18, 0xea }, /* was 0xcf, new from windrv 090403 */	{ 0x19, 0x02 }, /* was 0x06, new from windrv 090403 */	{ 0x1a, 0xf5 },	{ 0x1b, 0x00 },	{ 0x20, 0xd0 }, /* was 0x90, new from windrv 090403 */	{ 0x23, 0xc0 }, /* was 0x00, new from windrv 090403 */	{ 0x24, 0x30 }, /* was 0x1d, new from windrv 090403 */	{ 0x25, 0x50 }, /* was 0x57, new from windrv 090403 */	{ 0x26, 0xa2 },	{ 0x27, 0xea },	{ 0x28, 0x00 },	{ 0x29, 0x00 },	{ 0x2a, 0x80 },	{ 0x2b, 0xc8 }, /* was 0xcc, new from windrv 090403 */	{ 0x2c, 0xac },	{ 0x2d, 0x45 }, /* was 0xd5, new from windrv 090403 */	{ 0x2e, 0x80 },	{ 0x2f, 0x14 }, /* was 0x01, new from windrv 090403 */	{ 0x4c, 0x00 },	{ 0x4d, 0x30 }, /* was 0x10, new from windrv 090403 */	{ 0x60, 0x02 }, /* was 0x01, new from windrv 090403 */	{ 0x61, 0x00 }, /* was 0x09, new from windrv 090403 */	{ 0x62, 0x5f }, /* was 0xd7, new from windrv 090403 */	{ 0x63, 0xff },	{ 0x64, 0x53 }, /* new windrv 090403 says 0x57,			 * maybe thats wrong */	{ 0x65, 0x00 },	{ 0x66, 0x55 },	{ 0x67, 0xb0 },	{ 0x68, 0xc0 }, /* was 0xaf, new from windrv 090403 */	{ 0x69, 0x02 },	{ 0x6a, 0x22 },	{ 0x6b, 0x00 },	{ 0x6c, 0x99 }, /* was 0x80, old windrv says 0x00, but			 * deleting bit7 colors the first images red */	{ 0x6d, 0x11 }, /* was 0x00, new from windrv 090403 */	{ 0x6e, 0x11 }, /* was 0x00, new from windrv 090403 */	{ 0x6f, 0x01 },	{ 0x70, 0x8b },	{ 0x71, 0x00 },	{ 0x72, 0x14 },	{ 0x73, 0x54 },	{ 0x74, 0x00 },/* 0x60? - was 0x00, new from windrv 090403 */	{ 0x75, 0x0e },	{ 0x76, 0x02 }, /* was 0x02, new from windrv 090403 */	{ 0x77, 0xff },	{ 0x78, 0x80 },	{ 0x79, 0x80 },	{ 0x7a, 0x80 },	{ 0x7b, 0x10 }, /* was 0x13, new from windrv 090403 */	{ 0x7c, 0x00 },	{ 0x7d, 0x08 }, /* was 0x09, new from windrv 090403 */	{ 0x7e, 0x08 }, /* was 0xc0, new from windrv 090403 */	{ 0x7f, 0xfb },	{ 0x80, 0x28 },	{ 0x81, 0x00 },	{ 0x82, 0x23 },	{ 0x83, 0x0b },	{ 0x84, 0x00 },	{ 0x85, 0x62 }, /* was 0x61, new from windrv 090403 */	{ 0x86, 0xc9 },	{ 0x87, 0x00 },	{ 0x88, 0x00 },	{ 0x89, 0x01 },	{ 0x12, 0x20 },	{ 0x12, 0x25 }, /* was 0x24, new from windrv 090403 */};static unsigned char ov7670_abs_to_sm(unsigned char v){	if (v > 127)		return v & 0x7f;	return (128 - v) | 0x80;}/* Write a OV519 register */static int reg_w(struct sd *sd, __u16 index, __u8 value){	int ret;	sd->gspca_dev.usb_buf[0] = value;	ret = usb_control_msg(sd->gspca_dev.dev,			usb_sndctrlpipe(sd->gspca_dev.dev, 0),			1,			/* REQ_IO (ov518/519) */			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,			0, index,			sd->gspca_dev.usb_buf, 1, 500);	if (ret < 0)		PDEBUG(D_ERR, "Write reg [%02x] %02x failed", index, value);	return ret;}/* Read from a OV519 register *//* returns: negative is error, pos or zero is data */static int reg_r(struct sd *sd, __u16 index){	int ret;	ret = usb_control_msg(sd->gspca_dev.dev,			usb_rcvctrlpipe(sd->gspca_dev.dev, 0),			1,			/* REQ_IO */			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,			0, index, sd->gspca_dev.usb_buf, 1, 500);	if (ret >= 0)		ret = sd->gspca_dev.usb_buf[0];	else		PDEBUG(D_ERR, "Read reg [0x%02x] failed", index);	return ret;}/* Read 8 values from a OV519 register */static int reg_r8(struct sd *sd,		  __u16 index){	int ret;	ret = usb_control_msg(sd->gspca_dev.dev,			usb_rcvctrlpipe(sd->gspca_dev.dev, 0),			1,			/* REQ_IO */			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,			0, index, sd->gspca_dev.usb_buf, 8, 500);	if (ret >= 0)		ret = sd->gspca_dev.usb_buf[0];	else		PDEBUG(D_ERR, "Read reg 8 [0x%02x] failed", index);	return ret;}/* * Writes bits at positions specified by mask to an OV51x 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 reg_w_mask(struct sd *sd,			__u16 index,			__u8 value,			__u8 mask){	int ret;	__u8 oldval;	if (mask != 0xff) {		value &= mask;			/* Enforce mask on value */		ret = reg_r(sd, index);		if (ret < 0)			return ret;		oldval = ret & ~mask;		/* Clear the masked bits */		value |= oldval;		/* Set the desired bits */	}	return reg_w(sd, index, value);}/* * 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 i2c_w(struct sd *sd,		__u8 reg,		__u8 value){	int rc;	PDEBUG(D_USBO, "i2c 0x%02x -> [0x%02x]", value, reg);	/* Select camera register */	rc = reg_w(sd, R51x_I2C_SADDR_3, reg);	if (rc < 0)		return rc;	/* Write "value" to I2C data port of OV511 */	rc = reg_w(sd, R51x_I2C_DATA, value);	if (rc < 0)		return rc;	/* Initiate 3-byte write cycle */	rc = reg_w(sd, R518_I2C_CTL, 0x01);	/* wait for write complete */	msleep(4);	if (rc < 0)		return rc;	return reg_r8(sd, R518_I2C_CTL);}/* * returns: negative is error, pos or zero is data * * 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 i2c_r(struct sd *sd, __u8 reg){	int rc, value;	/* Select camera register */	rc = reg_w(sd, R51x_I2C_SADDR_2, reg);	if (rc < 0)		return rc;	/* Initiate 2-byte write cycle */	rc = reg_w(sd, R518_I2C_CTL, 0x03);	if (rc < 0)		return rc;	/* Initiate 2-byte read cycle */	rc = reg_w(sd, R518_I2C_CTL, 0x05);	if (rc < 0)		return rc;	value = reg_r(sd, R51x_I2C_DATA);	PDEBUG(D_USBI, "i2c [0x%02X] -> 0x%02X", reg, value);	return value;}/* 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 sd *sd,		   __u8 reg,		   __u8 value,		   __u8 mask){	int rc;	__u8 oldval;	value &= mask;			/* Enforce mask on value */	rc = i2c_r(sd, reg);	if (rc < 0)		return rc;	oldval = rc & ~mask;		/* Clear the masked bits */	value |= oldval;		/* Set the desired bits */	return i2c_w(sd, reg, value);}/* Temporarily stops OV511 from functioning. Must do this before changing * registers while the camera is streaming */static inline int ov51x_stop(struct sd *sd){	PDEBUG(D_STREAM, "stopping");	sd->stopped = 1;	return reg_w(sd, OV519_SYS_RESET1, 0x0f);}/* Restarts OV511 after ov511_stop() is called. Has no effect if it is not * actually stopped (for performance). */static inline int ov51x_restart(struct sd *sd){	PDEBUG(D_STREAM, "restarting");	if (!sd->stopped)		return 0;	sd->stopped = 0;	/* Reinitialize the stream */	return reg_w(sd, OV519_SYS_RESET1, 0x00);}/* This does an initial reset of an OmniVision sensor and ensures that I2C * is synchronized. Returns <0 on failure. */static int init_ov_sensor(struct sd *sd){	int i, success;	/* Reset the sensor */	if (i2c_w(sd, 0x12, 0x80) < 0)		return -EIO;	/* Wait for it to initialize */	msleep(150);	for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) {		if (i2c_r(sd, OV7610_REG_ID_HIGH) == 0x7f &&		    i2c_r(sd, OV7610_REG_ID_LOW) == 0xa2) {			success = 1;			continue;		}		/* Reset the sensor */		if (i2c_w(sd, 0x12, 0x80) < 0)			return -EIO;		/* Wait for it to initialize */		msleep(150);		/* Dummy read to sync I2C */		if (i2c_r(sd, 0x00) < 0)			return -EIO;	}	if (!success)		return -EIO;	PDEBUG(D_PROBE, "I2C synced in %d attempt(s)", i);	return 0;}/* Set the read and write slave IDs. The "slave" argument is the write slave, * and the read slave will be set to (slave + 1). * This should not be called from outside the i2c I/O functions. * Sets I2C read and write slave IDs. Returns <0 for error */static int ov51x_set_slave_ids(struct sd *sd,				__u8 slave){	int rc;	rc = reg_w(sd, R51x_I2C_W_SID, slave);	if (rc < 0)		return rc;	sd->primary_i2c_slave = slave;	return reg_w(sd, R51x_I2C_R_SID, slave + 1);}static int write_regvals(struct sd *sd,			 const struct ov_regvals *regvals,			 int n){	int rc;	while (--n >= 0) {		rc = reg_w(sd, regvals->reg, regvals->val);		if (rc < 0)			return rc;		regvals++;	}	return 0;}static int write_i2c_regvals(struct sd *sd,			     const struct ov_i2c_regvals *regvals,			     int n){	int rc;	while (--n >= 0) {		rc = i2c_w(sd, regvals->reg, regvals->val);		if (rc < 0)			return rc;		regvals++;	}	return 0;}/**************************************************************************** * * OV511 and sensor configuration * ***************************************************************************//* This initializes the OV8110, OV8610 sensor. The OV8110 uses

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?