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

📄 mt9d011_hw.c

📁 MT9D111基于LINUX下的摄像头驱动,希望对大家有所帮助
💻 C
字号:
/*
* mt9d011_hw.c
*
* mt9d011 Camera Module driver.
*
* Copyright (C) 2005, Nanwang Corporation
*
* Author: nanwang Inc.
* yulu
*
*
*/

#include <linux/types.h>
#include <asm/mach-types.h>
#include <asm/io.h>
#include <asm/semaphore.h>
#include <asm/hardware.h>
#include <asm/mach-types.h>
#include <asm/dma.h>
#include <asm/irq.h>

#include <linux/types.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/wrapper.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include "adcm2650_hw.h"
#include "pxa_camera.h"



void adcm2650_wait( int ms )
{
mdelay( ms );
}


/*****************************************************************************
* *
* I2C Management *
* *
*****************************************************************************/
void i2c_init(void)
{

//reset = 0 ,udelay
GPCR0 |= (1<<11);
udelay(20);

nw_set_clock(1,1,7);
udelay(20);
//reset = 1
GPSR0 |= (1<<11); 

//iic_test();

//configure i2c communication
nw_i2c_init();

//initialize camera sensor registers
nw_camera_init();

printk("\n yul adcm2650_hw:i2c init ok!!!");

}

void i2c_deinit(void)
{

}





