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

📄 ov9650.c

📁 基于intel xscale下的linux系统camera驱动程序
💻 C
字号:
/* 
    OV9650 CMOS sensor driver

    Copyright (C) 2005, ucdragon

    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., 675 Mass Ave, Cambridge, MA 02139, USA.
	
    Code Status:
    2004/10/19: Yan Yin <yan.yin@intel.com>
        - Ported to 2.6 kernel
        
    2005/07/02: antiscle <hzh12@tom.com>
    	- Ported to YL-PXA27X development board
*/

#include <linux/types.h>
#include <linux/config.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/ctype.h>
#include <linux/pagemap.h>
#include <linux/interrupt.h>
#include <asm/pgtable.h>
#include <asm/dma.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/semaphore.h>
#include <asm/hardware.h>
#include <asm/mach-types.h>
#include <asm/arch/pxa-regs.h>
#include <asm/arch/mainstone.h>

#include "camera.h"
#include "ci.h"

#define MCLK_DEFT	2600	// 26 MHz

#ifdef CONFIG_USER_I2C_INIT
#define sccb_init()
#define sccb_deinit()
#else
/***********************************************************************
 *
 * sccb Functions
 *
 ***********************************************************************/
#define OV9650_SCCB_ID 		0x60
#define OV9650_PRODUCT_ID	0x7FA2

#define SCCB_DELAY    40 
#define SCCB_DELAY2   40

#define SIO_C          (21)	//117
#define SIO_D          (22)	//118
#define MAKE_HIGH(_x)  (GPSR3 = 1<<(_x))
#define MAKE_LOW(_x)   (GPCR3 = 1<<(_x))
#define BIT_READ(_x)   ((GPLR3&(1<<(_x)))?1:0)
#define CFG_READ(_x)   pxa_gpio_mode(((_x)+96)|GPIO_IN)
#define CFG_WRITE(_x)  pxa_gpio_mode(((_x)+96)|GPIO_OUT)


#if SCCB_DELAY > 0
#  define WAIT_CYL udelay(SCCB_DELAY)
#else
#  define WAIT_CYL (void)(0)
#endif

#if SCCB_DELAY2 > 0
#  define WAIT_STAB udelay(SCCB_DELAY2)
#else
#  define WAIT_STAB (void)(0)
#endif
 

static int sccb_dev_id = OV9650_SCCB_ID;

static void __inline sccb_start(void)
{
	MAKE_HIGH(SIO_C);
	MAKE_HIGH(SIO_D);
	WAIT_STAB;
	MAKE_LOW(SIO_D);
	WAIT_STAB;
	MAKE_LOW(SIO_C);
	WAIT_STAB;
}

static void __inline sccb_end(void)
{
	MAKE_LOW(SIO_D);
	WAIT_STAB;
	MAKE_HIGH(SIO_C);
	WAIT_STAB;
	MAKE_HIGH(SIO_D);
	WAIT_STAB;
}

static void __inline sccb_write_bit(unsigned char bit)
{
	if (bit)
		MAKE_HIGH(SIO_D);
	else
		MAKE_LOW(SIO_D);
	WAIT_STAB;
	MAKE_HIGH(SIO_C);
	WAIT_CYL;
	MAKE_LOW(SIO_C);
	WAIT_STAB;
}

static int __inline sccb_read_bit(void)
{
	int tmp = 0;

	MAKE_HIGH(SIO_C);
	WAIT_CYL;
	tmp = BIT_READ(SIO_D);
	MAKE_LOW(SIO_C);
	WAIT_STAB;

	return tmp;
}	

static void __inline sccb_writechar(unsigned char data)
{
	int i = 0;

	/* data */
	for (i = 0; i < 8; i++ ) {
		sccb_write_bit(data & 0x80);
		data <<= 1;
	}

	/* 9th bit - Don't care */
	sccb_write_bit(1);
}

