ov519.c

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

C
2,231
字号
 * the same register settings as the OV8610, since they are very similar. */static int ov8xx0_configure(struct sd *sd){	int rc;	PDEBUG(D_PROBE, "starting ov8xx0 configuration");	/* Detect sensor (sub)type */	rc = i2c_r(sd, OV7610_REG_COM_I);	if (rc < 0) {		PDEBUG(D_ERR, "Error detecting sensor type");		return -1;	}	if ((rc & 3) == 1) {		sd->sensor = SEN_OV8610;	} else {		PDEBUG(D_ERR, "Unknown image sensor version: %d", rc & 3);		return -1;	}	/* Set sensor-specific vars *//*	sd->sif = 0;		already done */	return 0;}/* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses * the same register settings as the OV7610, since they are very similar. */static int ov7xx0_configure(struct sd *sd){	int rc, high, low;	PDEBUG(D_PROBE, "starting OV7xx0 configuration");	/* Detect sensor (sub)type */	rc = i2c_r(sd, OV7610_REG_COM_I);	/* add OV7670 here	 * it appears to be wrongly detected as a 7610 by default */	if (rc < 0) {		PDEBUG(D_ERR, "Error detecting sensor type");		return -1;	}	if ((rc & 3) == 3) {		/* quick hack to make OV7670s work */		high = i2c_r(sd, 0x0a);		low = i2c_r(sd, 0x0b);		/* info("%x, %x", high, low); */		if (high == 0x76 && low == 0x73) {			PDEBUG(D_PROBE, "Sensor is an OV7670");			sd->sensor = SEN_OV7670;		} else {			PDEBUG(D_PROBE, "Sensor is an OV7610");			sd->sensor = SEN_OV7610;		}	} else if ((rc & 3) == 1) {		/* I don't know what's different about the 76BE yet. */		if (i2c_r(sd, 0x15) & 1)			PDEBUG(D_PROBE, "Sensor is an OV7620AE");		else			PDEBUG(D_PROBE, "Sensor is an OV76BE");		/* OV511+ will return all zero isoc data unless we		 * configure the sensor as a 7620. Someone needs to		 * find the exact reg. setting that causes this. */		sd->sensor = SEN_OV76BE;	} else if ((rc & 3) == 0) {		/* try to read product id registers */		high = i2c_r(sd, 0x0a);		if (high < 0) {			PDEBUG(D_ERR, "Error detecting camera chip PID");			return high;		}		low = i2c_r(sd, 0x0b);		if (low < 0) {			PDEBUG(D_ERR, "Error detecting camera chip VER");			return low;		}		if (high == 0x76) {			switch (low) {			case 0x30:				PDEBUG(D_PROBE, "Sensor is an OV7630/OV7635");				PDEBUG(D_ERR,				      "7630 is not supported by this driver");				return -1;			case 0x40:				PDEBUG(D_PROBE, "Sensor is an OV7645");				sd->sensor = SEN_OV7640; /* FIXME */				break;			case 0x45:				PDEBUG(D_PROBE, "Sensor is an OV7645B");				sd->sensor = SEN_OV7640; /* FIXME */				break;			case 0x48:				PDEBUG(D_PROBE, "Sensor is an OV7648");				sd->sensor = SEN_OV7640; /* FIXME */				break;			default:				PDEBUG(D_PROBE, "Unknown sensor: 0x76%x", low);				return -1;			}		} else {			PDEBUG(D_PROBE, "Sensor is an OV7620");			sd->sensor = SEN_OV7620;		}	} else {		PDEBUG(D_ERR, "Unknown image sensor version: %d", rc & 3);		return -1;	}	/* Set sensor-specific vars *//*	sd->sif = 0;		already done */	return 0;}/* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */static int ov6xx0_configure(struct sd *sd){	int rc;	PDEBUG(D_PROBE, "starting OV6xx0 configuration");	/* Detect sensor (sub)type */	rc = i2c_r(sd, OV7610_REG_COM_I);	if (rc < 0) {		PDEBUG(D_ERR, "Error detecting sensor type");		return -1;	}	/* Ugh. The first two bits are the version bits, but	 * the entire register value must be used. I guess OVT	 * underestimated how many variants they would make. */	switch (rc) {	case 0x00:		sd->sensor = SEN_OV6630;		PDEBUG(D_ERR,			"WARNING: Sensor is an OV66308. Your camera may have");		PDEBUG(D_ERR, "been misdetected in previous driver versions.");		break;	case 0x01:		sd->sensor = SEN_OV6620;		break;	case 0x02:		sd->sensor = SEN_OV6630;		PDEBUG(D_PROBE, "Sensor is an OV66308AE");		break;	case 0x03:		sd->sensor = SEN_OV6630;		PDEBUG(D_PROBE, "Sensor is an OV66308AF");		break;	case 0x90:		sd->sensor = SEN_OV6630;		PDEBUG(D_ERR,			"WARNING: Sensor is an OV66307. Your camera may have");		PDEBUG(D_ERR, "been misdetected in previous driver versions.");		break;	default:		PDEBUG(D_ERR, "FATAL: Unknown sensor version: 0x%02x", rc);		return -1;	}	/* Set sensor-specific vars */	sd->sif = 1;	return 0;}/* Turns on or off the LED. Only has an effect with OV511+/OV518(+)/OV519 */static void ov51x_led_control(struct sd *sd, int on){/*	PDEBUG(D_STREAM, "LED (%s)", on ? "on" : "off"); */	reg_w_mask(sd, OV519_GPIO_DATA_OUT0, !on, 1);	/* 0 / 1 */}/* this function is called at probe time */static int sd_config(struct gspca_dev *gspca_dev,			const struct usb_device_id *id){	struct sd *sd = (struct sd *) gspca_dev;	struct cam *cam;	static const struct ov_regvals init_519[] = {		{ 0x5a,  0x6d }, /* EnableSystem */		{ 0x53,  0x9b },		{ 0x54,  0xff }, /* set bit2 to enable jpeg */		{ 0x5d,  0x03 },		{ 0x49,  0x01 },		{ 0x48,  0x00 },		/* Set LED pin to output mode. Bit 4 must be cleared or sensor		 * detection will fail. This deserves further investigation. */		{ OV519_GPIO_IO_CTRL0,   0xee },		{ 0x51,  0x0f }, /* SetUsbInit */		{ 0x51,  0x00 },		{ 0x22,  0x00 },		/* windows reads 0x55 at this point*/	};	if (write_regvals(sd, init_519, ARRAY_SIZE(init_519)))		goto error;	ov51x_led_control(sd, 0);	/* turn LED off */	/* Test for 76xx */	if (ov51x_set_slave_ids(sd, OV7xx0_SID) < 0)		goto error;	/* The OV519 must be more aggressive about sensor detection since	 * I2C write will never fail if the sensor is not present. We have	 * to try to initialize the sensor to detect its presence */	if (init_ov_sensor(sd) >= 0) {		if (ov7xx0_configure(sd) < 0) {			PDEBUG(D_ERR, "Failed to configure OV7xx0");			goto error;		}	} else {		/* Test for 6xx0 */		if (ov51x_set_slave_ids(sd, OV6xx0_SID) < 0)			goto error;		if (init_ov_sensor(sd) >= 0) {			if (ov6xx0_configure(sd) < 0) {				PDEBUG(D_ERR, "Failed to configure OV6xx0");				goto error;			}		} else {			/* Test for 8xx0 */			if (ov51x_set_slave_ids(sd, OV8xx0_SID) < 0)				goto error;			if (init_ov_sensor(sd) < 0) {				PDEBUG(D_ERR,					"Can't determine sensor slave IDs");				goto error;			}			if (ov8xx0_configure(sd) < 0) {				PDEBUG(D_ERR,				   "Failed to configure OV8xx0 sensor");				goto error;			}		}	}	cam = &gspca_dev->cam;	cam->epaddr = OV511_ENDPOINT_ADDRESS;	if (!sd->sif) {		cam->cam_mode = vga_mode;		cam->nmodes = ARRAY_SIZE(vga_mode);	} else {		cam->cam_mode = sif_mode;		cam->nmodes = ARRAY_SIZE(sif_mode);	}	sd->brightness = BRIGHTNESS_DEF;	sd->contrast = CONTRAST_DEF;	sd->colors = COLOR_DEF;	sd->hflip = HFLIP_DEF;	sd->vflip = VFLIP_DEF;	if (sd->sensor != SEN_OV7670)		gspca_dev->ctrl_dis = (1 << HFLIP_IDX)					| (1 << VFLIP_IDX);	return 0;error:	PDEBUG(D_ERR, "OV519 Config failed");	return -EBUSY;}/* this function is called at probe and resume time */static int sd_init(struct gspca_dev *gspca_dev){	struct sd *sd = (struct sd *) gspca_dev;	/* initialize the sensor */	switch (sd->sensor) {	case SEN_OV6620:		if (write_i2c_regvals(sd, norm_6x20, ARRAY_SIZE(norm_6x20)))			return -EIO;		break;	case SEN_OV6630:		if (write_i2c_regvals(sd, norm_6x30, ARRAY_SIZE(norm_6x30)))			return -EIO;		break;	default:/*	case SEN_OV7610: *//*	case SEN_OV76BE: */		if (write_i2c_regvals(sd, norm_7610, ARRAY_SIZE(norm_7610)))			return -EIO;		break;	case SEN_OV7620:		if (write_i2c_regvals(sd, norm_7620, ARRAY_SIZE(norm_7620)))			return -EIO;		break;	case SEN_OV7640:		if (write_i2c_regvals(sd, norm_7640, ARRAY_SIZE(norm_7640)))			return -EIO;		break;	case SEN_OV7670:		if (write_i2c_regvals(sd, norm_7670, ARRAY_SIZE(norm_7670)))			return -EIO;		break;	case SEN_OV8610:		if (write_i2c_regvals(sd, norm_8610, ARRAY_SIZE(norm_8610)))			return -EIO;		break;	}	return 0;}/* Sets up the OV519 with the given image parameters * * OV519 needs a completely different approach, until we can figure out what * the individual registers do. * * Do not put any sensor-specific code in here (including I2C I/O functions) */static int ov519_mode_init_regs(struct sd *sd){	static const struct ov_regvals mode_init_519_ov7670[] = {		{ 0x5d,	0x03 }, /* Turn off suspend mode */		{ 0x53,	0x9f }, /* was 9b in 1.65-1.08 */		{ 0x54,	0x0f }, /* bit2 (jpeg enable) */		{ 0xa2,	0x20 }, /* a2-a5 are undocumented */		{ 0xa3,	0x18 },		{ 0xa4,	0x04 },		{ 0xa5,	0x28 },		{ 0x37,	0x00 },	/* SetUsbInit */		{ 0x55,	0x02 }, /* 4.096 Mhz audio clock */		/* Enable both fields, YUV Input, disable defect comp (why?) */		{ 0x20,	0x0c },		{ 0x21,	0x38 },		{ 0x22,	0x1d },		{ 0x17,	0x50 }, /* undocumented */		{ 0x37,	0x00 }, /* undocumented */		{ 0x40,	0xff }, /* I2C timeout counter */		{ 0x46,	0x00 }, /* I2C clock prescaler */		{ 0x59,	0x04 },	/* new from windrv 090403 */		{ 0xff,	0x00 }, /* undocumented */		/* windows reads 0x55 at this point, why? */	};	static const struct ov_regvals mode_init_519[] = {		{ 0x5d,	0x03 }, /* Turn off suspend mode */		{ 0x53,	0x9f }, /* was 9b in 1.65-1.08 */		{ 0x54,	0x0f }, /* bit2 (jpeg enable) */		{ 0xa2,	0x20 }, /* a2-a5 are undocumented */		{ 0xa3,	0x18 },		{ 0xa4,	0x04 },		{ 0xa5,	0x28 },		{ 0x37,	0x00 },	/* SetUsbInit */		{ 0x55,	0x02 }, /* 4.096 Mhz audio clock */		/* Enable both fields, YUV Input, disable defect comp (why?) */		{ 0x22,	0x1d },		{ 0x17,	0x50 }, /* undocumented */		{ 0x37,	0x00 }, /* undocumented */		{ 0x40,	0xff }, /* I2C timeout counter */		{ 0x46,	0x00 }, /* I2C clock prescaler */		{ 0x59,	0x04 },	/* new from windrv 090403 */		{ 0xff,	0x00 }, /* undocumented */		/* windows reads 0x55 at this point, why? */	};	/******** Set the mode ********/	if (sd->sensor != SEN_OV7670) {		if (write_regvals(sd, mode_init_519,				  ARRAY_SIZE(mode_init_519)))			return -EIO;		if (sd->sensor == SEN_OV7640) {			/* Select 8-bit input mode */			reg_w_mask(sd, OV519_CAM_DFR, 0x10, 0x10);		}	} else {		if (write_regvals(sd, mode_init_519_ov7670,				  ARRAY_SIZE(mode_init_519_ov7670)))			return -EIO;	}	reg_w(sd, OV519_CAM_H_SIZE,	sd->gspca_dev.width >> 4);	reg_w(sd, OV519_CAM_V_SIZE,	sd->gspca_dev.height >> 3);	reg_w(sd, OV519_CAM_X_OFFSETL,	0x00);	reg_w(sd, OV519_CAM_X_OFFSETH,	0x00);	reg_w(sd, OV519_CAM_Y_OFFSETL,	0x00);	reg_w(sd, OV519_CAM_Y_OFFSETH,	0x00);	reg_w(sd, OV519_CAM_DIVIDER,	0x00);	reg_w(sd, OV519_CAM_FORMAT,	0x03); /* YUV422 */	reg_w(sd, 0x26,			0x00); /* Undocumented */	/******** Set the framerate ********/	if (frame_rate > 0)		sd->frame_rate = frame_rate;/* FIXME: These are only valid at the max resolution. */	sd->clockdiv = 0;	switch (sd->sensor) {	case SEN_OV7640:		switch (sd->frame_rate) {/*fixme: default was 30 fps */		case 30:			reg_w(sd, 0xa4, 0x0c);			reg_w(sd, 0x23, 0xff);			break;		case 25:			reg_w(sd, 0xa4, 0x0c);			reg_w(sd, 0x23, 0x1f);			break;		case 20:			reg_w(sd, 0xa4, 0x0c);			reg_w(sd, 0x23, 0x1b);			break;		default:/*		case 15: */			reg_w(sd, 0xa4, 0x04);			reg_w(sd, 0x23, 0xff);			sd->clockdiv = 1;			break;		case 10:			reg_w(sd, 0xa4, 0x04);			reg_w(sd, 0x23, 0x1f);			sd->clockdiv = 1;			break;		case 5:			reg_w(sd, 0xa4, 0x04);			reg_w(sd, 0x23, 0x1b);			sd->clockdiv = 1;			break;		}		break;	case SEN_OV8610:		switch (sd->frame_rate) {		default:	/* 15 fps *//*		case 15: */			reg_w(sd, 0xa4, 0x06);			reg_w(sd, 0x23, 0xff);			break;		case 10:			reg_w(sd, 0xa4, 0x06);			reg_w(sd, 0x23, 0x1f);			break;		case 5:			reg_w(sd, 0xa4, 0x06);			reg_w(sd, 0x23, 0x1b);			break;		}		break;	case SEN_OV7670:		/* guesses, based on 7640 */		PDEBUG(D_STREAM, "Setting framerate to %d fps",				 (sd->frame_rate == 0) ? 15 : sd->frame_rate);		reg_w(sd, 0xa4, 0x10);		switch (sd->frame_rate) {		case 30:			reg_w(sd, 0x23, 0xff);			break;		case 20:			reg_w(sd, 0x23, 0x1b);			break;		default:/*		case 15: */			reg_w(sd, 0x23, 0xff);			sd->clockdiv = 1;			break;		}		break;	}	return 0;}static int mode_init_ov_sensor_regs(struct sd *sd){	struct gspca_dev *gspca_dev;	int qvga;	gspca_dev = &sd->gspca_dev;	qvga = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;	/******** Mode (VGA/QVGA) and sensor specific regs ********/	switch (sd->sensor) {	case SEN_OV8610:		/* For OV8610 qvga means qsvga */		i2c_w_mask(sd, OV7610_REG_COM_C, qvga ? (1 << 5) : 0, 1 << 5);#if 0		/* FIXME: Does this improve the image quality or frame rate? */		i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20);		i2c_w(sd, 0x24, 0x10);		i2c_w(sd, 0x25, qvga ? 0x40 : 0x8a);		i2c_w(sd, 0x2f, qvga ? 0x30 : 0xb0);		i2c_w(sd, 0x35, qvga ? 0x1c : 0x9c);#endif		break;	case SEN_OV7610:		i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);#if 0		/* FIXME: Does this improve the image quality or frame rate? */		i2c_w_mask(sd, 0x28, qvga?0x00:0x20, 0x20);		i2c_w(sd, 0x24, 0x10);		i2c_w(sd, 0x25, qvga?0x40:0x8a);		i2c_w(sd, 0x2f, qvga?0x30:0xb0);		i2c_w(sd, 0x35, qvga?0x1c:0x9c);#endif		break;	case SEN_OV7620:/*		i2c_w(sd, 0x2b, 0x00); */		i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);		i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20);		i2c_w(sd, 0x24, qvga ? 0x20 : 0x3a);		i2c_w(sd, 0x25, qvga ? 0x30 : 0x60);		i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40);		i2c_w_mask(sd, 0x67, qvga ? 0xf0 : 0x90, 0xf0);		i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20);		break;	case SEN_OV76BE:/*		i2c_w(sd, 0x2b, 0x00); */		i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);#if 0		/* FIXME: Enable this once 7620AE uses 7620 initial settings */		i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20);		i2c_w(sd, 0x24, qvga ? 0x20 : 0x3a);		i2c_w(sd, 0x25, qvga ? 0x30 : 0x60);		i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40);		i2c_w_mask(sd, 0x67, qvga ? 0xb0 : 0x90, 0xf0);		i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20);#endif		break;	case SEN_OV7640:/*		i2c_w(sd, 0x2b, 0x00); */		i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);		i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20);/*		i2c_w(sd, 0x24, qvga ? 0x20 : 0x3a); *//*		i2c_w(sd, 0x25, qvga ? 0x30 : 0x60); *//*		i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40); *//*		i2c_w_mask(sd, 0x67, qvga ? 0xf0 : 0x90, 0xf0); *//*		i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20); */		break;	case SEN_OV7670:		/* set COM7_FMT_VGA or COM7_FMT_QVGA		 * do we need to set anything else?		 *	HSTART etc are set in set_ov_sensor_window itself */		i2c_w_mask(sd, OV7670_REG_COM7,			 qvga ? OV7670_COM7_FMT_QVGA : OV7670_COM7_FMT_VGA,			 OV7670_COM7_FMT_MASK);		break;	case SEN_OV6620:	case SEN_OV6630:		i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);		break;	default:		return -EINVAL;	}	/******** Palette-specific regs ********/	if (sd->sensor == SEN_OV7610 || sd->sensor == SEN_OV76BE) {		/* not valid on the OV6620/OV7620/6630? */		i2c_w_mask(sd, 0x0e, 0x00, 0x40);	}	/* The OV518 needs special treatment. Although both the OV518	 * and the OV6630 support a 16-bit video bus, only the 8 bit Y	 * bus is actually used. The UV bus is tied to ground.	 * Therefore, the OV6630 needs to be in 8-bit multiplexed

⌨️ 快捷键说明

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