Pinctrl 官方kernel文档翻译

PINCTRL 子系统

这个文档概述了Linux的Pin control子系统

这个子系统处理以下事情:

  1. 枚举和命名Pins
  2. Pins、pads、fingers等的复用,详情请见下文
  3. Pins、pads、finger等的电气配置,例如上下拉、开漏等

 

Top-level interface

===================

  • PIN CONTROLLER的定义:

Pin controller是一个硬件,通常是一组用来控制pins的寄存器。

它们可以用来为一个pins或一组pins配置复用、偏置、下上拉等。

  • PIN的定义

PINS就是pads、fingers等一切你想要控制的input/output line。PINS用一个从0-maxpins的整数表示。

这个number space(0-maxpins)取决于PIN CONTROLLER,所以在一个系统里可能有多个number space。

这个pin space不一定是连续的,它们中间可能有一些pin是不存在的。

 

当一个PIN CONTROLLER被实例化之后,它将注册一个descriptor(描述符)到pin control 框架中,

这个PIN CONTROLLER描述符包含一组pin描述符,这些pin描述符由这个pin controller处理。

 

下面是一个芯片的例子:

想要注册一个pin controller并且命名这个芯片上的所有pin,我们可以在驱动中这样写:

#include <linux/pinctrl/pinctrl.h>



const struct pinctrl_pin_desc foo_pins[] = {

      PINCTRL_PIN(0, "A8"),

      PINCTRL_PIN(1, "B8"),

      PINCTRL_PIN(2, "C8"),

      ...

      PINCTRL_PIN(61, "F1"),

      PINCTRL_PIN(62, "G1"),

      PINCTRL_PIN(63, "H1"),

};



static struct pinctrl_desc foo_desc = {

    .name = "foo",

    .pins = foo_pins,

    .npins = ARRAY_SIZE(foo_pins),

    .owner = THIS_MODULE,

};



int __init foo_probe(void)

{

    int error;



    struct pinctrl_dev *pctl;



    error = pinctrl_register_and_init(&foo_desc, <PARENT>, NULL, &pctl);

    if (error)

        return error;



    return pinctrl_enable(pctl);

}

 

想要启用pinctrl子系统、PINMUX和PINCONF的subgroups以及选定的驱动,

你需要在你的芯片的Kconfig条目中选择他们,因为他们通常是与你的芯片紧密联系的。

可以看看arch/arm/mach-u300/Kconfig作为例子。

pins name通常和上面描述的有所不同,你可以在芯片的datasheet中找到它们。

注意,pinctrl core中的pinctrl.h提供一个叫做PINCTRL_PIN()的宏用于创建pinctrl_pin_desc结构体。

你可以看到我用0~63枚举了从A8到H1的所有引脚。在实际使用中,你必须考虑这些数字所代表的pin,

使它们可以与你所用的芯片的寄存器布局相符合,否则代码会变得很复杂。

你还需要考虑offset是否和pin controller所控制的GPIO ranges符合。

 

 

Pin groups

==========

一些控制器需要处理一组pins,所以pin controller提供一个用于枚举和检索一组pin的机制。

以一组用于SPI的pins{0,8,16,24},和一组用于I2C的pin{24,25}作为例子。

这两组pin可以在pin controller中通过实例化一个 pinctrl_ops来表示:

 

#include <linux/pinctrl/pinctrl.h>

 

struct foo_group {

    const char *name;

    const unsigned int *pins;

    const unsigned num_pins;

};

 

static const unsigned int spi0_pins[] = { 0, 8, 16, 24 };

static const unsigned int i2c0_pins[] = { 24, 25 };

 

static const struct foo_group foo_groups[] = {

    {

       .name = "spi0_grp",

       .pins = spi0_pins,

       .num_pins = ARRAY_SIZE(spi0_pins),

    },

    {

       .name = "i2c0_grp",

       .pins = i2c0_pins,

       .num_pins = ARRAY_SIZE(i2c0_pins),

    },

};

 

 

static int foo_get_groups_count(struct pinctrl_dev *pctldev)

{

    return ARRAY_SIZE(foo_groups);

}

 

static const char *foo_get_group_name(struct pinctrl_dev *pctldev,

                     unsigned selector)

{

    return foo_groups[selector].name;

}

 

static int foo_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,

                  const unsigned **pins,

                  unsigned *num_pins)

{

    *pins = (unsigned *) foo_groups[selector].pins;

    *num_pins = foo_groups[selector].num_pins;

    return 0;

}

 

static struct pinctrl_ops foo_pctrl_ops = {

    .get_groups_count = foo_get_groups_count,

    .get_group_name = foo_get_group_name,

    .get_group_pins = foo_get_group_pins,

};

 

 

static struct pinctrl_desc foo_desc = {

       ...

       .pctlops = &foo_pctrl_ops,

};

 

Pin controller 子系统可以通过调用. get_groups_count()函数来获取group的数量,然后pin controller就可以通过调用foo_get_group_name()和foo_get_group_pins()来获取相应group的名字和其包含的pins。实际group的数据结构取决于驱动,这仅仅是个简单的例子。

 

Pin configuration

=================

Pin可以通过多种方式进行配置,大部分是作为inputs和outputs时的电气特性。举个例子,你想要配置某个pin为高阻抗,或是你想要用将一个pin配置为上/下拉。

可以通过添加条目到映射表来进行配置pin configuration,详情请见以下Board/machine configuration的部分。

配置参数的格式和含义,是由pin controller驱动定义的。例如PLATFORM_X_PULL_UP

Pin configuration驱动在pin controller中实现了设置引脚配置的回调函数:

 

#include <linux/pinctrl/pinctrl.h>

#include <linux/pinctrl/pinconf.h>

#include "platform_x_pindefs.h"

 

static int foo_pin_config_get(struct pinctrl_dev *pctldev,

           unsigned offset,

           unsigned long *config)

{

    struct my_conftype conf;

 

    ... Find setting for pin @ offset ...

 

    *config = (unsigned long) conf;

}

 

static int foo_pin_config_set(struct pinctrl_dev *pctldev,

           unsigned offset,

           unsigned long config)

{

    struct my_conftype *conf = (struct my_conftype *) config;

 

    switch (conf) {

       case PLATFORM_X_PULL_UP:

       ...

       }

    }

}

 

static int foo_pin_config_group_get (struct pinctrl_dev *pctldev,

           unsigned selector,

           unsigned long *config)

{

    ...

}

 

static int foo_pin_config_group_set (struct pinctrl_dev *pctldev,

           unsigned selector,

           unsigned long config)

{

    ...

}

 

static struct pinconf_ops foo_pconf_ops = {

    .pin_config_get = foo_pin_config_get,

    .pin_config_set = foo_pin_config_set,

    .pin_config_group_get = foo_pin_config_group_get,

    .pin_config_group_set = foo_pin_config_group_set,

};

 

/* Pin config operations are handled by some pin controller */

static struct pinctrl_desc foo_desc = {

    ...

    .confops = &foo_pconf_ops,

};

 

因为有些芯片有配置一整组pin的特殊逻辑,则它们可以通过特殊的回调函数来配置一整组pin。

对于其不想处理的组,pin_config_group_set()函数可以返回错误-EAGAIN。或者其只想做些组级的处理,

然后迭代处理所有的pin,这种情况下每个pin可以通过单独调用pin_config_set()进行配置。

 

与GPIO subsystem的协同作用

===================================

GPIO驱动可能需要在同一个pin上执行多种操作,并且这个pin已经在pin controller中注册。

首先最重要的,这两个子系统

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值