📄 omap_camera_if_link.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 + -