[笔记分享] [GPIO] MSM8x39 GPIO 软件部分小结

平台: MSM8X39
OS: Android4.4
Kernel: 3.10.28

GPIO SW:

Overview:

在之前的msm8926平台以及以前的平台 ,GPIO 作为一个整体存在,也就是说是一个GPIO子系统,不区分是控制什么功能。而在未来的msm8939/msm8994平台,GPIO模块引起了kernel支持的pinctrl系统。

出现pinctrl系统的原因应该是开发者想把GPIO里的内部功能给区分开来。
从硬件上来说,原有GPIO模块的功能可分为三大类:
1. 和IO端口本身的功能设定有关,称作pin controller. 通过设定它可以实现:
a. 引脚功能配置。 如是普通GPIO还是特殊功能pin。
b. 引脚特性配置。 如pull up/down, driver-strength设定。
2. 如果被配置成特殊功能如I2C, 那么pin就被连接到I2C controller。 如果被配置成 GPIO, 那么被连接到GPIO controller。在此情况下,可以配置GPIO controller:
a. 配置GPIO方向。
b. 如果是输出,可以配置高低电平。
c. 如果是输入,可获取GPIO电平状态。
3. 如果GPIO具有中断功能,那就可以被连接到interrupt controller block. 在此情况下可以配置:
a. 中断使能
b. 触发方式

因此,从SW层面上来说,GPIO模块就被划分成了pinctrl subsystem, gpio subsystem以及interrupt subsystem.另外,pinctrl subsystem 的存在也是为了将一些common的内容给抽象出来。

按照上述的理论,在我们脑中的框图应该是这样子:

这里写图片描述
GPIO和其他的复用功能并列存在,然后通过multiplexer来选择其中一个,pinctrl HW block单独控制pull up/down以及driver-strength.
事实上,在看过code之后,你会发现并非你想得那么理想,真实框图是这样:
这里写图片描述

也就是说GPIO的控制要经过pinctrl模块。具体的接口后面再描述。
基于此原因,gpio/pinctrl的初始化也是同时进行的了,gpio subsystem有兴趣可自行研究,后面描述此模块时只说到注册为止。

Pinctrl subsystem:

Overview:

再细分pinctrl主要完成的功能:
1. 管理系统中所有pins,后面会讲述系统如何初始化。
2. 管理pin的复用。
3. 配置pin的driver-strength , pull up/down.

由于pin相关的初始化定义/配置/状态都从 board-xxx-gpiomux.c中挪到Device
Tree,所以在看下面章节内容的前提是你知道device tree的语法。

device tree:

控制gpio的DT文件是msm8939-pinctrl.dtsi, 主要包含三部分内容:
1. Pinctrl 自身配置。
2. 各个controller设置。
3. 各个controller下面的pin设置。

Pinctrl配置:
这里写图片描述

Compatible用于和driver匹配。 Reg和interrupts就是之前.c文件中的
IORESOURCE_MEM和 IORESOURCE_IRQ 这两个资源。 表示memory是起始地址范围以及IRQ号。

各个controller设置:
Msm8939上有三个相关controller:
主要定义了pin的 type, nums, cells, gpio controller还定义了interrupt相关的内容。
 GPIO controller:

这里写图片描述
 SDC controller:
这里写图片描述

 QDSD controller: (trace)
这里写图片描述

Pin配置:
相关的配置是: gpio number, 用的是哪个function, active/sleep状态及对应的Pull up/down, drive-strength.
这里写图片描述

初始化:
可以想到,pinctrl subsystem 的一个主要任务就是将前面的msm8939-pinctrl.dtsi里的内容全部解析出来,以备后面使用。
另外一部分内容就是,初始化一些pinctrl接口供其他driver调用(系统其实是通过GPIO接口来设置pin)。
之前说过,由于GPIO通过pinctrl调用实现,所以这里也会提到gpio的枚举以及初始化相关接口。
我们就带着这些猜测直接看source code吧!

Note: 一般描述source code基本上会讲一些关键结构,然后再跟source code, 鄙人觉得有利也有弊,弊处是: 当第一次看到这些描述时,听得让人云里雾里。
所以本次想反其道而行之,先看source code,之后再回过来看下这些关键结构,就会让你觉得just so so…

根据设备匹配模型以及DT的compatible property 找到对应使用的文件入口是pinctrl-msm-tlmm-v4.c。
msm_tlmm_v4_probe():

[msm8939-pinctrl.dtsi]
    tlmm_pinmux: pinctrl@1000000 {
        compatible = "qcom,msm-tlmm-v4";
        reg = <0x1000000 0x300000>;
        interrupts = <0 208 0>;
…
};

[pinctrl-msm-tlmm-v4.c]

static struct platform_driver msm_tlmm_v4_drv = {
    .probe      = msm_tlmm_v4_probe,
    .driver = {
        /* 通过此元素来匹配*/
        .name   = "msm-tlmmv4-pinctrl",
        .owner  = THIS_MODULE,
        .of_match_table = of_match_ptr(msm_tlmm_v4_dt_match),
    },
};

struct msm_tlmm_pintype tlmm_v4_pintypes = {
    .num_entries = ARRAY_SIZE(tlmm_v4_pininfo),
    .pintype_info = tlmm_v4_pininfo,
};

static const struct of_device_id msm_tlmm_v4_dt_match[] = {
    { .compatible = "qcom,msm-tlmm-v4",
        .data = &tlmm_v4_pintypes, },
    {},
};

匹配成功调用后msm_tlmm_v4_probe():

static int msm_tlmm_v4_probe(struct platform_device *pdev)
{
    const struct of_device_id *match;
    const struct msm_tlmm_pintype *pinfo;
    struct msm_tlmm_desc *tlmm_desc;
    int irq, ret;
    struct resource *res;
    struct device_node *node = pdev->dev.of_node;

    /*取出msm_tlmm_v4_dt_match,主要是里面的data。 */
    match = of_match_node(msm_tlmm_v4_dt_match, node);
    if (IS_ERR(match))
        return PTR_ERR(match);
    pinfo = match->data;
    tlmm_desc = devm_kzalloc(&pdev->dev, sizeof(*tlmm_desc), GFP_KERNEL);
    if (!tlmm_desc) {
        dev_err(&pdev->dev, "Alloction failed for tlmm desc\n");
        return -ENOMEM;
    }
    /*获取IORESOURCE_MEM ,也就是dtsi中的interrupts = <0 208 0>; */
    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    if (!res) {
        dev_err(&pdev->dev, "cannot find IO resource\n");
        return -ENOENT;
    }
    tlmm_desc->base = devm_ioremap(&pdev->dev, res->start,
                            resource_size(res));
    if (IS_ERR(tlmm_desc->base))
        return PTR_ERR(tlmm_desc->base);
    tlmm_desc->irq = -EINVAL;
/*获取IORESOURCE_IRQ ,也就是dtsi中的reg = <0x1000000 0x300000>;*/
    res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
    if (res) {
        irq = res->start;
        ret =
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值