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

[笔记分享] [GPIO] MSM8x39 GPIO 软件部分小结平台:MSM8X39OS:Android4.4Kernel:3.10.28GPIOSW:Overview:在之前的msm8926平台以及以前的平台,GPIO作为一个整体存在,也就是说是一个GPIO子系统,不区分是控制什么功能。而在未来的msm8939/msm8994平台,GPIO模块引起了kernel支持的pinctrl系统。出现pinctrl系统的原因应该是开发者想把GPI

平台: 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 = devm_request_irq(&pdev->dev, irq, msm_tlmm_v4_handle_irq,
                            IRQF_TRIGGER_HIGH,
                            dev_name(&pdev->dev),
                            tlmm_desc);
        if (ret) {
            dev_err(&pdev->dev, "register for irq failed\n");
            return ret;
        }
        tlmm_desc->irq = irq;
    }
    /*和dtsi中的一致,有三个controller info, gpio/sdc/qdsd. pintype_info 就是下面的tlmm_v4_pininfo。 这里获取了三个controller 信息以及数量。 */
    tlmm_desc->pintypes = pinfo->pintype_info;
    tlmm_desc->num_pintypes = pinfo->num_entries;
    /*pinctrl probe滴干活!*/
    return msm_pinctrl_probe(pdev, tlmm_desc);
}
static struct msm_pintype_info tlmm_v4_pininfo[] = {
    {
        .prg_cfg = msm_tlmm_v4_gp_cfg,
        .prg_func = msm_tlmm_v4_gp_fn,
        .set_reg_base = msm_tlmm_v4_gp_set_reg_base,
        .reg_base = NULL,
        .prop_name = "qcom,pin-type-gp",
        .name = "gp",
        .gc = {
                .label        = "msm_tlmm_v4_gpio",
                .direction_input  = msm_tlmm_v4_gp_dir_in,
                .direction_output = msm_tlmm_v4_gp_dir_out,
                .get              = msm_tlmm_v4_gp_get,
                .set              = msm_tlmm_v4_gp_set,
                .to_irq           = msm_tlmm_v4_gp_to_irq,
        },
        .init_irq = msm_tlmm_v4_gp_irq_init,
        .irq_chip = &msm_tlmm_v4_gp_irq,
    },
    {
        .prg_cfg = msm_tlmm_v4_sdc_cfg,
        .set_reg_base = msm_tlmm_v4_sdc_set_reg_base,
        .reg_base = NULL,
        .prop_name = "qcom,pin-type-sdc",
        .name = "sdc",
    },
    {
        .prg_cfg = msm_tlmm_v4_qdsd_cfg,
        .set_reg_base = msm_tlmm_v4_qdsd_set_reg_base,
        .reg_base = NULL,
        .prop_name = "qcom,pin-type-qdsd",
        .name = "qdsd",
    }
};

msm_pinctrl_probe():
[pinctrl-msm.c]

int msm_pinctrl_probe(struct platform_device *pdev,
                    struct msm_tlmm_desc *tlmm_info)
{
    struct msm_pinctrl_dd *dd;
    struct device *dev = &pdev->dev;
    int ret;

    /*分配struct msm_pinctrl_dd */
    dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL);
    if (!dd) {
        dev_err(dev, "Alloction failed for driver data\n");
        return -ENOMEM;
    }
    dd->dev = dev;
    /*tlmm_info的信息再传递给dd.*/
    dd->msm_pintype = tlmm_info->pintypes;
    dd->base = tlmm_info->base;
    dd->irq = tlmm_info->irq;
    dd->num_pintypes = tlmm_info->num_pintypes;
    /*这里去解析DT里的内容了。下面会详细分析。*/
    ret = msm_pinctrl_get_drvdata(dd, pdev);
    if (ret) {
        dev_err(&pdev->dev, "driver data not available\n");
        return ret;
    }
    /*注册gpio chip,跟进去就是gpio subsystem的范畴了。*/
    msm_register_gpiochip(dd);
    /*注册pintrl */
    ret = msm_register_pinctrl(dd);
    if (ret) {
        msm_pinctrl_cleanup_dd(dd);
        return ret;
    }
    /*注册irq chip*/
    msm_register_irqchip(dd);
    platform_set_drvdata(pdev, dd);
    return 0;
}

msm_pinctrl_get_drvdata():

