1. 程式人生 > >nanopi s2 驅動開發心得(二) s5p4418的GPIO函式

nanopi s2 驅動開發心得(二) s5p4418的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");

核心模組不能載入問題

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;
}
自己的心得:#include<>尖括號中的標頭檔案去哪裡找,是makefile中定下來的,是linux原始碼中的,如上面的#include <mach/platform.h>,在我的nanopi 2s的配置情況下,對應linux原始檔目錄下arch\arm\plat-s5p4418\include\mach\platform.h,而這個檔案包含了arch\arm\plat-s5p4418\commom\cfg_type.h,而這個標頭檔案中對PAD_GPIO_A等進行了定義