static void __inline sccb_readchar(unsigned char *val)
{
	int i;
	int tmp = 0;

	CFG_READ(SIO_D);

	for (i = 7; i >= 0; i--)
		tmp |= sccb_read_bit() << i;

	CFG_WRITE(SIO_D);

	/* 9th bit - N.A. */
	sccb_write_bit(1);

	*val = tmp & 0xff;
}

/* 3-phase write */
void sccb_sendbyte(unsigned char subaddr, unsigned char data)
{
//	down(&dev.bus_lock);

	sccb_start();
	sccb_writechar(sccb_dev_id);
	sccb_writechar(subaddr);
	sccb_writechar(data);
	sccb_end();

	mdelay(5);

//	up(&dev.bus_lock);
}

/* 2-phase read */
unsigned char sccb_receivebyte(unsigned char subaddr)
{
	unsigned char value;

//	down(&dev.bus_lock);

	/* 2-phase write */
	sccb_start();
	sccb_writechar(sccb_dev_id);
	sccb_writechar(subaddr);
	sccb_end();

	/* 2-phase read */
	sccb_start();
	sccb_writechar(sccb_dev_id | 0x01);
	sccb_readchar(&value);
	sccb_end();

	mdelay(5);

//	up(&dev.bus_lock);

	return value;
}

static void __inline sccb_init(void)
{
	CFG_WRITE(SIO_C);
	CFG_WRITE(SIO_D);
	mdelay(10);
}

static void __inline sccb_deinit(void)
{
	CFG_READ(SIO_C);
	CFG_READ(SIO_D);
}

/***********************************************************************
 *
 * ov9650 initialize values
 *
 ***********************************************************************/
#define CHIP_DELAY 0xFF

struct ov7620_t {
	int subaddr;
	int value;
};

static struct ov7620_t ov9650_reg[] = 
{
	{0x12, 0x80},	// Camera Soft reset. Self cleared after reset.
	{CHIP_DELAY, 10},
//change 0x11[0x81->0x80], 0x15[0x02->0x20], 0x3a[0x01->0x0d]hzh
//{0x12,0x80},
{0x11,0x80},{0x6a,0x3e},{0x3b,0x09},{0x13,0xe0},{0x01,0x80},{0x02,0x80},{0x00,0x00},{0x10,0x00},
{0x13,0xe5},{0x39,0x43},{0x38,0x12},{0x37,0x00},{0x35,0x91},{0x0e,0xa0},{0x1e,0x04},{0xA8,0x80},
{0x12,0x40},{0x04,0x00},{0x0c,0x04},{0x0d,0x80},{0x18,0xc6},{0x17,0x26},{0x32,0xad},{0x03,0x00},
{0x1a,0x3d},{0x19,0x01},{0x3f,0xa6},{0x14,0x2e},{0x15,0x20},{0x41,0x02},{0x42,0x08},{0x1b,0x00},
{0x16,0x06},{0x33,0xe2},{0x34,0xbf},{0x96,0x04},{0x3a,0x00},{0x8e,0x00},{0x3c,0x77},{0x8B,0x06},
{0x94,0x88},{0x95,0x88},{0x40,0xc1},{0x29,0x3f},{0x0f,0x42},{0x3d,0x92},{0x69,0x40},{0x5C,0xb9},
{0x5D,0x96},{0x5E,0x10},{0x59,0xc0},{0x5A,0xaf},{0x5B,0x55},{0x43,0xf0},{0x44,0x10},{0x45,0x68},
{0x46,0x96},{0x47,0x60},{0x48,0x80},{0x5F,0xe0},{0x60,0x8c},{0x61,0x20},{0xa5,0xd9},{0xa4,0x74},
{0x8d,0x02},{0x13,0xe7},{0x4f,0x3a},{0x50,0x3d},{0x51,0x03},{0x52,0x12},{0x53,0x26},{0x54,0x38},
{0x55,0x40},{0x56,0x40},{0x57,0x40},{0x58,0x0d},{0x8C,0x23},{0x3E,0x02},{0xa9,0xb8},{0xaa,0x92},
{0xab,0x0a},{0x8f,0xdf},{0x90,0x00},{0x91,0x00},{0x9f,0x00},{0xa0,0x00},{0x3A,0x0d},{0x24,0x70},
{0x25,0x64},{0x26,0xc3},{0x2a,0x00},{0x2b,0x00},{0x6c,0x40},{0x6d,0x30},{0x6e,0x4b},{0x6f,0x60},
{0x70,0x70},{0x71,0x70},{0x72,0x70},{0x73,0x70},{0x74,0x60},{0x75,0x60},{0x76,0x50},{0x77,0x48},
{0x78,0x3a},{0x79,0x2e},{0x7a,0x28},{0x7b,0x22},{0x7c,0x04},{0x7d,0x07},{0x7e,0x10},{0x7f,0x28},
{0x80,0x36},{0x81,0x44},{0x82,0x52},{0x83,0x60},{0x84,0x6c},{0x85,0x78},{0x86,0x8c},{0x87,0x9e},
{0x88,0xbb},{0x89,0xd2},{0x8a,0xe6},
//	{0x3a, 0x0d},	//
	//{0x3a, 0x1d},	//for test
	//{0x67, 'U'},	//fixed value for U
	//{0x68, 'V'},	//fixed value for V
	//{0x15, 0x12},	//PCLK reverse, VSYNC negative
	//{0x12, 0x10},	//QVGA
	//{0x04, 0x20},	//QQVGA
	//{0x15, 0x20},	//no PCLK when HREF is low
};