static int msm_pinctrl_get_drvdata(struct msm_pinctrl_dd *dd,
                        struct platform_device *pdev)
{
    int ret;
    struct device_node *node = pdev->dev.of_node;

    /*解析各个controller信息。*/
    ret = msm_pinctrl_dt_parse_pintype(node, dd);
    if (ret)
        goto out;
    /*获取各个pins的信息*/
    ret = msm_pinctrl_dt_parse_pins(node, dd);
    if (ret)
        msm_pinctrl_cleanup_dd(dd);
out:
    return ret;
}

msm_pinctrl_dt_parse_pintype():

static int msm_pinctrl_dt_parse_pintype(struct device_node *dev_node,
                        struct msm_pinctrl_dd *dd)
{
    struct device_node *pt_node;
    struct msm_pindesc *msm_pindesc;
    struct msm_pintype_info *pintype, *pinfo;
    void __iomem **ptype_base;
    u32 num_pins, pinfo_entries, curr_pins;
    int i, ret;
    uint total_pins = 0;

    pinfo = dd->msm_pintype;
    pinfo_entries = dd->num_pintypes;
    curr_pins = 0;
    /*一次遍历解析每个controller.*/
    for_each_child_of_node(dev_node, pt_node) {
        for (i = 0; i < pinfo_entries; i++) {
            pintype = &pinfo[i];
            /* Check if node is pintype node */
            /*只有prop_name的值存在才能继续下一步。
可以看到pintype的值其实是和DT中的值是一致的,
三个都有:qcom,pin-type-gp , qcom,pin-type-sdc , 
qcom,pin-type-qdsd */
            if (!of_find_property(pt_node, pintype->prop_name,
                                    NULL))
                continue;
            /*取出DT 中的controller node.*/
            of_node_get(pt_node);
            pintype->node = pt_node;
            /* determine number of pins of given pin type */
            /*获取当前controller能控制的pin number.*/
            ret = of_property_read_u32(pt_node, "qcom,num-pins",
                                &num_pins);
            if (ret) {
                dev_err(dd->dev, "num pins not specified\n");
                return ret;
            }
            /* determine pin number range for given pin type */
            /*将pin number更新到pintype中。*/
            pintype->num_pins = num_pins;
            /*可以看出controller的end和下个controller的start的pin value是紧挨着的。*/
            pintype->pin_start = curr_pins;
            pintype->pin_end = curr_pins + num_pins;
            ptype_base = &pintype->reg_base;
            /*调用各个controller的set_reg_base, 例如gpio controller对应的是
msm_tlmm_v4_gp_set_reg_base(),将dd->base的值给pintype->reg_base.
前面有:dd->base = tlmm_info->base; */
            pintype->set_reg_base(ptype_base, dd->base);
            total_pins += num_pins;
            curr_pins += num_pins;
        }
    }
    /*又分配一个struct, 它保存了什么信息呢?
你看它分配了total_pins个! 说明肯定用来保存
所有pin的信息了. 可以带着疑问往下看!*/
    dd->msm_pindesc = devm_kzalloc(dd->dev,
                        sizeof(struct msm_pindesc) *
                        total_pins, GFP_KERNEL);
    if (!dd->msm_pindesc) {
        dev_err(dd->dev, "Unable to allocate msm pindesc");
        goto alloc_fail;
    }
    /*所有controller的pin number之和。*/
    dd->num_pins = total_pins;
    msm_pindesc = dd->msm_pindesc;
    /*
     * Populate pin descriptor based on each pin type present in Device
     * tree and supported by the driver
     */
    /*又遍历一遍controller,看它这次需要什么内容.*/
    for (i = 0; i < pinfo_entries; i++) {
        pintype = &pinfo[i];
        /* If entry not in device tree, skip */
        if (!pintype->node)
            continue;
        /*关键的是这一句,看来需要跟进去看看!*/
        msm_populate_pindesc(pintype, msm_pindesc);
    }
    return 0;
alloc_fail:
    for (i = 0; i < pinfo_entries; i++) {
        pintype = &pinfo[i];
        if (pintype->node)
            of_node_put(pintype->node);
    }
    return -ENOMEM;
}

msm_populate_pindesc():

static void msm_populate_pindesc(struct msm_pintype_info *pinfo,
                    struct msm_pindesc *msm_pindesc)
{
    int i;
    struct msm_pindesc *pindesc;

    for (i = 0; i < pinfo->num_pins; i++) {
        /*根据pin_start来获取,前面知道,pin_start是按照pin number的数量计算的, 并且controller之前连续。*/
        pindesc = &msm_pindesc[i + pinfo->pin_start];
        /*保存自己所属的pinfo,也就是对应的controller.*/
        pindesc->pin_info = pinfo;
        /*保存controller的name,并且后面后面-x来表示当前Pin的index, 注意这里的 i不一定正好是GPIO对应的number号。 到这里pindesc的用处验证了我们之前的猜测。*/
        snprintf(pindesc->name, sizeof(pindesc->name),
                    "%s-%d", pinfo->name, i);
    }
}

到这里,各个controller的信息,如base, pin number这些已经有了。
现在应该需要知道各个pin group内部的信息了吧!?
返回上一层到msm_pinctrl_dt_parse_pins().
msm_pinctrl_dt_parse_pins():

static int msm_pinctrl_dt_parse_pins(struct device_node *dev_node,
                        struct msm_pinctrl_dd *dd)
{
    struct device *dev;
    struct device_node *pgrp_np;
    struct msm_pin_grps *pin_grps, *curr_grp;
    struct msm_pmx_funcs *pmx_funcs, *curr_func;
    char *func_name;
    const char *grp_name;
    int ret, i, grp_index = 0, func_index = 0;
    uint pin = 0, *pins, num_grps = 0, num_pins = 0, len = 0;
    uint num_funcs = 0;
    u32 func = 0;

    dev = dd->dev;
    /*遍历msm8939-pinctrl.dtsi中的各个node.*/
    for_each_child_of_node(dev_node, pgrp_np) {
        /*如果有qcom,pins定义,才表明是一个pin group.*/
        if (!of_find_property(pgrp_np, "qcom,pins", NULL))
            continue;
        /*有功能复用的话就加1,像sdc controller就没有这个property.*/
        if (of_find_property(pgrp_np, "qcom,pin-func", NULL))
            num_funcs++;
        num_grps++;
    }
    /*根据num_grps来分配,所以此struct应该是存pin group的信息了.*/
    pin_grps = (struct msm_pin_grps *)devm_kzalloc(dd->dev,
                        sizeof(*pin_grps) * num_grps,
                        GFP_KERNEL);
    if (!pin_grps) {
        dev_err(dev, "Failed to allocate grp desc\n");
        return -ENOMEM;
    }
    /*根据num_funs分配,所以应该是保存功能复现相关信息了。*/
    pmx_funcs = (struct msm_pmx_funcs *)devm_kzalloc(dd->dev,
                        sizeof(*pmx_funcs) * num_funcs,
                        GFP_KERNEL);
    if (!pmx_funcs) {
        dev_err(dev, "Failed to allocate grp desc\n");
        return -ENOMEM;
    }
    /* * Iterate over all child nodes, and for nodes containing pin lists * populate corresponding pin group, and if provided, corresponding * function */
    /*遍历所有node*/
    for_each_child_of_node(dev_node, pgrp_np) {
        /*和之前一样,只遍历pin group node.*/
        if (!of_find_property(pgrp_np, "qcom,pins", NULL))
            continue;
        /*取出一个新的struct.*/
        curr_grp = pin_grps + grp_index;
        /* Get group name from label*/
        /*获取pin group对应的label name.*/
        ret = of_property_read_string(pgrp_np, "label", &grp_name);
        if (ret) {
            dev_err(dev, "Unable to allocate group name\n");
            return ret;
        }
        /*此值表示当前pin group要用到几个pin管脚。*/
        ret = of_property_read_u32(pgrp_np, "qcom,num-grp-pins",
                                &num_pins);
        if (ret) {
            dev_err(dev, "pin count not specified for groups %s\n",
                                grp_name);
            return ret;
        }
        /*我去,又分配了一个struct, 有num_pins,看来准备存 Pin group 中若干个 pin的信息了.*/
        pins = devm_kzalloc(dd->dev, sizeof(unsigned int) * num_pins,
                        GFP_KERNEL);
        if (!pins) {
            dev_err(dev, "Unable to allocte pins for %s\n",
                                grp_name);
            return -ENOMEM;
        }
        /*遍历当前controller所有的pins.*/
        for (i = 0; i < num_pins; i++) {
            /*当前猜测它是读取pin group里的内容,带着疑问一会儿 分析此函数是不是我们想的那样?*/
            ret = msm_of_get_pin(pgrp_np, i, dd, &pin);
            if (ret) {
                dev_err(dev, "Pin grp %s does not have pins\n",
                                grp_name);
                return ret;
            }
            pins[i] = pin;
        }
        /*每个pin group中对应的pin信息保存起来。*/
        curr_grp->pins = pins;
        curr_grp->num_pins = num_pins;
        curr_grp->name = grp_name;
        grp_index++;
        /* Check if func specified */
        /*如果没有复用功能,那就没必要执行下面的code了。*/
        if (!of_find_property(pgrp_np, "qcom,pin-func", NULL))
            continue;
        curr_func = pmx_funcs + func_index;
        len = strlen(grp_name) + strlen("-func") + 1;
        func_name = devm_kzalloc(dev, len, GFP_KERNEL);
        if (!func_name) {
            dev_err(dev, "Cannot allocate func name for grp %s",
                                grp_name);
            return -ENOMEM;
        }
        snprintf(func_name, len, "%s%s", grp_name, "-func");
        /*以grp_name – func的形式保存复用名字*/
        curr_func->name = func_name;
        curr_func->gps = devm_kzalloc(dev, sizeof(char *), GFP_KERNEL);
        if (!curr_func->gps) {
            dev_err(dev, "failed to alloc memory for group list ");
            return -ENOMEM;
        }
        /*读取具体复用值,可从gpio复用列表中查询值对应的具体功能。*/
        of_property_read_u32(pgrp_np, "qcom,pin-func", &func);
        curr_grp->func = func;
        curr_func->gps[0] = grp_name;
        curr_func->num_grps = 1;
        func_index++;
    }
    /*把前面得到的信息都放到dd中管理。*/
    dd->pin_grps = pin_grps;
    dd->num_grps = num_grps;
    dd->pmx_funcs = pmx_funcs;
    dd->num_funcs = num_funcs;
    return 0;
}

到此,msm_pinctrl_get_drvdata()分析完了,即dts解析完毕,下一步应该是注册了,接着看
msm_register_gpiochip():

static void msm_register_gpiochip(struct msm_pinctrl_dd *dd)
{

    struct gpio_chip *gc;
    struct msm_pintype_info *pintype, *pinfo;
    int i, ret = 0;

    pinfo = dd->msm_pintype;
    /*遍历controller.*/
    for (i = 0; i < dd->num_pintypes; i++) {
        pintype = &pinfo[i];
        /*gpio 类型才可以!*/
        if (!msm_pintype_supports_gpio(pintype))
            continue;
        /*填充gpio对应的信息已经函数指针,可以想到,后面在调用的时候会跑到这些函数了。*/
        gc = &pintype->gc;
        gc->request = msm_pinctrl_request_gpio;
        gc->free = msm_pinctrl_free_gpio;
        gc->dev = dd->dev;
        gc->ngpio = pintype->num_pins;
        gc->base = -1;
        /*添加即注册一个gpio chip到系统中。*/
        ret = gpiochip_add(gc);
        if (ret) {
            dev_err(dd->dev, "failed to register gpio chip\n");
            pinfo->supports_gpio = false;
        }
    }
}

/通过DT controller node中的 gpio-controller property来判断。/

static bool msm_pintype_supports_gpio(struct msm_pintype_info *pinfo)
{
    struct device_node *pt_node;

    if (!pinfo->node)
        return false;

    for_each_child_of_node(pinfo->node, pt_node) {
        if (of_find_property(pt_node, "gpio-controller", NULL)) {
            pinfo->gc.of_node = pt_node;
            pinfo->supports_gpio = true;
            return true;
        }
    }
    return false;
}

Gpio注册完之后,后面陆续注册pinctrl和irq.

msm_register_pinctrl():