//初始化camera sensor 的寄存器
int nw_camera_init(void)
{
u16 value = 0;
u16 regValue = 0;
int i;

//reset mcu
adcm2650_write(PAGE_REG, 1);
adcm2650_write(0xc3,0x0001);

mdelay(10);
adcm2650_write(0xc3,0x0000);

adcm2650_write(PAGE_REG, 0);
adcm2650_write(RESET, 0x1);

mdelay(10);
adcm2650_write(RESET, 0x0);

// for(i=0;i<100;i++)
// udelay(1000);
mdelay(10);


#if 0
/*pll registers*/
//program pll
adcm2650_write(PLL_CTRL_1, 0x1000); //m 0x28 n 0x9
adcm2650_write(PLL_CTRL_2, 0x0002); //p 0x2
//power up pll
adcm2650_write(CLK_CTRL, 0xa000); //use pll
udelay(300);
adcm2650_write(CLK_CTRL, 0x2000); //use pll

printk("\n p0 PLL_CTRL_1 = 0x%x",adcm2650_read(PLL_CTRL_1,&regValue));
printk("\n p0 PLL_CTRL_2 = 0x%x",adcm2650_read(PLL_CTRL_2,&regValue));
printk("\n p0 CLK_CTRL = 0x%x",adcm2650_read(CLK_CTRL,&regValue));
#endif



/*context A, PREVIEW*/
var_write8(1,0x20,0x0000);//SEQ_CAP_MODE
var_write8(1,0x03,0x0001);//SEQ_CMD 

#if 0 
/*resize contextA 240*320*/
var_write16(7,0x27,0x0000);//MODE_CROP_X0_A
var_write16(7,0x29,0x0320);//MODE_CROP_X1_A
var_write16(7,0x2b,0x0000);//MODE_CROP_Y0_A
var_write16(7,0x2d,0x0258);//MODE_CROP_Y1_A
var_write16(7,0x03,0x00f0);//MODE_OUTPUT_WIDTH_A
var_write16(7,0x05,0x0140);//MODE_OUTPUT_HEIGHT_A 
var_write8(1,0x03,0x0005);//SEQ_CMD 
mdelay(100);
#endif 


/*resize*/ 
adcm2650_write(PAGE_REG, 1);
adcm2650_write(0xC6, 0x2727);//MODE_CROP_X0_A 
adcm2650_write(0xC8, 0x0); //MODE_CROP_X0_A 
adcm2650_write(0xC6, 0x2729);//MODE_CROP_X1_A 
adcm2650_write(0xC8, 0x0320);//MODE_CROP_X1_A 
adcm2650_write(0xC6, 0x272B);//MODE_CROP_Y0_A 
adcm2650_write(0xC8, 0x0000);//MODE_CROP_Y0_A 
adcm2650_write(0xC6, 0x272D);//MODE_CROP_Y1_A 
adcm2650_write(0xC8, 0x0258);//MODE_CROP_Y1_A 
adcm2650_write(0xC6, 0x2703);//MODE_OUTPUT_WIDTH_A 
adcm2650_write(0xC8, 0x00f0);//MODE_OUTPUT_WIDTH_A 
adcm2650_write(0xC6, 0x2705);//MODE_OUTPUT_HEIGHT_A
adcm2650_write(0xC8, 0x0140);//MODE_OUTPUT_HEIGHT_A
adcm2650_write(0xC6, 0xA103);//SEQ_CMD 
adcm2650_write(0xC8, 0x0005);//SEQ_CMD 


#if 0 //yuv420 output
adcm2650_read(0x15,&regValue);
printk("\n yuv 420 = 0x%x",regValue);
regValue |= 1<<4;
adcm2650_write(0x15, regValue);//YUV420 ENABLE 
//printk("\n yuv 420 = 0x%x",regValue);
//printk("\n yuv 420 = 0x%x",adcm2650_read(0x15,&regValue)); 
#endif


#if 0 
/*disable cr ab */
adcm2650_read(0x98,&regValue);
regValue |= 0x05;
adcm2650_write(0x98, regValue); 

adcm2650_write(0x97,0x20); 


var_write16(7,0x7F,0x6443);//MODE_SPEC_EFFECTS_A
var_write8(1,0x03,0x0005);//SEQ_CMD refresh

adcm2650_write(PAGE_REG,0x1);
adcm2650_write(0xA4, 0x6441);



/************print size related reg&VAR****************/
adcm2650_write(PAGE_REG,0x1);
printk("\n weight x = 0x%x",adcm2650_read(0x16,&regValue));
printk("\n weight y = 0x%x",adcm2650_read(0x17,&regValue));

adcm2650_write(PAGE_REG,0x0);
printk("\n p0 ROW_WIDTH = 0x%x",adcm2650_read(ROW_WIDTH,&regValue));
printk("\n p0 COL_WIDTH = 0x%x",adcm2650_read(COL_WIDTH,&regValue));
printk("\n p0 0x0D = 0x%x",adcm2650_read(0x0D,&regValue));

adcm2650_write(PAGE_REG,0x2);
printk("\n p2,0x16 = 0x%x",adcm2650_read(0x16,&regValue));
printk("\n p2,0x17 = 0x%x",adcm2650_read(0x17,&regValue));

printk("\n p2,0x10 = 0x%x",adcm2650_read(0x10,&regValue));
printk("\n p2,0x11 = 0x%x",adcm2650_read(0x11,&regValue)); 

/************print mode related reg&VAR****************/ 
adcm2650_write(PAGE_REG,0x0);
printk("\n p0 CONTEXT CONTROL = 0x%x",adcm2650_read(0xF2,&regValue)); 

adcm2650_write(PAGE_REG,0x1);
printk("\n p1 0XC3 MCU RESET = 0x%x",adcm2650_read(0xC3,&regValue));


/************print effect related reg&VAR****************/
adcm2650_write(PAGE_REG,0x1);
printk("\n p0 0xA4 Special Effect= 0x%x",adcm2650_read(0xA4,&regValue));

printk("\n 7,0x7F Spec_effects_A= 0x%x",var_read16(7,0x7F));

/*************SFP REG VALUE******/
adcm2650_write(PAGE_REG,0x1);
adcm2650_write(198,0x9046);
printk("\n SFP LineCnt 0x1046 = 0x%x",adcm2650_read(200,&regValue));
adcm2650_write(198,0x9047);
printk("\n SFP LineCnt 0x1047 = 0x%x",adcm2650_read(200,&regValue));

adcm2650_write(198,0x1048);
printk("\n SFP ClockCnt 0x1048/9= 0x%x",adcm2650_read(200,&regValue));
adcm2650_write(198,0x104A);
printk("\n SFP ClockCnt 0x104A/B= 0x%x",adcm2650_read(200,&regValue));

adcm2650_write(PAGE_REG,0x0);
printk("\n CHIP_VER = 0x%x",adcm2650_read(CHIP_VER,&regValue)); 
printk("\n G1_GAIN = 0x%x",adcm2650_read(G1_GAIN,&regValue));
printk("\n B_GAIN = 0x%x",adcm2650_read(B_GAIN,&regValue));
printk("\n R_GAIN = 0x%x",adcm2650_read(R_GAIN,&regValue));
printk("\n G2_GAIN = 0x%x",adcm2650_read(G2_GAIN,&regValue));
printk("\n PLL_CTRL_1 = 0x%x",adcm2650_read(PLL_CTRL_1,&regValue));
printk("\n PLL_CTRL_2 = 0x%x",adcm2650_read(PLL_CTRL_2,&regValue));
printk("\n CLK_CTRL = 0x%x",adcm2650_read(CLK_CTRL,&regValue));
printk("\n ROW_START = 0x%x",adcm2650_read(ROW_START,&regValue));
printk("\n COL_START = 0x%x",adcm2650_read(COL_START,&regValue));
printk("\n ROW_WIDTH = 0x%x",adcm2650_read(ROW_WIDTH,&regValue));
printk("\n COL_WIDTH = 0x%x",adcm2650_read(COL_WIDTH,&regValue));
printk("\n SHUT_WIDTH = 0x%x",adcm2650_read(SHUT_WIDTH,&regValue));
printk("\n 0XF2 = 0x%x",adcm2650_read(0xF2,&regValue));
printk("\n 0X21 = 0x%x",adcm2650_read(0x21,&regValue));


adcm2650_write(PAGE_REG,0x1);
printk("\n 0XA4 = 0x%x",adcm2650_read(0xA4,&regValue));

printk("\n 7,0x03 = 0x%x",var_read16(7,0x03));
printk("\n 7,0x05 = 0x%x",var_read16(7,0x05));
printk("\n 7,0x27 = 0x%x",var_read16(7,0x27));
printk("\n 7,0x29 = 0x%x",var_read16(7,0x29));
printk("\n 7,0x2b = 0x%x",var_read16(7,0x2b));
printk("\n 7,0x2d = 0x%x",var_read16(7,0x2d));
printk("\n 7,0x79 = 0x%x",var_read16(7,0x79));
printk("\n 7,0x7b = 0x%x",var_read16(7,0x7b));
printk("\n 7,0x37 = 0x%x",var_read16(7,0x37));
printk("\n 7,0x3b = 0x%x",var_read16(7,0x3b));
printk("\n 7,0x7F = 0x%x",var_read16(7,0x7F));

printk("\n 7,0x02 = 0x%x",var_read8(7,0x02)); 
printk("\n 1,0x03 = 0x%x",var_read8(1,0x03));
printk("\n 1,0x20 = 0x%x",var_read8(1,0x20));
printk("\n 1,0x04 = 0x%x",var_read8(1,0x04));
printk("\n 1,0x07 = 0x%x",var_read8(1,0x07));
printk("\n 1,0x08 = 0x%x",var_read8(1,0x08));
printk("\n 1,0x09 = 0x%x",var_read8(1,0x09));
printk("\n p1,0x97 = 0x%x",adcm2650_read(0x97,&regValue));

adcm2650_write(PAGE_REG,0x2);
printk("\n p2,0x16 = 0x%x",adcm2650_read(0x16,&regValue));
printk("\n p2,0x17 = 0x%x",adcm2650_read(0x17,&regValue)); 
#endif
return 0;
}



