?? csi.c
字號:
/*
* MX21 CSI driver
*
* 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
*
* Copyright (C) 2004 Motorola Semiconductors Hong Kong.
*
*/
/**
*@defgroup CSI CSI driver
*/
/**@{*/
/**
*@file csi.c
*@brief CSI driver source file
*
* linux/drivers/csi/csi.c
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/version.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include <linux/ioport.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/hfs_sysdep.h>
#include <linux/compatmac.h>
#include <linux/hdreg.h>
#include <linux/vmalloc.h>
#include <linux/malloc.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/blkpg.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include <linux/i2c-id.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <linux/mm.h>
#include <linux/wrapper.h>
#include <asm/dma.h>
#include <linux/miscdevice.h>
#include <linux/proc_fs.h>
#include <asm/arch/mx2.h>
#include <asm/arch/platform.h>
#include <linux/pm.h>
#include <asm/arch/apmc.h>
#include "csi.h"
/*******************************************************************************
*---------------------------- HARDWARE SPECIFIC -------------------------------
*/
//tapeout 2 specific
#ifndef _reg_CSI_CSICR3
#define _reg_CSI_CSICR3 (*((volatile unsigned long *)(CSI_IO_ADDRESS(CSI_BASE_ADDR+0x1C))))
#endif
//global
static int g_csi_ver = 2;
//version check
//-- should be done by s/w, however in current csi design, there is no way to distinguish
// TO1 & 2 by software
static int g_csi_busy = 0;
static CSI_CFG g_csi_cfg;
static CSI_STATUS g_csi_status;
//cache copy of csi status register
//local
static void csihw_read_config(CSI_CFG * _cfg);
static void csihw_config(CSI_CFG * _cfg);
static int csihw_poll(unsigned int * _buf, int byte_size);
static void csihw_reset_frame_count(void);
static int csihw_get_frame_count(void);
static int csihw_pol_eof(int rxcnt); //block
static int csihw_pol_sof(void); //block
static void csihw_clock_enable(void);
static void csihw_clock_disable(void);
static void csihw_reset(void);
//reset values
#define CSICR1_RESET_VAL 0x40000800
#define CSICR2_RESET_VAL 0x0
#define CSICR3_RESET_VAL 0x0
//csi control reg 1
#define BIT_SWAP16_EN (0x1 << 31)
#define BIT_EXT_VSYNC (0x1 << 30)
#define BIT_EOF_INT_EN (0x1 << 29)
#define BIT_PRP_IF_EN (0x1 << 28)
#define BIT_CCIR_MODE (0x1 << 27)
#define BIT_COF_INT_EN (0x1 << 26)
#define BIT_SF_OR_INTEN (0x1 << 25)
#define BIT_RF_OR_INTEN (0x1 << 24)
#define BIT_STATFF_LEVEL (0x3 << 22)
#define BIT_STATFF_INTEN (0x1 << 21)
#define BIT_RXFF_LEVEL (0x3 << 19)
#define BIT_RXFF_INTEN (0x1 << 18)
#define BIT_SOF_POL (0x1 << 17)
#define BIT_SOF_INTEN (0x1 << 16)
#define BIT_MCLKDIV (0xF << 12)
#define BIT_HSYNC_POL (0x1 << 11)
#define BIT_CCIR_EN (0x1 << 10)
#define BIT_MCLKEN (0x1 << 9)
#define BIT_FCC (0x1 << 8)
#define BIT_PACK_DIR (0x1 << 7)
#define BIT_CLR_STATFIFO (0x1 << 6)
#define BIT_CLR_RXFIFO (0x1 << 5)
#define BIT_GCLK_MODE (0x1 << 4)
#define BIT_INV_DATA (0x1 << 3)
#define BIT_INV_PCLK (0x1 << 2)
#define BIT_REDGE (0x1 << 1)
#define SHIFT_STATFF_LEVEL 22
#define SHIFT_RXFF_LEVEL 19
#define SHIFT_MCLKDIV 12
//control reg 3
#define BIT_FRMCNT (0xFFFF << 16)
#define BIT_FRMCNT_RST (0x1 << 15)
#define BIT_CSI_SUP (0x1 << 3)
#define BIT_ZERO_PACK_EN (0x1 << 2)
#define BIT_ECC_INT_EN (0x1 << 1)
#define BIT_ECC_AUTO_EN (0x1)
#define SHIFT_FRMCNT 16
//csi status reg
#define BIT_SFF_OR_INT (0x1 << 25)
#define BIT_RFF_OR_INT (0x1 << 24)
#define BIT_STATFF_INT (0x1 << 21)
#define BIT_RXFF_INT (0x1 << 18)
#define BIT_EOF_INT (0x1 << 17)
#define BIT_SOF_INT (0x1 << 16)
#define BIT_F2_INT (0x1 << 15)
#define BIT_F1_INT (0x1 << 14)
#define BIT_COF_INT (0x1 << 13)
#define BIT_ECC_INT (0x1 << 1)
#define BIT_DRDY (0x1 << 0)
static void csihw_read_status(CSI_STATUS * _status)
{
_status->sff_or_int = (_reg_CSI_CSISR & BIT_SFF_OR_INT) ? 1 : 0;
_status->rff_or_int = (_reg_CSI_CSISR & BIT_RFF_OR_INT) ? 1 : 0;
_status->statff_int = (_reg_CSI_CSISR & BIT_STATFF_INT) ? 1 : 0;
_status->rxff_int = (_reg_CSI_CSISR & BIT_RXFF_INT) ? 1 : 0;
_status->eof_int = (_reg_CSI_CSISR & BIT_EOF_INT) ? 1 : 0;
_status->sof_int = (_reg_CSI_CSISR & BIT_SOF_INT) ? 1 : 0;
_status->f2_int = (_reg_CSI_CSISR & BIT_F2_INT) ? 1 : 0;
_status->f1_int = (_reg_CSI_CSISR & BIT_F1_INT) ? 1 : 0;
_status->cof_int = (_reg_CSI_CSISR & BIT_COF_INT) ? 1 : 0;
_status->ecc_int = (_reg_CSI_CSISR & BIT_ECC_INT) ? 1 : 0;
_status->drdy = (_reg_CSI_CSISR & BIT_DRDY) ? 1 : 0;
return;
}
static void csi_irq_handler(int irq, void * data, struct pt_regs * pt)
{
csihw_read_status(&g_csi_status);
//go to individual handlers
//leave it untouched if user has not enabled the interrupt
if(g_csi_cfg.rf_or_inten)
{
if(g_csi_status.rff_or_int)
{
g_csi_status.rff_or_int = 0;
printk("csi error: rxff overflow\n");
//flush fifo
_reg_CSI_CSICR1 &= ~BIT_FCC;
_reg_CSI_CSICR1 |= BIT_CLR_RXFIFO;
if(g_csi_cfg.fcc)
_reg_CSI_CSICR1 |= BIT_FCC;
_reg_CSI_CSISR = BIT_RFF_OR_INT;
}
}
if(g_csi_cfg.sof_inten)
{
if(g_csi_status.sof_int)
{
_reg_CSI_CSISR = BIT_SOF_INT;
g_csi_status.sof_int = 0;
}
}
return;
}
static void csihw_read_config(CSI_CFG * _cfg)
{
unsigned int tmp;
unsigned val;
//1. read from register
//control reg 1
val = _reg_CSI_CSICR1;
_cfg->swap16_en = (val & BIT_SWAP16_EN)? 1 : 0;
_cfg->ext_vsync = (val & BIT_EXT_VSYNC)? 1 : 0;
_cfg->eof_int_en = (val & BIT_EOF_INT_EN)? 1 : 0;
_cfg->prp_if_en = (val & BIT_PRP_IF_EN)? 1 : 0;
_cfg->ccir_mode = (val & BIT_CCIR_MODE)? 1 : 0;
_cfg->cof_int_en = (val & BIT_COF_INT_EN)? 1 : 0;
_cfg->sf_or_inten = (val & BIT_SF_OR_INTEN)? 1 : 0;
_cfg->rf_or_inten = (val & BIT_RF_OR_INTEN)? 1 : 0;
tmp = (val & BIT_STATFF_LEVEL) >> SHIFT_STATFF_LEVEL;
if(tmp == 0x3)
_cfg->statff_level = 16;
else if(tmp == 0x2)
_cfg->statff_level = 12;
else if(tmp == 0x1)
_cfg->statff_level = 8;
else
_cfg->statff_level = 4;
_cfg->staff_inten = (val & BIT_STATFF_INTEN)? 1 : 0;
tmp = (val & BIT_RXFF_LEVEL) >> SHIFT_RXFF_LEVEL;
if(tmp == 0x3)
_cfg->rxff_level = 24;
else if(tmp == 0x2)
_cfg->rxff_level = 16;
else if(tmp == 0x1)
_cfg->rxff_level = 8;
else
_cfg->rxff_level = 4;
_cfg->rxff_inten = (val & BIT_RXFF_INTEN)? 1 : 0;
_cfg->sof_pol = (val & BIT_SOF_POL)? 1 : 0;
_cfg->sof_inten = (val & BIT_SOF_INTEN)? 1 : 0;
tmp = (val & BIT_MCLKDIV) >> SHIFT_MCLKDIV;
_cfg->mclkdiv = (tmp + 1) * 2;
_cfg->hsync_pol = (val & BIT_HSYNC_POL)? 1 : 0;
_cfg->ccir_en = (val & BIT_CCIR_EN)? 1 : 0;
_cfg->mclken = (val & BIT_MCLKEN)? 1 : 0;
_cfg->fcc = (val & BIT_FCC)? 1 : 0;
_cfg->pack_dir = (val & BIT_PACK_DIR)? 1 : 0;
_cfg->gclk_mode = (val & BIT_GCLK_MODE)? 1 : 0;
_cfg->inv_data = (val & BIT_INV_DATA)? 1 : 0;
_cfg->inv_pclk = (val & BIT_INV_PCLK)? 1 : 0;
_cfg->redge = (val & BIT_REDGE)? 1 : 0;
//control reg 3
val = _reg_CSI_CSICR3;
_cfg->csi_sup = (val & BIT_CSI_SUP)? 1 : 0;
_cfg->zero_pack_en = (val & BIT_ZERO_PACK_EN)? 1 : 0;
_cfg->ecc_int_en = (val & BIT_ECC_INT_EN)? 1 : 0;
_cfg->ecc_auto_en = (val & BIT_ECC_AUTO_EN)? 1 : 0;
//rxfifo reg
val = _reg_CSI_CSIRXCNT;
//keep system settings
_cfg->module_irq_enable = g_csi_cfg.module_irq_enable;
//2. update global config
memcpy(&g_csi_cfg, _cfg, sizeof(CSI_CFG));
return;
}
static void csihw_config(CSI_CFG * _cfg)
{
unsigned int tmp;
unsigned val = 0x0;
int rt;
//1. write to registers
//control reg 1
if(_cfg->swap16_en)
val |= BIT_SWAP16_EN;
if(_cfg->ext_vsync)
val |= BIT_EXT_VSYNC;
if(_cfg->eof_int_en)
val |= BIT_EOF_INT_EN;
if(_cfg->prp_if_en)
val |= BIT_PRP_IF_EN;
if(_cfg->ccir_mode)
val |= BIT_CCIR_MODE;
if(_cfg->cof_int_en)
val |= BIT_COF_INT_EN;
if(_cfg->sf_or_inten)
val |= BIT_SF_OR_INTEN;
if(_cfg->rf_or_inten)
val |= BIT_RF_OR_INTEN;
if(_cfg->statff_level == 16)
tmp = 0x3;
else if(_cfg->statff_level == 12)
tmp = 0x2;
else if(_cfg->statff_level == 8)
tmp = 0x1;
else
tmp = 0x0;
val |= (tmp << SHIFT_STATFF_LEVEL);
if(_cfg->staff_inten)
val|= BIT_STATFF_INTEN;
if(_cfg->rxff_level == 24)
tmp = 0x3;
else if(_cfg->rxff_level == 16)
tmp = 0x2;
else if(_cfg->rxff_level == 8)
tmp = 0x1;
else
tmp = 0x0;
val |= (tmp << SHIFT_RXFF_LEVEL);
if(_cfg->rxff_inten)
val |= BIT_RXFF_INTEN;
if(_cfg->sof_pol)
val |= BIT_SOF_POL;
if(_cfg->sof_inten)
val |= BIT_SOF_INTEN;
tmp = (_cfg->mclkdiv / 2) - 1;
val |= (tmp << SHIFT_MCLKDIV);
if(_cfg->hsync_pol)
val |= BIT_HSYNC_POL;
if(_cfg->ccir_en)
val |= BIT_CCIR_EN;
if(_cfg->mclken)
val |= BIT_MCLKEN;
if(_cfg->fcc)
val |= BIT_FCC;
if(_cfg->pack_dir)
val |= BIT_PACK_DIR;
if(_cfg->gclk_mode)
val |= BIT_GCLK_MODE;
if(_cfg->inv_data)
val |= BIT_INV_DATA;
if(_cfg->inv_pclk)
val |= BIT_INV_PCLK;
if(_cfg->redge)
val |= BIT_REDGE;
_reg_CSI_CSICR1 = val;
//control reg 3
val = 0x0;
if(_cfg->csi_sup)
val |= BIT_CSI_SUP;
if(_cfg->zero_pack_en)
val |= BIT_ZERO_PACK_EN;
if(_cfg->ecc_int_en)
val |= BIT_ECC_INT_EN;
if(_cfg->ecc_auto_en)
val |= BIT_ECC_AUTO_EN;
_reg_CSI_CSICR3 = val;
//rxfifo counter
_reg_CSI_CSIRXCNT = _cfg->rxcnt;
//2. update global config
memcpy(&g_csi_cfg, _cfg, sizeof(CSI_CFG));
//3. interrupt enable
if(_cfg->module_irq_enable)
{
rt = request_irq(INT_CSI,
csi_irq_handler,
SA_INTERRUPT,
"csi",
"csi");
if(rt)
printk("csi error: irq request fail\n");
}
//4. init status flags
memset(&g_csi_status, 0, sizeof(CSI_CFG));
return;
}
//nothing special, simply set gpio
static void csihw_init(void)
{
//disable GPIO PB[21..10]
_reg_GPIO_GIUS(GPIOB) &= ~0x3FFC00;
//note -- csi version check should be here...
return;
}
static void csihw_cleanup(void)
{
//resume GPIO PB[21..10]
_reg_GPIO_GIUS(GPIOB) |= 0x3FFC00;
csihw_clock_disable();
csihw_reset();
return;
}
//generate default mclk to drive sensor
static void csihw_open(void)
{
unsigned int val;
unsigned int perclk4div = 3; //default set to fclk/3 => 88MHz
unsigned int mclkdiv = 4; //default set to perclk4/4 => 22MHz
csihw_clock_enable();
//set default perclk4 for mclk
if(g_csi_ver == 2)
{
val = _reg_CRM_PCDR1;
val &= ~(0x3F << 24);
val |= (perclk4div - 1) << 24;
_reg_CRM_PCDR1 = val;
}
csihw_reset();
//enable default mclk clock
val = CSICR1_RESET_VAL;
val |= ((mclkdiv / 2) - 1) << SHIFT_MCLKDIV;
val |= BIT_MCLKEN;
_reg_CSI_CSICR1 = val;
return;
}
static void csihw_release(void)
{
//nothing to do
//as a result, the csi state will not unchange unless the module is unloaded
return;
}
//Read a frame by polling
static int csihw_poll(unsigned int * _buf, int byte_size)
{
int i, j;
int word_size = byte_size >> 2;
unsigned int *_kbuf = NULL;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -