版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
/Linux/2011-09/43084.htm打算跟着友善之臂的《mini2440Linux移植开发指南》见/Linux/2011-06/37904.htm来做个LED驱动,虽然LED的原理简单得不能再简单了,但是要把kernel中针对于s3c24**的GPIO的一些数据结构,还有函数搞清楚也不是那么轻松的事,所以本文主要简单地说明下LED驱动中的相关数据结构以及函数/宏的定义,并对驱动加以验证注意:在/arch/arm/mach-s3c2410/include/mach/gpio-fns.h源代码中有如下说明:16/*Thesefunctionsareintheto-be-removedcategoryanditisstrongly*encouragednottousetheseinnewcode.Theywillbemarkeddeprecated*verysoon.**Mostofthefunctionalitycanbeeitherreplacedbythegpiocfgcalls*forthes3cplatformorbythegenericGPIOlibAPI.**Asof2.6.35-rc,thesewillberemoved,withthefewdriversusingthem*eitherreplacedorgivenawrapperuntilthecallscanberemoved.25*/该头文件包括:staticinlinevoids3c2410_gpio_cfgpin(unsignedintpin,unsignedintcfg)该函数直接使用linux/arch/arm/plat-s3c/gpio-config.c中的勺ints3c_gpio_cfgpin(unsignedintpin,unsignedintconfig)即可首先看一下设备初始化程序:/**设备初始化*/staticint__initdev_init(void){intret;inti;for(i=0;i<4;i++){〃设置LED对应的端口寄存器为输出(OUTPUT)if(s3c_gpio_cfgpin(led_table[i],led_cfg_table[i])<0)printk(KERN_INFO"configpin%dfailed",i);printk(KERN_INFO"configpin%dfailed",i);〃设置LED对应的端口寄存器为低电平输出,在模块加载>结束后,四个LED应该是全部都是发光状态s3c2410_gpio_setpin(led_table[i],0);}ret=misc_register(&misc);//注册设备printk(DEVICE_NAME"/tinitialized/n");//打印初始化信息returnret;}可以看到,这里涉及到两个函数,分别是s3c2410_gpio_cfgpin,s3c2410_gpio_setpin,这两个函数分别对四个LED进行配置,从函数名来看,cfgpin对引脚寄存器状态进行配置,而setpin应该是对寄存器数据值进行配置,我们在分析函数之前先弄清楚传入的参数到底是什么。led_table[i]//LED对应的GPIO端口列表staticunsignedlongled_table[]={30S3C2410_GPB(5),31S3C2410_GPB(6),32S3C2410_GPB(7),33S3C2410_GPB(8),34};这里S3C2410_GPB宏定义在mach/gpio-nrs.h中/*GPIObanksizes*/#defineS3C2410_GPIO_A_NR(32)#defineS3C2410_GPIO_B_NR(32)#defineS3C2410_GPIO_C_NR(32)#defineS3C2410_GPIO_D_NR(32)#defineS3C2410_GPIO_E_NR(32)#defineS3C2410_GPIO_F_NR(32)#defineS3C2410_GPIO_G_NR(32)#defineS3C2410_GPIO_H_NR(32)#defineS3C2410_GPIO_J_NR(32)/*technically16.*/#defineS3C2410_GPIO_K_NR(32)/*technically16.*/#defineS3C2410_GPIO_L_NR(32)/*technically15.*/#defineS3C2410_GPIO_M_NR(32)/*technically2.*/#ifCONFIG_S3C_GPIO_SPACE!=0#errorCONFIG_S3C_GPIO_SPACEcannotbezeroatthemoment#endif#defineS3C2410_GPIO_NEXT(__gpio)/((__gpio##_START)+(__gpio##_NR)+CONFIG_S3C_GPIO_SPACE+0)〃这里的C0NFIG_S3C_GPI0_SPAC是内核配置选项,在.config中可以找到,我的配置为:CONFIG_S3C_GPIO_SPACE=0enums3c_gpio_number{S3C2410_GPIO_A_START=0,S3C2410_GPIO_B_START=S3C2410_GPIO_NEXT(S3C2410_GPIO_A),S3C2410_GPIO_C_START=S3C2410_GPIO_NEXT(S3C2410_GPIO_B),S3C2410_GPIO_D_START=S3C2410_GPIO_NEXT(S3C2410_GPIO_C),S3C2410_GPIO_E_START=S3C2410_GPIO_NEXT(S3C2410_GPIO_D),S3C2410_GPIO_F_START=S3C2410_GPIO_NEXT(S3C2410_GPIO_E),S3C2410_GPIO_G_START=S3C2410_GPIO_NEXT(S3C2410_GPIO_F),S3C2410_GPIO_H_START=S3C2410_GPIO_NEXT(S3C2410_GPIO_G),S3C2410_GPIO_J_START=S3C2410_GPIO_NEXT(S3C2410_GPIO_H),S3C2410_GPIO_K_START=S3C2410_GPIO_NEXT(S3C2410_GPIO_J),S3C2410_GPIO_L_START=S3C2410_GPIO_NEXT(S3C2410_GPIO_K),S3C2410_GPIO_M_START=S3C2410_GPIO_NEXT(S3C2410_GPIO_L),};#defineS3C2410_GPB(_nr)(S3C2410_GPIO_B_START+(_nr))因此,以S3C2410_GPB(5)为例,其宏展开为:S3C2410_GPIO_NEXT(S3C2410_GPIO_A)+5=>(S3C2410_GPIO_A_START+S3C2410_GPIO_A_NR+CONFIG_S3C_GPIO_SPACE+0)+5=>很显然,S3C2410_GPB(5)就是从GPA的首地址+GPA个数+GPB的offset就是当前GPB的IO偏移量,即0+32+5=37,同理S3C2410_GPB(0)相当于32TOC\o"1-5"\h\zS3C2410_GPB(5)相当于37S3C2410_GPB(6)相当于38S3C2410_GPB(7)相当于39S3C2410_GPB(8)相当于40led_cfg_table[i]//LED对应端口将要输出的状态列表staticunsignedintled_cfg_table[]={S3C2410_GPIO_OUTPUT,S3C2410_GPIO_OUTPUT,S3C2410_GPIO_OUTPUT,S3C2410_GPIO_OUTPUT,};S3C2410_GPIO_OUTPUT定义在mach/regs-gpio.h#defineS3C2410_GPIO_LEAVE(0xFFFFFFFF)//最后两位是设置,11表示RESERVE#defineS3C2410_GPIO_INPUT(0xFFFFFFF0)/*notavailableonA*///最后两位是设置,00表示INPUT#defineS3C2410_GPIO_OUTPUT(0xFFFFFFF1)//最后两位是设置,01表示OUTPUT#defineS3C2410_GPIO_IRQ(0xFFFFFFF2)/*notavailableforall*/#defineS3C2410_GPIO_SFN2(0xFFFFFFF2)/*bankA=>addr/cs/nand*/#defineS3C2410_GPIO_SFN3(0xFFFFFFF3)/*notavailableonA*/根据前面的分析,s3c2410传入了当前GPIO的偏移地址,以及OUTPUT状态现在我们深入前面的两个函数:定义在linux/arch/arm/plat-s3c/gpio-config.cints3c_gpio_cfgpin(unsignedintpin,unsignedintconfig){structs3c_gpio_chip*chip=s3c_gpiolib_getchip(pin);//得到对应GPIO结构体首指针,里面包含了该GPIO的各种参数unsignedlongflags;intoffset;intret;if(!chip)return-EINVAL;//没找到的话,返回invalidoffset=pin-chip->chip.base;//否则offset等于该GPIO引脚相对于GPX(O)的偏移量,每个偏移1s3c_gpio」ock(chip,flags);//自旋锁锁住该GPIO,通过chip指针指向lock,看下面的define和图ret=s3c_gpio_do_setcfg(chip,offset,config);//设置该GPIO状态寄存器的数值为configs3c_gpio_unlock(chip,flags);//解锁//自旋锁操作/*lockingwrapperstodealwithmultipleaccesstothesamegpiobank*///#defines3c_gpio_lock(_oc,_fl)spin_lock_irqsave(&(_oc)->lock,_fl)//#defines3c_gpio_unlock(_oc,_fl)spin_unlock_irqrestore(&(_oc)->lock,_fl)//s3c_gpio_do_setcfg操作staticinlineints3c_gpio_do_setcfg(structs3c_gpio_chip*chip,unsignedintoff,unsignedintconfig){return(chip->config->set_config)(chip,off,config);}〃这里的set_config是一个函数指针,由后面的分析知道,如果针对GPA,该函数指针指向s3c_gpio_setcfg_s3c24xx_a,如果针对GPX应该是指向s3c_gpio_setcfg_s3c24xx但发现,如果是其他GPX,根本没有定义set_config!!!(这个问题已经解决,见后文s3c24xx_gpiolib_init函数,事实上,其余的config的确指向s3c_gpio_do_setcfg函数)structs3c_gpio_cfgs3c24xx_gpiocfg_default={.set_config=s3c_gpio_setcfg_s3c24xx,.get_config=s3c_gpio_getcfg_s3c24xx,};ints3c_gpio_setcfg_s3c24xx_a(structs3c_gpio_chip*chip,unsignedintoff,unsignedintcfg){void__iomem*reg=chip->base;//GPXCON的物理基地址unsignedintshift=off;//每个GPA对应一位u32con;if(s3c_gpio_is_cfg_special(cfg)){//OUTPUT状态是否为(OxfffffffX),是,返回1cfg&=0xf;//cfg=0xX/*Mapoutputto0,andSFN2to1*/本实验不会运行到这cfg-=1;if(cfg>1)return-EINVAL;cfg<<=shift;}con=__raw_readl(reg);//先读出该GPXCON的值,32位con&=~(0x1<<shift);//con|=cfg;//__raw_writel(con,reg);//将新值写入GPXCON
PS:#define__raw_writeb(v,a)(__chk_io_ptr(a),*(volatileunsignedchar__force*)(a)=(v))#define__raw_writew(v,a)(__chk_io_ptr(a),*(volatileunsignedshort__force*)(a)=(v))#define__raw_writel(v,a)(__chk_io_ptr(a),*(volatileunsignedint__force*)(a)=(v))#define__raw_readb(a)(__chk_io_ptr(a),*(volatileunsignedchar__force*)(a))#define__raw_readw(a)(__chk_io_ptr(a),*(volatileunsignedshort__force*)(a))#define__raw_readl(a)(__chk_io_ptr(a),*(volatileunsignedint__force*)(a))return0;}如果针对GPX情况ints3c_gpio_setcfg_s3c24xx(structs3c_gpio_chip*chip,unsignedintoff,unsignedintcfg){void__iomem*reg=chip->base;unsignedintshift=off*2;//每个GPX对应2位u32con;if(s3c_gpio_is_cfg_special(cfg)){cfg&=0xf;if(cfg>3)return-EINVAL;cfg<<=shift;}//将cfg的cfg<<=shift;}con=__raw_readl(reg);con&=~(0x3<<shift);con|=cfg;__raw_writel(con,reg);//读对应的GPXCON值//将GPXCON(pin)的两bits请0//设置config值//写入新的GPXCONreturn0;}
returnret;}returnret;}//ends3c_gpio_cfgpin这里涉及到了一个重要的数据结构,s3c_gpio_chip,此数据结构比较复杂,我贴出这个数据结构的结构图:这个重要的数据结构中可以记录每个GPIO所需要的所有数据,后面会遇到的s3c24xx_gpios[]结构体就是该结构体的集合,描述了芯片中所有的GPIO端口,之后我们需要时时回头看看这个结构。我们先来看s3c_gpiolib_getchip,它实现了返回对应pin值的GPIO结构体首指针的功能#include<mach/gpio-core.h>staticinlinestructs3c_gpio_chip*s3c_gpiolib_getchip(unsignedintpin){structs3c_gpio_chip*chip;if(pin>S3C_GPIO_END)〃如果超过GPJ(32)就returnNULLreturnNULL;chip=&s3c24xx_gpios[pin/32];//根据偏移,计算出对应pin的GPIO结构体指针return((pin-chip->chip.base)<chip->chip.ngpio)?chip:NULL;//这里验证,如果pin偏移超过了GPIO的个数,说明出错了,否则就返回该GPIO的结构体指针}回想以下之前s3c2410_gpio_cfgpin中,我们传入的参数是led_table[i]和led_cfg_table[i],/*GPIOsizesforvariousSoCs:*244224102412244024432416*A2322251625B111111119*C1615161616*D1616161616*E1616161616*F88888*G161616168*H111191515*J----1316--*K--------16*L------157*M------22*/structs3c_gpio_chips3c24xx_gpios[]={[0]={.base=S3C2410_GPACON,//datasheet上地址为0x56000000//#defineS3C2410_GPACONS3C2410_GPIOREG(0x00)#defineS3C2410_GPIOREG(x)((x)+S3C24XX_VA_GPIO)#defineS3C24XX_VA_GPIO((S3C24XX_PA_GPIO-S3C24XX_PA_UART)+S3C24XX_VA_UART)S3C24XX_PA_GPIO相当于(0x15600000)S3C24XX_PA_UART相当于(0x15000000)#defineS3C_VA_UARTS3C_ADDR(0x01000000)/*UART*/#defineS3C_ADDR_BASE0xF6000000#ifndef__ASSEMBLY__#defineS3C_ADDR(x)((void__iomem__force*)S3C_ADDR_BASE+(x))#else#defineS3C_ADDR(x)(S3C_ADDR_BASE+(x))#endif0x15600000-15000000+F7000000这里的S3C2410_GPACON应该怎么算?.pm=__gpio_pm(&s3c_gpio_pm_1bit),.config=&s3c24xx_gpiocfg_banka,//设置GPIO的函数指针staticstructs3c_gpio_cfgs3c24xx_gpiocfg_banka={.set_config=s3c_gpio_setcfg_s3c24xx_a,.get_config=s3c_gpio_getcfg_s3c24xx_a,};.chip={.base=S3C2410_GPA(0),//基地址,也是偏移量.owner=THIS_MODULE,.label="GPIOA",.ngpio=24,.direction_input=s3c24xx_gpiolib_banka_input,.direction_output=s3c24xx_gpiolib_banka_output,},},={.base=S3C2410_GPBCON,.pm=__gpio_pm(&s3c_gpio_pm_2bit),.chip={.base=S3C2410_GPB(0),.owner=THIS_MODULE,.label="GPIOB",.ngpio=16,},},={.base=S3C2410_GPCCON,.pm=__gpio_pm(&s3c_gpio_pm_2bit),.chip={.base=S3C2410_GPC(0),.owner=THIS_MODULE,.label="GPIOC",.ngpio=16,},},={.base=S3C2410_GPDCON,.pm=__gpio_pm(&s3c_gpio_pm_2bit),.chip={.base=S3C2410_GPD(0),.owner=THIS_MODULE,.label="GPIOD",.ngpio=16,},},={.base=S3C2410_GPECON,.pm=__gpio_pm(&s3c_gpio_pm_2bit),.chip={.base=S3C2410_GPE(0),.label="GPIOE",.owner=THIS_MODULE,.ngpio=16,},},={.base=S3C2410_GPFCON,.pm=__gpio_pm(&s3c_gpio_pm_2bit),.chip={.base=S3C2410_GPF(0),.owner=THIS_MODULE,.label="GPIOF",.ngpio=8,.to_irq=s3c24xx_gpiolib_bankf_toirq,},},={
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 考古发掘报告撰写员职业技能等级认定模拟试卷及答案
- 2026年注册公用设备工程师化工仪表专业模拟试卷及答案
- 财务会计岗位绩效考核分析表
- 能源行业项目经理低碳发展与能效评估绩效考核表
- 建筑设计师创意与执行水平评估表
- 电影制片人项目推进与资源协同绩效评定表
- 通信工程师现场维护技术人员绩效评估表
- 调整供应商供货时间商洽函(3篇)
- 2026年石家庄理工职业学院高职单招笔试物理历年参考题库含答案解析
- 2026年百色职业学院高职单招笔试职业技能测验历年参考题库含答案解析
- 外研版(2024)八年级上册英语Unit 1-Unit 6全册课文+翻译
- 消防水泵使用教程课件
- 2025湖北日报传媒集团招聘45人笔试参考题库附带答案详解
- GB/T 21499-2024粮油检验稻谷和糙米潜在出米率测定方法
- 航天科工测评题库
- 出疹性疾病的护理
- TCACM 1603-2024 手法通乳中医技术操作规范
- 地方病患者个人信息表
- RB/T 114-2023能源管理体系纯碱、焦化、橡塑制品、制药等化工企业认证要求
- DZ∕T 0033-2020 固体矿产地质勘查报告编写规范(正式版)
- 思念混声合唱简谱
评论
0/150
提交评论