int adcm2650_set_size( adcm_window_size * window )
{

if((window->height > 1600) || ( window->width > 1200))
{
printk("\n adcm2650_hw: window is out of the max!!!");
return ADCM_ERR_PARAMETER;
}
adcm2650_write(PAGE_REG, 0);

//input row width
adcm2650_write(ROW_WIDTH, window->height);

//input col width
adcm2650_write(COL_WIDTH, window->width);

//row start,column start
/*adcm2650_write(ROW_START, 0x1c);
adcm2650_write(COL_START, 0x3c);*/

return ADCM_ERR_NONE;
}






/*i2c的读写接口*/
int adcm2650_read(u16 addr, u16 *pvalue)
{
u16 res = 0;

res = iic_read(READ_SLAVE_ADDR,addr);
*pvalue = (u16)res;

return res;
}


int adcm2650_write(u16 addr, u16 value)
{

return iic_write(WRITE_SLAVE_ADDR,addr, value);
}
#if 1
int var_write16(u8 id, u16 offset, u16 value)
{
adcm2650_write(PAGE_REG,0x1);

adcm2650_write(VAR_ADDR,((id<<8) | offset | VAR_LOGIC_ACCESS ));

adcm2650_write(VAR_DATA,value);
}

int var_write8(u8 id, u16 offset, u16 value)
{
adcm2650_write(PAGE_REG,0x1);

adcm2650_write(VAR_ADDR,((id<<8) | offset | VAR_LOGIC_ACCESS | VAR_8_ACCESS));

adcm2650_write(VAR_DATA,value);
}



