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

📄 omap_camera_if_link.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
字号:
/*
 *  linux/drivers/media/video/omap/omap_camera_if_link.c
 *
 * Copyright (C) 2004 Texas Instruments Inc
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#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/hardware.h>
#include <asm/io.h>
#include <asm/scatterlist.h>

#include "camera_core.h"
#include "omap_camera_if.h"
#include "omap1610_camera_hw.h"

#include "common.h"
#include "camif.h"

int dma_channel_number1;
int dma_channel_number2;
static int new = 0;

struct sgdma_state *g_sgdma;
void *g_sgslot;

/* function prototypes */
extern void omap1610_camera_clk_set (unsigned int);
extern void omap_dma_callback(int, unsigned short, void *);
extern int camera_core_callback_sg_dma(struct camera_device *, void *arg);
void waitforVsync(void);
int xashu =0;

void configure_dma(void)
{
	omap1610_camera_mode_set(RAZ_FIFO);
	udelay(10);
	omap1610_camera_mode_clear(RAZ_FIFO);
	udelay(10);

	omap1610_set_dma_threshold ();
	omap1610_enable_dma ();
	omap1610_camera_clk_set (LCLK_EN); 
	
}

/* start the dma of chains */
int omap_dma_start_linked (struct camera_device *cam, struct sgdma_state *sgdma, void *sgslot)
{
	struct scatterlist *sglist;
	unsigned long irqflags;
	int dmach;
	int prev_dmach;
	int count;

	spin_lock_irqsave(&cam->dma_lock, irqflags);
	sglist = (struct scatterlist *)(sgdma->sglist + sgdma->next_sglist);

	if ( !cam->free_dmach) {
		spin_unlock_irqrestore(&cam->dma_lock, irqflags);
		return -EBUSY;
	} 
	dmach=cam->next_dmach;
	count = dmach == dma_channel_number2 ? 1:0;
	cam->camdma[count].arg = sgslot;
	
#ifdef CONFIG_MACH_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);
#endif

	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 == dma_channel_number2 ? dma_channel_number1:
							dma_channel_number2;
	
	if(cam->capture_started){
		if (!new) {
			new +=1;
			xashu = 1;
			waitforVsync();	
			xashu = 0;
		} else {
		if((omap_readw(OMAP_DMA_CCR(prev_dmach)) & (1 << 7)) || xashu ){
			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);

		}	
		}
	}else {
		if((omap_readw(OMAP_DMA_CCR(prev_dmach)) & (1 << 7)) || xashu ){
			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);

		}	
		if (!new)
		{
			++new;
			configure_dma();
		}	
	}
	
	cam->next_dmach = prev_dmach; 
	cam->free_dmach--;
	spin_unlock_irqrestore(&cam->dma_lock, irqflags);
	return 0;
}

/* dma callback routine. */
void omap_dma_link_callback(int lch, unsigned short ch_status, void *data)
{
	int ret;
	int count;
	u16 w;
	void * sgslot;
        struct sgdma_state *sgdma = sgdma;
	struct camera_device *cam = (struct camera_device *)data;

	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 == dma_channel_number1 ? dma_channel_number2 							: dma_channel_number1;
	}

	while( cam->free_dmach < 2)
	{
		if((w= omap_readw(OMAP_DMA_CCR(lch)) & (1 << 7) ))
		{
			break;	
		}
		count =  lch == dma_channel_number2 ? 1:0;
		sgslot = cam->camdma[count].arg;
		cam->free_dmach++;
		spin_unlock(&cam->dma_lock);
		
		ret = camera_core_callback_sg_dma (cam, sgslot);
		spin_lock(&cam->dma_lock);
		lch = lch == dma_channel_number2 ? dma_channel_number1 : 
							dma_channel_number2;
	}
	spin_unlock(&cam->dma_lock);
	
}

/* acquire h/w resources DMA */
int omap_camera_link_open(struct camera_device *cam)
{
	int ret;

	/* Acquire first dma channel */
	if ((ret = omap_request_dma(OMAP_DMA_CAMERA_IF_RX, 
				"camera dma 1", omap_dma_link_callback,
				(void *) cam, &dma_channel_number1))) {
                return ret;
	}
	/* Acquire second dma channel */
	if ((ret = omap_request_dma(OMAP_DMA_CAMERA_IF_RX, 
				"camera dma 2", omap_dma_link_callback,
				(void *) cam, &dma_channel_number2))) {
                printk ("No DMA available for camera\n");
                return ret;
        }
 	cam->next_dmach = dma_channel_number1;
	omap_writew(dma_channel_number2, 
				OMAP_DMA_CLNK_CTRL(dma_channel_number1));
	omap_writew(dma_channel_number1, 
				OMAP_DMA_CLNK_CTRL(dma_channel_number2));

        /* Enable the omap camera interface */
        omap1610_camera_enable (cam->ocp_clk);

        return 0;
}

/* free h/w resources, stop i/f */
int omap_camera_link_close(void)
{
	/* free dma channels */
	omap_stop_dma(dma_channel_number1);
	omap_stop_dma(dma_channel_number2);
	omap_free_dma (dma_channel_number1);
	omap_free_dma (dma_channel_number2);
	omap1610_camera_mode_set(RAZ_FIFO);
	udelay(10);
	omap1610_camera_mode_clear(RAZ_FIFO);
	new = 0;
	return 0;
}

⌨️ 快捷键说明

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