linux驱动学习笔记Camif文档格式.docx
《linux驱动学习笔记Camif文档格式.docx》由会员分享,可在线阅读,更多相关《linux驱动学习笔记Camif文档格式.docx(16页珍藏版)》请在冰豆网上搜索。
CFG_WRITE(SIO_D);
High(SIO_C);
High(SIO_D);
WAIT_STABLE();
return0;
}
由上面的图可以看出,CLK高电平时,DATA拉低,即为START
staticvoid__inline__sccb_start(void)
Low(SIO_D);
使用到一个信号量
staticDECLARE_MUTEX(bus_lock);
voidsccb_write(u8IdAddr,u8SubAddr,u8data)
down(&
bus_lock);
sccb_start();
sccb_write_byte(IdAddr);
sccb_write_byte(SubAddr);
sccb_write_byte(data);
sccb_stop();
up(&
首先把信号量数值降低,表示自己使用,如果此时信号量不大于0,表示bus正在使用,驱动会在此等待,知道信号量大于0,然后,将其减1,此时bus对外界不可用。
最后再把信号量加1,表示bus可用。
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
摄像头接口初始化:
/*
*camif_init()
*/
staticint__initcamif_init(void)
配置CAMIF的GPIO接口功能
/*setgpio-jtocameramode.*/
s3c2410_gpio_cfgpin(S3C2440_GPJ0,S3C2440_GPJ0_CAMDATA0);
s3c2410_gpio_cfgpin(S3C2440_GPJ1,S3C2440_GPJ1_CAMDATA1);
s3c2410_gpio_cfgpin(S3C2440_GPJ2,S3C2440_GPJ2_CAMDATA2);
s3c2410_gpio_cfgpin(S3C2440_GPJ3,S3C2440_GPJ3_CAMDATA3);
s3c2410_gpio_cfgpin(S3C2440_GPJ4,S3C2440_GPJ4_CAMDATA4);
s3c2410_gpio_cfgpin(S3C2440_GPJ5,S3C2440_GPJ5_CAMDATA5);
s3c2410_gpio_cfgpin(S3C2440_GPJ6,S3C2440_GPJ6_CAMDATA6);
s3c2410_gpio_cfgpin(S3C2440_GPJ7,S3C2440_GPJ7_CAMDATA7);
s3c2410_gpio_cfgpin(S3C2440_GPJ8,S3C2440_GPJ8_CAMPCLK);
s3c2410_gpio_cfgpin(S3C2440_GPJ9,S3C2440_GPJ9_CAMVSYNC);
s3c2410_gpio_cfgpin(S3C2440_GPJ10,S3C2440_GPJ10_CAMHREF);
s3c2410_gpio_cfgpin(S3C2440_GPJ11,S3C2440_GPJ11_CAMCLKOUT);
s3c2410_gpio_cfgpin(S3C2440_GPJ12,S3C2440_GPJ12_CAMRESET);
申请CAMIF的寄存器区域,由于OS的系统统一管理,所以,需要确定,该寄存器区域没有被别的进程获取,所以要申请。
/*initcamera'
svirtualmemory.*/
if(!
request_mem_region((unsignedlong)S3C2440_PA_CAMIF,S3C2440_SZ_CAMIF,CARD_NAME))
{
ret=-EBUSY;
gotoerror1;
}
申请到了寄存器区域,相当于物理地址可用,然后,再将该物理地址映射到虚拟地址。
/*remapthevirtualmemory.*/
camif_base_addr=(unsignedlong)ioremap_nocache((unsignedlong)S3C2440_PA_CAMIF,S3C2440_SZ_CAMIF);
if(camif_base_addr==(unsignedlong)NULL)
gotoerror2;
获取CAMIF的时钟,使用24M
/*initcameraclock.*/
pdev->
clk=clk_get(NULL,"
camif"
);
if(IS_ERR(pdev->
clk))
ret=-ENOENT;
gotoerror3;
clk_enable(pdev->
clk);
camif_upll_clk=clk_get(NULL,"
camif-upll"
clk_set_rate(camif_upll_clk,);
mdelay(100);
初始化CAMIF的状态
/*initcamifstateanditslock.*/
state=CAMIF_STATE_FREE;
CAMIFDEV的状态:
/*fors3c2440camif_dev->
statefield.*/
enum
CAMIF_STATE_FREE=0,//notopenned
CAMIF_STATE_READY=1,//openned,butstandby
CAMIF_STATE_PREVIEWING=2,//inpreviewing
CAMIF_STATE_CODECING=3//incapturing
};
注册杂项设备:
/*registertovideodevlayer.*/
if(misc_register(&
misc)<
0)
gotoerror4;
printk(KERN_ALERT"
s3c2440camifinitdone\n"
初始化SCCB接口,SerialCameraControlBus,其实是I2C接口
sccb_init();
硬件复位CAMIF
hw_reset_camif();
其实是软件复位,对CIGCTRL寄存器配置软件复位
/*softwareresetcamerainterface.*/
staticvoid__inline__hw_reset_camif(void)
u32cigctrl;
cigctrl=(1<
<
30)|(1<
29);
iowrite32(cigctrl,S3C244X_CIGCTRL);
mdelay(10);
检测是否存在OV9650,GPG4连的是LCD_PWR,不知道为什么?
has_ov9650=s3c2440_ov9650_init()>
=0;
s3c2410_gpio_setpin(S3C2410_GPG4,1);
OV9650的初始化:
ints3c2440_ov9650_init(void)
LoadingOV9650driver.........\n"
/*poweron.*/
ov9650_poweron();
/*checkdevice.*/
if(ov9650_check()==0&
&
ov9650_check()==0)
printk(KERN_ERR"
NoOV9650found!
!
\n"
return-ENODEV;
show_ov9650_product_id();
ov9650_init_regs();
printk("
ov9650initdone!
OV9650上电,这里对GPG12设置为输出,这里使用的虽然是中断引脚,但似乎没有用中断,这是一个电源控制引脚,PWDN,0:
poweron,1:
powerdown
staticvoid__inline__ov9650_poweron(void)
s3c2410_gpio_cfgpin(S3C2410_GPG12,S3C2410_GPG12_OUTP);
s3c2410_gpio_setpin(S3C2410_GPG12,0);
mdelay(20);
OV9650检测,读取OV9650的ManuID
staticint__inline__ov9650_check(void)
u32mid;
mid=sccb_read(OV9650_SCCB_ADDR,0x1c)<
8;
mid|=sccb_read(OV9650_SCCB_ADDR,0x1d);
SCCBaddress0x%02X,manufactureID0x%04X,expect0x%04X\n"
OV9650_SCCB_ADDR,mid,OV9650_MANUFACT_ID);
return(mid==OV9650_MANUFACT_ID)?
1:
0;
#defineOV9650_SCCB_ADDR0x60
#defineOV9650_MANUFACT_ID0x7FA2
#defineOV9650_PRODUCT_ID0x9650
摄像头接口打开:
*camif_open()
staticintcamif_open(structinode*inode,structfile*file)
首先判断是否存在OV9650camera是文件开始的一个static变量。
structs3c2440camif_dev*pdev;
structs3c2440camif_fh*fh;
intret;
has_ov9650){
pdev=&
camera;
为filehandle分配内存
fh=kzalloc(sizeof(*fh),GFP_KERNEL);
//allocmemoryforfilehandle
设置设备状态为openandstandby,初始化CAMIF的配置。
pdev->
state=CAMIF_STATE_READY;
init_camif_config(fh);
对CAMIF进行配置,最后更新一下配置
/*configcamifwhenmaster-opencamera.*/
staticvoidinit_camif_config(structs3c2440camif_fh*fh)
structs3c2440camif_dev*pdev;
pdev=fh->
dev;
input=0;
//FIXME,thedefaultinputimageformat,seeinputs[]fordetail.
/*thesourceimagesize(inputfromexternalcamera).*/
srcHsize=1280;
//FIXME,theOV9650'
shorizontaloutputpixels.
srcVsize=1024;
svericaloutputpixels.
/*thewindowedimagesize.*/
wndHsize=1280;
wndVsize=1024;
/*codec-pathtarget(output)imagesize.*/
coTargetHsize=pdev->
wndHsize;
coTargetVsize=pdev->
wndVsize;
/*preview-pathtarget(preview)imagesize.*/
preTargetHsize=640;
preTargetVsize=512;
update_camif_config(fh,CAMIF_CMD_STOP);
由于设备状态是CAMIF_STATE_READY所以,直接更新寄存器。
/*updatecamerainterfacewiththenewconfig.*/
staticvoidupdate_camif_config(structs3c2440camif_fh*fh,u32cmdcode)
switch(pdev->
state)
caseCAMIF_STATE_READY:
update_camif_regs(fh->
dev);
//configtheregsdirectly.
break;
caseCAMIF_STATE_PREVIEWING:
/*camifispreviewingimage.*/
disable_irq(IRQ_S3C2440_CAM_P);
//disablecam-previewirq.
/*sourceimageformat.*/
if(cmdcode&
CAMIF_CMD_SFMT)
{
//ignoreit,nothingtodonow.
}
/*targetimageformat.*/
CAMIF_CMD_TFMT)
/*changetargetimageformatonly.*/
pdev->
cmdcode|=CAMIF_CMD_TFMT;
不知为什么要等待VSYNC为L?
然后对寄存器进行配置。
/*updatecamifregisters,calledonlywhencamifready,orISR.*/
staticvoid__inline__update_camif_regs(structs3c2440camif_dev*pdev)
in_irq())
while
(1)//waituntilVSYNCis'
L'
barrier();
if((ioread32(S3C244X_CICOSTATUS)&
(1<
28))==0)
break;
/*WARNING:
don'
tchangethestatementsortbelow!
update_source_fmt_regs(pdev);
update_target_wnd_regs(pdev);
update_target_fmt_regs(pdev);
update_target_zoom_regs(pdev);
初始化CAMIF的DMA内存。
ret=init_image_buffer();
//initimagebuffer.
这里为DMA分配内存,按页分配,内存管理的知识需要学习?
/*initimagebuffer(onlywhenthecamifisfirstopen).*/
staticint__inline__init_image_buffer(void)
intsize1,size2;
unsignedlongsize;
unsignedintorder;
/*size1isthemaximagesizeofcodecpath.*/
size1=MAX_C_WIDTH*MAX_C_HEIGHT*16/8;
/*size2isthemaximagesizeofpreviewpath.*/
size2=MAX_P_WIDTH*MAX_P_HEIGHT*16/8;
size=(size1>
size2)?
size1:
size2;
order=get_order(size);
//获取需要分配字节的2的阶数,内存按页分配
img_buff[0].order=order;
img_buff[0].virt_base=__get_free_pages(GFP_KERNEL|GFP_DMA,img_buff[0].order);
if(img_buff[0].virt_base==(unsignedlong)NULL)
gotoerror0;
img_buff[0].phy_base=img_buff[0].virt_base-PAGE_OFFSET+PHYS_OFFSET;
//theDMAaddress.
申请中断,分别为Codec的中断和Preview的中断
request_irq(IRQ_S3C2440_CAM_C,on_camif_irq_c,IRQF_DISABLED,"
CAM_C"
pdev);
request_irq(IRQ_S3C2440_CAM_P,on_camif_irq_p,IRQF_DISABLED,"
CAM_P"
使能时钟,软件复位,更新CAMIF的配置。
//andenablecamifclock.
soft_reset_camif();
file->
private_data=fh;
fh->
dev=pdev;
update_camif_config(fh,0);
摄像头接口读取函数:
staticssize_tcamif_read(structfile*file,char__user*data,size_tcount,loff_t*ppos)
inti;
structs3c2440camif_fh*fh;
fh=file->
private_data;
if(start_capture(pdev,0)!
=0)//此处是捕获一张图片,所以会阻塞在此,直至中断发生。
return-ERESTARTSYS;
//中断已经发生,数据已经更新。
disable_irq(IRQ_S3C2440_CAM_C);
disable_irq(IRQ_S3C2440_CAM_P);
for(i=0;
i<
4;
i++)
if(img_buff[i].state!
=CAMIF_BUFF_INVALID)//如果数据已经更新,移动数据
copy_to_user(data,(void*)img_buff[i].virt_base,count);
img_buff[i].state=CAMIF_BUFF_INVALID;
//设置数据无效
enable_irq(IRQ_S3C2440_CAM_P);
//重新使能中断
enable_irq(IRQ_S3C2440_CAM_C);
returncount;
开始捕获函数,设置windowoffset
/*startimagecapture.
*
*param'
stream'
meanscapturepicturesstreamly