linux内核中GPIO的使用(一)--IO内存

2019-07-13 01:28发布

一、相关概念
使用IO内存将物理地址映射为虚拟地址,再通过对虚拟地址的操作来控制硬件。所谓的IO内存是指一种编址方式,不同cpu平台使用的编址方式不同,一种是“IO内存”方式,也叫统一编址方式,是指内存和外设的地址是在同一个地址空间上的,如:ARM、powerpc 、MIPS等平台;另一种是“IO端口”方式,也叫独立编址方式,是指内存的地址空间和外设的地址空间是分开的,如x86平台。在嵌入式系统中,可以通过查看两个文件中的内容来确认是哪一种编址方式:/proc/iomem/proc/ioports,哪一个文件有内容就表示该平台使用哪一种编址方式。 二、程序设计思路
驱动安装—>申请IO内存资源—>物理地址的映射—>得到虚拟地址—>访问虚拟地址—>控制外设硬件
驱动卸载—>解除地址映射—>释放IO内存资源
用到的函数有:
request_mem_region()、ioremap()、release_mem_region()、iounmap() 三、程序设计与分析
1)申请IO内存资源 struct resource * request_mem_region( resource_size_t start, resource_size_t n, const char *name) 参数分析: resource_size_t start:IO内存的开始地址,该地址是物理地址; resource_size_t n:要申请的IO内存资源的大小,单位为字节; const char *name:给所申请的IP内存资源取一个名字; 返回值: 申请成功,返回一个struct resource类型的指针; 申请失败,返回NULL 2)释放IO内存资源 void release_mem_region(resource_size_t start, resource_size_t n) 参数分析: resource_size_t start:IO内存的开始地址,该地址是物理地址; resource_size_t n:要申请的IO内存资源的大小,单位为字节; 3)IO内存映射(物理地址—>虚拟地址) void __iomem *ioremap(phys_addr_t offset, unsigned long size) 参数分析: phys_addr_t offset:准备映射的物理地址空间的开始地址 unsigned long size:要映射的物理地址空间的大小,单位为字节 返回值: 映射成功,返回一个虚拟地址 映射失败,返回NULL 4)IO内存映射的解除 void iounmap(volatile void __iomem *addr); 参数分析: volatile void __iomem *addr:前面映射得到的虚拟地址 四、简单的实例
简单的LED驱动,实现对基于S5PV210平台的LED灯控制,所用寄存器:GPJ2CON(0xe0200280)、GPJ2DAT(0xe0200284),主要代码如下: static int * GPJ2CON_VA; /*定义全局变量*/ static int * GPJ2DAT_VA; static struct resource * gpio_led_source; ..... 在驱动的初始化函数static int __init leddev_init(void)中添加相关代码: gpio_led_source = request_mem_region(0xe0200280, 8, “GPIO_LED”); if(gpio_led_source == NULL) { printk("led_request_mem_region error! "); goto err_led_request_mem_region; /*出错处理*/ } GPJ2CON_VA = ioremap(0xe0200280, 8); if(GPJ2CON_VA == NULL) { printk("led ioremap error! "); goto err_led_ioremap; /*出错处理*/ } GPJ2DAT_VA = GPJ2CON_VA + 1; /* GPJ2CON和GPJ2DAT的地址刚好相邻*/ *GPJ2CON_VA &= ~0xffff; /*initial led GPIO*/ *GPJ2CON_VA |= 0x1111; *GPJ2DAT_VA |= 0xf; printk("GPIO initial success! "); 在驱动的退出函数static int __exit leddev_exit(void)中: iounmap(GPJ2CON_VA); /*解除IO映射*/ release_mem_region(0xe0200280, 8); /*释放IO内存资源*/ unregister_chrdev_region(MKDEV(leddev_Major, leddev_Minor), 1); /*注销设备号*/ cdev_del(&ledodev); /*从内核中删除设备 */