谷动谷力

 找回密码
 立即注册
查看: 1953|回复: 0
打印 上一主题 下一主题
收起左侧

MT7688/MT7628-GPIO使用

[复制链接]
跳转到指定楼层
楼主
发表于 2022-9-3 18:09:49 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
MT7688/MT7628-GPIO使用
7688/7628的GPIO一共有47个,GPIO0-GPIO46,这些GPIO有复用的功能,按功能模块进行配置,比如I2C有两根线,将其设置为GPIO模式,则两根就都是GPIO模式了,不可为别的功能。
一般有两种方法配置
1.通过寄存器进行配置
下面的使用前提不要被DTS或者驱动什么占用,如switch芯片的network配置
功能的定义由两个地址寄存器。
GPIO1_MODE = 0x10000060



image.png


GPIO2_MODE = 0x10000064



image.png


可以看到两个寄存器覆盖了所有的复用引脚,举个例子,如要将GPIO0/1设置成GPIO模式:
先查看GPIO0/1引脚的默认功能如下,为I2S的引脚。



image.png

所以需要找到I2S的配置寄存器,以下为部分GPIO1_MODE寄存器的含义:



image.png


可看到I2C为GPIO1_MODE的第20:21位。
所以需要做的就是将原本GPIO1_MODE寄存器的值都出来,然后将7:6位设置成01即可。
comnIoctlRegOption(GPIO1_MODE, 0x1 << 6, 0x3 << 6);      //I2S,GPIO0-40000000010x1 << 6即 val = 001000000000000110x3 << 6即 mask = 011000000reg_val[2] = {0, 0};有两个值,一个是传进去的addr,一个该地址返回的valreg_val[0] = add; read(fd, reg_val, 8); //reg_val[0]为传入的addr,reg_val[1]为valreg_val[1] &= ~mask; //A &= ~B,将A值的B位清0,即011000000,第6、7位清0reg_val[1] |= (val & mask); //A |= B,将A值的B位置1,即001000000,第6位置1_INT32 comnIoctlRegOption(_UINT32 add, _UINT32 val, _UINT32 mask){    int fd = -1;    _UINT32 reg_val[2] = {0, 0};        fd = open(REG_DEV_NAME , O_RDWR|O_NOCTTY|O_NDELAY);    if(fd < 0)    {        printf("comnIoctl(RegOption) Cann't Open %s\r\n", REG_DEV_NAME);        return EOS_ERROR;    }    //set Reset IO Output    reg_val[0] = add;    read(fd, reg_val, 8);    reg_val[1] &= ~mask;        reg_val[1] |= (val & mask);            write(fd, reg_val, 8);    close(fd);    return EOS_OK;}
comnIoctlRegOption(GPIO1_MODE, 0x1 << 10, 0x3 << 10);    //SD,GPIO22-29comnIoctlRegOption(GPIO1_MODE, 0x1 << 2, 0x3 << 2);      //SPIS,GPIO14-17comnIoctlRegOption(GPIO1_MODE, 0x1 << 26, 0x3 << 26);    //UART2,GPIO20-21comnIoctlGpioInit(GPIO_SIM_CP, GPIO_DIR_OUT, 1);comnIoctlGpioInit(GPIO_SIM_PL, GPIO_DIR_OUT, 1);comnIoctlGpioInit(GPIO_SIM_DET0, GPIO_DIR_IN, 1);comnIoctlGpioInit(GPIO_SIM_DET1, GPIO_DIR_IN, 1);
#define GPIO1_MODE_ADD  0x10000060#define GPIO2_MODE_ADD  0x10000064#define GPIO0_CTRL_ADD  0X10000600#define GPIO0_DATA_ADD  0X10000620    //read or write data#define GPIO1_CTRL_ADD  0X10000604#define GPIO1_DATA_ADD  0X10000624
下面给出几个已经封装好的函数,以前后期直接使用
1、寄存器配置_INT32 comnIoctlRegOption(_UINT32 add, _UINT32 val, _UINT32 mask){    int fd = -1;    _UINT32 reg_val[2] = {0, 0};        fd = open(REG_DEV_NAME , O_RDWR|O_NOCTTY|O_NDELAY);    if(fd < 0)    {        printf("comnIoctl(RegOption) Cann't Open %s\r\n", REG_DEV_NAME);        return EOS_ERROR;    }    //set Reset IO Output    reg_val[0] = add;    read(fd, reg_val, 8);    reg_val[1] &= ~mask;        reg_val[1] |= (val & mask);            write(fd, reg_val, 8);    close(fd);    return EOS_OK;}
2、输入输出模式配置_INT32 comnIoctlGpioInit(_UCHAR8 gpio, _UCHAR8 dir, _UCHAR8 val){    _INT32 fd = -1;    _UINT32 reg_val[2] = {0, 0};    _UINT32 gpio_ctrl_reg_add = 0;    _UINT32 gpio_data_reg_add = 0;        if(gpio < 32)    {        gpio_ctrl_reg_add = REG_GPIO_CTRL0;        gpio_data_reg_add = REG_GPIO_DATA0;    }    else if(gpio >= 32)    {        gpio_ctrl_reg_add = REG_GPIO_CTRL1;        gpio_data_reg_add = REG_GPIO_DATA1;        gpio -= 32;    }        fd = open(REG_DEV_NAME , O_RDWR|O_NOCTTY|O_NDELAY);    if(fd < 0)    {        printf("comnIoctl(GpioInit) Cann't Open %s\r\n", REG_DEV_NAME);        return EOS_ERROR;    }    //set the io port,out or in    reg_val[0] = gpio_ctrl_reg_add;    read(fd, reg_val, 8);        if(dir == GPIO_DIR_OUT)    {        reg_val[1] |= 1 << gpio;    }    else if(dir == GPIO_DIR_IN)    {        reg_val[1] &= ~(1 << gpio);    }    write(fd, reg_val, 8);        //set the val    reg_val[0] = gpio_data_reg_add;    read(fd, reg_val, 8);    if(val > 0)    {        reg_val[1] |= 1 << gpio;    }    else    {        reg_val[1] &= ~(1 << gpio);    }    write(fd, reg_val, 8);    close(fd);        return EOS_OK;}
3、输出高低_INT32 comnIoctlGpioSetValue(_UCHAR8 gpio, _UCHAR8 val){    _INT32 fd = -1;    _UINT32 reg_val[2] = {0, 0};    _UINT32 gpio_data_reg_add = 0;        if((gpio > 63) || (val > 1))    {        printf("comnIoctl(GpioSetValue) paramer is wrong!\n");        return EOS_ERROR;    }        if(gpio < 32)    {        gpio_data_reg_add = REG_GPIO_DATA0;    }    else if(gpio >= 32)    {        gpio_data_reg_add = REG_GPIO_DATA1;        gpio -= 32;    }        fd = open(REG_DEV_NAME , O_RDWR|O_NOCTTY|O_NDELAY);    if(fd < 0)    {        //printf("comnIoctl(GpioSetValue) Cann't Open %s\r\n", REG_DEV_NAME);        return EOS_ERROR;    }    //输出0/1    reg_val[0] = gpio_data_reg_add;    read(fd, reg_val, 8);    if(val == 0)    {        reg_val[1] &= ~(1 << gpio);    }    else if(val == 1)    {        reg_val[1] |= 1 << gpio;    }    write(fd, reg_val, 8);        close(fd);    return EOS_OK;}
4、读IO电平_INT32 comnIoctlGpioGetValue(_UCHAR8 gpio){    _INT32 fd = -1;    _UINT32 reg_val[2] = {0, 0};    _UINT32 gpio_data_reg_add = 0;        if(gpio > 63)    {        printf("comnIoctl(GpioGetValue) paramer is wrong!\n");        return EOS_ERROR;    }        if(gpio < 32)    {        gpio_data_reg_add = REG_GPIO_DATA0;    }    else if(gpio >= 32)    {        gpio_data_reg_add = REG_GPIO_DATA1;        gpio -= 32;    }        fd = open(REG_DEV_NAME , O_RDWR|O_NOCTTY|O_NDELAY);    if(fd < 0)    {        //printf("comnIoctl(GpioGetValue) Cann't Open %s\r\n", REG_DEV_NAME);        return EOS_ERROR;    }    //输出0/1    reg_val[0] = gpio_data_reg_add;    read(fd, reg_val, 8);    close(fd);        return ((reg_val[1] >> gpio) & 1);}
2.多寄存器控制的GPIO



image.png

如上图,SD卡由EPHY_AGPIO_AIO_EN(非EPHY_APGIO_AIO_EN)和SD_MODE两个寄存器控制,都要置1才可以



image.png

对于SD_MODE置1比较容易,上面已经给出方法,如下:
comnIoctlRegOption(GPIO1_MODE, 0x1 << 10, 0x3 << 10);    //SD,GPIO22-29
EPHY_AGPIO_AIO_EN即AGPIO_CFG的17-29位置1,为了通用comnIoctlRegOption函数,做如下设置。
comnIoctlRegOption(AGPIO_CFG, 0xF << 17, 0xF << 17);     //EPHY_AGPIO_AIO_EN[4:1],GPIO14-290000011110xF << 6即 val = 00001111 00000000 000000000000011110xF << 6即 mask = 00001111 00000000 000000000reg_val[2] = {0, 0};有两个值,一个是传进去的addr,一个该地址返回的valreg_val[0] = add; read(fd, reg_val, 8); //reg_val[0]为传入的addr,reg_val[1]为valreg_val[1] &= ~mask; //A &= ~B,将A值的B位清0,第17-20位清0reg_val[1] |= (val & mask); //A |= B,将A值的B位置1,第17-20位置1
3.通过DTS进行配置
DTS格式有点类似Json,一般系统都会有两个dts,一个芯片的dtsi,如:$(TOPDIR)/target/linux/ramips/dts/mt7628an.dts另一个板子的配置dts,如:$(TOPDIR)/target/linux/ramips/dts/WRTNODE2P.dts。板子配置的dts会include芯片的dtsi,如下:
/dts-v1/;/include/ "mt7628an.dtsi"
1、MT7620
mt7620a.dtsi
结合mt7620的datasheet里GPIO pin share schemes以及在mt7620n.dtsi里我们看到有,将GPIO#0到GPIO#72(中间有仅仅做GPO或GPI的)分为四组GPIO0-GPIO3;
  • 对应GPIO0是从GPIO#0开始到GPIO#23,一共有24个;
  • 对应GPIO1是从GPIO#24开始到GPIO#39,一共有16个;
  • 对应GPIO2是从GPIO#40开始到GPIO#71,一共有32个;
  • 对应GPIO3对应的是GPIO#72,仅有一个。
gpio0: gpio@600 {    compatible = "ralink,mt7620a-gpio", "ralink,rt2880-gpio";    reg = <0x600 0x34>;    resets = <&rstctrl 13>;    reset-names = "pio";    interrupt-parent = <&intc>;    interrupts = <6>;    gpio-controller;    #gpio-cells = <2>;    ralink,gpio-base = <0>;    ralink,num-gpios = <24>;    ralink,register-map = [ 00 04 08 0c                20 24 28 2c                30 34 ];};gpio1: gpio@638 {    compatible = "ralink,mt7620a-gpio", "ralink,rt2880-gpio";    reg = <0x638 0x24>;    interrupt-parent = <&intc>;    interrupts = <6>;    gpio-controller;    #gpio-cells = <2>;    ralink,gpio-base = <24>;    ralink,num-gpios = <16>;    ralink,register-map = [ 00 04 08 0c                10 14 18 1c                20 24 ];    status = "disabled";};gpio2: gpio@660 {    compatible = "ralink,mt7620a-gpio", "ralink,rt2880-gpio";    reg = <0x660 0x24>;    interrupt-parent = <&intc>;    interrupts = <6>;    gpio-controller;    #gpio-cells = <2>;    ralink,gpio-base = <40>;    ralink,num-gpios = <32>;    ralink,register-map = [ 00 04 08 0c                10 14 18 1c                20 24 ];    status = "disabled";};gpio3: gpio@688 {    compatible = "ralink,mt7620a-gpio", "ralink,rt2880-gpio";    reg = <0x688 0x24>;    interrupt-parent = <&intc>;    interrupts = <6>;    gpio-controller;    #gpio-cells = <2>;    ralink,gpio-base = <72>;    ralink,num-gpios = <1>;    ralink,register-map = [ 00 04 08 0c                10 14 18 1c                20 24 ];    status = "disabled";};
上面的gpio1/2/3的status = "disabled",默认是关闭的,如果要使用需要在dts里面打开,如下:
palmbus@10000000 {        gpio1: gpio@638 {            status = "okay";        };        gpio2: gpio@660 {            status = "okay";        };        gpio3: gpio@688 {            status = "okay";        };}
如果引脚的功能有被复用到的,也需要把复用引脚释放,添加到ralink,group里面,如下:
pinctrl {    state_default: pinctrl0 {        default {            ralink,group = "ephy", "wled", "pa", "i2c", "wdt", "uartf", "spi refclk";            ralink,function = "gpio";        };    };};
上面的ephy/i2c/spi refclk等名称在build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7628/linux-3.18.29/arch/mips/ralink/mt7620.c里面有定义,如下:
static struct rt2880_pmx_group mt7620a_pinmux_data[] = {    GRP("i2c", i2c_grp, 1, MT7620_GPIO_MODE_I2C),    GRP("uartf", uartf_grp, MT7620_GPIO_MODE_UART0_MASK,        MT7620_GPIO_MODE_UART0_SHIFT),    GRP("spi", spi_grp, 1, MT7620_GPIO_MODE_SPI),    GRP("uartlite", uartlite_grp, 1, MT7620_GPIO_MODE_UART1),    GRP_G("wdt", wdt_grp, MT7620_GPIO_MODE_WDT_MASK,        MT7620_GPIO_MODE_WDT_GPIO, MT7620_GPIO_MODE_WDT_SHIFT),    GRP("mdio", mdio_grp, 1, MT7620_GPIO_MODE_MDIO),    GRP("rgmii1", rgmii1_grp, 1, MT7620_GPIO_MODE_RGMII1),    GRP("spi refclk", refclk_grp, 1, MT7620_GPIO_MODE_SPI_REF_CLK),    GRP_G("pcie", pcie_rst_grp, MT7620_GPIO_MODE_PCIE_MASK,        MT7620_GPIO_MODE_PCIE_GPIO, MT7620_GPIO_MODE_PCIE_SHIFT),    GRP_G("nd_sd", nd_sd_grp, MT7620_GPIO_MODE_ND_SD_MASK,        MT7620_GPIO_MODE_ND_SD_GPIO, MT7620_GPIO_MODE_ND_SD_SHIFT),    GRP("rgmii2", rgmii2_grp, 1, MT7620_GPIO_MODE_RGMII2),    GRP("wled", wled_grp, 1, MT7620_GPIO_MODE_WLED),    GRP("ephy", ephy_grp, 1, MT7620_GPIO_MODE_EPHY),    GRP("pa", pa_grp, 1, MT7620_GPIO_MODE_PA),    { 0 }};
第一个参数就是名称,第二个参数,对应该组引脚的解析个数,如:
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 mdio_grp[] = { FUNC("mdio", 0, 22, 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) };
i2c后面的1,2,代表从gpio1开始,占用2个引脚;spi refclk的37,3,代表从gpio37开始,占用3个引脚;这些跟功能引脚的定义其实是对应的,如下:




image

gpio-leds {    compatible = "gpio-leds";    indicator {        label = "wrtnode:blue:indicator";        gpios = <&gpio1 14 0>;    };};
2、MT7688
mt7628an.dtsi
mt7628an.dtsi里有对gpio的注册,一共将GPIO分为三组,分别为gpio0、gpio1、gpio2
每组gpio包含32个gpio;在WRTnode2R/2P上只用到了gpio0和gpio1两组。
gpio@600 {    #address-cells = <1>;    #size-cells = <0>;    compatible = "mtk,mt7628-gpio", "mtk,mt7621-gpio";    reg = <0x600 0x100>;    interrupt-parent = <&intc>;    interrupts = <6>;    gpio0: bank@0 {        reg = <0>;        compatible = "mtk,mt7621-gpio-bank";        gpio-controller;        #gpio-cells = <2>;    };    gpio1: bank@1 {        reg = <1>;        compatible = "mtk,mt7621-gpio-bank";        gpio-controller;        #gpio-cells = <2>;    };    gpio2: bank@2 {        reg = <2>;        compatible = "mtk,mt7621-gpio-bank";        gpio-controller;        #gpio-cells = <2>;    };};
与MT7620不同的是,这三组gpio都是开启的,在dts中就不用在操作。
与MT7620相同的是,如果引脚的功能有被复用到的,也需要把复用引脚释放,添加到ralink,group里面,如下:
    pinctrl {        state_default: pinctrl0 {            gpio {                ralink,group = "i2c", "gpio", "jtag";                ralink,function = "gpio";            };        };    };
不过MT7620个MT7628的引脚功能分布式不一样的,所以在build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7628/linux-3.18.29/arch/mips/ralink/mt7620.c里定义也是不一样的,如下:
static struct rt2880_pmx_group mt7628an_pinmux_data[] = {    GRP_G("pwm1", pwm1_grp_mt7628, MT7628_GPIO_MODE_MASK, 1, MT7628_GPIO_MODE_PWM1),    GRP_G("pwm0", pwm0_grp_mt7628, MT7628_GPIO_MODE_MASK, 1, MT7628_GPIO_MODE_PWM0),    GRP_G("uart2", uart2_grp_mt7628, MT7628_GPIO_MODE_MASK, 1, MT7628_GPIO_MODE_UART2),    GRP_G("uart1", uart1_grp_mt7628, MT7628_GPIO_MODE_MASK, 1, MT7628_GPIO_MODE_UART1),    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),    GRP_G("i2s", i2s_grp_mt7628, MT7628_GPIO_MODE_MASK, 1, MT7628_GPIO_MODE_I2S),    GRP_G("spi cs1", spi_cs1_grp_mt7628, MT7628_GPIO_MODE_MASK, 1, MT7628_GPIO_MODE_CS1),    GRP_G("spis", spis_grp_mt7628, MT7628_GPIO_MODE_MASK, 1, MT7628_GPIO_MODE_SPIS),    GRP_G("gpio", gpio_grp_mt7628, MT7628_GPIO_MODE_MASK, 1, MT7628_GPIO_MODE_GPIO),    GRP_G("wled_an", wled_an_grp_mt7628, MT7628_GPIO_MODE_MASK, 1, MT7628_GPIO_MODE_WLED_AN),    GRP_G("wled_kn", wled_kn_grp_mt7628, MT7628_GPIO_MODE_MASK, 1, MT7628_GPIO_MODE_WLED_KN),    { 0 }};
第二个参数,对应该组引脚的解析个数,如:
static struct rt2880_pmx_func i2c_grp_mt7628[] = {    FUNC("-", 3, 4, 2),    FUNC("debug", 2, 4, 2),    FUNC("gpio", 1, 4, 2),    FUNC("i2c", 0, 4, 2),};
i2c后面的4,2,代表从gpio4开始,占用2个引脚;与MT7620的gpio1-2是不一样的。




image

gpio_export {    compatible = "gpio-export";    #size-cells = <0>;    lte4power {        gpio-export,name = "G4Power";        gpio-export,output = <0>;        gpios = <&gpio0 29 0>;      //GPIO_ACTIVE_HIGH    };    lte4reset {        gpio-export,name = "G4Reset";        gpio-export,output = <0>;        gpios = <&gpio0 28 0>;    };    lte4status {        gpio-export,name = "G4Status";        gpio-export,input = <0>;        gpios = <&gpio0 22 0>;      //GPIO_ACTIVE_HIGH    };}
    gpio-leds {        compatible = "gpio-leds";        indicator {            label = "wrtnode:blue:indicator";            gpios = <&gpio1 9 1>;        };    };    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 = <0x198>;        };    };root@OpenWrt:/sys/class/leds# lswrtnode:blue:indicator

+10
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|深圳市光明谷科技有限公司|光明谷商城|Sunshine Silicon Corpporation ( 粤ICP备14060730号|Sitemap

GMT+8, 2024-12-29 08:46 , Processed in 0.107249 second(s), 39 queries .

Powered by Discuz! X3.2 Licensed

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表