#define OV9650_REGS (sizeof(ov9650_reg)/sizeof(ov9650_reg[0]))

static void __inline ov9650_config(void)
{
	int i;

	for (i = 0; i < OV9650_REGS; i++) {
		if (ov9650_reg[i].subaddr == CHIP_DELAY)
			mdelay(ov9650_reg[i].value);
		else
			sccb_sendbyte(ov9650_reg[i].subaddr & 0xff
					, ov9650_reg[i].value & 0xff);
	}
}

#endif	/* USER_I2C_INIT */
/***********************************************************************
 *
 * OV9650 Functions
 *
 ***********************************************************************/
static int pwr_rst_lvl;

static __inline void camera_power_on(void)
{
	int v = 0;

	if(pwr_rst_lvl&1)
		v |= 1<<24;
	if(pwr_rst_lvl&2)
		v |= 1<<25;

	GPSR2 = v;
	GPCR2 = v^(3<<3);
}

static __inline void camera_power_off(void)
{
	int v = 0;

	if(pwr_rst_lvl&1)
		v |= 1<<24;
	if(pwr_rst_lvl&2)
		v |= 1<<25;

	GPCR2 = v;
	GPSR2 = v^(3<<3);
}

static __inline void camera_reset_on(void)
{
	if(pwr_rst_lvl&2)
		GPCR2 = 1<<25;
	else
		GPSR2 = 1<<25;
}

static __inline void camera_reset_off(void)
{
	if(pwr_rst_lvl&2)
		GPSR2 = 1<<25;
	else
		GPCR2 = 1<<25;
}

void camera_ov9650_set_level(int lvl)
{
	if(pwr_rst_lvl!=lvl) {
		pwr_rst_lvl = lvl;
		camera_power_on();
		camera_reset_on();
		current->state = TASK_INTERRUPTIBLE;
		schedule_timeout(HZ/10);
		camera_reset_off();
	}
}