int var_read8(u8 id, u16 offset)
{
u16 value;
adcm2650_write(PAGE_REG,0x1);

adcm2650_write(VAR_ADDR,((id<<8) | offset | VAR_LOGIC_ACCESS | VAR_8_ACCESS));

adcm2650_read(VAR_DATA,&value);

return value;

}

int var_read16(u8 id, u16 offset )
{
u16 value;
adcm2650_write(PAGE_REG,0x1);

adcm2650_write(VAR_ADDR,((id<<8) | offset | VAR_LOGIC_ACCESS));

adcm2650_read(VAR_DATA,&value);

return value;

}
#endif



/*配置i2c初始化*/
static int nw_i2c_init()
{
//printk("\nnanwang iic init here\n");
CKEN |= CKEN14_I2C;
set_GPIO_mode(117 | GPIO_ALT_FN_1_IN);
set_GPIO_mode(118 | GPIO_ALT_FN_1_IN);
ICR |= ICR_UR;
udelay(1000);
ICR &= ~ICR_UR;
udelay(1000);
ICR &= ~ICR_IUE;
ISAR = 0xff;
ISR = 0;
ICR = ICR_IUE | ICR_SCLE | ICR_GCD;
udelay(100);
return 0;
}

static int iic_read(unsigned char dev_addr,unsigned char reg_addr)
{
int i;
u16 value = 0;
unsigned char data1 = 0;
unsigned char data2 = 0;
//printk(" dev_addr = 0x%x, reg_addr = 0x%x\n",dev_addr,reg_addr);

//send start signal and device addr here
IDBR = (unsigned int)dev_addr;
ICR &= ~(ICR_STOP | ICR_ALDIE | ICR_TB);
ICR |= ICR_START | ICR_TB;
for(i=0;i<0x100000;i++)
{
if((ISR & ISR_ITE) == ISR_ITE)
break;
}
if(i >= 0x100000)
{
printk("time out at dev_addr\n");
printk("IDBR = 0x%x\n",IDBR);
printk("ICR = 0x%x\n",ICR);
printk("ISR = 0x%x\n",ISR);
}
//while((ISR & ISR_ITE) == 0);
ISR &= ISR_ITE;
while(ISR & ISR_ACKNAK);
udelay(2);

//send slaveaddr here
IDBR = (unsigned int)reg_addr;
ICR &= ~(ICR_TB | ICR_START | ICR_STOP | ICR_ALDIE);
ICR |= ICR_TB;
for(i=0;i<0x100000;i++)
{
if((ISR & ISR_ITE) == ISR_ITE)
break;
}
if(i >= 0x100000)
{
printk("time out at dev_addr\n");
}
//while((ISR & ISR_ITE) == 0);
ISR &= ISR_ITE;
while(ISR & ISR_ACKNAK);
udelay(2);

//send start signal and dev_addr read
IDBR = (unsigned int)dev_addr | 0x01;
ICR &= ~(ICR_TB | ICR_STOP | ICR_ALDIE);
ICR |= ICR_TB | ICR_START;
for(i=0;i<0x100000;i++)
{
if((ISR & ISR_ITE) == ISR_ITE)
break;
}
if(i >= 0x100000)
{
printk("time out at dev_addr\n");
}
//while((ISR & ISR_ITE) == 0);
ISR &= ISR_ITE;
while(ISR & ISR_ACKNAK);
udelay(2);

//init read
ICR &= ~(ICR_START | ICR_STOP | ICR_TB | ICR_ACKNAK | ICR_ALDIE);
ICR |= ICR_TB;
for(i=0;i<0x100000;i++)
{
if((ISR & ISR_IRF) == ISR_IRF)
break;
}
if(i >= 0x100000)
{
printk("time out at dev_addr\n");
}
ISR &= ISR_IRF;
//while(ISR & ISR_ACKNAK);
data1 = (unsigned char)IDBR;
ICR &= ~(ICR_STOP | ICR_ACKNAK);
udelay(2);
ICR &= ~(ICR_START | ICR_TB | ICR_ALDIE | ICR_ACKNAK);
ICR |= ICR_TB | ICR_STOP | ICR_ACKNAK;
for(i=0;i<0x100000;i++)
{
if((ISR & ISR_IRF) == ISR_IRF)
break;
}
if(i >= 0x100000)
{
printk("time out at dev_addr\n");
}
ISR &= ISR_IRF;
//while(ISR & ISR_ACKNAK);
data2 = (unsigned char)IDBR; 
ICR &= ~(ICR_STOP | ICR_ACKNAK);
//data = (unsigned char)IDBR | (data << 8);
udelay(20);

value = (data1 << 8) | data2;

return (value);
}

