📄 omap1610_camera_hw.c
字号:
/*
* linux/drivers/media/video/omap/omap1610_camera_hw.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 <asm/io.h>
#include <asm/semaphore.h>
#include <asm/processor.h>
#include <linux/interrupt.h>
#include <asm/arch/dma.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <asm/arch/clocks.h>
#include <asm/arch/hardware.h>
#include "camera_core.h"
#include "omap_camera_if.h"
#include "omap1610_camera_hw.h"
camera_regs_t *camera_regs= NULL;
static wait_queue_head_t vsync_wait;
void omap1610_waitfvsync(void);
static void camif_wait_for_vsync_edge(u32 );
extern int dma_channel_number1;
extern int ck_get_rate(ck_t);
int omap1610_set_xclk (int , int );
void omap1610_camera_initenable (void)
{
#ifdef CONFIG_MACH_OMAP_H3
camera_regs->gpio = 0; /*enable camera */
#else
camera_regs->gpio = 1; /*enable camera */
#endif
/* give clock to camera_module */
camera_regs->ctrlclock = 0x00000035;
camera_regs->mode = 0;
mdelay(10);
}
/* Enables the camera. Takes camera out of reset. Enables the clocks. */
void omap1610_camera_enable (int mclk)
{
#ifdef CONFIG_MACH_OMAP_H3
camera_regs->gpio = 0; /*enable camera */
#else
camera_regs->gpio = 1; /*enable camera */
#endif
/* give clock to camera_module */
camera_regs->mode = 0x4000;
camera_regs->ctrlclock = 0x00000030;
#ifdef CONFIG_MACH_OMAP_H3
omap1610_set_xclk(24000000, mclk);
#endif
mdelay(10);
/* wait for camera to settle down */
camif_wait_for_vsync_edge(EN_V_DOWN);
camif_wait_for_vsync_edge(EN_V_DOWN);
camif_wait_for_vsync_edge(EN_V_DOWN);
}
void omap1610_close(void)
{
camera_regs->mode = 0x0;
camera_regs->ctrlclock = 0x00000000;
omap1610_camera_mode_set(RAZ_FIFO);
udelay(10);
omap1610_camera_mode_clear(RAZ_FIFO);
#ifdef CONFIG_MACH_OMAP_H3
camera_regs->gpio = 1;
#else
camera_regs->gpio = 0;
#endif
}
/* change the XCLK value */
int omap1610_set_xclk (int xclk, int ocp_clk)
{
int xclk_val;
int divisor = 1;
divisor = ocp_clk/xclk;
if ( divisor * xclk < 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;
}
/* Change the XCLK clock */
camera_regs->ctrlclock &= ~CAMEXCLK_EN;
camera_regs->ctrlclock &= ~0x7;
camera_regs->ctrlclock |= xclk_val;
camera_regs->ctrlclock |= CAMEXCLK_EN;
return (ocp_clk/divisor);
}
/* Disables all the camera clocks. Put the camera interface in reset. */
void omap1610_camera_disable (void)
{
camera_regs->ctrlclock = 0;
camera_regs->gpio = 1;
camera_regs->mode = 0;
}
/* Set the bits in the mode control register specified by mask. */
void omap1610_camera_mode_set (unsigned int mask)
{
camera_regs->mode |= mask;
}
void omap1610_camera_clk_set (unsigned int mask)
{
camera_regs->ctrlclock |= mask;
}
void omap1610_camera_clk_clear (unsigned int mask)
{
camera_regs->ctrlclock &= ~mask;
}
/* clear the bits in the mode control register specified by mask. */
void omap1610_camera_mode_clear (unsigned int mask)
{
camera_regs->mode &= ~mask;
}
/* Clears the camera data FIFO by setting RAZ_FIFO bit in MODE configuration register. */
void omap1610_clear_fifo (void)
{
camera_regs->ctrlclock &= ~LCLK_EN;
omap1610_camera_mode_set(RAZ_FIFO);
udelay(10);
omap1610_camera_mode_clear(RAZ_FIFO);
camera_regs->ctrlclock |= LCLK_EN;
}
/* sets the dma threshold value in MODE configuration register. */
void omap1610_set_dma_threshold (void)
{
camera_regs->mode = (FIFO_TRIGGER_LVL << THRESHOLD_BIT);
}
/* Enable the DMA by setting the DMA bit in the MODE configuration register. */
void omap1610_enable_dma (void)
{
camera_regs->mode |= EN_DMA;
}
/* Disable Lclk and stop dma transfer. */
void omap1610_capture_abort (void)
{
/* Turn off the capture hardware */
camera_regs->ctrlclock &= ~(LCLK_EN);
camera_regs->mode = 0;
}
irqreturn_t omap1610_isr(int irq, void *client_data,
struct pt_regs *regs)
{
unsigned int itstat;
itstat = camera_regs->it_status;
/* VSYNC UP interrupt */
if (itstat & V_UP) {
omap1610_clear_fifo();
omap_start_dma(dma_channel_number1);
omap1610_camera_mode_clear(EN_V_UP);
omap1610_camera_mode_set(EN_DMA | EN_FIFO_FULL);
wake_up_interruptible(&vsync_wait);
}
if( itstat & 0x2){
wake_up_interruptible(&vsync_wait);
}
if( itstat & 0x2){
omap1610_camera_mode_clear(EN_V_DOWN);
}
if( itstat & 0x4)
printk(" H_UP \n");
if( itstat & 0x8)
printk(" H_DOWN \n");
if( itstat & 0x10){
omap1610_clear_fifo();
printk(" FIFO_FULL \n");
}
if( itstat & 0x20)
printk(" DATA_TRANS \n");
return IRQ_HANDLED;
}
static void camif_wait_for_vsync_edge(u32 edge_mask)
{
omap1610_camera_mode_set(edge_mask);
/* wait for VSYNC edge */
do {
interruptible_sleep_on(&vsync_wait);
} while (signal_pending(current));
omap1610_camera_mode_clear(edge_mask);
omap1610_clear_fifo();
}
void waitforVsync(void)
{
camera_regs->mode = 0x4002;
omap1610_camera_mode_set(EN_V_UP);
do{
interruptible_sleep_on(&vsync_wait);
} while (signal_pending(current));
omap_start_dma(dma_channel_number1);
}
void omap1610_cleanup(unsigned long iobase_phys)
{
#ifdef CONFIG_MACH_OMAP_H3
if(camera_regs) {
iounmap((void *)camera_regs);
camera_regs= NULL;
}
#endif
if(iobase_phys) {
release_mem_region(iobase_phys, CAMERA_IOSIZE);
}
}
/*
* Initialise the OMAP1610 camera Interface
* - Configure the MUX control registers
* - Enable the omap1610 camera.
*/
int omap1610_camera_init (unsigned long * iobase_phys)
{
#ifdef CONFIG_MACH_OMAP_H3
unsigned long cam_iobase;
#endif
/*
* Call request_region to reserve the area of
* memory assigned for omap1610 camera interface control registers
*/
if (!request_region(CAMERA_BASE, CAMERA_IOSIZE, "OV9640 Camera")) {
printk ("OMAP1610 Parallel Camera Interface is already in use\n");
return -1;
}
*iobase_phys = CAMERA_BASE;
#ifdef CONFIG_MACH_OMAP_H3
cam_iobase = (unsigned long) ioremap (CAMERA_BASE, CAMERA_IOSIZE);
if (!cam_iobase){
printk(" CANNOT MAP CAMERA REGISTER \n");
return -1;
}
/* Set the base address of the camera registers */
camera_regs = (camera_regs_t *)cam_iobase;
#else
camera_regs = (camera_regs_t *)CAMERA_BASE;
#endif
/*
* FIXME - Use mux API's instead of directly writing in to MUX registers
*/
omap_writel(omap_readl(FUNC_MUX_CTRL_4) & ~(0x1ff << 21), FUNC_MUX_CTRL_4);
omap_writel(0, FUNC_MUX_CTRL_5);
omap_writel(omap_readl(PULL_DWN_CTRL_0) & ~(0x1FFF << 17), PULL_DWN_CTRL_0);
omap_writel(omap_readl(PU_PD_SEL_0) & ~(0x1FFF << 17), PU_PD_SEL_0);
omap_writel(0xeaef, COMP_MODE_CTRL_0);
omap_writel(omap_readl(OMAP16XX_RESET_CONTROL) & ~(1 << 5), OMAP16XX_RESET_CONTROL);
omap_writel(omap_readl(OMAP16XX_RESET_CONTROL) | (1 << 5), OMAP16XX_RESET_CONTROL);
/* Enable peripheral reset */
omap_writew(omap_readw(ARM_RSTCT2) | (1 << 0), ARM_RSTCT2);
/* enable peripheral clock */
omap_writew(omap_readw(ARM_IDLECT2) | (1 << EN_XORPCK), ARM_IDLECT2);
init_waitqueue_head(&vsync_wait);
/* Enable the camera */
omap1610_camera_initenable();
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -