基于NanoPi2的Linux3.4内核GPIO驱动

硬件环境

开发板:nanopi2 (cpu:A9 s5p4418 )

软件环境

内核版本: linux3.4.39
交叉编译器:arm-linux-gcc version 4.9.3 (ctng-1.21.0-229g-FA) 64位系统版本

Linux3.4内核GPIO驱动说明

Kernel 2.6.32版本以上提供了gpio口管理的库文件/kernel/drivers/gpio/gpiolib.c。

相关的接口:
1.int gpio_request(unsigned gpio, const char *label)
申请一个pin脚作为gpio口,命名为 * label,如果经过判断空闲的 申请成功了做一些初始的bit位设置。
2.void gpio_free(unsigned gpio)
释放这个gpio口
3.int gpio_direction_input(unsigned gpio)
设置gpio口为输入模式
4.int gpio_direction_output(unsigned gpio, int value)
设置gpio口为输出模式 value为初始值 0为高电平/1为低电平
5.void __gpio_set_value(unsigned gpio, int value)
设置gpio口的值
6.int __gpio_get_value(unsigned gpio)
获取gpio口的值

底层芯片具体实现

在drivers/gpio下实现了通用的基于gpiolib的GPIO驱动,其中定义了一个通用的用于描述底层GPIO控制器的gpio_chip结构体,并要求具体的SoC实现gpio_chip结构体的成员函数,最后透过gpiochip_add()注册gpio_chip。

驱动程序源码

#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/hrtimer.h>
#include <linux/ktime.h>
#include <linux/device.h>
#include <linux/kdev_t.h>
#include <linux/interrupt.h> 
#include <linux/sched.h>
#include <linux/miscdevice.h>
#include <mach/platform.h>
#include <mach/devices.h>

#define DEVICE_NAME "4418_relay"

//nanopi2 4418
unsigned int J1_GPIO = PAD_GPIO_C + 11;//模块GPIO脚
unsigned int J2_GPIO = PAD_GPIO_C + 12;//模块GPIO脚


#define J1_OFF 0x00
#define J1_ON 0x01
#define J2_OFF 0x10
#define J2_ON 0x11


char drv_buf[2];

static int update_relay(void)
{

    switch(drv_buf[0]) {
    case J1_ON:
        gpio_set_value(J1_GPIO, 0);  //输出低电平
        return 0;
    case J1_OFF:
        gpio_set_value(J1_GPIO, 1);  //输出高电平
        return 0;
    case J2_ON:
        gpio_set_value(J2_GPIO, 0);  //输出低电平
        return 0;
    case J2_OFF:
        gpio_set_value(J2_GPIO, 1);  //输出高电平
        return 0;
    default:
        return -EINVAL;
    }
}


static int relay_write(struct file *file, const char * buffer, size_t count, loff_t * ppos)
{
    unsigned long err;          
    err = copy_from_user(drv_buf, buffer, 1);
    update_relay();
    return 1;
}

static struct file_operations dev_fops={
    write:relay_write,
};

static struct miscdevice misc = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = DEVICE_NAME,
    .fops = &dev_fops,
};


static int __init my_relay_init(void)
{
    int ret;

    gpio_direction_output(J1_GPIO, 1);//设置输出
    gpio_direction_output(J2_GPIO, 1);//设置输出


    ret = misc_register(&misc);
    printk (DEVICE_NAME"\t#NanoPi2 J1 J2 initialized\n"); 
    return ret; 
}

static void __exit my_relay_exit(void)
{
    misc_deregister(&misc);
}

module_init(my_relay_init);
module_exit(my_relay_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("TONY");
MODULE_DESCRIPTION("91arm.com Relay Driver");

修改内核配置菜单,增加当前驱动配置。

内核配置参考文档

内核模块编译

make CROSS_COMPILE=arm-linux- modules

内核模块不能加载问题

insmod 加载出现如下问题

root@nanopi2:/home/fa# insmod 4418_relay.ko 
insmod: ERROR: could not insert module 4418_relay.ko: Invalid module format

查看错误信息,version magic驱动程序同开发板内核不匹配。

root@nanopi2:/home/fa# dmesg |tail

[ 2589.164000] 4418_relay: version magic '3.4.39-s5p4418 SMP preempt mod_unload ARMv7 p2v8 ' should be '3.4.39-FriendlyARM SMP preempt mod_unload ARMv7 p2v8 '

修改内核版本信息,-s5p4418改成内核的FriendlyARM

测试程序源码

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <errno.h> 

#define DEV_FILE "/dev/4418_relay"

#define J1_OFF 0x00
#define J1_ON 0x01
#define J2_OFF 0x10
#define J2_ON 0x11

int main()
{
    int fd_dev=-1;
    char dat[2];
    int cmd;
    printf("nanoPi driver Test\n");

    fd_dev = open(DEV_FILE,O_RDWR);
    if(fd_dev<0){
        printf("open device err\n");
        return 0;
    }

    while(1){
        printf("1:J1 OFF 2:J1 ON 3:J2 OFF 4:J2 ON\n");
        printf("Please input:"); 
        scanf("%d",&cmd);
        switch(cmd){
            case 1:     
                dat[0] = J1_OFF;
                break;
            case 2:
                dat[0] = J1_ON;
                break;
            case 3:
                dat[0] = J2_OFF;
                break;
            case 4:
                dat[0] = J2_ON;
                break;
            default:
                break;
        }
        write(fd_dev,dat,1);
    }

    return 0;
}

你可能感兴趣的:(内核,驱动,GPIO,linux3-4)