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

📄 s3c2440_ov7620.c

📁 三星s3c2440 ARM9芯片在linux下的摄像头驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * 1. Orignal :  *    OV7620 on S3C24A0 CAMIF *     bushi@mizi.com * * 2. 2003-09-01: SW.LEE <hitchcar@sec.samsung.com> *     <S3C2440 > *     $\> Camera Clock Set.  *         make sure that your board support 24Mhz *         Change OV7620 Clock from 12Mhz to 24Mhz *     $\> Take care of GPEDAT (Open drain) *         that is why I use write_gpio_bit_clear()  *     $\> if you have no image from camera, DISABLE ov7620_config() *        if it works, change SCCB_DELAY *     * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive * for more details. */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/irq.h>#include <linux/tqueue.h>#include <linux/locks.h>#include <linux/completion.h>#include <linux/delay.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <linux/miscdevice.h>#include <linux/wait.h>#include <asm/io.h>#include <asm/semaphore.h>#include <asm/hardware.h>#include <asm/uaccess.h>#include <asm/arch/cpu_s3c2440.h>#include "smdk2440_ov7620.h"#include <asm/arch/S3C2440.h>#define DEBUG_OVERLAY_TO_FB 0#define DEBUG_WORK_STANDALONE 0//#define DEBUG_PRINTK//#define DEBUG_PRINTK2#ifdef DEBUG_PRINTK#define DPRINTK(x...) printk(x)#else#define DPRINTK(x...) do {} while (0) /* !!!! */#endif#ifdef DEBUG_PRINTK2#define DPRINTK2(x...) printk(x)#else#define DPRINTK2(x...) do {} while (0) /* !!!! */#endif#define CAMIF_TYPE_RGB16 0#define CAMIF_TYPE_RGB32 1#define CAMIF_TYPE_YUV420 2#define CAM_SRC_X 640#define CAM_SRC_Y 480#define CAMIF_DST_X 240#define CAMIF_DST_Y 180static int camif_dst_x = CAMIF_DST_X;static int camif_dst_y = CAMIF_DST_Y;#define MORE_STABLE_BUT_SLOW 0#define CAMIF_DEFAULT_FMT CAMIF_TYPE_RGB16/**************** global **************/static struct s3c2440_camif_cfg_t {	int src_x;	int src_y;	int dst_x;	int dst_y;	int use_vpost;	int dst_type;	void (*camif_frame_handler)(int frame, struct s3c2440_camif_cfg_t *cfg);} s3c2440_camif_cfg;struct img_buf_t {	unsigned int phys_addr;	unsigned char *buf;};static int frame_to_user = 0;static struct img_buf_t yuv_buf[4];static struct img_buf_t rgb_buf[4];#define CAPTURE_PORT_A() \	{CAM_CTRL = (1<<20) /*| (1<<13) */| (1<<18) | (1<<17) | (1<<6);}static DECLARE_WAIT_QUEUE_HEAD(camdev_wait);static unsigned long camdev_cam_status;static unsigned char *camdev_status_data = (unsigned char*)&camdev_cam_status;#define CAM_CAPTURING 1#define CAM_OPENED  2#define SET_CAM(x) set_bit(x, camdev_status_data)#define IS_CAM(x) test_bit(x, camdev_status_data)#define UNSET_CAM(x) clear_bit(x, camdev_status_data)#define YUV_TUPLE_SIZE (640*480*2) // maximum#define YUV_IMG_BUF_SIZE PAGE_ALIGN(YUV_TUPLE_SIZE + PAGE_SIZE)static unsigned char *camif_yuv_buf = NULL;static dma_addr_t camif_yuv_buf_dma = 0;#define RGB_TUPLE_SIZE (640*480*4) // maximum RGB32 ????//#define RGB_TUPLE_SIZE (640*480*2)#define RGB_IMG_BUF_SIZE PAGE_ALIGN(RGB_TUPLE_SIZE + PAGE_SIZE)static unsigned char *camif_rgb_buf = NULL;static dma_addr_t camif_rgb_buf_dma = 0;#if MORE_STABLE_BUT_SLOW#define USER_TUPLE_SIZE RGB_TUPLE_SIZEstatic unsigned char *camif_user_buf = NULL;static DECLARE_WAIT_QUEUE_HEAD(cam_wait);#endif/********* end of global **************//*********** start of OV7620 ********************//* refer to 25p of OV7620 datasheet */#  define OV7620_SCCB_ID 0x42  /* CS[2:0] = 000 */#  define OV7620_MAX_CLK 24000000 // 24MHz#  define OV7620_PRODUCT_ID 0x7FA2#  define OV7620_SCCB_DELAY    100 #  define OV7620_SCCB_DELAY2   100#  define SIO_C          (GPIO_E14)#  define SIO_D          (GPIO_E15)#  define MAKE_HIGH(_x)  write_gpio_bit_set(_x)#  define MAKE_LOW(_x)   write_gpio_bit_clear(_x)#  define BIT_READ(_x)   read_gpio_bit(_x)#  define CFG_READ(_x)   set_gpio_ctrl(_x | GPIO_PULLUP_DIS | GPIO_MODE_IN)#  define CFG_WRITE(_x)  set_gpio_ctrl(_x | GPIO_PULLUP_DIS | GPIO_MODE_OUT)#if OV7620_SCCB_DELAY > 0#  define WAIT_CYL udelay(OV7620_SCCB_DELAY)#else#  define WAIT_CYL (void)(0)#endif#if OV7620_SCCB_DELAY2 > 0#  define WAIT_STAB udelay(OV7620_SCCB_DELAY2)#else#  define WAIT_STAB (void)(0)#endifstatic unsigned int get_camera_clk(void){	return OV7620_MAX_CLK;}/* 2-wire SCCB */void inline ov7620_sccb_start(void){	MAKE_HIGH(SIO_C);	MAKE_HIGH(SIO_D);	WAIT_STAB;	MAKE_LOW(SIO_D);	WAIT_STAB;	MAKE_LOW(SIO_C);	WAIT_STAB;}/* 2-wire SCCB */void inline ov7620_sccb_end(void){	MAKE_LOW(SIO_D);	WAIT_STAB;	MAKE_HIGH(SIO_C);	WAIT_STAB;	MAKE_HIGH(SIO_D);	WAIT_STAB;}void inline ov7620_sccb_write_bit(unsigned char bit){	if (bit)		MAKE_HIGH(SIO_D);	else		MAKE_LOW(SIO_D);	WAIT_STAB;	MAKE_HIGH(SIO_C);	WAIT_CYL;	MAKE_LOW(SIO_C);	WAIT_STAB;}int inline ov7620_sccb_read_bit(void){	int tmp = 0;	MAKE_HIGH(SIO_C);	WAIT_CYL;	tmp = BIT_READ(SIO_D);	MAKE_LOW(SIO_C);	WAIT_STAB;	return tmp;}	void inline ov7620_sccb_writechar(unsigned char data){	int i = 0;	/* data */	for (i = 0; i < 8; i++ ) {		ov7620_sccb_write_bit(data & 0x80);		data <<= 1;	}	/* 9th bit - Don't care */	ov7620_sccb_write_bit(1);}void inline ov7620_sccb_readchar(unsigned char *val){	int i;	int tmp = 0;	CFG_READ(SIO_D);	for (i = 7; i >= 0; i--)		tmp |= ov7620_sccb_read_bit() << i;	CFG_WRITE(SIO_D);	/* 9th bit - N.A. */	ov7620_sccb_write_bit(1);	*val = tmp & 0xff;}/* 3-phase write */static void ov7620_sccb_sendbyte(unsigned char subaddr, unsigned char data){//	down(&dev.bus_lock);	ov7620_sccb_start();	ov7620_sccb_writechar(OV7620_SCCB_ID);	ov7620_sccb_writechar(subaddr);	ov7620_sccb_writechar(data);	ov7620_sccb_end();	mdelay(7);//	up(&dev.bus_lock);}/* 2-phase read */static unsigned char ov7620_sccb_receivebyte(unsigned char subaddr){	unsigned char value;//	down(&dev.bus_lock);	/* 2-phase write */	ov7620_sccb_start();	ov7620_sccb_writechar(OV7620_SCCB_ID);	ov7620_sccb_writechar(subaddr);	ov7620_sccb_end();	/* 2-phase read */	ov7620_sccb_start();	ov7620_sccb_writechar(OV7620_SCCB_ID | 0x01);	ov7620_sccb_readchar(&value);	ov7620_sccb_end();	mdelay(7);//	up(&dev.bus_lock);	return value;}void inline ov7620_init(void){	CFG_WRITE(SIO_C);	CFG_WRITE(SIO_D);	mdelay(10);}void inline ov7620_deinit(void){	CFG_READ(SIO_C);	CFG_READ(SIO_D);}void inline ov7620_config(void){	int i;	for (i = 0; i < OV7620_REGS; i++) {		if (ov7620_reg[i].subaddr == CHIP_DELAY)			mdelay(ov7620_reg[i].value);		else			ov7620_sccb_sendbyte(ov7620_reg[i].subaddr & 0xff					, ov7620_reg[i].value & 0xff);	}}int inline check_ov7620(void){	int ret = 0;	int ov7620_mid = 0;	int try_count =0;try_again:	ov7620_mid = (ov7620_sccb_receivebyte(0x1c) << 8);	ov7620_mid |= ov7620_sccb_receivebyte(0x1d);	if (ov7620_mid != OV7620_PRODUCT_ID) {		if (!try_count++) goto try_again;		printk("Invalid manufacture ID (0x%04X). there is no OV7620(0x%04X)\n",				ov7620_mid, OV7620_PRODUCT_ID);		ret = -ENODEV;	} else {		printk("OV7620(0x%04X) detected.\n", ov7620_mid);	}	return ret;}/********* end of OV7620 ********************//********** start of S/W YUV2RGB ************/#define XLATTABSIZE      256#define MulDiv(x, y, z)	((long)((int) x * (int) y) / (int) z)//#define CLIP(x)	min_t(int, 255, max_t(int, 0, (x)))#define CLIP(x) {if(x<0) x=0;if(x>255) x=255;}#define RED_REGION      0xf800#define GREEN_REGION    0x07e0#define BLUE_REGION     0x001fint XlatY[XLATTABSIZE] = { 0 };int XlatV_B[XLATTABSIZE] = { 0 };int XlatV_G[XLATTABSIZE] = { 0 };int XlatU_G[XLATTABSIZE] = { 0 };int XlatU_R[XLATTABSIZE] = { 0 };#define ORIG_XLAT 1void __init init_yuvtable (void){	int i, j;	for (i = 0; i < XLATTABSIZE; i++) {#if ORIG_XLAT		j = min_t(int, 253, max_t(int, 16, i));#else		j = (255 * i + 110) / 220;	// scale up		j = min_t(int, 255, max_t(int, j, 16));#endif		// orig: XlatY[i] = (int ) j;		XlatY[i] = j-16;	}	for (i = 0; i < XLATTABSIZE; i++) {#if ORIG_XLAT		j = min_t(int, 240, max_t(int, 16, i));		j -= 128;#else		j = i - 128;		// make signed		if (j < 0)			j++;			// noise reduction		j = (127 * j + 56) / 112;	// scale up		j = min_t(int, 127, max_t(int, -128, j));#endif		XlatV_B[i] = MulDiv (j, 1000, 564);	/* j*219/126 */		XlatV_G[i] = MulDiv (j, 1100, 3328);		XlatU_G[i] = MulDiv (j, 3100, 4207);		XlatU_R[i] = MulDiv (j, 1000, 713);	}}#define MORE_QUALITY 1void inline yuv_convert_rgb16(unsigned char *rawY, unsigned char *rawU,	  	unsigned char *rawV, unsigned char *rgb, int size){	unsigned short  buf1, buf3;	int   red;	int   blue;	int   green;	unsigned long   cnt;	int    Y, U, V;	unsigned short  data;	unsigned short  data2;	for ( cnt = 0 ; cnt < size; cnt +=2){		buf1 = *(rawY+cnt) & 0xff;  // Y data		buf3 = *(rawY+cnt+1) & 0xff;  // Y data		U = *(rawV+cnt/2) & 0xff;		V = *(rawU+cnt/2) & 0xff;#if MORE_QUALITY		Y = buf1;#else		Y = ((buf1+buf3)/2);#endif		red = XlatY[Y] + XlatU_R[U];		CLIP(red);		green = XlatY[Y] - XlatV_G[V] - XlatU_G[U];		CLIP(green);		blue = XlatY[Y] + XlatV_B[V];		CLIP(blue);		data = ((red << 8) & RED_REGION)				| ((green << 3) & GREEN_REGION)				| (blue >> 3);#if MORE_QUALITY		Y = buf3;		red = XlatY[Y] + XlatU_R[U];		CLIP(red);		green = XlatY[Y] - XlatV_G[V] - XlatU_G[U];		CLIP(green);		blue = XlatY[Y] + XlatV_B[V];		CLIP(blue);		data2 = ((red << 8) & RED_REGION)				| ((green << 3) & GREEN_REGION)				| (blue >> 3);#else		data2 = data;#endif		*(unsigned short *)(rgb + 2 * cnt) = data;		*(unsigned short *)(rgb + 2 * (cnt + 1))= data2;	}}void inline yuv_convert_rgb32(unsigned char *rawY, unsigned char *rawU, 		unsigned char *rawV, unsigned char *rgb, int size){	unsigned short  buf1, buf3;	int   red;	int   blue;	int   green;	unsigned long   cnt;	int    Y, U, V;	for ( cnt = 0 ; cnt < size; cnt +=2){		buf1 = *(rawY+cnt) & 0xff;  // Y data		buf3 = *(rawY+cnt+1) & 0xff;  // Y data		U = *(rawV+cnt/2) & 0xff;		V = *(rawU+cnt/2) & 0xff;#if MORE_QUALITY		Y = buf1;#else		Y = ((buf1+buf3)/2);#endif		red = XlatY[Y] + XlatU_R[U];		CLIP(red);		green = XlatY[Y] - XlatV_G[V] - XlatU_G[U];		CLIP(green);		blue = XlatY[Y] + XlatV_B[V];		CLIP(blue);		*(unsigned int*)(rgb) = (red << 16) | (green << 8) | blue;		rgb += 4;#if MORE_QUALITY		Y = buf3;		red = XlatY[Y] + XlatU_R[U];		CLIP(red);		green = XlatY[Y] - XlatV_G[V] - XlatU_G[U];		CLIP(green);		blue = XlatY[Y] + XlatV_B[V];		CLIP(blue);#endif		*(unsigned int*)(rgb) = (red << 16) | (green << 8) | blue;		rgb += 4;	}}/********** end of S/W YUV2RGB ******************//************** start of CAMIF **********/static struct tq_struct cam_s_task; static void cam_to_rgb16_sw(int frame, struct s3c2440_camif_cfg_t *cfg){	int i;	for (i = 0; i < cfg->dst_y; i++)		yuv_convert_rgb16(yuv_buf[frame].buf + i * cfg->dst_x,				yuv_buf[frame].buf + cfg->dst_x*cfg->dst_y 					+ (i/2) * cfg->dst_x / 2,				yuv_buf[frame].buf + cfg->dst_x*cfg->dst_y/2*3 					+ (i/2) * cfg->dst_x / 2,				rgb_buf[frame].buf + i * cfg->dst_x * 2,				cfg->dst_x);	frame_to_user = frame;#define CAMTEST_FB_BASE					0xC0381000	#if DEBUG_OVERLAY_TO_FB	/* 	 * for TEST 	 *   overlay to 240x320 FB	 */	{		int k;		int maxy = min_t(int, 320, cfg->dst_y);		int maxx = min_t(int, 240, cfg->dst_x);		unsigned char *fb_base = (unsigned char *)(CAMTEST_FB_BASE);		for (k = 0; k < maxy; k++)			memcpy( fb_base + (240 * 2 * k), 					rgb_buf[frame].buf + (cfg->dst_x * 2 * k),					maxx * 2);

⌨️ 快捷键说明

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