欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Openwrt MT7628/MT7620/MT7621——GPIO及LED/KEY的功能实现

程序员文章站 2024-02-22 10:04:41
...

GPIO及LED/KEY的功能实现

流程介绍

GPIO功能注册和控制

MT7628支持引脚功能的复用,通过配置GPIO1_MODE和GPIO2_MODE寄存器可指定引脚的功能,通常在dts文件中对引脚功能进行注册。

Openwrt MT7628/MT7620/MT7621——GPIO及LED/KEY的功能实现

Openwrt MT7628/MT7620/MT7621——GPIO及LED/KEY的功能实现

MT7628引脚的GPIO注册位于/target/linux/ramips/dts/mt7628an.dtsi文件中,GPIO总共被分为3组,gpio0(GPIO#0——GPIO#31)、gpio1(GPIO#32——GPIO#63)和gpio2(GPIO#64——GPIO#95), @指明了gpio寄存器的起始地址为0x600,节点中compatible属性值指定了设备使用驱动为 mtk,mt7621-gpio。

    aaa@qq.com {
        #address-cells = <1>;
        #size-cells = <0>;

        compatible = "mtk,mt7628-gpio", "mtk,mt7621-gpio";
        reg = <0x600 0x100>;

        interrupt-parent = <&intc>;
        interrupts = <6>;

        gpio0: aaa@qq.com {
            reg = <0>;
            compatible = "mtk,mt7621-gpio-bank";
            gpio-controller;
            #gpio-cells = <2>;
        };

        gpio1: aaa@qq.com {
            reg = <1>;
            compatible = "mtk,mt7621-gpio-bank";
            gpio-controller;
            #gpio-cells = <2>;
        };

        gpio2: aaa@qq.com {
            reg = <2>;
            compatible = "mtk,mt7621-gpio-bank";
            gpio-controller;
            #gpio-cells = <2>;
        };
    };

使用GPIO引脚除了注册GPIO外,还需要释放GPIO引脚复用功能,将功能名称添加至 ralink group 属性中:

&pinctrl {
    state_default: pinctrl0 {
        gpio {
            ralink,group = "i2c", "gpio", "jtag", "i2s", "spi cs1", "uart2", "pwm0", "pwm1", "sdmode", "spis";
            ralink,function = "gpio";
        };
    };

与dts文件对应的引脚复用定义在source-17.01.4/build_dir/target-mipsel_24kc_musl-1.1.16/linux-ramips_mt7628/linux-4.4.92/arch/mips/ralink/mt7620.c中。

如以下代码中i2c复用的gpio引脚定义为gpio#1和gpio#2(从gpio#1开始占用2个gpio), spi refclk复用的gpio引脚定义为gpio#37、gpio#38、gpio#39。同理,其他复用引脚的定义一样。

static struct rt2880_pmx_func i2c_grp[] =  { FUNC("i2c", 0, 1, 2) };
static struct rt2880_pmx_func spi_grp[] = { FUNC("spi", 0, 3, 4) };
static struct rt2880_pmx_func uartlite_grp[] = { FUNC("uartlite", 0, 15, 2) };
static struct rt2880_pmx_func rgmii1_grp[] = { FUNC("rgmii1", 0, 24, 12) };
static struct rt2880_pmx_func refclk_grp[] = { FUNC("spi refclk", 0, 37, 3) };

如以下代码中与WRTNODE2P.dts中ralink group属性的GPIO复用功能相对应。

static struct rt2880_pmx_group mt7628an_pinmux_data[] = {
……
    GRP_G("i2c", i2c_grp_mt7628, MT7628_GPIO_MODE_MASK,
                1, MT7628_GPIO_MODE_I2C),
    GRP("refclk", refclk_grp_mt7628, 1, MT7628_GPIO_MODE_REFCLK),
    GRP("perst", perst_grp_mt7628, 1, MT7628_GPIO_MODE_PERST),
    GRP("wdt", wdt_grp_mt7628, 1, MT7628_GPIO_MODE_WDT),
    GRP("spi", spi_grp_mt7628, 1, MT7628_GPIO_MODE_SPI),
    GRP_G("sdmode", sd_mode_grp_mt7628, MT7628_GPIO_MODE_MASK,
                1, MT7628_GPIO_MODE_SDMODE),
    GRP_G("uart0", uart0_grp_mt7628, MT7628_GPIO_MODE_MASK,
                1, MT7628_GPIO_MODE_UART0),
……
    { 0 }
};

用户可以通过sysfs接口方式访问GPIO(目录位于/sys/class/gpio),gpio目录中包括 export文件、 unexport文件、gpiochipx目录、gpiox目录。

/sys/class/export文件用于通过GPIO引脚编号导出控制的gpio文件,/sys/class/unexport文件用于通过GPIO引脚编号去除控制的gpio文件。export导出成功后会在目录中生成/sys/class/gpio/gpiox目录,如果未出现相应的目录,说明该引脚不可导出。

/sys/class/gpiochipx/目录用于管理和控制一组GPIO的控制器, 目录保存该组GPIO寄存器信息,如寄存器控制引脚的起始编号base、寄存器名称label、引脚总数ngpio。

/sys/class/gpiox/目录用于具体的GPIO引脚控制,目录下有 direction、 value、edge等属性文件。其中direction文件定义为GPIO引脚方向(out为输出、in为输入)。value文件定义为GPIO引脚的电平(0为低电平,1为高电平), 当GPIO引脚方向配置为输出时,value文件值可写(任何非零的值都将输出高电平),当GPIO引脚方向配置为输入时,value文件值可读(cat value)。edge定义为中断的触发方式。

GPIO-LED功能注册和控制

在将GPIO注册为LED设备之前需要在配置界面(make menuconfig命令进入配置界面)选择添加Led驱动(默认编译时已经选上)
Led驱动: > Kernel modules > LED modules > <*> kmod-leds-gpio

 

WRTNODE2P.dts文件中将GPIO注册为LED设备,compatible属性值与LED驱动文件leds-gpio.c中的compatible属性值相对应。label值最终对应为文件系统/sys/class/leds/目录下LED设备的名称。

    gpio-leds {
        compatible = "gpio-leds";

        indicator {
            label = "wrtnode:blue:indicator";
            gpios = <&gpio1 9 1>;
        };
        gpio35 {
            label = "wrtnode:red:sys_status";
            gpios = <&gpio1 12 1>;
        };
        gpio3 {
            label = "wrtnode:yellow:3g_wwan1";
            gpios = <&gpio0 3 1>;
        };
    }; 

烧录固件后进入 /sys/class/leds 可查看注册成功的led设备,可通过对brightness文件写入1和0的方式控制LED亮灭。

 

GPIO-KEY功能注册和控制

将GPIO注册为KEY设备与LED的方法类似,需要在配置界面(make menuconfig命令进入配置界面)选择添加Button的驱动(默认编译时已经选上)
Button 驱动: > Kernel modules > Other modules > kmod-gpio-button-hotplug

同理WRTNODE2P.dts文件中将GPIO#5注册为名为"reset"的KEY,通过调试状态查看KEY值,hi 表示高电平,lo 表示低电平。

    gpio-keys-polled {
        compatible = "gpio-keys-polled";
        #address-cells = <1>;
        #size-cells = <0>;
        poll-interval = <20>;

        reset {
            label = "reset";
            gpios = <&gpio0 5 1>;
            linux,code = <KEY_RESTART>;
        };
    };  

 

按键驱动文件 package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c中对按键的键值和名称进行了映射,比如"reset"按键,键值为 KEY_RESTART,当按下或释放该按键时驱动会向用户层发送事件执行/etc/rc.button/目录下所对应的脚本 reset.

static struct bh_map button_map[] = {
    BH_MAP(BTN_0,           "BTN_0"),
    BH_MAP(BTN_1,           "BTN_1"),
    BH_MAP(BTN_2,           "BTN_2"),
    BH_MAP(BTN_3,           "BTN_3"),
    BH_MAP(BTN_4,           "BTN_4"),
    BH_MAP(BTN_5,           "BTN_5"),
    BH_MAP(BTN_6,           "BTN_6"),
    BH_MAP(BTN_7,           "BTN_7"),
    BH_MAP(BTN_8,           "BTN_8"),
    BH_MAP(BTN_9,           "BTN_9"),
    BH_MAP(KEY_BRIGHTNESS_ZERO, "brightness_zero"),
    BH_MAP(KEY_CONFIG,      "config"),
    BH_MAP(KEY_COPY,        "copy"),
    BH_MAP(KEY_EJECTCD,     "eject"),
    BH_MAP(KEY_HELP,        "help"),
    BH_MAP(KEY_LIGHTS_TOGGLE,   "lights_toggle"),
    BH_MAP(KEY_PHONE,       "phone"),
    BH_MAP(KEY_POWER,       "power"),
    BH_MAP(KEY_RESTART,     "reset"),
    BH_MAP(KEY_RFKILL,      "rfkill"),
    BH_MAP(KEY_VIDEO,       "video"),
    BH_MAP(KEY_WIMAX,       "wwan"),
    BH_MAP(KEY_WLAN,        "wlan"),
    BH_MAP(KEY_WPS_BUTTON,      "wps"),
};

例子代码

1.dts文件需要引入头文件

#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
2.dts文件配置reset功能 32+6=38 对应GPIO38

 gpio-keys {
         compatible = "gpio-keys-polled";
         poll-interval = <20>;
         reset {
              label = "reset";
              gpios = <&gpio1 6 GPIO_ACTIVE_LOW>;
            linux,code = <KEY_RESTART>;
        };

};

3. 修改/etc/rc.button/reset脚本

. /lib/functions.sh

OVERLAY="$( grep ' /overlay ' /proc/mounts )"
case "$ACTION" in
pressed)
        [ -z "$OVERLAY" ] && return 0

        return 5
;;
timeout)
        . /etc/diag.sh
        set_state failsafe
;;
released)
        if [ "$SEEN" -ge 3 -a "$SEEN" -lt 8 ]
        then
                echo "REBOOT" > /dev/console
                sync
                reboot
        elif [ "$SEEN" -ge 10 -a -n "$OVERLAY" ]
        then
                echo "FACTORY RESET" > /dev/console
                jffs2reset -y && reboot &
        fi
;;
esac

参考链接 

https://www.imooc.com/article/43412

https://blog.csdn.net/zhjmyx/article/details/103593528

相关标签: Openwrt