📄 ov9650.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 + -