15 内核里控制IO口

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ForFuture_/article/details/79394513

内核里控制IO口


在linux内核里mmu已经启用,不能直接访问物理地址,必须要把物理地址映射到一个虚拟地址上,然后通过该虚拟地址来访问原物理地址。


相关函数:

void *ioremap(cookie, size) //用于把指定的物理地址映射到一个虚拟地址上
                            //cookie用于指定要映射的物理地址,size表示映射的大小范围
                            //返回值为映射得到的虚拟地址

iounmap(void *addr) //用于取消虚拟地址的映射关系

ioread8(地址)/readb()    //读地址上的8位值,readb是比较老的函数
ioread16(地址)/readw()   //读地址上的16位值
ioread32(地址)/readl()   //读32位值

iowrite8(值, 地址)/writeb   //把8位的值写到指定的地址上,writeb是比较老的函数
iowrite16(值, 地址)/writew  //把16位的值写到指定的地址上
iowrite32(值, 地址)/writel  //把32位的值写到指定的地址上

事例代码(控制板子上的LED灯亮灭)(xxx.c):

#include <linux/init.h>
#include <linux/module.h>
#include <asm/io.h>

#define BASE_DDR  0x01c20800 //基地址
#define PA_CFG1_OFFSET  0x04 //PA组IO口的功能配置寄存器1对基地址偏移为4字节
#define PA_DATA_OFFSET  0x10 //PA组IO口的数据寄存器对基地址偏移为0x10字节

u8 *vaddr;//用于记录映射得到的虚拟地址

static int __init myled_init(void)
{
    u32 val;

    vaddr = ioremap(BASEDDR, SZ_4K); //映射寄存器的基地址到一个虚拟地址上

    val = ioread32(vaddr+PA_CFG1_OFFSET) & (~(7<<28));//vaddr加上相应寄存器地址偏移就是对应着寄存器原物理地址
    iowrite32(val|(1<<28),vaddr+PA_CFG1_OFFSET);//PA15设为输出功能

    val = ioread32(vaddr+PA_DATA_OFFSET);
    iowrite32(val|(1<<15), vaddr+PA_DATA_OFFSET);// PA15输出高电平,LED亮

    printk("myled init success\n");

    return 0;
}

static void __exit myled_exit(void)
{
    u32 val;

    val = ioread32(vaddr+PA_DATA_OFFSET);
    iowrite32(val & (~(1<<15)), vaddr+PA_DATA_OFFSET); //PA15输出低电平,LED灭

    iounmap(vaddr);//取消虚拟地址的映射关系

    printk("myled exited\n");
}

module_init(myled_init);
module_exit(myled_exit);

MODULE_LICENSE("GPL");

linux内核里有标准的GPIO操作方法,其中有对芯片厂商的要求,芯片厂商需要在内核里实现相关的GPIO控制器的驱动配置,让内核里的gpiolib(drivers/gpio/目录下)可以统一管理整个芯片的gpio口,让我们驱动人员可以用内核提供的gpio标准操作函数,通过gpiolib来调用控制芯片的io口。


gpio提供io口的调用函数包括:

#include <linux/gpio.h> //里面声明io口的操作函数

int gpio_request(unsigned gpio, const char *label);//每个io只能被请求一次,可防止多个驱动来控制同一个IO口

void gpio_free(unsigned gpio);//释放已请求的io口

int gpio_direction_input(unsigned gpio);//把指定的IO口作输入功能,gpio用于指定具体哪个io口

int gpio_direction_output(unsigned gpio, int value);//作输出功能,并根据value的值输出高低电平

int gpio_get_value(unsigned gpio);//获取指定IO口的电平

void gpio_set_value(unsigned gpio, int value);//设置IO口的电平为value(0/1)

int gpio_to_irq(unsigned gpio);//根据io口,获取到它对应的中断号(io口大都有外部中断功能)

一般情况下,io口的定义是在内核源码的arch/arm/mach-xxxx/include/mach/gpio.h
Orange Pi(H3)io口定义是在内核源码的arch/arm/mach-sunxi/include/mach/gpio.h

包括以下的宏(n表示这组里的第几个IO口):

#define GPIOA(n)    (SUNXI_PA_BASE + (n))
#define GPIOB(n)    (SUNXI_PB_BASE + (n))    
#define GPIOC(n)    (SUNXI_PC_BASE + (n))
#define GPIOD(n)    (SUNXI_PD_BASE + (n))
#define GPIOE(n)    (SUNXI_PE_BASE + (n))
#define GPIOF(n)    (SUNXI_PF_BASE + (n))
#define GPIOG(n)    (SUNXI_PG_BASE + (n))
#define GPIOH(n)    (SUNXI_PH_BASE + (n))
#define GPIOI(n)    (SUNXI_PI_BASE + (n))
#define GPIOJ(n)    (SUNXI_PJ_BASE + (n))
#define GPIOK(n)    (SUNXI_PK_BASE + (n))
#define GPIOL(n)    (SUNXI_PL_BASE + (n))
#define GPIOM(n)    (SUNXI_PM_BASE + (n))
#define GPION(n)    (SUNXI_PN_BASE + (n))
#define GPIOO(n)    (SUNXI_PO_BASE + (n))
#define GPIO_AXP(n) (AXP_PIN_BASE  + (n))

使用gpio实现在驱动模块初始化时led亮灯,卸载时灭灯(xxx.c):

#include <linux/init.h>
#include <linux/module.h>
#include <mach/gpio.h> //芯片io口的宏定义
#include <linux/gpio.h> //io口的调用函数

#define LED_GPIO  GPIOA(15)     //PA15

static int __init test_init(void)
{
    int ret;

    ret = gpio_request(LED_GPIO, "myled");//每个io只能被请求一次,可防止多个驱动来控制同一个IO口;如请求失败,则表示此io口已被其它驱动使用
    if (ret < 0)
        return ret;

    gpio_direction_output(LED_GPIO, 1);//亮灯

    return 0;
}

static void __exit test_exit(void)
{
    gpio_set_value(LED_GPIO, 0);//灭灯

    gpio_free(LED_GPIO);//最后记得释放请求的io,不然之后再申请时会被占用
}

module_init(test_init);
module_exit(test_exit);

MODULE_LICENSE("GPL");

Makefile文件:

obj-m += xxx.o

KSRC := /目录路径/orangepi_sdk/source/linux-3.4.112/
export ARCH := arm
export CROSS_COMPILE := arm-linux-gnueabihf-

all : 
    make -C $(KSRC) modules M=`pwd`

.PHONY : clean
clean : 
    make -C $(KSRC) modules clean M=`pwd`

猜你喜欢

转载自blog.csdn.net/ForFuture_/article/details/79394513
15
今日推荐