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

📄 camera_ov6x30.c

📁 pxa270下的摄像头mtd91111的驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * camera_ov6x30.c * * Implementation of Camera for OmniVision OV6630 digital camera. * * Copyright (C) 2003-2004 MontaVista Software, Inc. * * Author: MontaVista Software, Inc. *              stevel@mvista.com or source@mvista.com * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */#include <linux/config.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/videodev.h>#include <asm/uaccess.h>#define MODULE_NAME "ov6x30"#include "common.h"#include "camif.h"#define OV6X30_BPP 2#define REG_GAIN		0x00	/* gain setting (5:0) */#define REG_BLUE		0x01	/* blue channel balance */#define REG_RED			0x02	/* red channel balance */#define REG_SAT			0x03	/* saturation */					/* 04 reserved */#define REG_CNT			0x05	/* Y contrast */#define REG_BRT			0x06	/* Y brightness */					/* 08-0b reserved */#define REG_BLUE_BIAS		0x0C	/* blue channel bias (5:0) */#define REG_RED_BIAS		0x0D	/* read channel bias (5:0) */#define REG_GAMMA_COEFF		0x0E	/* gamma settings */#define REG_WB_RANGE		0x0F	/* AEC/ALC/S-AWB settings */#define REG_EXP			0x10	/* manual exposure setting *//* Window parameters */#define HWSBASE 0x38#define HWEBASE 0x3A#define VWSBASE 0x05#define VWEBASE 0x06#define HORZCONST 0x38 // as per CCD chip specs.#define VERTCONST 0x03 // as per CCD chip specs.#define MAXWIDTH  CIF_WIDTH#define MAXHEIGHT CIF_HEIGHTstatic struct camera * this;#define DEF_BRIGHTNESS  149#define DEF_CONTRAST     10#define DEF_SATURATION   24#define DEF_BLUE        153#define DEF_RED         (255 - DEF_BLUE)#define DEF_AWB           1#define DEF_EXPOSURE    154#define DEF_GAIN         31#define DEF_AUTOGAIN      1#define DEF_HFLIP         1#define DEF_BANDFILT      1#define DEF_AUTOBRIGHT    1#define DEF_FREEZE_AGCAEC 0#define DEF_DISABLE_AEC   0// Our own specific controls#define V4L2_CID_BANDFILT   V4L2_CID_PRIVATE_BASE+0#define V4L2_CID_AUTOBRIGHT V4L2_CID_PRIVATE_BASE+1#define V4L2_CID_DISABLE_AEC V4L2_CID_PRIVATE_BASE+2#define V4L2_CID_FREEZE_AGCAEC V4L2_CID_PRIVATE_BASE+3#define V4L2_CID_LAST_PRIV  V4L2_CID_FREEZE_AGCAECstatic int current_frame_period = 333667; // .1 usec (30 fps)static int current_xclk = 24000000; // Hz/*  Video controls  */static struct vcontrol {	int current_value;	u8 reg;	u8 mask;	u8 start_bit;	struct v4l2_queryctrl qc;} control[] = {	{ 0, 0x05, 0x0f, 0,	  { V4L2_CID_CONTRAST,   "Contrast",   0,  15, 1, DEF_CONTRAST,	    V4L2_CTRL_TYPE_INTEGER }},	{ 0, REG_BRT, 0xff, 0,	  { V4L2_CID_BRIGHTNESS, "Brightness", 0, 255, 1, DEF_BRIGHTNESS,	    V4L2_CTRL_TYPE_INTEGER }},	{ 0, REG_SAT, 0xf8, 3,	  { V4L2_CID_SATURATION, "Saturation", 0,  31, 1, DEF_SATURATION,	    V4L2_CTRL_TYPE_INTEGER }},	{ 0, 0x12, 0x04, 2,	  { V4L2_CID_AUTO_WHITE_BALANCE, "Auto White Balance", 0, 1, 0, DEF_AWB,	    V4L2_CTRL_TYPE_BOOLEAN }},	{ 0, REG_BLUE, 0xff, 0,	  { V4L2_CID_BLUE_BALANCE, "Blue Balance", 0, 255, 1, DEF_BLUE,	    V4L2_CTRL_TYPE_INTEGER }},	{ 0, REG_RED, 0xff, 0,	  { V4L2_CID_RED_BALANCE, "Red Balance", 0, 255, 1, DEF_RED,	    V4L2_CTRL_TYPE_INTEGER }},	{ 0, 0x12, 0x20, 5,	  { V4L2_CID_AUTOGAIN, "Auto Gain", 0, 1, 0, DEF_AUTOGAIN,	    V4L2_CTRL_TYPE_BOOLEAN }},	{ 0, 0x00, 0xff, 0,	  { V4L2_CID_GAIN, "Gain",             0,  63, 1, DEF_GAIN,	    V4L2_CTRL_TYPE_INTEGER }},	{ 0, 0x29, 0x80, 7,	  { V4L2_CID_DISABLE_AEC, "Disable Auto Exposure", 0, 1, 0, DEF_DISABLE_AEC,	    V4L2_CTRL_TYPE_BOOLEAN }},	{ 0, REG_EXP, 0xff, 0,	  { V4L2_CID_EXPOSURE, "Exposure",     0, 255, 1, DEF_EXPOSURE,	    V4L2_CTRL_TYPE_INTEGER }},	{ 0, 0x28, 0x10, 4,	  { V4L2_CID_FREEZE_AGCAEC, "Freeze AGC/AEC", 0, 1, 0, DEF_FREEZE_AGCAEC,	    V4L2_CTRL_TYPE_BOOLEAN }},	{ 0, 0x12, 0x40, 6,	  { V4L2_CID_HFLIP, "Mirror Image",    0,   1, 0, DEF_HFLIP,	    V4L2_CTRL_TYPE_BOOLEAN }},	{ 0, 0x2d, 0x04, 2,	  { V4L2_CID_BANDFILT, "Band Filter",  0,   1, 0, DEF_BANDFILT,	    V4L2_CTRL_TYPE_BOOLEAN }},	{ 0, 0x2d, 0x10, 4,	  { V4L2_CID_AUTOBRIGHT, "Auto Black Expand", 0, 1, 0, DEF_AUTOBRIGHT,	    V4L2_CTRL_TYPE_BOOLEAN }},};#define NUM_CONTROLS (sizeof(control)/sizeof(control[0]))static struct {	u8 reg;	u8 val;	int no_verify;} init_regtbl[] = {	{ 0x12, 0x80, 1 }, /* reset */	{ 0x00, DEF_GAIN }, /* Gain */	{ 0x01, DEF_BLUE }, /* Blue gain */	{ 0x02, DEF_RED }, /* Red gain */	{ 0x03, DEF_SATURATION<<3 }, /* Saturation */	{ 0x05, DEF_CONTRAST }, /* Contrast */	{ 0x06, DEF_BRIGHTNESS}, /* Brightness */	{ 0x07, 0x2d }, /* Sharpness */	{ 0x0c, 0x20 },	{ 0x0d, 0x20 },	{ 0x0e, 0x20 },	{ 0x0f, 0x05 },	{ 0x10, DEF_EXPOSURE }, // exposure check	{ 0x11, 0x40 }, /* Pixel clock = fastest, VSYNC negative */	{ 0x12, (DEF_AWB<<2) | (DEF_AUTOGAIN<<5) | (DEF_HFLIP<<6) | (1<<3) },	{ 0x13, 0x29 },	{ 0x14, 0xb0 },	{ 0x15, 0x01 },	{ 0x16, 0x03 },	{ 0x17, 0x38 },	{ 0x18, 0xe8 }, // ea	{ 0x19, 0x03 }, // 04	{ 0x1a, 0x92 }, // 93	{ 0x1b, 0x00 },	{ 0x1c, 0x7f },	{ 0x1d, 0xa2 },	{ 0x1e, 0xc4 },	{ 0x1f, 0x04 },	{ 0x20, 0x20 },	{ 0x21, 0x10 },	{ 0x22, 0x88 },	{ 0x23, 0xc0 }, /* Crystal circuit power level */	{ 0x25, 0x9a }, /* Increase AEC black pixel ratio */	{ 0x26, 0xb2 }, /* BLC enable */	{ 0x27, 0xa2 },	{ 0x28, (DEF_FREEZE_AGCAEC<<4) | (1<<0) },	{ 0x29, (DEF_DISABLE_AEC<<7) },	{ 0x2c, 0xa0 },	/* This next setting is critical. It seems to improve	 * the gain or the contrast. The "reserved" bits seem	 * to have some effect in this case. */	{ 0x2d, (DEF_AUTOBRIGHT<<4) | (DEF_BANDFILT<<2) | (1<<7) | (1<<0) },	{ 0x2e, 0x88 },	{ 0x33, 0x26 },	// Reg 0x34: More 6620 reserved junk	{ 0x34, 0x03 },	{ 0x36, 0x8f }, 	{ 0x37, 0x80 },	{ 0x38, 0x91 },	{ 0x39, 0x80 },	{ 0x3a, 0x0f }, 	{ 0x3b, 0x3c },	{ 0x3c, 0x1a },	{ 0x3d, 0x80 },	{ 0x3e, 0x80 },	{ 0x3f, 0x0e }, 	{ 0x40, 0x00 }, /* White bal */	{ 0x41, 0x00 }, /* White bal */	{ 0x42, 0x80 },	{ 0x43, 0x3f }, /* White bal */	{ 0x44, 0x80 },	{ 0x45, 0x20 },	{ 0x46, 0x20 },	{ 0x47, 0x80 },	{ 0x48, 0x7f },	{ 0x49, 0x00 },	{ 0x4a, 0x00 }, 	{ 0x4b, 0x80 },	{ 0x4c, 0xd0 },	{ 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */	{ 0x4e, 0x40 }, /* AEC/AGC reference voltage level */	{ 0x4f, 0x07 }, /* UV average mode, color killer: strongest */	{ 0x50, 0xff },	{ 0x54, 0x23 }, /* Max AGC gain: 18dB */	{ 0x55, 0xff },	{ 0x56, 0x12 },	{ 0x57, 0x81 }, /* (default) */	{ 0x58, 0x75 },	{ 0x59, 0x01 }, /* AGC dark current compensation: +1 */	{ 0x5a, 0x2c },	{ 0x5b, 0x0f }, /* AWB chrominance levels */	{ 0x5c, 0x10 },	{ 0x3d, 0x80 },	{ 0x27, 0xa6 },	// Toggle AWB off and on	{ 0x12, (0<<2) | (DEF_AUTOGAIN<<5) | (DEF_HFLIP<<6) | (1<<3) },	{ 0x12, (DEF_AWB<<2) | (DEF_AUTOGAIN<<5) | (DEF_HFLIP<<6) | (1<<3) },};#define INIT_REGTBL_SIZE (sizeof(init_regtbl)/sizeof(init_regtbl[0]))typedef struct {	u8 R;	u8 G1;	u8 G2;	u8 B;} ov6x30_rgb_t;static inline void get_qcif_rgb(u8* s, ov6x30_rgb_t* rgb){	rgb->G2 = *s++;	rgb->B  = *s++;	rgb->G1 = *s++;	rgb->R  = *s;}static inline void get_cif_rgb(u8* s, ov6x30_rgb_t* rgb){	rgb->G2 = *s++;	rgb->R  = *s++;	rgb->G1 = *s++;	rgb->B  = *s;}static inline void convert_to_RGB565(u8* s, u16* d, int to_user, int qcif){	ov6x30_rgb_t rgb;	u16 p1, p2;		if (qcif)		get_qcif_rgb(s, &rgb);	else		get_cif_rgb(s, &rgb);	p1  = ((rgb.R & 0xf8)  << 8); // upper 5 bits of red at bit 11	p1 |= ((rgb.G1 & 0xFC) << 3); // upper 6 bits of grn at bit 5	p1 |= ((rgb.B & 0xf8)  >> 3); // upper 5 bits of blu at bit 0		p2  = ((rgb.R & 0xf8)  << 8);	p2 |= ((rgb.G2 & 0xFC) << 3);	p2 |= ((rgb.B & 0xf8)  >> 3);	if (to_user) {		put_user(p1, d++);		put_user(p2, d);	} else {		*d++ = p1;		*d = p2;	}}static inline void convert_to_BGR24(u8* s, u8* d, int to_user, int qcif){	ov6x30_rgb_t rgb;	u8 pixbuf[6];		if (qcif)		get_qcif_rgb(s, &rgb);	else		get_cif_rgb(s, &rgb);		pixbuf[0] = rgb.R;	pixbuf[1] = rgb.G1;	pixbuf[2] = rgb.B;	pixbuf[3] = rgb.R;	pixbuf[4] = rgb.G2;	pixbuf[5] = rgb.B;		if (to_user)		copy_to_user(d, pixbuf, sizeof(pixbuf));	else		memcpy(d, pixbuf, sizeof(pixbuf));}// **************************// Routine:// Description:// **************************static int ov6x30_convert_image(u8* src,				void* dest,				int to_user,				int dest_stride,				struct v4l2_pix_format* fmt){	int x, y;	int line_gap;	int dest_BPP = (fmt->depth+7) >> 3;	int width = omap_image_size[this->imgfmt].width;	int height = omap_image_size[this->imgfmt].height;	int qcif = (this->imgfmt == QCIF);		line_gap = dest_stride - (width * dest_BPP);	#ifndef CONFIG_OMAP_INNOVATOR	// Special Case, Since the first 32bit word transfered	// from the DMA is garbage. The second 32bit word is	// really the start of our image frame data. So, advance	// the pointer to that first pixel.	// This of course means that the last two	// pixels of the frame will now be random data since we will	// be reading 4 bytes beyond the real end of the dma buffer	// but we do this since having a frame with only two bad	// pixels is better than displaying the *whole* image	// shifted by two pixels. This feels like a work around	// for a h/w issue. Why is that first 32bit value xfered	// by the DMA an extra one that always proceeds the real	// data we are interested in? In my analysis that first	// pixel is a left over one from the prior frame. It is	// as if enabling the DMA xfer *immediately* triggers a	// transfer of that left over 32bit value which is then	// followed by the real pixels of the new image we're	// capturing on each new Lclk rising edge.	src+=4;#endif  	switch (fmt->pixelformat) {	case V4L2_PIX_FMT_RGB565:		// Convert camera data into rgb565.		for (y = 0; y < height; y++) {			for (x = 0 ; x < width/2 ; x++) {				convert_to_RGB565(src, (u16*)dest,						  to_user, qcif);				src += 2*OV6X30_BPP;				dest += 2*dest_BPP;			}			dest += line_gap;		}		break;	case V4L2_PIX_FMT_BGR24:		// Convert camera data into BGR24.		for (y = 0; y < height; y++) {			for (x = 0 ; x < width/2 ; x++) {				convert_to_BGR24(src, (u8*)dest,						 to_user, qcif);				src += 2*OV6X30_BPP;				dest += 2*dest_BPP;			}			dest += line_gap;		}		break;	default:		err("unsupported conversion request.\n");		return -ENXIO;	}	return 0;}#if 0static void ov6x30_dump(void){	struct camera_serial_bus * sbus = this->camif->sbus;	u8 buf[0x60];	memset(buf, 0, sizeof(buf));	sbus->read(0x00, buf, 0x5c);	DUMP_BUF(buf, sizeof(buf));}#endifstatic intfind_vctrl(int id){	int i;	if (id < V4L2_CID_BASE || id > V4L2_CID_LAST_PRIV)		return -EDOM;	for (i = NUM_CONTROLS - 1; i >= 0; i--)		if (control[i].qc.id == id)			break;	if (i < 0)		i = -EINVAL;	return i;}static intov6x30_querymenu(struct v4l2_querymenu *qm){#if 0	static char *expo_menu[] = {		"1/60",		"1/100",		"1/250",		"1/1000",		"1/5000",

⌨️ 快捷键说明

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