佐须之男的博客

技术需要沉淀,成长需要痛苦,成功需要坚持,敬仰需要奉献

MediaTech(MTK) MT7628 MT7688 Linux 下使用mmap实现用户态 GPIO 驱动

版权声明:

    本文章版权归属 forgotfun.org 佐须之男,未经允许请勿转载。佐须之男,从事网络设备开发10年,可承接定制业务和技术咨询。

前言:

    最近在使用Widora mt7688开发板的时候,发现OpenWRT默认的GPIO驱动非常恼人,只提供了sysfs默认的调用接口。编程时需要和一堆文件打交道,用来做做简单的gpio开发是够了,但是要实现复杂点的逻辑这套就显得力不从心和不优雅了。

    所以就萌生了在用户态实现gpio驱动的想法,其实思路非常简单,无非就是先mmap mt7628/mt7688的寄存器,这样就可以直接在用户态实现对gpio的访问和控制。使用mmap的好处其实挺多的:第一通用可以在OpenWRT和SDK上运行,不需要考虑系统的差异性。第二性能相比sysfs的模式,可以得到明显的提升。使用示波器测试gpio产生方波可以到7.4M。下面是截图


 MediaTech(MTK) MT7628 MT7688 Linux 下使用mmap实现用户态 GPIO 驱动  路由器开发


代码部分:

    我实现了几个基本的操作,一个是gpio_set_pin_direction 用来设置gpio的输入和输出模式,一个是gpio_get_pin用来获取gpio的输入状态,另一个是gpio_set_pin_value用来设置gpio的输出值。代码部分参考了sdk里驱动的实现,和内核态的驱动几乎一致。


/* forgotfun.org 佐须之男 */

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>


#define MMAP_PATH    "/dev/mem"


#define RALINK_GPIO_DIR_IN        0
#define RALINK_GPIO_DIR_OUT        1

#define RALINK_REG_PIOINT        0x690
#define RALINK_REG_PIOEDGE        0x6A0
#define RALINK_REG_PIORENA        0x650
#define RALINK_REG_PIOFENA        0x660
#define RALINK_REG_PIODATA        0x620
#define RALINK_REG_PIODIR        0x600
#define RALINK_REG_PIOSET        0x630
#define RALINK_REG_PIORESET        0x640

#define RALINK_REG_PIO6332INT        0x694
#define RALINK_REG_PIO6332EDGE        0x6A4
#define RALINK_REG_PIO6332RENA        0x654
#define RALINK_REG_PIO6332FENA        0x664
#define RALINK_REG_PIO6332DATA        0x624
#define RALINK_REG_PIO6332DIR        0x604
#define RALINK_REG_PIO6332SET        0x634
#define RALINK_REG_PIO6332RESET        0x644

#define RALINK_REG_PIO9564INT        0x698
#define RALINK_REG_PIO9564EDGE        0x6A8
#define RALINK_REG_PIO9564RENA        0x658
#define RALINK_REG_PIO9564FENA        0x668
#define RALINK_REG_PIO9564DATA        0x628
#define RALINK_REG_PIO9564DIR        0x608
#define RALINK_REG_PIO9564SET        0x638
#define RALINK_REG_PIO9564RESET        0x648


static uint8_t* gpio_mmap_reg = NULL;
static int gpio_mmap_fd = 0;

static int gpio_mmap(void)
{
    if ((gpio_mmap_fd = open(MMAP_PATH, O_RDWR)) < 0) {
        fprintf(stderr, "unable to open mmap file");
        return -1;
    }

    gpio_mmap_reg = (uint8_t*) mmap(NULL, 1024, PROT_READ | PROT_WRITE,
        MAP_FILE | MAP_SHARED, gpio_mmap_fd, 0x10000000);
    if (gpio_mmap_reg == MAP_FAILED) {
        perror("foo");
        fprintf(stderr, "failed to mmap");
        gpio_mmap_reg = NULL;
        close(gpio_mmap_fd);
        return -1;
    }

    return 0;
}

int mt76x8_gpio_get_pin(int pin)
{
    uint32_t tmp = 0;

    /* MT7621, MT7628 */
    if (pin <= 31) {
        tmp = *(volatile uint32_t *)(gpio_mmap_reg + RALINK_REG_PIODATA);
        tmp = (tmp >> pin) & 1u;
    } else if (pin <= 63) {
        tmp = *(volatile uint32_t *)(gpio_mmap_reg + RALINK_REG_PIO6332DATA);
        tmp = (tmp >> (pin-32)) & 1u;
    } else if (pin <= 95) {
        tmp = *(volatile uint32_t *)(gpio_mmap_reg + RALINK_REG_PIO9564DATA);
        tmp = (tmp >> (pin-64)) & 1u;
        tmp = (tmp >> (pin-24)) & 1u;
    }
    return tmp;

}

