• uboot的GPIO驱动分析--基于全志的A10芯片【转】


    本文转载自:http://blog.csdn.net/lw2011cg/article/details/68954707

    uboot的GPIO驱动分析--基于全志的A10芯片

    转载至:http://blog.sina.com.cn/s/blog_b5020b670101ft49.html

    (2013-12-28 10:47:31)
    标签:

    it

    分类:uboot的驱动分析
    uboot的GPIO相当简单,其就是三层结构。分别为:
    1、顶层接口层,其只定义了通用的接口,并不负责实现,实现是我们具体根据具体的芯片来实现的。
    2、中间接口实现层,用具体的板子的GPIO来实现顶层的接口
    3、 底层具体芯片GPIO的实现层 。
     
    现在具体分析:
    顶层接口层
     
    int gpio_request(unsigned gpio, const char *label);//申请GPIO资源
    int gpio_free(unsigned gpio); //释放申请的GPIO资源
    int gpio_direction_input(unsigned gpio); //设置GPIO为输入模式
    int gpio_direction_output(unsigned gpio, int value);//设置GPIO为输出模式
    int gpio_get_value(unsigned gpio); //得到GPIO的值
    int gpio_set_value(unsigned gpio, int value);//设置GPIO的值
    说明:unsigned gpio为逻辑号,虽然和实际的物理GPIO地址有一定的关系,但并不是实际的物理GPIO地址。
     
    中间接口实现层:
    用具体的芯片的GPIO来实现其顶层接口
     
    int gpio_request(unsigned gpio, const char *label)
    {
     return 0;
    }
     
    int gpio_free(unsigned gpio)
    {
     return 0;
    }
     
    int gpio_direction_input(unsigned gpio)
    {
     sunxi_gpio_set_cfgpin(gpio,SUNXI_GPIO_INPUT);
     
     return sunxi_gpio_input(gpio);
    }
     
    int gpio_direction_output(unsigned gpio, int value)
    {
     sunxi_gpio_set_cfgpin(gpio,SUNXI_GPIO_OUTPUT);
     
     return sunxi_gpio_output(gpio, value);
    }
     
    int gpio_get_value(unsigned gpio)
    {
     return sunxi_gpio_input(gpio);
    }
     
    int gpio_set_value(unsigned gpio, int value)
    {
     return sunxi_gpio_output(gpio, value);
    }
     
    底层具体芯片GPIO的实现层:
    在实现的时候,其用了一个小技巧,其目的是把GPIO的物理寄存器放到结构体里面来,从而把物理的地址操作转换为数据结构的操作。
    其实现如下:
    把SUNXI_PIO_BASE 强制转换为sunxi_gpio_reg *指针来实现。
    #define SUNXI_PIO_BASE 0x01c20800
    struct sunxi_gpio {
     u32 cfg[4];
     u32 dat;
     u32 drv[2];
     u32 pull[2];
    };
     
     
    struct sunxi_gpio_int {
     u32 cfg[3];
     u32 ctl;
     u32 sta;
     u32 deb;
    };
     
    struct sunxi_gpio_reg {
     struct sunxi_gpio gpio_bank[9];
     u8 res[0xbc];
     struct sunxi_gpio_int gpio_int;
    };
     
     
    我们实现具体的芯片的GPIO的操作的思想是:
    使用逻辑符号unsigned gpio,通过SUNXI_PIO_BASE强制转换为sunxi_gpio_reg *指针的指针来操作相关寄存器
     
    但是逻辑符号unsigned gpio要通过SUNXI_PIO_BASE强制转换为sunxi_gpio_reg *指针的指针来操作相关寄存器,必须要解决一个问题,即如何在众多的寄存器的中,找到指定的那个寄存器,并且在该寄存器上找到指定的那些相关位。
    即gpio---->bank------>bank中的offset
     
    这个映射关系和具体的芯片有关。
    这里只讨论全志的a10芯片。
     
    先看逻辑符号gpio的定义:
     
    #define SUNXI_GPIO_A_NR 32
    #define SUNXI_GPIO_B_NR 32
    #define SUNXI_GPIO_C_NR 32
    #define SUNXI_GPIO_D_NR 32
    #define SUNXI_GPIO_E_NR 32
    #define SUNXI_GPIO_F_NR 32
    #define SUNXI_GPIO_G_NR 32
    #define SUNXI_GPIO_H_NR 32
    #define SUNXI_GPIO_I_NR 32
     
    #define SUNXI_GPIO_NEXT(__gpio)
     ((__gpio##_START) + (__gpio##_NR) + 0)
     
    enum sunxi_gpio_number {
     SUNXI_GPIO_A_START = 0,
     SUNXI_GPIO_B_START =SUNXI_GPIO_NEXT(SUNXI_GPIO_A),
     SUNXI_GPIO_C_START =SUNXI_GPIO_NEXT(SUNXI_GPIO_B),
     SUNXI_GPIO_D_START =SUNXI_GPIO_NEXT(SUNXI_GPIO_C),
     SUNXI_GPIO_E_START =SUNXI_GPIO_NEXT(SUNXI_GPIO_D),
     SUNXI_GPIO_F_START =SUNXI_GPIO_NEXT(SUNXI_GPIO_E),
     SUNXI_GPIO_G_START =SUNXI_GPIO_NEXT(SUNXI_GPIO_F),
     SUNXI_GPIO_H_START =SUNXI_GPIO_NEXT(SUNXI_GPIO_G),
     SUNXI_GPIO_I_START =SUNXI_GPIO_NEXT(SUNXI_GPIO_H),
    };
     
     
    #define SUNXI_GPA(_nr) (SUNXI_GPIO_A_START + (_nr))
    #define SUNXI_GPB(_nr) (SUNXI_GPIO_B_START + (_nr))
    #define SUNXI_GPC(_nr) (SUNXI_GPIO_C_START + (_nr))
    #define SUNXI_GPD(_nr) (SUNXI_GPIO_D_START + (_nr))
    #define SUNXI_GPE(_nr) (SUNXI_GPIO_E_START + (_nr))
    #define SUNXI_GPF(_nr) (SUNXI_GPIO_F_START + (_nr))
    #define SUNXI_GPG(_nr) (SUNXI_GPIO_G_START + (_nr))
    #define SUNXI_GPH(_nr) (SUNXI_GPIO_H_START + (_nr))
    #define SUNXI_GPI(_nr) (SUNXI_GPIO_I_START + (_nr))
     
     
    从这些定义可以得出结论:
    A到I这九大组的gpio是从0开始的,每个为32位的标记,(当然基本上每组的gpio号都是用不完的,但为了方面就定义每个组的大小都为32)
    即第x组的第y个gpio的索引为x*32+y
     
    逻辑索引gpio通过SUNXI_PIO_BASE 强制转换为sunxi_gpio_reg *指针的指针,来指向到具体寄存器的映射如下:
     
     
    #define GPIO_BANK(pin) ((pin) >> 5)
    #define GPIO_NUM(pin) ((pin) & 0x1f)
     
    所以写逻辑gpio指定的GPIO可以这样:
    static int sunxi_gpio_output(u32 pin, u32 val)
    {
     u32 dat;
     u32 bank = GPIO_BANK(pin);
     u32 num = GPIO_NUM(pin);
     struct sunxi_gpio *pio =
        &((struct sunxi_gpio_reg*)SUNXI_PIO_BASE)->gpio_bank[bank];//通过组号索引得到该gpio的多个寄存器的首地址
     
     dat = readl(&pio->dat); //读其输入输出寄存器
     if (val)
      dat |= 0x1 << num;
     else
      dat &= ~(0x1 << num);
     
     writel(dat, &pio->dat);//写入其输入输入寄存器
     
     return 0;
    }
     
     
    #define GPIO_CFG_INDEX(pin) (((pin) & 0x1f) >> 3)
    #define GPIO_CFG_OFFSET(pin) ((((pin) & 0x1f) & 0x7)<< 2)
     
    所以配置逻辑gpio指定的GPIO可以这样:
    int sunxi_gpio_set_cfgpin(u32 pin, u32 val)
    {
     u32 cfg;
     u32 bank = GPIO_BANK(pin);
     u32 index = GPIO_CFG_INDEX(pin);//为配置寄存器的下标索引
     u32 offset = GPIO_CFG_OFFSET(pin);//在配置寄存器的偏移
     struct sunxi_gpio *pio =
        &((struct sunxi_gpio_reg*)SUNXI_PIO_BASE)->gpio_bank[bank];//通过组号索引得到该gpio的多个寄存器的首地址
     
     cfg = readl(&pio->cfg[0] + index);//&pio->cfg[0]为该组的多个配置寄存器的首地址,通过index索引得到其配置寄存器的地址
     cfg &= ~(0xf << offset);
     cfg |= val << offset; //这两行为设置配置寄存器的值
     
     writel(cfg, &pio->cfg[0] + index);//写入指定的配置寄存器
     
     return 0;
    }
     
     
     
     
    #define GPIO_PULL_INDEX(pin) (((pin) & 0x1f) >> 4)
    #define GPIO_PULL_OFFSET(pin) ((((pin) & 0x1f) & 0xf)<< 1)
     
    上拉的设置和配置寄存器的一样,这里就不多做说明了。
  • 相关阅读:
    AJAX中所谓的异步
    前端性能优化方案
    文字超出隐藏
    创建值的两种方式及其区别
    单例模式
    自定义数据属性
    时间字符串的处理
    日期函数及时钟案例
    很low的四位验证码实现
    使用Ajax发送http请求(get&post请求)--转载
  • 原文地址:https://www.cnblogs.com/zzb-Dream-90Time/p/7666265.html
Copyright © 2020-2023  润新知