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

📄 csi.c

📁 嵌入式Linux系统下,ov965摄像头驱动.
💻 C
📖 第 1 页 / 共 2 页
字号:
	unsigned int perclk4div = 3;	//default set to fclk/3 => 88MHz
	unsigned int mclkdiv = 4;	//default set to perclk4/4 => 22MHz
	_reg_GPIO_GIUS(GPIOD) &= ~0x60000;
	_reg_GPIO_GPR(GPIOD) &= ~0x60000;
//disable GPIO PB[21..10]
	_reg_GPIO_GIUS(GPIOB) &= ~0x3FFC00;
	_reg_GPIO_GIUS(GPIOD) &= ~0x800000;
	_reg_GPIO_PUEN(GPIOD) &= ~0x800000;
	_reg_GPIO_DDIR(GPIOD) |= 0x800000;
	_reg_GPIO_OCR2(GPIOD) |= 0xC000;
	_reg_GPIO_DR(GPIOD) &= ~0x800000;

//hclk clock enable
	_reg_CRM_PCCR0 |= 0x80000000;

//temp solution
//version check should be done in run time
	g_csi_ver = 2;

//reset
	_reg_CSI_CSICR1 = CSICR1_RESET_VAL;
	_reg_CSI_CSICR2 = CSICR2_RESET_VAL;
	if(g_csi_ver == 2)
		_reg_CSI_CSICR3 = CSICR3_RESET_VAL;
			//need to enable hclk before CSICR3 can be access

//enable perclk4
	_reg_CRM_PCCR0 |= 0x00400000;
	val = _reg_CRM_PCDR1;
	val &= ~(0x3F << 24);
	val |= (perclk4div - 1) << 24;
	_reg_CRM_PCDR1 = val;
	
	_reg_CSI_CSICR1 = CSICR1_RESET_VAL;
	_reg_CSI_CSICR2 = CSICR2_RESET_VAL;
	_reg_CSI_CSICR3 = CSICR3_RESET_VAL;
	
//enable default mclk clock
	val = CSICR1_RESET_VAL;
	val |= ((mclkdiv / 2) - 1) << SHIFT_MCLKDIV;
	val |= BIT_MCLKEN;
	_reg_CSI_CSICR1 = val;

	return;
}


static void csi_cleanup(void)
{
	_reg_CSI_CSICR1 = CSICR1_RESET_VAL;
	_reg_CSI_CSICR2 = CSICR2_RESET_VAL;
	_reg_CSI_CSICR3 = CSICR3_RESET_VAL;
	return;
}


//Read a frame by polling
static int csi_poll(unsigned int * _buf, int byte_size)
{
	int i, j;
	int word_size = byte_size >> 2;

	unsigned int *_kbuf;
	int korder;
	int required_pages;
	int extra_pages;
//alloc a tmp buffer in kernel space
	required_pages = byte_size >> PAGE_SHIFT;
	for (korder = 0 ; required_pages >> korder ; korder++) {;}
	extra_pages = (1 << korder) - required_pages;
	_kbuf = (unsigned int *)__get_free_pages(GFP_KERNEL, korder);
	if(!_kbuf)
	{
		printk("csi error: buffer alloc failed\n");
		return -1;
	}
	
//poll sof
	_reg_CSI_CSISR = BIT_SOF_INT;
	while(!(_reg_CSI_CSISR & BIT_SOF_INT));
	_reg_CSI_CSISR = BIT_SOF_INT;

//clear fifo overflow
	if(_reg_CSI_CSISR & BIT_RFF_OR_INT)
		_reg_CSI_CSISR = BIT_RFF_OR_INT;

//read rx fifo
	j = 0;
	while(1)
	{
	//overflow check
		if(_reg_CSI_CSISR & BIT_RFF_OR_INT)
		{
//			printk("csi error: overflow\n");
			_reg_CSI_CSISR = BIT_RFF_OR_INT;
		}
	//poll rx fifo full
		if(_reg_CSI_CSISR & BIT_RXFF_INT)
		{
			for(i = 0; i < 8; i ++)
				_kbuf[j ++] = _reg_CSI_CSIRXR;
		}
		if(j >= word_size)
			break;
	}
	copy_to_user(_buf, _kbuf, byte_size);
	free_pages((int)_kbuf, korder);

	return 0;
}

static void csi_reset_frame_count(void)
{
	_reg_CSI_CSICR3 |= BIT_FRMCNT_RST;
	return;
}

static int csi_get_frame_count(void)
{
	int count;
	count = _reg_CSI_CSICR3 >> SHIFT_FRMCNT;

	return count;
}


//global static
static devfs_handle_t devfs_handle;
static int gMajor = 0;

//functions and interface
static int 		csi_open(struct inode *inode, struct file *filp);
static int 		csi_release(struct inode *inode, struct file *filp);
static ssize_t 	csi_read(struct file *filp, char *buf, size_t size, loff_t *l);
static ssize_t 	csi_write(struct file *filp, const char *buf, size_t size, loff_t *l);
static int 		csi_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);

struct file_operations csi_fops = 
{
	open:		csi_open,
	release:	csi_release,
	read:		csi_read,
	write:		csi_write,
	ioctl:		csi_ioctl,
};
static OV9650_CFG g_ov9650_cfg;


//init module does only the basic things
//dma & irq are turned on later according to csi config
int __init init_module()
{
	int result;

	csi_module_init();
	_reg_CRM_PCDR1 &= ~0x3f000000;
	_reg_CRM_PCDR1 |= 0x2000000;
	_reg_CSI_CSICR1 |= 0x2;  //latch on rising edge
	_reg_CSI_CSICR1 |= 0x4;	// invert the PIXCLK
	_reg_CSI_CSICR1 |= 0x40000000;
	_reg_CSI_CSICR1 |= 0x40000;
	_reg_CSI_CSICR1 |= 0x1000000;
	_reg_CSI_CSICR1 |= 0x100000;
	_reg_CSI_CSICR1 |= 0x10000000;
	_reg_CSI_CSICR1 |= 0x10; //gated clock mode
	_reg_CSI_CSICR1 |= 0x800;
	_reg_CSI_CSICR1 |= 0x80; //big endian
	_reg_CSI_CSICR1 |= 0x100;        //sync FIFO clear
	_reg_CSI_CSICR1 |= 0x0200;       //MCLK = HCLK / 2
	_reg_CSI_CSICR1 |= 0x1000;         //HHTech add:set clock divider(=4)
	_reg_CSI_CSICR1 |= 0x20000;      //SOF rising edge
	_reg_CSI_CSICR1 &= ~0xF000;
//	_reg_CSI_CSICR1 |= 0x1000;
	_reg_CSI_CSICR1 &= ~0x18000;
	_reg_CSI_CSICR1 |= 0x10000;
	_reg_CSI_CSICR1 |= 0x80000000;
	_reg_CSI_CSICR1 &= ~0x80;
	printk("MX21 CSI driver\n");
	printk("h/w version %d\n", g_csi_ver);
	printk("s/w version 0.0\n"__DATE__" / "__TIME__"\n");
	printk("CSI_CSICR1 0x%8x\n",_reg_CSI_CSICR1);

//register CSI character device
 	result = devfs_register_chrdev(0, "csi2c", &csi_fops);
 	if ( result < 0 )
 	{
		printk("csi error: unable to register driver\n");
		return -ENODEV;
	}
	devfs_handle = devfs_register(NULL, "csi2c", DEVFS_FL_DEFAULT,
				      result, 0,
				      S_IFCHR | S_IRUSR | S_IWUSR,
				      &csi_fops, NULL);   	
	gMajor = result;
        if (request_irq
            (31, csi_intr_handler, SA_INTERRUPT, "CSI", NULL))
                printk
                    ("*** Cannot register interrupt handler for CSI ! ***\n");
        else
                printk("CSI interrupt handler registered\n");

	malloc_buffer();

	sensor_reset();
	i2c_test();
	
	ov9650_config_SENSOR(&g_ov9650_cfg);
//	ov9650_config_QVGA(&g_ov9650_cfg);
	printk("OV9650 Sensor Init OK!\n");

   	return 0;
}


void __exit cleanup_module()
{    
	csi_cleanup();

   	if(gMajor > 0)
   	{
		devfs_unregister_chrdev(gMajor, "csi");
		devfs_unregister(devfs_handle);
	}

	printk("CSI driver is unloaded sucessfully\n\n");
        free_irq(31,0);
        free_buffer();	
	return;
}
// DMA support HHTECH

static int csi_open(struct inode *inode, struct file *filp)
{
        dma_request_t csi_dma_req = {0};
       
        MOD_INC_USE_COUNT;
        return 0;
}


static int csi_release(struct inode *inode, struct file *filp)
{
        MOD_DEC_USE_COUNT;
	return 0;	
}


static ssize_t csi_read(struct file *filp, char *buf, size_t size, loff_t *l)
{
	int i;
	while(!PRP_poll_ch1_buf1_complete());
	copy_to_user(buf, csi_data_buf, size);
	return 0;
}


static ssize_t csi_write(struct file *filp, const char *buf, size_t size, loff_t *l)
{
	printk("csi error: write ioctl is not implemented\n");
	return -1;
}


static int csi_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
	switch(cmd)
	{
		case IOCTL_CSI_READ_CONFIG:
		{
			csi_read_cfg(&g_csi_cfg);

			if(copy_to_user((void *)arg, (void *)&g_csi_cfg, sizeof(CSI_CFG)))
				return -EFAULT;

			break;
		}
		case IOCTL_CSI_CONFIG:
		{
			if(copy_from_user((void *)&g_csi_cfg, (void *)arg, sizeof(CSI_CFG)))
				return -EFAULT;

			csi_config(&g_csi_cfg);

			break;
		}
		case IOCTL_I2C_R:
		{
			unsigned char val,reg;
			reg = (unsigned char *) arg;
			i2c_read(reg,&val);
			return val;
		}
		case IOCTL_I2C_W:
		{
			unsigned char val,reg;
			reg = (unsigned char *)((arg >> 8) & 0xff);
			val = (unsigned char *)(arg & 0xff);
			i2c_write(reg, val);
			return 0;
		}
		case IOCTL_CSI_READ_STATUS:
		{
			csi_read_status(&g_csi_status);

			if(copy_to_user((void *)arg, (void *)&g_csi_status, sizeof(CSI_STATUS)))
				return -EFAULT;
			
			break;
		}
		case IOCTL_CSI_GET_FRMCNT:
		{
			int count;
			count = csi_get_frame_count();
			if(copy_to_user((void *)arg, (void *)&count, sizeof(int)))
				return -EFAULT;
			
			break;
		}
		case IOCTL_CSI_RST_FRMCNT:
		{
			csi_reset_frame_count();
			
			break;
		}
                case IOCTL_DMA_CAPTURE:
 	        {      
        	        return SFCM_capture_DMA((U32) arg);
 			break;
                }
	        case IOCTL_STOP_CAPTURE:
                	break;
		case IOCTL_SET_FMT:
			switch(arg)
			{
			case 0:
				PRP_init33(dma_buf_phy_addr,0xc2103000,0xc2106000,0xc2109000);
				ov9650_config_QVGA(&g_ov9650_cfg);
				break;
			case 1:
				PRP_init32(dma_buf_phy_addr,0xc2103000,0xc2106000,0xc2109000);
				ov9650_config_VGA(&g_ov9650_cfg);
				break;
			case 2:
				PRP_init31(dma_buf_phy_addr,0xc2103000,0xc2106000,0xc2109000);
				ov9650_config_SXGA(&g_ov9650_cfg);	
				break;
			case 3:
				PRP_init33(dma_buf_phy_addr,0xc2103000,0xc2106000,0xc2109000);
				ov9650_config_V_Q(&g_ov9650_cfg);
				break;
			case 4:
				PRP_init33(dma_buf_phy_addr,0xc2103000,0xc2106000,0xc2109000);
				ov9650_config_S_Q(&g_ov9650_cfg);
				break;
			}
			break;
	}
	
	return 0;
}

⌨️ 快捷键说明

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