static int iic_write(unsigned char dev_addr,unsigned char reg_addr,unsigned short value)
{
int i;
u8 data1,data2 = 0;

data1 = (value & 0xff00) >> 8;
data2 = value & 0xff;

//printk("\niic write here dev_addr = 0x%x,reg_addr = 0x%x, data1 = 0x%x, data2 = 0x%x\n",dev_addr,reg_addr,data1,data2);
// mdelay(10);
for(i=0;i<100;i++)
udelay(1000);
IDBR = (unsigned int)dev_addr;
ICR &= ~(ICR_STOP | ICR_ALDIE | ICR_TB);
ICR |= ICR_START | ICR_TB;
for(i=0;i<0x100000;i++)
{
if((ISR & ISR_ITE) == ISR_ITE)
break;
}
if(i >= 0x100000)
{
printk("time out at dev_addr\n");
}
//while((ISR & ISR_ITE) == 0);
ISR &= ISR_ITE;
while(ISR & ISR_ACKNAK);
udelay(2);

//send slaveaddr here
IDBR = (unsigned int)reg_addr;
ICR &= ~(ICR_TB | ICR_START | ICR_STOP | ICR_ALDIE);
ICR |= ICR_TB;
for(i=0;i<0x100000;i++)
{
if((ISR & ISR_ITE) == ISR_ITE)
break;
}
if(i >= 0x100000)
{
printk("time out at reg_addr\n");
}
//while((ISR & ISR_ITE ) == 0);
ISR &= ISR_ITE;
while(ISR & ISR_ACKNAK);
udelay(2);

//send data here
IDBR = (unsigned int)data1;
ICR &= ~(ICR_TB | ICR_START | ICR_STOP | ICR_ALDIE);
ICR |= ICR_TB;
for(i=0;i<0x100000;i++)
{
if((ISR & ISR_ITE) == ISR_ITE)
break;
}
if(i >= 0x100000)
{
printk("time out at data1\n");
}
//while((ISR & ISR_ITE ) == 0);
ISR &= ISR_ITE;
//while(PWRISR & ISR_ACKNAK);
udelay(2);

IDBR = (unsigned int)data2;
ICR &= ~(ICR_TB | ICR_START | ICR_ALDIE);
ICR |= ICR_TB | ICR_STOP;
for(i=0;i<0x100000;i++)
{
if((ISR & ISR_ITE) == ISR_ITE)
break;
}
if(i >= 0x100000)
{
printk("time out at data2\n");
}
//while((ISR & ISR_ITE ) == 0);
ISR &= ISR_ITE;
udelay(20);

return 0;
}


static void nw_set_clock(int pclk_enable, int mclk_enable, unsigned int mclk_khz)
{
unsigned int ciclk, value, div, cccr_l, K;

// determine the LCLK frequency programmed into the CCCR.
cccr_l = (CCCR & 0x0000001F);

if (cccr_l < 8)
K = 1;
else if (cccr_l < 17)
K = 2;
else 
K = 3;

ciclk = (13 * cccr_l) / K;

//div = ciclk / ( 2 * mclk_khz ) - 1 ; 
div = 0; //not div by yul
// write cicr4
value = CICR4;
value &= ~(CI_CICR4_PCLK_EN | CI_CICR4_MCLK_EN | CI_CICR4_DIV_SMASK<<CI_CICR4_DIV_SHIFT);
value |= (pclk_enable) ? CI_CICR4_PCLK_EN : 0;
value |= (mclk_enable) ? CI_CICR4_MCLK_EN : 0;
value |= div << CI_CICR4_DIV_SHIFT;
//value |= 0x2;
CICR4 = value; 
return; 
}


⌨️ 快捷键说明

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