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

📄 csi.c

📁 linux下基于Arm9的嵌入式linux摄像头接口驱动。非常实用的源码!
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * 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 + -