本文转载自: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)
 
上拉的设置和配置寄存器的一样,这里就不多做说明了。

uboot的GPIO驱动分析--基于全志的A10芯片【转】的更多相关文章

  1. bcm53344 gpio驱动分析

    /********************************************************************************* * 1.查看代码是在vim下,使用 ...

  2. 基于335X的UBOOT网口驱动分析

    基于335X的UBOOT网口驱动分析 一.软硬件平台资料 1.  开发板:创龙AM3359核心板,网口采用RMII形式 2.  UBOOT版本:U-Boot-2016.05,采用FDT和DM. 参考链 ...

  3. 基于S3C2440的U-BOOT的start.S分析

    基于S3C2440的U-BOOT的start.S分析 在了解了ARM相关的汇编指令后,同时结合网上各位大虾的提点开始阅读u-boot的启动代码,现将分析过程记录如下 可执行文件及内存映射 我们可以把可 ...

  4. Linux下GPIO驱动(三) ----gpio_desc()的分析

    上篇最后提出的疑问是结构体gpio_chip中的成员函数set等是怎么实现的,在回答之前先介绍下gpio_desc这个结构体. 如上图所示,右上方部分为GPIO驱动对其它驱动提供的GPIO操作接口,其 ...

  5. Xilinx Uboot网卡驱动分析

    1.MAC控制器.网卡.PHY.MDIO.mii.gmii.rgmii概念扫盲 网卡在功能上包含OSI模型的两个层,数据链路层和物理层.物理层定义了数据传送与接收所需要的电与光信号.线路状态.时钟基准 ...

  6. 基于335X的Linux网口驱动分析

    基于335X的linux网口驱动分析 一. 系统构成 1.  硬件平台 AM335X 2.  LINUX内核版本 4.4.12 二. 网口驱动构架(mdio部分) mdio网口驱动部分 使用 总线.设 ...

  7. u-boot支持LCD显示(基于TQ2440)【转】

    本文转载自:http://www.cnblogs.com/pengdonglin137/p/4633877.html u-boot支持LCD显示(基于TQ2440)   阅读目录(Content) 平 ...

  8. linux内核SPI总线驱动分析(一)(转)

    linux内核SPI总线驱动分析(一)(转) 下面有两个大的模块: 一个是SPI总线驱动的分析            (研究了具体实现的过程) 另一个是SPI总线驱动的编写(不用研究具体的实现过程) ...

  9. Linux SD/MMC/SDIO驱动分析_转

    转自:Linux SD/MMC/SDIO驱动分析    https://www.cnblogs.com/cslunatic/p/3678045.html#3053341 一.SD/MMC/SDIO概念 ...

随机推荐

  1. Discuz!伪静态原理分析

    伪静态在seo火热的时代,是每个站长都比较关注的问题,discuz!论坛如何伪静态,为什么伪静态失效了,为什么列表页无法实现伪静态,为什么有些页面不是伪静态呢?下面dz官方nxy105从两个角度入手为 ...

  2. nginx平滑升级实战

    Nginx 平滑升级 1.查看旧版Nginx的编译参数 [root@master ~]# /usr/local/nginx/sbin/nginx -V [root@master ~]# ll ngin ...

  3. react 导航切换

    <ul class="nav"> <li onClick={() => this.changeFontColor(0)} className={`${0 = ...

  4. Ice Cream Tower(The 2016 ACM-ICPC Asia China-Final Contest 二分&贪心)

    题目: Mr. Panda likes ice cream very much especially the ice cream tower. An ice cream tower consists ...

  5. Linux学习笔记(四) vi编辑器

    一.vi 编辑器 vi 编辑器 (Visual Interface) 是所有 Unix 及 Linux 系统下标准的编辑器,相当于 Windows 系统中的记事本 它有三种模式,分别是: Comman ...

  6. 移动端placeholder不能垂直居中解决方案

    1.问题描述 问题如图:手机端placeholder文字偏上,垂直方向不居中,input光标显示偏上解决IE下不支持placeholder属性 2.解决方案 css .phoneNumber inpu ...

  7. BZOJ 4976 [Lydsy1708月赛]宝石镶嵌

    [题解] 我们设总共有m个二进制位出现过1,那么如果n-k≥m,显然所有的1都可以出现,那么答案就是把所有的数或起来. 如果n-k<m,那么因为k不超过100,ai不超过1e5,所以n不超过11 ...

  8. 返回通知&异常通知&环绕通知

    [返回通知] LoggingAspect.java: @Aspect @Component public class LoggingAspect { /* * 在方法正常执行后执行的通知叫返回通知 * ...

  9. 【Codeforces 1034A】Enlarge GCD

    [链接] 我是链接,点我呀:) [题意] 题意 [题解] 设原来n个数字的gcd为g 减少某些数字之后 新的gcd肯定是g的倍数 即gx 我们可以枚举这个x值(x>=2) 看看原来的数字里面有多 ...

  10. 46. Spring Boot中使用AOP统一处理Web请求日志

    在之前一系列的文章中都是提供了全部的代码,在之后的文章中就提供核心的代码进行讲解.有什么问题大家可以给我留言或者加我QQ,进行咨询. AOP为Aspect Oriented Programming的缩 ...