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

📄 sensor_ov9640.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 3 页
字号:
            DEF_BLUE },          0, OV9640_BLUE, 0xff, 0 },        { { V4L2_CID_AUTO_WHITE_BALANCE, V4L2_CTRL_TYPE_BOOLEAN, "Auto White Balance", 0,1,0,            DEF_AWB },          0, OV9640_COM8, 0x02, 1 },        { { V4L2_CID_HFLIP, V4L2_CTRL_TYPE_BOOLEAN, "Mirror Image", 0, 1, 0,            DEF_HFLIP },          0, OV9640_MVFP, 0x20, 5 },        { { V4L2_CID_VFLIP, V4L2_CTRL_TYPE_BOOLEAN, "Vertical Flip", 0, 1, 0,            DEF_VFLIP },          0, OV9640_MVFP, 0x10, 4 },};#define NUM_CONTROLS (sizeof(control)/sizeof(control[0]))const static struct ov9640_reg *	ov9640_reg_init[NUM_PIXEL_FORMATS][NUM_IMAGE_SIZES] ={ { qqcif_yuv, qqvga_yuv, qcif_yuv, qvga_yuv, cif_yuv, vga_yuv, sxga_yuv }, { qqcif_565, qqvga_565, qcif_565, qvga_565, cif_565, vga_565, sxga_565 }, { qqcif_555, qqvga_555, qcif_555, qvga_555, cif_555, vga_555, sxga_555 },};/*  * Read a value from a register in an OV9640 sensor device.  The value is  * returned in 'val'. * Returns zero if successful, or non-zero otherwise. */static int ov9640_read_reg(struct i2c_client *client, u8 reg, u8 *val){	int err;	struct i2c_msg msg[1];	unsigned char data[1];	if (!client->adapter)		return -ENODEV;	msg->addr = client->addr;	msg->flags = 0;	msg->len = 1;	msg->buf = data;	*data = reg;	err = i2c_transfer(client->adapter, msg, 1);	if (err >= 0) {		msg->flags = I2C_M_RD;		err = i2c_transfer(client->adapter, msg, 1);	}	if (err >= 0) {		*val = *data;		return 0;	}	return err;}/* Write a value to a register in an OV9640 sensor device. * Returns zero if successful, or non-zero otherwise. */static int ov9640_write_reg(struct i2c_client *client, u8 reg, u8 val){	int err;	struct i2c_msg msg[1];	unsigned char data[2];	if (!client->adapter)		return -ENODEV;		msg->addr = client->addr;	msg->flags = 0;	msg->len = 2;	msg->buf = data;	data[0] = reg;	data[1] = val;	err = i2c_transfer(client->adapter, msg, 1);	if (err >= 0)		return 0;	return err;}static int ov9640_write_reg_mask(struct i2c_client *client, u8 reg, u8 *val, u8 mask){	u8 oldval, newval;	int rc;	if (mask == 0xff) {		newval = *val;	} else {		/* need to do read - modify - write */		if ((rc = ov9640_read_reg(client, reg, &oldval)))			return rc;		oldval &= (~mask);              /* Clear the masked bits */		*val &= mask;                  /* Enforce mask on value */		newval = oldval | *val;        /* Set the desired bits */	}	/* write the new value to the register */	if ((rc = ov9640_write_reg(client, reg, newval)))		return rc;	if ((rc = ov9640_read_reg(client, reg, &newval)))		return rc;	*val = newval & mask;	return 0;}static int ov9640_read_reg_mask(struct i2c_client *client, u8 reg, u8 *val, u8 mask){	int rc;	if ((rc = ov9640_read_reg(client, reg, val)))		return rc;	(*val) &= mask;	return 0;}/* Initialize a list of OV9640 registers. * The list of registers is terminated by the pair of values  * { OV9640_REG_TERM, OV9640_VAL_TERM }. * Returns zero if successful, or non-zero otherwise. */static int ov9640_write_regs(struct i2c_client *client, const struct ov9640_reg reglist[]){	int err;	const struct ov9640_reg *next = reglist;		while (!((next->reg == OV9640_REG_TERM) 		&& (next->val == OV9640_VAL_TERM)))	{		err = ov9640_write_reg(client, next->reg, next->val);		udelay(100);		if (err)			return err;		next++;	}	return 0;}/* Returns the index of the requested ID from the control structure array */static intfind_vctrl(int id){	int i;	if (id < V4L2_CID_BASE)		return -EDOM;	for (i = NUM_CONTROLS - 1; i >= 0; i--)		if (control[i].qc.id == id)			break;	if (i < 0)		i = -EINVAL;	return i;}/* Calculate the internal clock divisor (value of the CLKRC register) of the  * OV9640 given the image size, the frequency (in Hz) of its XCLK input and a  * desired frame period (in seconds).  The frame period 'fper' is expressed as  * a fraction.  The frame period is an input/output parameter. * Returns the value of the OV9640 CLKRC register that will yield the frame  * period returned in 'fper' at the specified xclk frequency.  The  * returned period will be as close to the requested period as possible. */static unsigned charov9640_clkrc(enum image_size isize, unsigned long xclk, struct v4l2_fract *fper){	unsigned long fpm, fpm_max;	/* frames per minute */	unsigned long divisor;	const unsigned long divisor_max = 64;	const static unsigned long clks_per_frame[] = #ifdef  CONFIG_ARCH_OMAP24XX		{ 200000, 400000, 200000, 400000, 400000, 800000, 3200000 };	/*         QQCIF   QQVGA    QCIF    QVGA     CIF     VGA     SXGA	 *actually 199680,400000, 199680, 400000, 399360, 800000, 3200000	 */#else		{ 200000, 200000, 200000, 200000, 400000, 800000, 3200000 };#endif	  	if (fper->numerator > 0)		fpm = (fper->denominator*60)/fper->numerator;	else		fpm = 0xffffffff;	fpm_max = (xclk*60)/clks_per_frame[isize];	if (fpm_max == 0)		fpm_max = 1;	if (fpm > fpm_max)		fpm = fpm_max;	if (fpm == 0)		fpm = 1;	divisor = fpm_max/fpm;	if (divisor > divisor_max)		divisor = divisor_max;	fper->numerator = divisor*60;	fper->denominator = fpm_max;	/* try to reduce the fraction */	while (!(fper->denominator % 5) && !(fper->numerator % 5)) {		fper->numerator /= 5;		fper->denominator /= 5;	}	while (!(fper->denominator % 3) && !(fper->numerator % 3)) {		fper->numerator /= 3;		fper->denominator /= 3;	}	while (!(fper->denominator % 2) && !(fper->numerator % 2)) {		fper->numerator /= 2;		fper->denominator /= 2;	}	if (fper->numerator < fper->denominator) {		if (!(fper->denominator % fper->numerator)) {			fper->denominator /= fper->numerator;			fper->numerator = 1;		}	}	else {		if (!(fper->numerator % fper->denominator)) {			fper->numerator /= fper->denominator;			fper->denominator = 1;		}	}	/* we set bit 7 in CLKRC to enable the digital PLL */	return (0x80 | (divisor - 1));}/* Configure the OV9640 for a specified image size, pixel format, and frame  * period.  xclk is the frequency (in Hz) of the xclk input to the OV9640.   * fper is the frame period (in seconds) expressed as a fraction. * Returns zero if successful, or non-zero otherwise. * The actual frame period is returned in fper. */static intov9640_configure(struct i2c_client *client, 	enum image_size isize, 	enum pixel_format pfmt,	unsigned long xclk,	struct v4l2_fract *fper){	int err;	unsigned char clkrc;	/* common register initialization */	err = ov9640_write_regs(client, ov9640_common);	if (err)		return err;	/* configure image size and pixel format */	err = ov9640_write_regs(client, ov9640_reg_init[pfmt][isize]);	if (err)		return err;	/* configure frame rate */	clkrc = ov9640_clkrc(isize, xclk, fper);	err = ov9640_write_reg(client, OV9640_CLKRC, clkrc);	if (err)		return err;	return 0;}/* Write to GPIO EXPA on the board. * The GPIO expanders need an independent I2C client driver. */static intwrite_gpio_expa(u8 val, int add){	struct i2c_adapter *adap;	int err;	struct i2c_msg msg[1];	unsigned char data[1];	adap = i2c_get_adapter(0);	if (!adap)		return -ENODEV;	msg->addr = add;	/* I2C address of GPIO EXPA */	msg->flags = 0;	msg->len = 1;	msg->buf = data;	data[0] = val;	err = i2c_transfer(adap, msg, 1);	if (err >= 0)		return 0;	return err;}/* Read from GPIO EXPA on the board. * The GPIO expanders need an independent I2C client driver. */static intread_gpio_expa(u8 *val, int add){	struct i2c_adapter *adap;	int err;	struct i2c_msg msg[1];	unsigned char data[1];	adap = i2c_get_adapter(0);	if (!adap)		return -ENODEV;	msg->addr = add;	/* I2C address of GPIO EXPA */	msg->flags = I2C_M_RD;	msg->len = 1;	msg->buf = data;	err = i2c_transfer(adap, msg, 1);	*val = data[0];	if (err >= 0)		return 0;	return err;}#ifdef CONFIG_ARCH_OMAP24XX/* Power-up the OV9640 sensor on the H4 board. * Returns 0 if successful, non-zero otherwise. */static intov9640_powerup(void){	unsigned char expa;	int err;	/* read current state of GPIO EXPA outputs */	if ((err = read_gpio_expa(&expa, 0x20))) {		printk(KERN_ERR "Error reading GPIO EXPA\n");		return err;	}	/* Set GPIO EXPA P3 (CAMERA_MODULE_EN) to power-up sensor */	if ((err = write_gpio_expa(expa | 0x08, 0x20))) {		printk(KERN_ERR "Error writing to GPIO EXPA\n");		return err;	}	/* read current state of GPIO EXPA outputs */	if ((err = read_gpio_expa(&expa, 0x22))) {		printk(KERN_ERR "Error reading GPIO EXPA\n");		return err;	}	/* Clear GPIO EXPA P7 (CAM_RST) */	if ((err = write_gpio_expa(expa & ~0x80, 0x22))) {		printk(KERN_ERR "Error writing to GPIO EXPA\n");		return err;	}	return 0;}/* Power-down the OV9640 sensor on the H4 board. * Returns 0 if successful, non-zero otherwise. */static intov9640_powerdown(void){	unsigned char expa;	int err;	/* read current state of GPIO EXPA outputs */	if ((err = read_gpio_expa(&expa, 0x20))) {		printk(KERN_ERR "Error reading GPIO EXPA\n");		return err;	}	/* Clear GPIO EXPA P3 (CAMERA_MODULE_EN) to power-down sensor */	if ((err = write_gpio_expa(expa & ~0x08, 0x20))) {		printk(KERN_ERR "Error writing to GPIO EXPA\n");		return err;	}	return 0;}#elsestatic intov9640_powerup(void){	unsigned char expa;	int err;	if (machine_is_omap_h2())		return 0;	/* read the current state of GPIO EXPA output */	if (( err = read_gpio_expa(&expa, 0x27))){		printk(KERN_ERR "Error reading GPIO EXPA \n");		return err;	}	/* set GPIO EXPA P7 CAMERA_MOD_EN to power-up sensor */	if ((err = write_gpio_expa(expa | 0x80, 0x27))) {		printk(KERN_ERR "Error writing to GPIO EXPA \n");		return err;	}	return 0;}static intov9640_powerdown(void){	unsigned char expa;	int err;	if (machine_is_omap_h2())		return 0;	/* read the current state of GPIO EXPA output */	if (( err = read_gpio_expa(&expa, 0x27))){		printk(KERN_ERR "Error reading GPIO EXPA \n");		return err;	}	/* clear GPIO EXPA P7 CAMERA_MOD_EN to power-up sensor */	if ((err = write_gpio_expa(expa & ~0x80, 0x27))) {		printk(KERN_ERR "Error writing to GPIO EXPA \n");		return err;	}	return 0;}#endif/* Detect if an OV9640 is present, and if so which revision.  * A device is considered to be detected if the manufacturer ID (MIDH and MIDL)  * and the product ID (PID) registers match the expected values.   * Any value of the version ID (VER) register is accepted. * Here are the version numbers we know about: *	0x48 --> OV9640 Revision 1 or OV9640 Revision 2 *	0x49 --> OV9640 Revision 3 * Returns a negative error number if no device is detected, or the  * non-negative value of the version ID register if a device is detected. */static intov9640_detect(struct i2c_client *client){	u8 midh, midl, pid, ver;	if (!client)		return -ENODEV; 	if (ov9640_read_reg(client, OV9640_MIDH, &midh))		return -ENODEV;	if (ov9640_read_reg(client, OV9640_MIDL, &midl))		return -ENODEV;	if (ov9640_read_reg(client, OV9640_PID, &pid))		return -ENODEV;	if (ov9640_read_reg(client, OV9640_VER, &ver))		return -ENODEV;

⌨️ 快捷键说明

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