LInux-3.0.8中基于S5PV210的GPIO模块代码追踪和分析

  编写按键驱动时,想知道内核是如何管理GPIO的,所以开始追踪代码,中间走了一些弯路,现记录于此。

  追踪代码之前,我猜测:第一,这部分代码应该在系统set up阶段执行;第二,GPIO的代码应该在machine或者platform或者vendor相关的目录下。事实证明,第一点是正确的,第二点基本是错误的,因为内核依靠对GPIO的抽象来管理之,这层抽象层给具体的machine留出了一些它们需要是实现的接口,这与其他的设备驱动框架在使用上是很类似的,当然,GPIO也是一种设备啊... ...所以,管理GPIO的多数代码位于drivers/gpio/目录下。

  好了,开始走读代码,那么对于S5PV210这块SoC,GPIO子系统的入口函数在哪里呢?在drivers/gpio/gpio-s5pv210.c中,入口函数的实现如下图所示:

  入口函数没几行代码,但是下面所有的内容都要从它开始,所以一点一点来吧,这里先罗列一下下面要叙述的内容:

1. struct s3c_gpio_chip的内容,以及重要的数组s5pv210_gpio_4bit;

2. 上述结构体中的成员config和base;

3. samsung_gpiolib_add_4bit_chips()的分析,这部分比较长。

  第一部分,struct s3c_gpio_chip的介绍以及重要的数组s5pv210_gpio_4bit

  

  从面向对象的角度来看,s3c_gpio_chip是gpio_chip的子类,但是又新增了一些新的属性和操作。虽说它的名字是chip,但是一个s3c_gpio_chip描述的是一个GPIO bank,如GPA0、GPA1、GPB等等, 这一点在接着要介绍的数组s5pv210_gpio_4bit中得以清晰体现。

  base成员表示的是当前bank的控制寄存器的起始虚拟地址,注意是虚拟地址。

  config成员的类型是struct s3c_gpio_cfg,具体的结构是:

 1 struct s3c_gpio_cfg {
 2     unsigned int    cfg_eint;
 3
 4     s3c_gpio_pull_t    (*get_pull)(struct s3c_gpio_chip *chip, unsigned offs);
 5     int        (*set_pull)(struct s3c_gpio_chip *chip, unsigned offs,
 6                     s3c_gpio_pull_t pull);
 7
 8     unsigned (*get_config)(struct s3c_gpio_chip *chip, unsigned offs);
 9     int     (*set_config)(struct s3c_gpio_chip *chip, unsigned offs,
10                    unsigned config);
11 };

  可见config成员用于控制和查看当前bank的某个pin的上下拉电阻的状态,以及设置和查看某引脚上的复用功能,这个成员作为子类struct s3c_gpio_cfg的新成员,说明以上这两种功能在不同的machine以及GPIO IP上的差别是不能忽略的。

  struct s3c_gpio_cfg中很重要的一个成员就是它的父类struct gpio_chip,它内容很多,不过看成员名字就基本能明白含义:

 1 struct gpio_chip {
 2     const char        *label;
 3     struct device        *dev;
 4     struct module        *owner;
 5
 6     int            (*request)(struct gpio_chip *chip,
 7                         unsigned offset);
 8     void            (*free)(struct gpio_chip *chip,
 9                         unsigned offset);
10
11     int            (*direction_input)(struct gpio_chip *chip,
12                         unsigned offset);
13     int            (*get)(struct gpio_chip *chip,
14                         unsigned offset);
15     int            (*direction_output)(struct gpio_chip *chip,
16                         unsigned offset, int value);
17     int            (*set_debounce)(struct gpio_chip *chip,
18                         unsigned offset, unsigned debounce);
19
20     void            (*set)(struct gpio_chip *chip,
21                         unsigned offset, int value);
22
23     int            (*to_irq)(struct gpio_chip *chip,
24                         unsigned offset);
25
26     void            (*dbg_show)(struct seq_file *s,
27                         struct gpio_chip *chip);
28     int            base;
29     u16            ngpio;
30     const char        *const *names;
31     unsigned        can_sleep:1;
32     unsigned        exported:1;
33
34 #if defined(CONFIG_OF_GPIO)
35     /*
36      * If CONFIG_OF is enabled, then all GPIO controllers described in the
37      * device tree automatically may have an OF translation
38      */
39     struct device_node *of_node;
40     int of_gpio_n_cells;
41     int (*of_xlate)(struct gpio_chip *gc, struct device_node *np,
42                 const void *gpio_spec, u32 *flags);
43 #endif
44 };

  这个结构体中的request free等函数指针与gpio的request、free、direction_input、direction_output等函数的实现有关系。

  接着看一下数组s5pv210_gpio_4bit,首先,这个名字中包含4bit,意思是每个bank的gpio控制寄存器中,每4bit控制一个gpio pin。这个数组很长,我们只取出个别元素看一下:

 1 static struct s3c_gpio_chip s5pv210_gpio_4bit[] = {
 2     {
 3         .chip    = {
 4             .base    = S5PV210_GPA0(0),
 5             .ngpio    = S5PV210_GPIO_A0_NR,
 6             .label    = "GPA0",
 7         },
 8     }, {
 9         .chip    = {
10             .base    = S5PV210_GPA1(0),
11             .ngpio    = S5PV210_GPIO_A1_NR,
12             .label    = "GPA1",
13         },
14     }, {
15         .chip    = {
16             .base    = S5PV210_GPB(0),
17             .ngpio    = S5PV210_GPIO_B_NR,
18             .label    = "GPB",
19         },
20     },
21 ... ....
22 {
23         .base    = (S5P_VA_GPIO + 0xC40),
24         .config    = &gpio_cfg_noint,
25         .irq_base = IRQ_EINT(16),
26         .chip    = {
27             .base    = S5PV210_GPH2(0),
28             .ngpio    = S5PV210_GPIO_H2_NR,
29             .label    = "GPH2",
30             .to_irq = samsung_gpiolib_to_irq,
31         },
32     }, {
33         .base    = (S5P_VA_GPIO + 0xC60),
34         .config    = &gpio_cfg_noint,
35         .irq_base = IRQ_EINT(24),
36         .chip    = {
37             .base    = S5PV210_GPH3(0),
38             .ngpio    = S5PV210_GPIO_H3_NR,
39             .label    = "GPH3",
40             .to_irq = samsung_gpiolib_to_irq,
41         },
42     },
43 };

  这个数组描述了一些S5PV210上的gpio,但是对比数据手册,有一些gpio并没有出现在这里,但是这已经足够多了,可以说这个数组描述了系统中多数能够使用的gpio,并初始化了一些信息,比如当前bank的第一个pin的编号、这个bank中所有pin的数量等等,这些都是宏定义,具体的需要看mach-s5pv210相关的头文件,由于涉及到的宏太多,而且没什么难度,这里就不记录了。

  第二部分,struct s3c_gpio_chip中的config成员和base成员初始化。

  这一部分的处理在s5pv210_gpiolib_init函数中,可以看到s5pv210_gpio_4bit中很多元素的config成员没有初始化,也就是NULL,那么这里就需要给其赋值为gpio_cfg,这个变量就在当前文件中,定义如下:

1 static struct s3c_gpio_cfg gpio_cfg = {
2     .set_config    = s3c_gpio_setcfg_s3c64xx_4bit,
3     .set_pull    = s3c_gpio_setpull_updown,
4     .get_pull    = s3c_gpio_getpull_updown,
5 };

  下面就看看这三个函数吧,看名字应该就能知道其功能了。

#ifdef CONFIG_S3C_GPIO_CFG_S3C64XX
int s3c_gpio_setcfg_s3c64xx_4bit(struct s3c_gpio_chip *chip,
                 unsigned int off, unsigned int cfg)
{
    void __iomem *reg = chip->base;
    unsigned int shift = (off & 7) * 4;
    u32 con;

    if (off < 8 && chip->chip.ngpio > 8)
        reg -= 4;

    if (s3c_gpio_is_cfg_special(cfg)) {
        cfg &= 0xf;
        cfg <<= shift;
    }

    con = __raw_readl(reg);
    con &= ~(0xf << shift);
    con |= cfg;
    __raw_writel(con, reg);

    return 0;
}

  代码逻辑很简单,获取当前bank的控制寄存器的虚拟地址,根据offset计算要控制的引脚在控制寄存器中的起始位,然后将要设置的cfg值写入到控制寄存器,完成工作。不过这里有个宏CONFIG_S3C_GPIO_CFG_S3C64XX,查看相关的Kconfig就可知道,一旦选中s5p相关的平台,那么S3C_GPIO_CFG_S3C64XX这个宏一定会定义。

原文地址:https://www.cnblogs.com/tech-lqh/p/9201718.html

时间: 2024-11-08 09:29:58

LInux-3.0.8中基于S5PV210的GPIO模块代码追踪和分析的相关文章

LInux-3.0.8中基于S5PV210的IRQ模块代码追踪和分析

init/main.c: 1 asmlinkage void start_kernel(void) 2 { 3 ...... 4 early_irq_init(); 5 init_IRQ(); 6 ...... 7 } early_irq_init()函数有两种实现,一种是基于radix tree,一种是定义静态数组,如果要使用radix tree实现的,那么需要打开SPARSE_IRQ配置选项,由于我对数据结构不了解,所以分析以下静态数组实现方式版本的. /kernel/irq/irqdesc

linux ubuntu14.0.4中配置Apache tomcat的方法

