linux内核中GPIO的使用(二)--标准接口函数

在linux内核中,有一些基本模块可以使用标准的接口函数来操作,比如GPIO、interrupt、clock,所谓的标准接口函数是指一些与硬件平台无关的、linux下做驱动通用的函数,
常用的有:
gpio_request();gpio_free();gpio_direction_output();gpio_direction_input();gpio_set_value();gpio_get_value()等;

函数分析:

1)GPIO申请:

        int gpio_request(unsigned gpio, const char *label)
参数分析:
    unsigned gpio:gpio端口号;
    const char *label:给该gpio端口起的名字;
返回值:
    成功返回0;失败返回负数的错误码;

不同平台的gpio端口号是不同的,比如在s5pv210平台上,在内核源码的arch/arm/mach-s5pv210/include/mach下有一个gpio.h的头文件,其中有:

/* S5PV210 GPIO number definitions */
#define S5PV210_GPA0(_nr)       (S5PV210_GPIO_A0_START + (_nr))
#define S5PV210_GPA1(_nr)       (S5PV210_GPIO_A1_START + (_nr))
#define S5PV210_GPB(_nr)        (S5PV210_GPIO_B_START + (_nr))
#define S5PV210_GPC0(_nr)       (S5PV210_GPIO_C0_START + (_nr))
#define S5PV210_GPC1(_nr)       (S5PV210_GPIO_C1_START + (_nr))
#define S5PV210_GPD0(_nr)       (S5PV210_GPIO_D0_START + (_nr))
#define S5PV210_GPD1(_nr)       (S5PV210_GPIO_D1_START + (_nr))
…..

例如端口GPJD0_1就对应宏定义的S5PV210_GPD0(1)。

2)GPIO的初始化

        初始化为输出,并设置输出电平:
        int gpio_direction_output(unsigned gpio, int value);
        初始化为输入:
        int gpio_direction_input(unsigned gpio);

3)GPIO的输出电平设置:

        void gpio_set_value(unsigned gpio, int value);

4)得到GPIO的电平

        int gpio_get_value(unsigned gpio);

5)释放GPIO

        void gpio_free(unsigned gpio);

下面做一个简单的led驱动,实现对基于S5PV210平台的4盏LED灯控制,对应的GPIO口为GPJ2_0、GPJ2_0、GPJ2_0、GPJ2_0。

static int __init leddev_init(void)
{   
    int ret;
/*************led gpio request and initial**************/
    int i;
    for( i = 0; i < 4; i++)
    {
        ret = gpio_request(S5PV210_GPJ2(i), "led_gpio");
        if(ret < 0)
        {
            printk("S5PV210_GPJ2(%d)_request error!\n", i);
            goto err_gpio_request;
        }
        gpio_direction_output(S5PV210_GPJ2(i), 1);
    }
    printk("led initial success!\n");   

    if(cdev_Major)  //初始值不为0,则手动分配设备号
    {
        cdev_num = MKDEV(cdev_Major, cdev_Minor);  
        ret= register_chrdev_region(cdev_num, 1, cdev_name);
    }
    else
    {
        ret = alloc_chrdev_region(&cdev_num, cdev_Minor, 1, cdev_name);  //动态分配设备号
        cdev_Major = MAJOR(cdev_num);
    }
    if(ret < 0)
    {
        printk(KERN_WARNING"can not get major %d\n", cdev_Major);
        goto err_leddev_region;
    }
    cdev_init(&leddev, &leddev_fops);//建立字符设备与文件操作集的联系
    gpiodev.owner = THIS_MODULE;        
    ret = cdev_add(&leddev, cdev_num, 1);
    if(ret)
    {
        printk("error while register device!\n");
        goto err_gpiodev_add;
    }

/******************auto create device file****************/
    class_ret = class_create(THIS_MODULE, "ledclass");
    if(class_ret == NULL)
    {
        printk("class_create error!\n");
        goto err_class_creat;
    }

    device_ret = device_create(class_ret, NULL, cdev_num, NULL, "leddev");
    if(device_ret == NULL)
    {
        printk("device_create error!\n");
        goto err_device_create;
    }

    return 0;

err_device_create:
    class_destroy(class_ret);
err_class_creat:        
err_leddev_add:
    unregister_chrdev_region(MKDEV(cdev_Major, cdev_Minor), 1);
err_leddev_region:
err_gpio_request:
for( ; i > 0; i--)                              
    {
        gpio_free(S5PV210_GPJ2(i - 1));
    }
    return ret;
}

static void __exit leddev_exit(void)
{
    int  i;
    printk("exit from leddev!\n");
    for(i = 0 ; i < 4; i++)                              
    {
        gpio_free(S5PV210_GPJ2(i));
    }
    class_destroy(class_ret);
    device_destroy(class_ret, cdev_num);
    unregister_chrdev_region(MKDEV(cdev_Major, cdev_Minor), 1);
    cdev_del(&leddev);
}

module_init(leddev_init);
module_exit(leddev_exit);

MODULE_AUTHOR("Mr.Huang");
MODULE_DESCRIPTION("This is a leddev for testing!");
MODULE_LICENSE("GPL");

你可能感兴趣的:(linux)