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

📄 s3c2440_camif.c

📁 2440mmc-and-camera-linux-driver 2440mmc-and-camera-linux-driver
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Camera interface on S3C2440 * * bushi@mizi.com * *  ToDo: *   - support "V4L2_FLAG_STREAMING" * * $Revision: 1.1.1.1 $ * * 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. *   Oct 25 2003 SeonKon Choi <bushi@mizi.com>    - initial    - support "V4L2_FLAG_READ"     Oct   2003 SW.LEE <hitchcar@sec.samsung.com>      $\> Take care of GPEDAT (Open drain)                       that is why I use write_gpio_bit_clear()      $\> make sure that your board support 24Mhz(or 12Mhz) Camera clock (using a internal clock)      $\> make sure that S3C2440 Evalution Board version is Rev 0.17 or above      $\> make sure that you jummper setting (J12 --5 voltage omnivisoin )      $\> make sure that       your CAMERA modules C3188A  (using a internel clock , do not use extenal clock 12MHz)		                       have no OSC and JP1 connected.      $\> s3c2440_camif.c needs the feedback from external camera modules as like the followings		1. IMGFMT ITU601,656, SWAP Order, need for Reset.. 	 */#include <linux/config.h>#include <linux/module.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/version.h>#include <linux/wait.h>#include <linux/irq.h>#include <linux/delay.h>#include <linux/sched.h>#include <linux/locks.h>#include <linux/mm.h>#include <linux/slab.h>#include <linux/completion.h>#include "videodev.h"#include <asm/io.h>#include <asm/hardware.h>#include <asm/semaphore.h>#include <asm/uaccess.h>#include <asm/arch/cpu_s3c2440.h>#include "s3c2440_camif.h"#define OV7620_MAX_CLK 24000000 #if DEBUG#define DPRINTK(x...) printk(x)#else#define DPRINTK(x...) /* !!!! */#endif#define CAMERA_RESET() \	{CAM_CTRL |= (1<<19); \	mdelay(50); \	CAM_CTRL &=  ~(1<<19); }enum {	VCTRL_BRIGHTNESS = 0,	VCTRL_REDBALANCE,	VCTRL_BLUEBALANCE,	VCTRL_EXPOSURE,	VCTRL_AUTOWHITEBALANCE,	NUM_OF_HW_CONTROL};static struct v4l2_queryctrl capture_control[NUM_OF_HW_CONTROL] ={	/* id, name, min, max, step, default, type, flags, category, group */	[VCTRL_BRIGHTNESS] =		 {V4L2_CID_BRIGHTNESS, "Brightness", 			0, 255,  1, 128, V4L2_CTRL_TYPE_INTEGER, 0, V4L2_CTRL_CAT_VIDEO},	[VCTRL_REDBALANCE] =		 {V4L2_CID_RED_BALANCE, "RedBalance", 			0, 255,  1, 128, V4L2_CTRL_TYPE_INTEGER, 0, V4L2_CTRL_CAT_VIDEO},	[VCTRL_BLUEBALANCE] =		 {V4L2_CID_BLUE_BALANCE, "BlueBalance", 			0, 255,  1, 128, V4L2_CTRL_TYPE_INTEGER, 0, V4L2_CTRL_CAT_VIDEO},	[VCTRL_EXPOSURE] =		 {V4L2_CID_EXPOSURE, "Exposure", 			0, 255,  1, 128, V4L2_CTRL_TYPE_INTEGER, 0, V4L2_CTRL_CAT_VIDEO},	[VCTRL_AUTOWHITEBALANCE] =		 {V4L2_CID_AUTO_WHITE_BALANCE, "AutoWhiteBalance", 			0, 1,  1, 1, V4L2_CTRL_TYPE_BOOLEAN, 0, V4L2_CTRL_CAT_VIDEO},};typedef int (control_fn) (int in, unsigned int *out);static control_fn *hw_control_func[NUM_OF_HW_CONTROL] = {0,};static struct v4l2_fmtdesc capfmt[] = {	/* index, description, pixel_format, flags, depth, reserved[2] */	{ 		0, {"RGB565"},	   	V4L2_PIX_FMT_RGB565, 0, 16, {0, 0} 	},#ifdef TEST_RGB32	{ 		1, {"RGB32(x-R-G-B)"}, 		V4L2_PIX_FMT_RGB32 , 0, 32, {0, 0} 	},#endif	{ 		2, {"YUV 4:2:0 (planar)"}, 		V4L2_PIX_FMT_YUV420, V4L2_FMT_CS_601YUV, 12, {0, 0} 	},};#define NUM_CAPFMT ARRAY_SIZE(capfmt)static unsigned long camdev_status;static unsigned long *camdev_status_data = &camdev_status;static struct s3c2440_camif_cfg_t s3c2440_camif_cfg;static struct img_buf_t yuv_buf[4];static struct img_buf_t rgb_buf[4];#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_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;static struct tq_struct cam_s_task; static DECLARE_MUTEX(cam_flag);static struct s3c2440_camif camif; // v4l2 devstatic void cam_to_yuv420_sw(int frame, struct s3c2440_camif_cfg_t *cfg);static void cam_to_rgb16_sw(int frame, struct s3c2440_camif_cfg_t *cfg);static void cam_to_rgb32_sw(int frame, struct s3c2440_camif_cfg_t *cfg);static int v4l2_cam_open(struct v4l2_device *v, int flags, void **idptr);static void v4l2_cam_close(void *id);static int v4l2_cam_ioctl(void *id, unsigned int cmd, void *arg);//static int v4l2_cam_mmap(void *id, struct vm_area_struct *vma);static long v4l2_cam_read(void *id, char *buf, unsigned long count, int noblock);//static long v4l2_cam_write(void *id, const char *buf, unsigned long count, int noblock);static int v4l2_cam_poll(void *id, struct file *file, poll_table * table);static int v4l2_cam_initdone (struct v4l2_device *v);/*  *  $\> SW.LEE *    *   OV7620_CLK is 12Mhz or 24Mhz *  *   CAMCLK = OV7620_CLK; *   CAMCLK_DIV =  UPLL / ( CAMCLK * 2)  - 1 ;  */static unsigned int get_camera_clk(void){        return OV7620_MAX_CLK;}static void cam_gpio_init(void){	set_gpio_ctrl(GPIO_CAMDATA0);	set_gpio_ctrl(GPIO_CAMDATA1);	set_gpio_ctrl(GPIO_CAMDATA2);	set_gpio_ctrl(GPIO_CAMDATA3);	set_gpio_ctrl(GPIO_CAMDATA4);	set_gpio_ctrl(GPIO_CAMDATA5);	set_gpio_ctrl(GPIO_CAMDATA6);	set_gpio_ctrl(GPIO_CAMDATA7);	set_gpio_ctrl(GPIO_CAMPCLKIN);	set_gpio_ctrl(GPIO_CAMVSYNC);	set_gpio_ctrl(GPIO_CAMHREF);	set_gpio_ctrl(GPIO_CAMPCLKOUT);	set_gpio_ctrl(GPIO_CAMRESET);}static void inline s3c2440_camif_init(void){	unsigned int upll, uclk, camclk,camclk_div;	cam_gpio_init();	camclk = get_camera_clk();	CLKCON |= CLKCON_CAMIF;	/* Supposed that you must set UPLL at first */	UPLLCON = FInsrt(0x38, fPLL_MDIV) | FInsrt(0x02, fPLL_PDIV)		| FInsrt(0x02, fPLL_SDIV);	upll = s3c2440_get_bus_clk(GET_UPLL);	uclk = (CLKDIVN & DIVN_UPLL_EN) ? upll/2 : upll;	printk("CAMERA : UPLL %08d  UCLK %08d CAMCLK %08d \n",upll, uclk, camclk);	camclk_div = upll /( camclk * 2) -1 ;	CAMDIVN = CAMCLK_SET_DIV | (camclk_div & 0xf ) ;	CAMERA_RESET();	mdelay(100);	}static void s3c2440_camif_deinit(void){	CLKCON &= ~CLKCON_CAMIF;	CAM_CTRL = 0;	mdelay(5);}static void cfg_dma_burst(int width){	int y_mburst, y_rburst;	int c_mburst, c_rburst;#if 0		switch (width) {	case 1024:		/* XGA 1024x768 */		y_mburst = c_mburst = 16;		break; 	case 800:		/* SVGA 800x600 */		y_mburst = c_mburst = 16;		break; 	case 640: 		/* VGA 640x480 */		y_mburst = c_mburst = 16;		break;	case 352:		/* CIF 352x288 */		y_mburst = 8;		c_mburst = 4;		break;	case 320:		/* QVGA 320x240 */		y_mburst = c_mburst = 8;		break;	case 176:		/* QCIF 176x144 */		/* fall throu */	default:		y_mburst = c_mburst = 4;		break;	}#endif	y_mburst = c_mburst = 4;	y_rburst = (width / 4) % y_mburst;		/* 4 means basic burst unit */	y_rburst = y_rburst ? y_rburst : y_mburst;	CAM_AYBURST = CAM_BURST_M(y_mburst) | CAM_BURST_R(y_rburst);	DPRINTK("YBURST = %d,%d = 0x%08lx\n", y_mburst, y_rburst			, CAM_BURST_M(y_mburst) | CAM_BURST_R(y_rburst));	c_rburst = (width / 2 / 4) % c_mburst;	c_rburst = c_rburst ? c_rburst : c_mburst;	CAM_ACBBURST = CAM_BURST_M(c_mburst) | CAM_BURST_R(c_rburst);	CAM_ACRBURST = CAM_BURST_M(c_mburst) | CAM_BURST_R(c_rburst);	DPRINTK("CBBURST = %d,%d = 0x%08lx\n", c_mburst, c_rburst			, CAM_BURST_M(c_mburst) | CAM_BURST_R(c_rburst));}static void s3c2440_camif_configure(struct s3c2440_camif_cfg_t *cfg){	int i;	unsigned long adist, awidth;	unsigned long hratio, vratio;	for (i = 0; i < 4; i++) {		yuv_buf[i].buf = camif_yuv_buf;		yuv_buf[i].phys_addr = (unsigned int)camif_yuv_buf_dma;		DPRINTK("yuv_buf[%d] : virt=0x%08lx, phys = 0x%08lx\n",				i, (unsigned long)yuv_buf[i].buf, (unsigned long)yuv_buf[i].phys_addr);		rgb_buf[i].buf = camif_rgb_buf;		rgb_buf[i].phys_addr = (unsigned int)camif_rgb_buf_dma;		DPRINTK("rgb_buf[%d] : virt=0x%08lx, phys = 0x%08lx\n",				i, (unsigned long)rgb_buf[i].buf, (unsigned long)rgb_buf[i].phys_addr);		CAM_STAY(i) = yuv_buf[i].phys_addr;		DPRINTK("STAY%d  = 0x%08x\n", i, yuv_buf[i].phys_addr);		CAM_STACB(i) = yuv_buf[i].phys_addr 				+ cfg->dev->clientfmt.width * cfg->dev->clientfmt.height;		DPRINTK("STACB%d = 0x%08x\n", i, 			yuv_buf[i].phys_addr + cfg->dev->clientfmt.width * cfg->dev->clientfmt.height);		CAM_STACR(i) = yuv_buf[i].phys_addr 				+ cfg->dev->clientfmt.width * cfg->dev->clientfmt.height / 2 * 3;		DPRINTK("STACR%d = 0x%08x\n", i, 			yuv_buf[i].phys_addr + cfg->dev->clientfmt.width * cfg->dev->clientfmt.height / 2 * 3);	}	DPRINTK("CAMIF: src = (%dx%d), dst = (%dx%d)\n",			cfg->src_x, cfg->src_y, cfg->dev->clientfmt.width, cfg->dev->clientfmt.height);	CAM_ASIZE = CAM_SIZE_H(cfg->dev->clientfmt.width) | CAM_SIZE_V(cfg->dev->clientfmt.height);	cfg_dma_burst(cfg->dev->clientfmt.width);	/*	 *      Adist =  ( MemoryBusClk/CameraClk ) * 3 * Width	 *                  * CameraClk = UPLL / [(CAMCLK_DIV + 1) * 2]	 */	adist = (s3c2440_get_bus_clk(GET_HCLK) * 3 * cfg->src_x) / get_camera_clk();						awidth = adist;	CAM_ADISTWIDTH = CAM_DISTWIDTH_D(adist) | CAM_DISTWIDTH_W(awidth);	DPRINTK("HCLK = %ld, pixel_clock = %ld, adist = %ld\n" , 		 s3c2440_get_bus_clk(GET_HCLK) ,  get_camera_clk() , adist);		DPRINTK("CAM_ADISTWIDTH = 0x%08lx\n"			, CAM_DISTWIDTH_D(adist) | CAM_DISTWIDTH_W(awidth));	hratio = (cfg->src_x * 4096) / cfg->dev->clientfmt.width;	vratio = (cfg->src_y * 4096) / cfg->dev->clientfmt.height;	CAM_YRATIO = CAM_RATIO_H(hratio) | CAM_RATIO_V(vratio);	DPRINTK("YRATIO = %ld,%ld = 0x%08lx\n", hratio, vratio			, CAM_RATIO_H(hratio) | CAM_RATIO_V(vratio));	hratio = ((cfg->src_x/2) * 4096) / (cfg->dev->clientfmt.width/2);	vratio = (cfg->src_y * 4096) / (cfg->dev->clientfmt.height/2);	CAM_CRATIO = CAM_RATIO_H(hratio) | CAM_RATIO_V(vratio);	DPRINTK("CRATIO = %ld,%ld = 0x%08lx\n", hratio, vratio			, CAM_RATIO_H(hratio) | CAM_RATIO_V(vratio));	CAM_YORIGINAL = CAM_ORIGINAL_H(cfg->src_x) | CAM_ORIGINAL_V(cfg->src_y);	DPRINTK("YORIGINAL = 0x%08lx\n", 			CAM_ORIGINAL_H(cfg->src_x) | CAM_ORIGINAL_V(cfg->src_y));	CAM_CORIGINAL = CAM_ORIGINAL_H((cfg->src_x/2)) | CAM_ORIGINAL_V(cfg->src_y);	DPRINTK("CORIGINAL = 0x%08lx\n", 			CAM_ORIGINAL_H((cfg->src_x/2)) | CAM_ORIGINAL_V(cfg->src_y));	if (cfg->use_vpost) {			panic("Not Supporting H/W post-processing \n");	} else {		switch (cfg->dev->clientfmt.pixelformat ) {			case V4L2_PIX_FMT_RGB565:				cfg->camif_frame_handler =  cam_to_rgb16_sw;				break;#ifdef TEST_RGB32			case V4L2_PIX_FMT_RGB32:				cfg->camif_frame_handler = cam_to_rgb32_sw;				break;#endif			case V4L2_PIX_FMT_YUV420:				cfg->camif_frame_handler = cam_to_yuv420_sw;				break;			default:				panic("unknown destination type.\n");		}	}	if (!cfg->camif_frame_handler)		panic("\nunknown dst_type.\n");}static void cam_s_task_handler(void * data){	struct s3c2440_camif_cfg_t *cfg = (struct s3c2440_camif_cfg_t *)data;		int frame = (CAM_STAT_FRAME(CAM_RDSTAT) ); // + 3) % 4;//	DPRINTK("frame = %d\n", frame);	cfg->camif_frame_handler(frame, cfg);}static void s3c2440_camif_isr_s(int irq, void *dev_id, struct pt_regs *regs){	schedule_task(&cam_s_task);}#define XLATTABSIZE      256#define MulDiv(x, y, z) ((long)((int) x * (int) y) / (int) z)#define CLIP(x) {if(x<0) x=0;if(x>255) x=255;}#define RED_REGION      0xf800#define GREEN_REGION    0x07e0#define BLUE_REGION     0x001fstatic int XlatY[XLATTABSIZE] = { 0 };static int XlatV_B[XLATTABSIZE] = { 0 };static int XlatV_G[XLATTABSIZE] = { 0 };static int XlatU_G[XLATTABSIZE] = { 0 };static int XlatU_R[XLATTABSIZE] = { 0 };static void __init init_yuvtable (void){	int i, j;	for (i = 0; i < XLATTABSIZE; i++) {		j = min_t(int, 253, max_t(int, 16, i));		// orig: XlatY[i] = (int ) j;		XlatY[i] = j-16;	}	for (i = 0; i < XLATTABSIZE; i++) {		j = min_t(int, 240, max_t(int, 16, i));		j -= 128;		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);	}}static void 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;		Y = buf1;		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);		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);		*(unsigned short *)(rgb + 2 * cnt) = data;		*(unsigned short *)(rgb + 2 * (cnt + 1))= data2;	}}static 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;		Y = buf1;		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;		Y = buf3;		red = XlatY[Y] + XlatU_R[U];		CLIP(red);		green = XlatY[Y] - XlatV_G[V] - XlatU_G[U];

⌨️ 快捷键说明

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