首先我们要安装tomcat服务器,首先肯定得装java运行环境jdk,因为tomcat是用java编写的服务器,安装jdk见:http://blog.csdn.net/u013412497/article/details/47000275 安装好jdk后,在官网上下载apache,我下载的是目前的最小版本apache-tomcat-8.0.24.tar.gz,当然高版本是兼容低版本的,如果我们在myeclipse中开发的时候,我们也可以选择比这个低的其他版本. 下载下来后,解压文件.下载的默认地

Web浏览器中动态添加修改HTML页面代码的问题分析

引言:在Web的世界里,浏览器加载页面,展示给用户最终的内容,可是最终展示的HTML代码与服务器上存储的代码一致吗? 1.  xpath为什么不能正常工作? XPath是用来快速定位页面元素的方式和方法,忽然有一天,发现在页面中截取的XPath在代码的匹配中是无法工作的,那问题出在哪里呢? 页面地址:http://www.66ip.cn/ 截取匹配页面中的IP地址,基于Chrome浏览器自带的开发者工具,我们截取到某一个匹配的XPath路径为: //*[@id="main"]/div/

Linux——获取IP及其中发现的问题

由于最近在学习网络编程,喜欢玩弄IP地址. 首先,我需要搞清楚如何获得本机IP. 1.利用Linux系统 在bash中输入ifconfig可获得以下代码: (ev1)[[email protected] bin]# ifconfig lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:16436 Metric:1

Linux 4.0+内核对硬件交换模块的支持(HW Switch Offload)

Linux内核最近跃进到了4.x时代,初看没啥大的动作,但是对于我而言,最令人兴奋的还是它对硬交换模块的支持.这也是为全面迎合SDN做好准备的第一步. Linux上的路由与交换 Linux诞生于网络,天生对网络拥有全面且强大的支持,即便再复杂的协议,再封闭的技术,几乎都可以找到对应的Linux实现.然而这并不是说Linux网络就天下无敌了,它存在很多不合理的地方.       Linux拥有对路由的强大支持,在数据平面,你可以很轻松地实现一种路由查找算法,在控制平面,你也可以在用户态实现任何已有

基于Linux 3.0.8 Samsung FIMC(S5PV210) 的摄像头驱动框架解读

作者:咕唧咕唧liukun321 来自:http://blog.csdn.net/liukun321 FIMC这个名字应该是从S5P100开始出现的,在s5pv210里面的定义是摄像头接口,但是它同样具有图像数据颜色空间转换的作用.而exynos4412对它的定义看起来更清晰些,摄像头接口被定义为FIMC-LITE .颜色空间转换的硬件结构被定义为FIMC-IS.不多说了,我们先来看看Linux3.0.8 三星的BSP包中与fimc驱动相关的文件. 上面的源码文件组成了整个fimc的驱动框架.通

嵌入式Linux学习笔记(基于S5PV210 TQ210)

基于S5PV210.TQ210平台. 本文更多的是教会大家如何学习! 包括如下内容: 1.前言 2.开发环境搭建 3.制作交叉编译器 4.裸机编程 4.1.汇编学习 4.2.S5PV210启动流程 4.3.点亮一个LED 4.4.串口 4.5.实现printf 4.6.时钟配置 4.7.重定位 4.8.DDR 4.9.NAND读写 4.11.LCD操作 5.移植u-boot(基于u-boot-2014.4版本) 5.1.概述 5.2.u-boot配置过程分析 5.3.u-boot编译过程分析 5

《Linux设备驱动开发具体解释(第3版)》(即《Linux设备驱动开发具体解释:基于最新的Linux 4.0内核》)网购链接

<Linux设备驱动开发具体解释:基于最新的Linux 4.0内核> china-pub   spm=a1z10.3-b.w4011-10017777404.30.kvceXB&id=521111707813&rn=4cf013961288ab7c4dfd2016aeb21fa8&abbucket=5">天猫     dangdang   京东 China-pub 8月新书销售榜 推荐序一 技术日新月异,产业斗转星移,滚滚红尘,消逝的事物太多,新事物的诞

《Linux设备驱动开发详解:基于最新的Linux 4.0内核》china-pub预售

<Linux设备驱动开发详解:基于最新的Linux 4.0内核>china-pub今日上线进入预售阶段: http://product.china-pub.com/4733972 推荐序一 技术日新月异,产业斗转星移,滚滚红尘,消逝的事物太多,新事物的诞生也更迅猛.众多新生事物如灿烂烟花,转瞬即逝.当我们仰望星空时,在浩如烟海的专业名词中寻找,赫然发现,Linux的生命力之旺盛顽强,斗志之昂扬雄壮,令人称奇.它正以摧枯拉朽之势迅速占领包括服务器.云计算.消费电子.工业控制.仪器仪表.导航娱乐等