omap16xxcam.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 596 行

C
596
字号
/* * drivers/media/video/omap/omap16xxcam.c * * Copyright (C) 2004 Texas Instruments, Inc.  *  * Video-for-Linux (Version 2) camera capture driver for * the OMAP H2 and H3 camera controller. * * leverage some code from CEE distribution  * Copyright (C) 2003-2004 MontaVista Software, Inc. *  * This package 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.  *  * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.  */ #include <linux/config.h>#include <linux/vmalloc.h>#include <linux/slab.h>#include <linux/proc_fs.h>#include <linux/ctype.h>#include <linux/delay.h>#include <linux/device.h>#include <linux/dma-mapping.h>#include <linux/interrupt.h>#include <asm/arch/irqs.h>#include <asm/arch/dma.h>#include <asm/arch/mux.h>#include <asm/arch/hardware.h>#include <asm/hardware/clock.h>#include <asm/io.h>#include <asm/scatterlist.h>#include <asm/mach-types.h>#include "omap16xxcam.h"#include "camera_hw_if.h"#include "camera_core.h"  #define CONF_CAMERAIF_RESET_R 5#define EN_TC2CK  	4#define EN_PER	  	0#define EN_PERCK	2#define EN_XORPCK   1/* NUM_CAMDMA_CHANNELS is the number of logical channels used for * DMA data transfer. */#define NUM_CAMDMA_CHANNELS 2typedef struct {        unsigned int ctrlclock;     /* 00 */        unsigned int it_status;     /* 04 */        unsigned int mode;          /* 08 */        unsigned int status;        /* 0C */        unsigned int camdata;       /* 10 */        unsigned int gpio;   	    /* 14 */        unsigned int peak_counter;  /* 18 */} camera_regs_t;struct camdma_state {	dma_callback_t callback;	void *arg1;	void *arg2;};struct omap16xxcam {	camera_regs_t *camera_regs;	unsigned long iobase_phys;	/* frequncy (in Hz) of camera interface functional clock (ocp_clk) */	unsigned long ocp_clk; 	/* dma related stuff */	spinlock_t dma_lock;	int free_dmach;	int next_dmach;	struct camdma_state camdma[NUM_CAMDMA_CHANNELS];	int dma_channel_number1;	int dma_channel_number2;	wait_queue_head_t vsync_wait;		int new;};static struct omap16xxcam hardware_data;   static int omap16xxcam_set_xclk(int, void *);static void omap16xx_cam_dma_link_callback(int, unsigned short, void *);/* Clears the camera data FIFO by setting RAZ_FIFO bit in MODE configuration   register. */static voidomap16xx_cam_clear_fifo(struct omap16xxcam *data){	data->camera_regs->mode |= RAZ_FIFO;	udelay(10);	data->camera_regs->mode &= ~RAZ_FIFO;}  static voidomap16xx_cam_reset(struct omap16xxcam *data, int yes){	if (machine_is_omap_h3())		data->camera_regs->gpio = yes ? 0 : 1;	else		data->camera_regs->gpio = yes ? 1 : 0;}static void omap16xx_cam_init(void){	omap_cfg_reg(H19_1610_CAM_EXCLK);	omap_cfg_reg(J15_1610_CAM_LCLK);	omap_cfg_reg(J18_1610_CAM_D7);	omap_cfg_reg(J19_1610_CAM_D6);	omap_cfg_reg(J14_1610_CAM_D5);	omap_cfg_reg(K18_1610_CAM_D4);	omap_cfg_reg(K19_1610_CAM_D3);	omap_cfg_reg(K15_1610_CAM_D2);	omap_cfg_reg(K14_1610_CAM_D1);	omap_cfg_reg(L19_1610_CAM_D0);	omap_cfg_reg(L18_1610_CAM_VS);	omap_cfg_reg(L15_1610_CAM_HS);	omap_cfg_reg(M19_1610_CAM_RSTZ);	omap_writel(0xeaef, COMP_MODE_CTRL_0);	omap_writel(omap_readl(OMAP16XX_RESET_CONTROL) & ~(1 << CONF_CAMERAIF_RESET_R),			OMAP16XX_RESET_CONTROL);	omap_writel(omap_readl(OMAP16XX_RESET_CONTROL) | (1 << CONF_CAMERAIF_RESET_R),			OMAP16XX_RESET_CONTROL);    	/* Enable peripheral reset */	omap_writew(omap_readw(ARM_RSTCT2) | (1 << EN_PER), ARM_RSTCT2); 	/* enable peripheral clock */	if (machine_is_omap_h3())		omap_writew(omap_readw(OMAP16XX_ARM_IDLECT3) | (1 << EN_TC2CK),			OMAP16XX_ARM_IDLECT3);	else {		omap_writew(omap_readw(ARM_IDLECT2) | (1 << EN_PERCK), ARM_IDLECT2);		omap_writew(omap_readw(ARM_IDLECT2) | (1 << EN_XORPCK), ARM_IDLECT2);	}		}static voidomap16xx_cam_waitfor_syncedge(struct omap16xxcam *data, u32 edge_mask){	data->camera_regs->mode = (FIFO_TRIGGER_LVL << THRESHOLD_BIT) | edge_mask;	do {		interruptible_sleep_on(&data->vsync_wait);	} while (signal_pending(current));}static voidomap16xx_cam_configure_dma(struct omap16xxcam *data){	data->camera_regs->mode = (FIFO_TRIGGER_LVL << THRESHOLD_BIT)			 | EN_DMA | EN_FIFO_FULL;	data->camera_regs->ctrlclock |= LCLK_EN; }/* acquire h/w resources DMA */static intomap16xx_cam_link_open(struct omap16xxcam *data){	int ret;	/* Acquire first dma channel */	if ((ret = omap_request_dma(OMAP_DMA_CAMERA_IF_RX, 				"camera dma 1", omap16xx_cam_dma_link_callback,				(void *)data, &data->dma_channel_number1))) {                return ret;	}	/* Acquire second dma channel */	if ((ret = omap_request_dma(OMAP_DMA_CAMERA_IF_RX, 				"camera dma 2", omap16xx_cam_dma_link_callback,				(void *)data, &data->dma_channel_number2))) {                printk ("No DMA available for camera\n");                return ret;        } 	data->next_dmach = data->dma_channel_number1;	omap_writew(data->dma_channel_number2, 				OMAP_DMA_CLNK_CTRL(data->dma_channel_number1));	omap_writew(data->dma_channel_number1, 				OMAP_DMA_CLNK_CTRL(data->dma_channel_number2));	return 0;}/* free h/w resources, stop i/f */static intomap16xx_cam_link_close(struct omap16xxcam *data){	/* free dma channels */	omap_stop_dma(data->dma_channel_number1);	omap_stop_dma(data->dma_channel_number2);	omap_free_dma (data->dma_channel_number1);	omap_free_dma (data->dma_channel_number2);	return 0;}/* dma callback routine. */static voidomap16xx_cam_dma_link_callback(int lch, unsigned short ch_status, void *data){	int count;	void *arg1, *arg2;	struct sgdma_state *sgdma = sgdma;	struct omap16xxcam *cam = (struct omap16xxcam *)data;	dma_callback_t callback;	spin_lock(&cam->dma_lock);	if (cam->free_dmach == 2)	{		printk("callback all CHANNELS WERE IDLE \n");		spin_unlock(&cam->dma_lock);		return;	}	if (cam->free_dmach == 0) {		lch = cam->next_dmach;	} else {		lch = cam->next_dmach == cam->dma_channel_number1 ? 			cam->dma_channel_number2 : cam->dma_channel_number1;	}	while (cam->free_dmach < 2)	{		if ((omap_readw(OMAP_DMA_CCR(lch)) & (1 << 7) ))			break;			count = (lch == cam->dma_channel_number2) ? 1 : 0;		callback = cam->camdma[count].callback; 		arg1 = cam->camdma[count].arg1;		arg2 = cam->camdma[count].arg2;		cam->free_dmach++;		spin_unlock(&cam->dma_lock);		 		callback(arg1, arg2);		spin_lock(&cam->dma_lock);		lch = (lch == cam->dma_channel_number2) ? cam->dma_channel_number1 :							cam->dma_channel_number2;	}	spin_unlock(&cam->dma_lock);	}static irqreturn_tomap16xx_cam_isr(int irq, void *client_data, struct pt_regs *regs){	struct omap16xxcam *data = (struct omap16xxcam *)client_data;	unsigned int itstat = data->camera_regs->it_status;	/* VSYNC UP interrupt, start filling FIFO and enabling DMA */	if (itstat & V_UP) {				data->camera_regs->mode &= ~EN_V_UP;	 	omap16xx_cam_clear_fifo(data);			omap16xx_cam_configure_dma(data);		omap_start_dma(data->next_dmach);		wake_up_interruptible(&data->vsync_wait);	}	if (itstat & V_DOWN) {		data->camera_regs->mode &= ~EN_V_DOWN;		wake_up_interruptible(&data->vsync_wait);	}	if (itstat & H_UP)		printk("H_UP\n");		if (itstat & H_DOWN)		printk("H_DOWN\n");		if (itstat & FIFO_FULL) {		//omap16xx_cam_clear_fifo(data);			//printk("FIFO_FULL\n");	}		if (itstat & DATA_XFER)		printk("DATA_TRANS\n");		return IRQ_HANDLED;} /* ------------- below are interface functions ----------------- *//* ------------- these functions are named omap16xxcam_<name> -- */static intomap16xxcam_init_dma(void *priv){	int ch;	struct omap16xxcam *data = (struct omap16xxcam *) priv;	spin_lock_init(data->dma_lock);	data->free_dmach = 2;	for (ch = 0; ch < 2; ++ch) {		data->camdma[ch].callback = NULL;		data->camdma[ch].arg1 = NULL;		data->camdma[ch].arg2 = NULL;	}	return 0;}/* start the dma of chains */static int omap16xxcam_start_dma(struct sgdma_state *sgdma,		dma_callback_t callback, void *arg1, void *arg2, void *priv){	struct omap16xxcam *data = (struct omap16xxcam *) priv;	struct scatterlist *sglist;	unsigned long irqflags;	int dmach;	int prev_dmach;	int count;	spin_lock_irqsave(&data->dma_lock, irqflags);	sglist = (struct scatterlist *)(sgdma->sglist + sgdma->next_sglist);	if (!data->free_dmach) {		spin_unlock_irqrestore(&data->dma_lock, irqflags);		return -EBUSY;	} 	dmach = data->next_dmach;	count = (dmach == data->dma_channel_number2) ? 1:0;	data->camdma[count].callback = callback;	data->camdma[count].arg1 = arg1;	data->camdma[count].arg2 = arg2;		if (machine_is_omap_h3())		omap_set_dma_src_params(dmach, OMAP_DMA_PORT_OCP_T1,			    OMAP_DMA_AMODE_CONSTANT, CAM_CAMDATA_REG);	else		omap_set_dma_src_params(dmach, OMAP_DMA_PORT_TIPB,			    OMAP_DMA_AMODE_CONSTANT, CAM_CAMDATA_REG);	omap_set_dma_dest_params(dmach, OMAP_DMA_PORT_EMIFF,	                     OMAP_DMA_AMODE_POST_INC, sg_dma_address(sglist));	omap_set_dma_transfer_params(dmach, OMAP_DMA_DATA_TYPE_S32,			FIFO_TRIGGER_LVL, 			sg_dma_len(sglist)/(4 * FIFO_TRIGGER_LVL),  			OMAP_DMA_SYNC_FRAME);		omap_writew(omap_readw(OMAP_DMA_CLNK_CTRL(dmach)) & ~(1<<15), 					OMAP_DMA_CLNK_CTRL(dmach));	prev_dmach = (dmach == data->dma_channel_number2) ? 		data->dma_channel_number1 : data->dma_channel_number2;		if (data->new) {		data->new = 0;		omap16xx_cam_waitfor_syncedge(data, EN_V_UP);	} else {		if (omap_readw(OMAP_DMA_CCR(prev_dmach)) & (1 << 7)) {			omap_writew((omap_readw(OMAP_DMA_CLNK_CTRL(prev_dmach)) |					 (1 << 15)),			OMAP_DMA_CLNK_CTRL(prev_dmach));		}		else {			/* no transfer is in progress */  			omap_start_dma(dmach);		}		} 		data->next_dmach = prev_dmach; 	data->free_dmach--;	spin_unlock_irqrestore(&data->dma_lock, irqflags);	return 0;}int staticomap16xxcam_finish_dma(void *priv){	struct omap16xxcam *data = (struct omap16xxcam *) priv;	while (data->free_dmach < 2)		mdelay(1);	return 0;}/* Enables the camera. Takes camera out of reset. Enables the clocks. */ static intomap16xxcam_enable(void *priv){	struct omap16xxcam *data = (struct omap16xxcam *) priv;	omap16xx_cam_reset(data, 1);		/* give clock to camera_module */	data->camera_regs->mode = (FIFO_TRIGGER_LVL << THRESHOLD_BIT);	data->camera_regs->ctrlclock = MCLK_EN | CAMEXCLK_EN;	omap16xx_cam_clear_fifo(data);	/* wait for camera to settle down */	mdelay(5);	return 0;} /* Disables all the camera clocks. Put the camera interface in reset. */static intomap16xxcam_disable(void *priv){ 		struct omap16xxcam *data = (struct omap16xxcam *) priv;	omap16xx_cam_clear_fifo(data);	data->camera_regs->ctrlclock = 0x00000000;     	data->camera_regs->mode = 0x00000000;		omap16xx_cam_reset(data, 0);	return 0;}/* Abort the data transfer */static intomap16xxcam_abort(void *priv){	return omap16xxcam_disable(priv);}static intomap16xxcam_set_xclk(int xclk, void *priv){ 		struct omap16xxcam *data = (struct omap16xxcam *) priv; 	int xclk_val;	int divisor = 1;	divisor = data->ocp_clk/xclk;	if ( divisor * xclk < data->ocp_clk)		++divisor; 	switch (divisor) {		case 1:		case 2:			xclk_val = FOSCMOD_TC2_CK2;			break;		case 3:			xclk_val = FOSCMOD_TC2_CK3;			break;		case 4:		case 5:		case 6:		case 7:			xclk_val = FOSCMOD_TC2_CK4;			break;		case 8:		case 9:			xclk_val = FOSCMOD_TC2_CK8;			break;		case 10:		case 11:			xclk_val = FOSCMOD_TC2_CK10;			break;		case 12:		case 13:		case 14:		case 15:			xclk_val = FOSCMOD_TC2_CK12;			break;		case 16:			xclk_val = FOSCMOD_TC2_CK16;			break;		default:			xclk_val = FOSCMOD_TC2_CK16;	}		/* follow the protocol to change the XCLK clock */	data->camera_regs->ctrlclock &= ~CAMEXCLK_EN;	data->camera_regs->ctrlclock |= xclk_val;	data->camera_regs->ctrlclock |= CAMEXCLK_EN;	return (data->ocp_clk/divisor);}static intomap16xxcam_open(void *priv){	struct omap16xxcam *data = (struct omap16xxcam *) priv;	int ret;	if ((ret = request_irq(INT_CAMERA, omap16xx_cam_isr, SA_INTERRUPT, 					"camera", data))) {		printk("FAILED to aquire irq\n");		return ret;	}	data->new = 1;	omap16xxcam_enable(priv);	return omap16xx_cam_link_open(data);}static intomap16xxcam_close(void *priv){	struct omap16xxcam *data = (struct omap16xxcam *) priv;	omap16xxcam_disable(priv);	 	free_irq(INT_CAMERA, data);		return omap16xx_cam_link_close(data);}static intomap16xxcam_cleanup(void *priv){	struct omap16xxcam *data = (struct omap16xxcam *) priv;	if (machine_is_omap_h3()) {		if (data->camera_regs) {				iounmap((void *)data->camera_regs);			data->camera_regs= NULL;		}	}	if (data->iobase_phys) {		release_region(data->iobase_phys, CAMERA_IOSIZE);		data->iobase_phys = 0;	}	return 0;}/* Initialise the OMAP camera interface */static void *omap16xxcam_init(void){	unsigned long cam_iobase;	struct clk *ocp_clk;	if (!request_region(CAMERA_BASE, CAMERA_IOSIZE, "OAMP16xx Camera")) {		printk ("OMAP16XX Parallel Camera Interface is already in use\n");		return NULL;	}	if (machine_is_omap_h3()) {		cam_iobase = (unsigned long) ioremap (CAMERA_BASE, CAMERA_IOSIZE);		if (!cam_iobase) {			printk("CANNOT MAP CAMERA REGISTER\n");			return NULL;		}	}	else		cam_iobase = io_p2v(CAMERA_BASE);	/* Set the base address of the camera registers */	hardware_data.camera_regs = (camera_regs_t *)cam_iobase;	hardware_data.iobase_phys = (unsigned long) CAMERA_BASE; 	/* get the input clock value to camera interface and store it */	if (machine_is_omap_h3())		ocp_clk = clk_get(0, "tc_ck");	else		ocp_clk = clk_get(0, "armper_ck");	hardware_data.ocp_clk = clk_get_rate(ocp_clk);	/* Init the camera IF */	omap16xx_cam_init();	/* enable it. This is needed for sensor detection */	omap16xxcam_enable((void*)&hardware_data);	/* Init dma data */	omap16xxcam_init_dma((void*)&hardware_data);	init_waitqueue_head(&hardware_data.vsync_wait);	return (void*)&hardware_data;}struct camera_hardware camera_hardware_if = {	version		: 0x01, 	name		: "OMAP16xx Camera Parallel", 	init		: omap16xxcam_init,	cleanup		: omap16xxcam_cleanup,	open 		: omap16xxcam_open, 	close  		: omap16xxcam_close,	enable 		: omap16xxcam_enable, 	disable  	: omap16xxcam_disable,	abort		: omap16xxcam_abort,	set_xclk	: omap16xxcam_set_xclk,	init_dma	: omap16xxcam_init_dma,	start_dma	: omap16xxcam_start_dma,	finish_dma	: omap16xxcam_finish_dma,};

⌨️ 快捷键说明

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