gpio 开发文档
简述
对于gpio的操作,一定要如下几部分满足条件才能正常的操作gpio。
-
引脚功能选择,例如 引脚TSEC1_RX_CLK/DMA_DACK_B0/GPIO14上不只有gpio的功能,需要将其选在为gpio后才能当gpio一样使用。
-
gpio模式 例如 开漏 推挽等等,不同的应用需要配成不同的模式。
-
gpio的方向,是input还是output,从cpu往外发数据去配置器件叫output,器件的数据返回给cpu叫input。
-
往gpio里写高低电平。
centec gpio功能选择
首先是查手册,在手册P1010RM.pdf的1723页,有如下的做功能选择的寄存器。
E_0060寄存器的4 5位为1 0,gpio14被选为gpio模式;6 7位被填写1 0引脚被选为GPIO15。
需要通过如下驱动做功能选择:
\cnos\platform\linux\arch\powerpc\platforms\85xx\p1010_ctc_gb.c
p1010_ctc_setup_arch
//fpga片选引脚功能选择
alter_fun_addr = ioremap(0xffee0060, 0x1000);
if(alter_fun_addr == NULL) {
printk(KERN_EMERG "alter_fun_addr can not map.\r\n");
}
guts_pmuxcr1 = in_be32(alter_fun_addr);
//gpio14 gpio15 功能选择为gpio模式,参考文档P1010RM.pdf 1723页。
out_be32(alter_fun_addr, guts_pmuxcr1|0x0A000000);
guts_pmuxcr1 = in_be32(alter_fun_addr);
iounmap(alter_fun_addr);
地址0xffee0060是怎么找到的?
代码中看到 gpio_logic_addr = ioremap(0xffe0f000, 0x1000) ; 在和手册上的Memory Map的内存映射图进行比较,得出应该是这个地址。
相关系统函数的分析
ioremap 是将物理地址映射为虚拟地址,物理地址是不能直接访问的。
in_be32(alter_fun_addr)相当于将虚拟地址alter_fun_addr里的内容读出来。
out_be32(alter_fun_addr, guts_pmuxcr1|0x0A000000); 将第二个参数的内容,写到第二个参数的地址中。
上边代码流程
相当于将E0060寄存里的内容先读出来,按手册修改相应bit位后,在写回寄存器中,起到功能选择的作用。
gpio模式配置为开漏方向配置为输出模式
\cnos\system\drvs\drvio\ctc_gpio\ctc_gpio.c
ctc_gpio_init
加入如下代码
/*fpga cs gpio config*/
#define FPGA1_EN 14
#define FPGA0_EN 15
printk("config fpga chip select gpio mode.dir,%x,od:%x\r\n",gpio_virtual_addr,gpio_virtual_addr + 4);
/*dir is output*/
setbits32(gpio_virtual_addr,(0x1 << (31-FPGA0_EN)));
setbits32(gpio_virtual_addr,(0x1 << (31-FPGA1_EN)));
/*set them as open drain mode*/
setbits32(gpio_virtual_addr + 4,(0x1 << (31-FPGA0_EN)));
setbits32(gpio_virtual_addr + 4,(0x1 << (31-FPGA1_EN)));
代码原理讲解:
#define setbits32(_addr, _v) out_be32((_addr), in_be32(_addr) | (_v))
所调用的函数setbits32 相当于将寄存器里的内容读出来,改变相应的bit后再写回去。
gpio_virtual_addr 寄存器的基地址,第一个寄存器为GPIO_GPDIR,方向寄存器,寄存器里的bit位,每一位代表一个gpio的方向,写1位输出,写0位输入。
基地址+4 为GPIO_GPODR 寄存器,开漏寄存器,是否配成开漏输出模式。
具体参考P1010RM.pdf 第24章。
gpio的数据的读写
对gpio数据读写要操作寄存器GPIO_GPDAT,gpio基地址偏移8,具体操作参考文档P1010RM.pdf 第24章。
gpio操作上层应用程序的调用
gpio_fd = open("/dev/ctc_gpio", O_RDWR); //open
ioctl(gpio_fd, CTC_GPIO_GPIO_INIT, 0); //初始化
ioctl(gpio_fd, CTC_GPIO_WRITE, (long) &gpio_value); //读写