static int msm_register_pinctrl(struct msm_pinctrl_dd *dd)
{
    int i;
    struct pinctrl_pin_desc *pindesc;
    struct msm_pintype_info *pinfo, *pintype;
    struct pinctrl_desc *ctrl_desc = &dd->pctl;

    /*填充ctrl_desc, 主要是这些函数操作指针,设置的时候会被调用到。*/
    ctrl_desc->name = "msm-pinctrl";
    ctrl_desc->owner = THIS_MODULE;
    ctrl_desc->pmxops = &msm_pmxops;
    ctrl_desc->confops = &msm_pconfops;
    ctrl_desc->pctlops = &msm_pctrlops;

    pindesc = devm_kzalloc(dd->dev, sizeof(*pindesc) * dd->num_pins,
                             GFP_KERNEL);
    if (!pindesc) {
        dev_err(dd->dev, "Failed to allocate pinctrl pin desc\n");
        return -ENOMEM;
    }


    /*保存所有pin的index, name信息。*/
    for (i = 0; i < dd->num_pins; i++) {
        pindesc[i].number = i;
        pindesc[i].name = dd->msm_pindesc[i].name;
    }
    ctrl_desc->pins = pindesc;
    ctrl_desc->npins = dd->num_pins;
    /*注册pinctrl. 后面有时间再分解吧!*/
    dd->pctl_dev = pinctrl_register(ctrl_desc, dd->dev, dd);
    if (!dd->pctl_dev) {
        dev_err(dd->dev, "could not register pinctrl driver\n");
        return -EINVAL;
    }
    /*把各个controller作为一个range来管理。*/
    pinfo = dd->msm_pintype;
    for (i = 0; i < dd->num_pintypes; i++) {
        pintype = &pinfo[i];
        if (!pintype->supports_gpio)
            continue;
        pintype->grange.name = pintype->name;
        pintype->grange.id = i;
        pintype->grange.pin_base = pintype->pin_start;
        pintype->grange.base = pintype->gc.base;
        pintype->grange.npins = pintype->gc.ngpio;
        pintype->grange.gc = &pintype->gc;
        /*添加到gpio range中*/
        pinctrl_add_gpio_range(dd->pctl_dev, &pintype->grange);
    }
    return 0;
}

接口的注册还没叙述,脑细胞死多了,伤不起.
pinctrl_register():

struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
                    struct device *dev, void *driver_data)
{
    struct pinctrl_dev *pctldev;
    int ret;

    if (!pctldesc)
        return NULL;
    if (!pctldesc->name)
        return NULL;

    pctldev = kzalloc(sizeof(*pctldev), GFP_KERNEL);
    if (pctldev == NULL) {
        dev_err(dev, "failed to alloc struct pinctrl_dev\n");
        return NULL;
    }

    /* Initialize pin control device struct */
    pctldev->owner = pctldesc->owner;
    pctldev->desc = pctldesc;
    pctldev->driver_data = driver_data;
    INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL);
    INIT_LIST_HEAD(&pctldev->gpio_ranges);
    pctldev->dev = dev;
    mutex_init(&pctldev->mutex);
    /*一堆检查,不管。*/
    /* check core ops for sanity */
    if (pinctrl_check_ops(pctldev)) {
        dev_err(dev, "pinctrl ops lacks necessary functions\n");
        goto out_err;
    }

    /* If we're implementing pinmuxing, check the ops for sanity */
    if (pctldesc->pmxops) {
        if (pinmux_check_ops(pctldev))
            goto out_err;
    }

    /* If we're implementing pinconfig, check the ops for sanity */
    if (pctldesc->confops) {
        if (pinconf_check_ops(pctldev))
            goto out_err;
    }

    /* Register all the pins */
    dev_dbg(dev, "try to register %d pins ...\n",  pctldesc->npins);
    /*将之前解析到的所有pins加到系统中去*/
    ret = pinctrl_register_pins(pctldev, pctldesc->pins, pctldesc->npins);
    if (ret) {
        dev_err(dev, "error during pin registration\n");
        pinctrl_free_pindescs(pctldev, pctldesc->pins,
                      pctldesc->npins);
        goto out_err;
    }

    mutex_lock(&pinctrldev_list_mutex);
    list_add_tail(&pctldev->node, &pinctrldev_list);
    mutex_unlock(&pinctrldev_list_mutex);
    /*这个函数看似简单,其实内藏玄机,有没有发现pin group里的active/sleep 状态我们到现在还没解析到? 这里其实就是解析state的。 不过在此流程里面,只是解析controller对应的state,DT中没用到, 所以应该查找失败会失败。 各个device的state解析会在内部driver init的 时候来解析。*/
    pctldev->p = pinctrl_get(pctldev->dev);

    if (!IS_ERR(pctldev->p)) {
        pctldev->hog_default =
            pinctrl_lookup_state(pctldev->p, PINCTRL_STATE_DEFAULT);
        if (IS_ERR(pctldev->hog_default)) {
            dev_dbg(dev, "failed to lookup the default state\n");
        } else {
            if (pinctrl_select_state(pctldev->p,
                        pctldev->hog_default))
                dev_err(dev,
                    "failed to select default state\n");
        }

        pctldev->hog_sleep =
            pinctrl_lookup_state(pctldev->p,
                            PINCTRL_STATE_SLEEP);
        if (IS_ERR(pctldev->hog_sleep))
            dev_dbg(dev, "failed to lookup the sleep state\n");
    }
    /*创建debugfs文件。*/
    pinctrl_init_device_debugfs(pctldev);

    return pctldev;