int camera_func_ov9650_init(  p_camera_context_t camera_context )
{
	u16 cm_rev, regv;
/*	CI_MP_TIMING timing = {
		.BLW	= 0,
		.BFW	= 0,
	};
*/
	// Configure CI according to ADCM2650's hardware
	// master parallel with 8 data pins
	ci_set_mode(CI_MODE_MP, CI_DATA_WIDTH8);

	// enable pixel clock(sensor will provide pclock) and master clock = 26MHZ
	ci_set_clock(camera_context->clk_reg_base, 1, 1, MCLK_DEFT);

	// data sample on rising and h,vsync active high
	ci_set_polarity(0, 0, 0);

	// fifo control, threshold=32, enable FIFO1, FIFO2
	ci_set_fifo(0, CI_FIFO_THL_32, 1, 1); // quality
	
	//ci_set_frame_rate(7);	//1/8
	
	//ci_set_image_format(CI_YCBCR422, CI_YCBCR422_PLANAR);
	
	//ci_configure_mp(639, 479, &timing);

	// Turn on M_CLK using xx MHz and wait for 150 ms.
	//ci_enable(1);	//don't enable ci at this time, hzh
	//mdelay(150);
	
	// sensor power on
	camera_power_on();
	camera_reset_on();
	current->state = TASK_INTERRUPTIBLE;
	schedule_timeout(HZ/10);
	camera_reset_off();
	
	sccb_init();

#ifdef CONFIG_USER_I2C_INIT
	cm_rev = regv;
#else
	// read out version	
	cm_rev  = sccb_receivebyte(0x1c) << 8;
	cm_rev |= sccb_receivebyte(0x1d);
	if(cm_rev!=OV9650_PRODUCT_ID) {
		printk("Invalid manufacture ID (0x%04X). there is no OV9650(0x%04X)\n",
				cm_rev, OV9650_PRODUCT_ID);
		return STATUS_FAILURE;
	}
	
	regv  = sccb_receivebyte(0x0a) << 8;
	regv |= sccb_receivebyte(0x0b);
	printk("Product ID is 0x%04x\n", regv);
	
//	ov9650_config();
#endif
	return 0;
}

int camera_func_ov9650_deinit(  p_camera_context_t camera_context )
{
	// sensor power off
	camera_power_off();
	
	sccb_deinit();
	
	// disable CI
	ci_disable(1);  // quick disable

	return 0;
}

int camera_func_ov9650_set_capture_format(  p_camera_context_t camera_context )
{
/*	adcm_window_size wsize;
	u16 adcm_format;

	// set sensor input/output window
	wsize.width = camera_context->capture_width;
	wsize.height = camera_context->capture_height;
	adcm2650_viewfinder_input_size(&wsize);
	adcm2650_viewfinder_output_size(&wsize);
 	adcm2650_stillframe_input_size(&wsize);
	adcm2650_stillframe_output_size(&wsize);
	
	// set sensor format
	switch(camera_context->capture_input_format) {
	case CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR:
	case CAMERA_IMAGE_FORMAT_YCBCR422_PACKED:
		adcm_format = O_FORMAT_422_B_YCbYCr;
		break;
	case CAMERA_IMAGE_FORMAT_RGB565:
		adcm_format = O_FORMAT_565_RGB;
		break;
	case CAMERA_IMAGE_FORMAT_RGB888_PACKED:
	case CAMERA_IMAGE_FORMAT_RGB888_PLANAR:
		adcm_format = O_FORMAT_888RGB;
		break;
	default:
		adcm_format = O_FORMAT_422_B_YCbYCr;
		break;
	}
	adcm2650_viewfinder_cfg_output(adcm_format);
	adcm2650_stillframe_cfg_output(adcm_format);
*/
	return 0;
}

int camera_func_ov9650_start_capture(  p_camera_context_t camera_context, unsigned int frames )
{   	
/*	// frames=0 means continues capture	
	if (frames == 0) {
		// set viewfinder to infinite output
		adcm2650_resume_to_full_output_mode();
		adcm2650_viewfinder_on();
	}
	else {
		// halt viewfinder output
		adcm2650_halt_video_output();
		// limit output frames
		adcm2650_pipeline_write(UART_CREDITS, frames);
	}	
	
	// turn viewfinder on
	adcm2650_viewfinder_on();
*/	
	ci_enable(1);	//enable ci here, hzh
	mdelay(150);

	return 0;
}

int camera_func_ov9650_stop_capture(  p_camera_context_t camera_context )
{
/*	adcm2650_viewfinder_off();
	mdelay(200);
*/
	return 0;
}

⌨️ 快捷键说明

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