void mt76x8_gpio_set_pin_direction(int pin, int is_output)
{
    uint32_t tmp;

    /* MT7621, MT7628 */
    if (pin <= 31) {
        tmp = *(volatile uint32_t *)(gpio_mmap_reg + RALINK_REG_PIODIR);
        if (is_output)
            tmp |=  (1u << pin);
        else
            tmp &= ~(1u << pin);
        *(volatile uint32_t *)(gpio_mmap_reg + RALINK_REG_PIODIR) = tmp;
    } else if (pin <= 63) {
        tmp = *(volatile uint32_t *)(gpio_mmap_reg + RALINK_REG_PIO6332DIR);
        if (is_output)
            tmp |=  (1u << (pin-32));
        else
            tmp &= ~(1u << (pin-32));
        *(volatile uint32_t *)(gpio_mmap_reg + RALINK_REG_PIO6332DIR) = tmp;
    } else if (pin <= 95) {
        tmp = *(volatile uint32_t *)(gpio_mmap_reg + RALINK_REG_PIO9564DIR);
        if (is_output)
            tmp |=  (1u << (pin-64));
        else
            tmp &= ~(1u << (pin-64));
        *(volatile uint32_t *)(gpio_mmap_reg + RALINK_REG_PIO9564DIR) = tmp;
    }
}

void mt76x8_gpio_set_pin_value(int pin, int value)
{
    uint32_t tmp;

    /* MT7621, MT7628 */
    if (pin <= 31) {
        tmp = (1u << pin);
        if (value)
            *(volatile uint32_t *)(gpio_mmap_reg + RALINK_REG_PIOSET) = tmp;
        else
            *(volatile uint32_t *)(gpio_mmap_reg + RALINK_REG_PIORESET) = tmp;
    } else if (pin <= 63) {
        tmp = (1u << (pin-32));
        if (value)
            *(volatile uint32_t *)(gpio_mmap_reg + RALINK_REG_PIO6332SET) = tmp;
        else
            *(volatile uint32_t *)(gpio_mmap_reg + RALINK_REG_PIO6332RESET) = tmp;
    } else if (pin <= 95) {
        tmp = (1u << (pin-64));
        if (value)
            *(volatile uint32_t *)(gpio_mmap_reg + RALINK_REG_PIO9564SET) = tmp;
        else
            *(volatile uint32_t *)(gpio_mmap_reg + RALINK_REG_PIO9564RESET) = tmp;
    }
}

int main(int argc, char **argv)
{
    int ret = -1;

    if (gpio_mmap())
        return -1;

    printf("get pin 39 input %d\n", mt76x8_gpio_get_pin(39));
    printf("get pin 40 input %d\n", mt76x8_gpio_get_pin(40));
    printf("get pin 41 input %d\n", mt76x8_gpio_get_pin(41));
    printf("get pin 42 input %d\n", mt76x8_gpio_get_pin(42));

    
    printf("set pin 39 output 1\n");
    mt76x8_gpio_set_pin_direction(39, 1);
    mt76x8_gpio_set_pin_value(39, 1);
    printf("set pin 40 output 0\n");
    mt76x8_gpio_set_pin_direction(40, 1);
    mt76x8_gpio_set_pin_value(40, 0);
    printf("set pin 41 output 1\n");
    mt76x8_gpio_set_pin_direction(41, 1);
    mt76x8_gpio_set_pin_value(41, 1);
    printf("set pin 42 output 0\n");
    mt76x8_gpio_set_pin_direction(42, 1);
    mt76x8_gpio_set_pin_value(42, 0);

    while (1)
    {
        mt76x8_gpio_set_pin_value(42, 0);
        mt76x8_gpio_set_pin_value(42, 1);
    }
    close(gpio_mmap_fd);

    return ret;
}


    更多代码可以到 https://github.com/ForgotFun/mt76x8 下载,如有疑问可邮件联系。


« 上一篇 下一篇 »

© 2016 佐须之男版权所有 | 业务合作 181-1435-4589 (陆工)