out_err:
    mutex_destroy(&pctldev->mutex);
    kfree(pctldev);
    return NULL;
}

Pinctrl_get()不展开了,也是一般解析DT的方法,这里给出过程:
这里写图片描述

还剩一个irq注册没讲。
msm_register_irqchip():

static int msm_register_irqchip(struct msm_pinctrl_dd *dd)
{
    struct msm_pintype_info *pintype, *pinfo;
    int i, ret = 0;

    pinfo = dd->msm_pintype;
    for (i = 0; i < dd->num_pintypes; i++) {
        pintype = &pinfo[i];
        if (!msm_pintype_supports_irq(pintype))
            continue;
        /*调用的是gpio controller 的init_irq函数指针,即msm_tlmm_v4_gp_irq_init()*/
ret = pintype->init_irq(dd->irq, pintype, dd->dev);
        return ret;
    }
    return 0;
}

msm_tlmm_v4_gp_irq_init():
这个函数大家应该都能看懂了,不想码字了…

static int msm_tlmm_v4_gp_irq_init(int irq, struct msm_pintype_info *pinfo,
                        struct device *tlmm_dev)
{
    int num_irqs;
    struct msm_tlmm_irq_chip *ic = pinfo->irq_chip;

    if (!ic->domain)
        return 0;

    num_irqs = ic->num_irqs;
    ic->enabled_irqs = devm_kzalloc(tlmm_dev, sizeof(unsigned long)
                    * BITS_TO_LONGS(num_irqs), GFP_KERNEL);
    if (IS_ERR(ic->enabled_irqs)) {
        dev_err(tlmm_dev, "Unable to allocate enabled irqs bitmap\n");
        return PTR_ERR(ic->enabled_irqs);
    }
    ic->dual_edge_irqs = devm_kzalloc(tlmm_dev, sizeof(unsigned long)
                    * BITS_TO_LONGS(num_irqs), GFP_KERNEL);
    if (IS_ERR(ic->dual_edge_irqs)) {
        dev_err(tlmm_dev, "Unable to allocate dual edge irqs bitmap\n");
        return PTR_ERR(ic->dual_edge_irqs);
    }
    ic->wake_irqs = devm_kzalloc(tlmm_dev, sizeof(unsigned long)
                    * BITS_TO_LONGS(num_irqs), GFP_KERNEL);
    if (IS_ERR(ic->wake_irqs)) {
        dev_err(tlmm_dev, "Unable to allocate wake irqs bitmap\n");
        return PTR_ERR(ic->wake_irqs);
    }
    spin_lock_init(&ic->irq_lock);
    ic->chip_base = pinfo->reg_base;
    ic->irq = irq;
    ic->dev = tlmm_dev;
    ic->num_irqs = pinfo->num_pins;
    ic->pinfo = pinfo;
    register_syscore_ops(&msm_tlmm_v4_irq_syscore_ops);
    return 0;
}

虽然定义了好多的struct,不过分析完code之后,就可以很清楚的知道他们分别是用来干什么的,不像一开始上来云里雾里的。

接口使用:

Active/sleep状态设置:
对应pinctrl,重要而且常用的有如下几个接口:
 devm_pinctrl_get():
获取对应的pinctrl,你可以认为是拿到DT对应node中信息。
 pinctrl_lookup_state():
获取对应pinctrl state,其实就是获取自己在node中配置的actvie/sleep state.
 pinctrl_select_state():
根据active/sleep的信息设置为对应的state。

上面三个函数其实是取代了之前board-xxxx-gpiomux.c的设置active/sleep方法。

GPIO配置:
GPIO对外的接口基本上没变化,差异在内部通过调用pinctrl系统的API实现。
那gpio_direction_input()举例,现在的调用过程变成:
这里写图片描述
其他接口类似。


参考文档:

80-NL239-47_A_MSM8916_APSS_GPIO_Pin_Control_SW.pdf

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/37756.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注