linux驱动学习笔记Camif.docx

上传人:b****5 文档编号:8359620 上传时间:2023-01-30 格式:DOCX 页数:16 大小:20.59KB
下载 相关 举报
linux驱动学习笔记Camif.docx_第1页
第1页 / 共16页
linux驱动学习笔记Camif.docx_第2页
第2页 / 共16页
linux驱动学习笔记Camif.docx_第3页
第3页 / 共16页
linux驱动学习笔记Camif.docx_第4页
第4页 / 共16页
linux驱动学习笔记Camif.docx_第5页
第5页 / 共16页
点击查看更多>>
下载资源
资源描述

linux驱动学习笔记Camif.docx

《linux驱动学习笔记Camif.docx》由会员分享,可在线阅读,更多相关《linux驱动学习笔记Camif.docx(16页珍藏版)》请在冰豆网上搜索。

linux驱动学习笔记Camif.docx

linux驱动学习笔记Camif

触摸屏驱动学习:

\drivers\media\video\s3c2440camif.c

\drivers\media\video\s3c2440_ov9650.c

\drivers\media\video\sccb.c

硬件连接

I2C总线连接

I2CSCL——GPE14

I2CSDA——GPE15

Sccb.h

#defineSIO_CS3C2410_GPE14

#defineSIO_DS3C2410_GPE15

#defineState(x)s3c2410_gpio_getpin(x)

#defineHigh(x)do{s3c2410_gpio_setpin(x,1);smp_mb();}while(0)

#defineLow(x)do{s3c2410_gpio_setpin(x,0);smp_mb();}while(0)

#defineWAIT_STABLE()do{udelay(10);}while(0)

#defineWAIT_CYCLE()do{udelay(90);}while(0)

#defineCFG_READ(x)do{s3c2410_gpio_cfgpin(x,S3C2410_GPIO_INPUT);smp_mb();}while(0)

#defineCFG_WRITE(x)do{s3c2410_gpio_cfgpin(x,S3C2410_GPIO_OUTPUT);smp_mb();}while(0)

voidsccb_write(u8IdAddr,u8SubAddr,u8data);

u8sccb_read(u8IdAddr,u8SubAddr);

CFG_WRITE(x)把GPIO设置为输出

CFG_READ(x)把GPIO设置为输入

High(x)把GPIO设置为高电平

Low(x)把GPIO设置为低电平

Sccb.c

把SCL和Data都拉高,即为默认初始化状态电平

intsccb_init(void)

{

CFG_WRITE(SIO_C);

CFG_WRITE(SIO_D);

High(SIO_C);

High(SIO_D);

WAIT_STABLE();

return0;

}

由上面的图可以看出,CLK高电平时,DATA拉低,即为START

staticvoid__inline__sccb_start(void)

{

CFG_WRITE(SIO_D);

Low(SIO_D);

WAIT_STABLE();

}

使用到一个信号量

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(&bus_lock);

}

首先把信号量数值降低,表示自己使用,如果此时信号量不大于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)

{

ret=-EBUSY;

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.*/

pdev->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)

{

ret=-EBUSY;

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);

cigctrl=(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)

{

printk(KERN_ALERT"LoadingOV9650driver.........\n");

/*poweron.*/

ov9650_poweron();

mdelay(100);

/*checkdevice.*/

if(ov9650_check()==0&&ov9650_check()==0)

{

printk(KERN_ERR"NoOV9650found!

!

!

\n");

return-ENODEV;

}

show_ov9650_product_id();

ov9650_init_regs();

printk("ov9650initdone!

\n");

return0;

}

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);

printk("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;

if(!

has_ov9650){

return-ENODEV;

}

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;

pdev->input=0;//FIXME,thedefaultinputimageformat,seeinputs[]fordetail.

/*thesourceimagesize(inputfromexternalcamera).*/

pdev->srcHsize=1280;//FIXME,theOV9650'shorizontaloutputpixels.

pdev->srcVsize=1024;//FIXME,theOV9650'svericaloutputpixels.

/*thewindowedimagesize.*/

pdev->wndHsize=1280;

pdev->wndVsize=1024;

/*codec-pathtarget(output)imagesize.*/

pdev->coTargetHsize=pdev->wndHsize;

pdev->coTargetVsize=pdev->wndVsize;

/*preview-pathtarget(preview)imagesize.*/

pdev->preTargetHsize=640;

pdev->preTargetVsize=512;

update_camif_config(fh,CAMIF_CMD_STOP);

}

由于设备状态是CAMIF_STATE_READY所以,直接更新寄存器。

/*updatecamerainterfacewiththenewconfig.*/

staticvoidupdate_camif_config(structs3c2440camif_fh*fh,u32cmdcode)

{

structs3c2440camif_dev*pdev;

pdev=fh->dev;

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.*/

if(cmdcode&CAMIF_CMD_TFMT)

{

/*changetargetimageformatonly.*/

pdev->cmdcode|=CAMIF_CMD_TFMT;

}

不知为什么要等待VSYNC为L?

然后对寄存器进行配置。

/*updatecamifregisters,calledonlywhencamifready,orISR.*/

staticvoid__inline__update_camif_regs(structs3c2440camif_dev*pdev)

{

if(!

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",pdev);

使能时钟,软件复位,更新CAMIF的配置。

clk_enable(pdev->clk);//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;

structs3c2440camif_dev*pdev;

fh=file->private_data;

pdev=fh->dev;

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

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 初中教育

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1