pinctrl 子系统

    分析总结 pinctrl 子系统框架结构,平台 mtk6771 内核版本 kernel-4.4 , 本文所有的分析均基于此版本。

一、pinctrl 子系统基本概念

     引脚控制子系统(pin control subsystem),和设备模型一样是linux驱动最基础的系统之一。 对于一块 soc 的 cpu 上有很多引脚,驱动工程师需要根据其应用场景使其处于我们需要的状态,例如配置某个引脚为 gpio 或者 配置其为 i2c。对于不同的 cpu 其寄存器的地址往往是不一样的,比如 S3C2440 的 gpio 控制器的基地址为 0x53000000,而 mtk 的 gpio 地址为 0x10005000,而且寄存器的地址的位也表示不同的含义,而内核为了兼容不同的芯片于是创建出 pinctrl 子系统,该系统用于将板级信息从内核分离出来,对于真正的寄存器的操作,由 soc 厂家来完成(bsp工程师),而对于普通的驱动工程师来讲,我们调用内核给出的统一接口来设置对应的pin脚就行了。

1、pinctrl_dev

    该结构是 pinctrl 子系统的核心结构,每一个 soc 都需要向内核注册一个 pinctrl_dev 来描述该 pinctl 子系统,它包含下面几部分内容。

  1. 注册到该子系统的 soc 的引脚控制器 pinctrl_desc
  2. 注册到该子系统的 pin 脚 pin_desc_tree
  3. 注册到该子系统的 pin 脚对应的 gpio_rang
  4. 注册到该子系统的 私有数据
  5. soc 的 pin 脚的默认状态以及,板子休眠时 pin 脚的状态,我看了一下 mtk 平台好像并没有用到这部分功能,不知道其他平台有没有用到这个功能。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct pinctrl_dev {
struct list_head node; // 挂接到全局 pinctrldev_list
struct pinctrl_desc *desc; // 引脚控制器描述符
struct radix_tree_root pin_desc_tree; // 用于挂接所有注册到该设备的 pin 脚,注册的 pin 脚由
struct list_head gpio_ranges; // 用于挂接 gpio_range
struct device *dev; // 设备模型中的设备
struct module *owner;
void *driver_data; // 私有数据
struct pinctrl *p; // 当前设备的 pinctrl ,用于管理整个 soc 板子的 pin 脚状态。
struct pinctrl_state *hog_default; // 板子默认的 pin 脚状态
struct pinctrl_state *hog_sleep; // 板子休眠时的 pin 脚状态
struct mutex mutex;
#ifdef CONFIG_DEBUG_FS
struct dentry *device_root;
#endif
};

2、pinctrl_desc

    pinctrl_desc 表示引脚控制器,它是软件上抽象出来的概念,抽象这个结构是为了方便代码的编写,实际硬件并不存在这样的控制器,该结构描述对 pin 脚寄存器真正的操作接口,该接口通常由 soc 厂完成,一般情况一个 soc 只有一个 pinctrl_desc 结构,它包含了下面内容。

  1. soc 要处理的所有引脚的软件描述
  2. 获取每个(组)引脚的 pin 脚信息的操作接口 pctlops
  3. 每个(组)引脚的复用(pinmux)操作接口 pmxops
  4. 每个(组)引脚的电器特性(pinconfig)操作接口 confops
  5. 支持客制化的 pinconfig
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 引脚控制器描述符,将其注册到引脚控制子系统
struct pinctrl_desc {
const char *name; // 引脚控制器的名称
const struct pinctrl_pin_desc *pins; // 引脚描述符数组,描述此引脚控制器处理的所有引脚
unsigned int npins; // 数组中描述符的数量,通常只是上面的 pin 字段的 ARRAY_SIZE()
const struct pinctrl_ops *pctlops; // 用于获取pin group 信息以及将设备树中的引脚配置(引脚复用以及pinconfig)转换为对应的 pinctrl_map
const struct pinmux_ops *pmxops; // pin 复用相关操作,以 group 为单位进行操作
const struct pinconf_ops *confops; // 配饰 pin 的 pinconfg(上拉、下拉、输出方式等),以 pin 或 group 为操作对象
struct module *owner; // 提供引脚控制器的模块,用于重新计数
#ifdef CONFIG_GENERIC_PINCONF
unsigned int num_custom_params; // 客制化引脚支持的 pinconfig 的数量
const struct pinconf_generic_params *custom_params; // 客制化引脚支持的 pinconfig
const struct pin_config_item *custom_conf_items; // 有关如何在 debugfs 中打印 @params 的信息,必须与 @custom_params 大小相同,即 @num_custom_params
#endif
};

1) pinctrl_pin_desc

     soc上有大量引脚,每一个引脚使用 pinctrl_pin_desc 来描述

1
2
3
4
5
6
//内核中用其描述 pin 的信息
struct pinctrl_pin_desc {
unsigned number; // pin 引脚号
const char *name; // 此引脚的名称,将用来初始化 pin_desc 的 name,如果为空将使用 PIN + number 例如:PIN0
void *drv_data; // 私有数据
};

2) pinctrl_ops

    对于引脚的使用,有时候一次性会使用到多个引脚,I2C接口会同时使用 2 个引脚,SPI 接口会同时使用 4 个引脚。需要以 group 为单位,访问控制多个 pin,这就是 pin groups。但是 mtk 平台采取的策略则是每一个 pin 就是一个 group。,而 pinctrl_ops 则用于获取对应 group 的 pin 脚信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
struct pinctrl_ops {
// 获取 pin group 的数量,对于mtk平台这里就是 pin 脚的数量
int (*get_groups_count) (struct pinctrl_dev *pctldev);

// 获取使用 selector 作为数组下标指定 group 的名称
const char *(*get_group_name) (struct pinctrl_dev *pctldev, unsigned selector);

// 获取 selector 作为数组下标返回指定 group 所用到的 pins 以及 pin 的数量 num_pins,由于mtk 平台采一个 pin 就是一个 group,因此这里固定返回 1.
int (*get_group_pins) (struct pinctrl_dev *pctldev, unsigned selector, const unsigned **pins, unsigned *num_pins);

// debug 相关
void (*pin_dbg_show) (struct pinctrl_dev *pctldev, struct seq_file *s, unsigned offset);

// 用于将设备树中的引脚配置转换为对应的 pinctrl_map
int (*dt_node_to_map) (struct pinctrl_dev *pctldev, struct device_node *np_config, struct pinctrl_map **map, unsigned *num_maps);

// 用于释放前面创建的 pinctrl_map
void (*dt_free_map) (struct pinctrl_dev *pctldev, struct pinctrl_map *map, unsigned num_maps);
};

    需要注意的是该接口除了能够获取 pin group 信息之外,还有一个非常重要的回调接口 dt_node_to_map ,用于将设备树中的引脚配置转换为对应的 pinctrl_map。 该接口的实现通常由soc原厂实现。

3) pinmux

    pinmux 表示引脚复,用这个概念就不做解释了。需要注意的是引脚复用和引脚的电器特性(pinconfig)并不是相同的概念, pinctrl子系统中引脚的复用类型用 func 来描述,例如,某 pin 可以复用为 i2c 也可复用为 spi,那么这个引脚则拥有两个 func。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
struct pinmux_ops {

// 检查某个 pin 是否已作它用,用于管脚复用时的互斥(避免多个功能同时使用某个 pin 而不知道,导致奇怪的错误)。
int (*request) (struct pinctrl_dev *pctldev, unsigned offset);

int (*free) (struct pinctrl_dev *pctldev, unsigned offset);

// 返回板子 functions 支持的引脚复用的类型的总数,spi0、i2c0、mmc0 这三种类型则应该返回 3
int (*get_functions_count) (struct pinctrl_dev *pctldev);

// 通过数组下标 selector 返回 functions 数组中对应的引脚复用为什么功能
const char *(*get_function_name) (struct pinctrl_dev *pctldev, unsigned selector);

// 返回 selector 表示的复用功能有哪些 group, 例如:当 selector 表示的复用功能为 i2c 的数组下标时,可能返回 "i2c-0","i2c-1",num_groups = 2.
int (*get_function_groups) (struct pinctrl_dev *pctldev, unsigned selector, const char * const **groups, unsigned *num_groups);

// 设置 group 为 func_selector 表示的复用功能
int (*set_mux) (struct pinctrl_dev *pctldev, unsigned func_selector, unsigned group_selector);

// 下面是gpio相关
int (*gpio_request_enable) (struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset);
void (*gpio_disable_free) (struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset);
int (*gpio_set_direction) (struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset, bool input);

bool strict;
};

4) pinconf_ops

    对于每一个引脚都有其特定的电器特性,如上拉、下拉、三态、强推挽输出等用 pinconfig 来描述,pinctrl子系统同样也给出了电器特性的操作函数回调接口。对于电器特性的操作既可以操作一个引脚,也可以操作一组引脚。对于 mtk 平台每个 pin 都是一个 group,因此只用到了 pin_config_group_get 和 pin_config_group_set 接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
struct pinconf_ops {
#ifdef CONFIG_GENERIC_PINCONF
bool is_generic;
#endif
//获取一个引脚的 pinconfig
int (*pin_config_get) (struct pinctrl_dev *pctldev, unsigned pin, unsigned long *config);

//设置一个引脚的 pinconfig
int (*pin_config_set) (struct pinctrl_dev *pctldev, unsigned pin, unsigned long *configs, unsigned num_configs);

//获取一个 group 描述的 pin 的 pinconfig
int (*pin_config_group_get) (struct pinctrl_dev *pctldev, unsigned selector, unsigned long *config);

//设置一个 group 描述的 pin 的 pinconfig
int (*pin_config_group_set) (struct pinctrl_dev *pctldev, unsigned selector, unsigned long *configs, unsigned num_configs);

//后面这写接口基本用不着,debug相关接口
int (*pin_config_dbg_parse_modify) (struct pinctrl_dev *pctldev, const char *arg, unsigned long *config);
void (*pin_config_dbg_show) (struct pinctrl_dev *pctldev, struct seq_file *s, unsigned offset);
void (*pin_config_group_dbg_show) (struct pinctrl_dev *pctldev, struct seq_file *s, unsigned selector);
void (*pin_config_config_dbg_show) (struct pinctrl_dev *pctldev, struct seq_file *s, unsigned long config);
};

3、pinctrl

    对于不同的设备的引脚状态统一由属于该设备的 pinctrl 统一管理。也就是说每一个设备都有一个属于自己的 pinctrl ,该 pinctrl 管理着该设备的 pinctrl_state。相关结构如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
struct pinctrl {
struct list_head node; // 挂接到全局的 pinctrl_list
struct device *dev; // 表示所属的 dev
struct list_head states; // 挂接该 pinctrl 所有的 state
struct pinctrl_state *state;
struct list_head dt_maps; // 用来挂接 pinctrl_dt_map ,该结构管理着 pinctrl 下所有的 pinctrl_map
struct kref users;
};

// 每个设备中都有自己的 pin_info
struct device {
...
#ifdef CONFIG_PINCTRL
struct dev_pin_info *pins;
#endif
...
}

struct dev_pin_info {
struct pinctrl *p; //每个创建的设备中的 pinctrl

//默认的 state
struct pinctrl_state *default_state;
struct pinctrl_state *init_state;
#ifdef CONFIG_PM
struct pinctrl_state *sleep_state;
struct pinctrl_state *idle_state;
#endif
};

1) pinctrl_state

用于描述设备上的 pin 脚所处的状态,一个设备上的 pin 脚可以有多种状态。

1
2
3
4
5
struct pinctrl_state {
struct list_head node; // 挂接到所属的 pinctrl
const char *name; // 对应的 pinctrl_map 的 name
struct list_head settings; // 挂接该 state 下所有的 setting
};

每一个 pin 脚有两个状态, 引脚复用(pinmux),和引脚状态(pinconfig),这两种状态由 pinctrl_setting 来描述。

2) pinctrl_setting

    一个 pinctrl_setting 只能表示一个引脚复用(pinmux)或者一组电器特性(pinconfig),通过 pinctrl_map_type 来区分当前的 pinctrl_setting 是描述 pinmux 还是描述 pinconfig,如果 pinctrl_map_type 为 PIN_MAP_TYPE_MUX_GROUP 表示该 setting 或 pinctrl_map 为引脚复用,如果为 PIN_MAP_TYPE_CONFIGS_GROUP 则表示 setting 或 pinctrl_map 为 pinconfig。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
struct pinctrl_setting {
struct list_head node; // 挂接到所属的 state
enum pinctrl_map_type type; // 该 setting 的 pinctrl_map 的类型
struct pinctrl_dev *pctldev; // 该 pinctrl_map 所属的 pinctrl_dev
const char *dev_name; // 被设置为 pinctrl_map->dev_name
union {
struct pinctrl_setting_mux mux; //如果 type 为 PIN_MAP_TYPE_MUX_GROUP 则使用这个结构来保存引脚复用相关参数
struct pinctrl_setting_configs configs; //如果 type 为 PIN_MAP_TYPE_CONFIGS_PIN 或者 PIN_MAP_TYPE_CONFIGS_GROUP 则使用这个结构来保存引脚电器特性相关参数
} data;
};

struct pinctrl_setting_mux {
unsigned group; // 要用到的 pin group 的数组下标
unsigned func; // 要用到的 func 的数组下标
};

struct pinctrl_setting_configs {
unsigned group_or_pin; // 要配置的 pin 或者 pin group 的数组下标
unsigned long *configs; // 对应的 pinconfig,具体的含义由 soc 原厂定义
unsigned num_configs; // config 数量
};

不过这个结构需要通过中间结构 pinctrl_map 转化而来,这个结构又通过 dts 配置的引脚参数创建而来。

3) pinctrl_map

该结构也是提供对应的索引,不过它提供的索引是以字符串的形式提供的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
struct pinctrl_map { //三个 name 都是在 pinctrl_dt_to_map 函数获取,在 dt_remember_or_free_map 函数进行初始化。
const char *dev_name; // 所属 pinctrl 的 name
const char *name; // 设备树中的 pinctrl-names 的属性值

// 当前 pinctrl_map 所属的类别,一般用到的有两大类,复用(mux) 和 pinconfig,
// 当使用 mux 时使用 pinctrl_map_mux,而 pinconfig 则使用 pinctrl_map_configs
enum pinctrl_map_type type;

const char *ctrl_dev_name; // 所属的 pinctrl_dev 的 name
union {
struct pinctrl_map_mux mux; // 当 type 为 PIN_MAP_TYPE_MUX_GROUP 则使用这个
struct pinctrl_map_configs configs; // 当 type为 IN_MAP_TYPE_CONFIGS_PIN、PIN_MAP_TYPE_CONFIGS_GROUP 使用这个
} data;
};

struct pinctrl_map_mux {
const char *group; //具体用到的group,例如:i2c0 有 "i2c0_grp1"、"i2c0_grp1",如果使用 "i2c0_grp1" 这组,则 group = "i2c0_grp1"
const char *function; //要用到的复用功能,例如: i2c0、i2c1、spi1 等
};

struct pinctrl_map_configs {
const char *group_or_pin; // 该 pin 或者pin group的名字
unsigned long *configs; // 要设置的 pinconfig 数组首地址
unsigned num_configs; // 数组大小
};

二、mtk 平台寄存器的表示方式

如下图所示,mtk 平台的寄存器在内核中的数据组织方式如下所示:

mtk 平台寄存器的表示方式

三、pinctrl 子系统的系统框架

1、框架接口

    pinctrl 子系统提供的服务并不复杂,主要提供了以下两个服务,向驱动工程师提供操作 pin 的接口也就是具体的设备要使用的接口,向 bsp 工程师提供对应的寄存器操作的接口。

pinctrl 子系统的系统框架

2、内部实现

    pinctrl 子系统提供的服务接口很简单,但它的内部实现还是有点复杂的。内核驱动都是基于设备模型来开发的,因此对引脚的操作都是基于设备来讲的。对于一个设备首先要做的就是配置其需要使用到的软硬件资源,当然其中就包括 pin 脚资源。而 pinctrl 子系统则需要解析处理我们配置的 pin 脚资源。当我们配置设备的引脚资源后 pinctrl 会在合适的时机来解析我们配置的引脚资源,什么时机是最合适的呢,显而易见设备和驱动匹配的时候。因为设备资源最终的使用者是驱动,当驱动匹配到设备的时候也就是要使用该资源的时候。当完成对资源的解析,我们只需要调用简单的接口就能使我们的设备上的 pin 脚处于我们需要的状态。

1) 配置设备的引脚资源

     配置引脚资源有两种方式首先是使用设备树,这也是目前主流的方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
lcm_dev: lcm {
pinctrl-names = "lcm_1v8_en_low" , "lcm_1v8_en_high"; //对应的 pinctrl_state 的 name

pinctrl-0 = <&gpio_lcm_pwr1v8_low>; //----这是一个 pinctrl_state
pinctrl-1 = <&gpio_lcm_pwr1v8_high>; //----这是一个 pinctrl_state
status = "okay";
};

&pio {

gpio_lcm_pwr1v8_low: gpio_lcm_pwr1v8_low { //----这是一组 pinctrl_map
pins_cmd_dat {
pinmux = <PINMUX_GPIO5__FUNC_GPIO5>; //这被解析 pinctrl_map->data->mux
slew-rate = <1>; //这两个被解析到pinctrl_map->data->configs
output-low;
}; //于是这里将创建有 2 个 pinctrl_map 的数组
};

gpio_lcm_pwr1v8_high: gpio_lcm_pwr1v8_high { //----这是一组 pinctrl_map
pins_cmd_dat {
pinmux = <PINMUX_GPIO5__FUNC_GPIO5>; //这被解析到 pinctrl_map->data->mux
output-high; //这被解析到 pinctrl_map->data->configs
}; // 于是这里将创建有 2 个 pinctrl_map 的数组
}

上述 lcm 配置了两个 state ,他们分别是"lcm_1v8_en_low" 和 “lcm_1v8_en_high”.

2) 解析设备引脚资源的时机

    当设备和驱动匹配的时候在 really_probe 函数中会调用 pinctrl_bind_pins 来解析并创建属于该设备的 pinctrl,匹配流程可以参考linux设备模型

1
2
3
4
5
6
7
static int really_probe(struct device *dev, struct device_driver *drv)
{
....
/* If using pinctrl, bind pins now before probing */
ret = pinctrl_bind_pins(dev);
....
}

来看看这个函数做了什么

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
int pinctrl_bind_pins(struct device *dev)
{
int ret;

dev->pins = devm_kzalloc(dev, sizeof(*(dev->pins)), GFP_KERNEL);
if (!dev->pins)
return -ENOMEM;

//解析 pin 脚信息并返回 pinctrl
dev->pins->p = devm_pinctrl_get(dev);
if (IS_ERR(dev->pins->p)) {
dev_dbg(dev, "no pinctrl handle\n");
ret = PTR_ERR(dev->pins->p);
goto cleanup_alloc;
}

//返回 default 的 sate
dev->pins->default_state = pinctrl_lookup_state(dev->pins->p,
PINCTRL_STATE_DEFAULT);
if (IS_ERR(dev->pins->default_state)) {
dev_dbg(dev, "no default pinctrl state\n");
ret = 0;
goto cleanup_get;
}

// 查找 init 的 state 如果不存在则设置为 default 否则设置为 init
dev->pins->init_state = pinctrl_lookup_state(dev->pins->p,
PINCTRL_STATE_INIT);
if (IS_ERR(dev->pins->init_state)) {
/* Not supplying this state is perfectly legal */
dev_dbg(dev, "no init pinctrl state\n");

ret = pinctrl_select_state(dev->pins->p,
dev->pins->default_state);
} else {
ret = pinctrl_select_state(dev->pins->p, dev->pins->init_state);
}

if (ret) {
dev_dbg(dev, "failed to activate initial pinctrl state\n");
goto cleanup_get;
}

#ifdef CONFIG_PM
//查找 sleep 的 state
dev->pins->sleep_state = pinctrl_lookup_state(dev->pins->p,
PINCTRL_STATE_SLEEP);
if (IS_ERR(dev->pins->sleep_state))
/* Not supplying this state is perfectly legal */
dev_dbg(dev, "no sleep pinctrl state\n");

//查找 sleep 的 state
dev->pins->idle_state = pinctrl_lookup_state(dev->pins->p,
PINCTRL_STATE_IDLE);
if (IS_ERR(dev->pins->idle_state))
/* Not supplying this state is perfectly legal */
dev_dbg(dev, "no idle pinctrl state\n");
#endif

return 0;

cleanup_get:
devm_pinctrl_put(dev->pins->p);
cleanup_alloc:
devm_kfree(dev, dev->pins);
dev->pins = NULL;

/* Only return deferrals */
if (ret != -EPROBE_DEFER)
ret = 0;

return ret;
}

这个函数解析 pin 脚信息并返回 pinctrl ,获取 default 以及其他默认state,这些state 在 include/linux/pinctrl/pinctrl-state.h 中提供

1
2
3
4
#define PINCTRL_STATE_DEFAULT "default"
#define PINCTRL_STATE_INIT "init"
#define PINCTRL_STATE_IDLE "idle"
#define PINCTRL_STATE_SLEEP "sleep"

在 default 之后查找 init 的 state 如果不存在则设置为 default ,从代码也可以看出如果没有 default 也不会去获取后面的 state ,因此如果需要使用到 init、idle、sleep 这三个 state 必须配置 default state。由于解析过程涉及的函数比较多因此先给出内部数据结构的组织结构方便理解。

设备 pinctr 的内部数据组织结构

可以从数据结构中看出涉及到两个关键的数据 pinctrl_map 和 pinctrl_setting, 这两个数据结构是直接连接到外部的 pinmux 信息和 pinconfig 信息。

3) pinctrl 解析设备引脚资源

解析过程如下图所示

设备树 pin_state 解析流程

4) 源码分析

涉及到的代码相对比较多就不去排版了,每个函数都有注释可以作为一个手册阅读。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 1. 在 pinctrl_list 链表中查找属于本设备的 pinctrl
// 2. 如果不存在则注册一个 pinctrl
struct pinctrl *pinctrl_get(struct device *dev)
{
struct pinctrl *p;

if (WARN_ON(!dev))
return ERR_PTR(-EINVAL);

// 如果 pinctrl 被注册则,直接返回该 pinctrl
p = find_pinctrl(dev);
if (p != NULL) {
dev_dbg(dev, "obtain a copy of previously claimed pinctrl\n");
kref_get(&p->users);
return p;
}

//创建 pinctrl
return create_pinctrl(dev);
}

// 在 pinctrl_list 链表中查找属于本设备的 pinctrl
static struct pinctrl *find_pinctrl(struct device *dev)
{
struct pinctrl *p;

mutex_lock(&pinctrl_list_mutex);
list_for_each_entry(p, &pinctrl_list, node)
if (p->dev == dev) {
mutex_unlock(&pinctrl_list_mutex);
return p;
}

mutex_unlock(&pinctrl_list_mutex);
return NULL;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
static struct pinctrl *create_pinctrl(struct device *dev)
{
struct pinctrl *p;
const char *devname;
struct pinctrl_maps *maps_node; //map索引
int i;
struct pinctrl_map const *map;
int ret;

// 创建并初始化 pinctrl -------------------------- part 1
p = kzalloc(sizeof(*p), GFP_KERNEL);
if (p == NULL) {
dev_err(dev, "failed to alloc struct pinctrl\n");
return ERR_PTR(-ENOMEM);
}

p->dev = dev; //初始化所属的dev
INIT_LIST_HEAD(&p->states); //初始化 states 链表
INIT_LIST_HEAD(&p->dt_maps); //初始化 dt_maps链表

// 将该设备 dts 中的 pin state 转化为 pinctrl_map ------------------- part 2
ret = pinctrl_dt_to_map(p);
if (ret < 0) {
kfree(p);
return ERR_PTR(ret);
}

devname = dev_name(dev);

mutex_lock(&pinctrl_maps_mutex);

//对于 maps_node 中的每一组属于该设备的 map 调用 add_setting,将对应的 pinctrl_map 转换为 pinctrl_setting ------ patr 3
for_each_maps(maps_node, i, map) {
/* Map must be for this device */
if (strcmp(map->dev_name, devname))
continue;

ret = add_setting(p, map);

if (ret == -EPROBE_DEFER) {
pinctrl_free(p, false);
mutex_unlock(&pinctrl_maps_mutex);
return ERR_PTR(ret);
}
}

mutex_unlock(&pinctrl_maps_mutex);

if (ret < 0) {
/* If some other error than deferral occured, return here */
pinctrl_free(p, false);
return ERR_PTR(ret);
}

kref_init(&p->users);

mutex_lock(&pinctrl_list_mutex);
//将 pinctrl 加入到全局链表 pinctrl_list
list_add_tail(&p->node, &pinctrl_list);
mutex_unlock(&pinctrl_list_mutex);

return p;
}

其实整个解析过程也是分为三步、part1-创建本设备的 pinctrl、part2-将 dts 转化为对应的 pinctrl_map、part3-最后是将 pinctrl_map 转换为pinctrl_setting

a. 创建 pinctrl_map
pinctrl_dt_to_map
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
// 1. 从state = 0 开始,递增判断 pinctrl 所属的设备的的设备树节点是否存在 pinctrl-state ,不存在则直接返回
// 2. 如果存在则 state 作为 index 获取 pinctrl-names 属性的值 statename
// 3. 遍历 pinctrl-0 属性的值所表示的节点,在 pinctrldev_list 中查找属于该节点的父节点的 pinctrl_dev
// 然后调用 pctldev->desc->pctlops->dt_node_to_map(pctldev, np_config, &map, &num_maps); 函数, 创建出需要的 pinctrl_map
// 4. 进一步初始化 pinctrl_map
int pinctrl_dt_to_map(struct pinctrl *p)
{
struct device_node *np = p->dev->of_node; //获取到 pinctrl 所属的设备的设备节点
int state, ret;
char *propname;
struct property *prop;
const char *statename;
const __be32 *list;
int size, config;
phandle phandle;
struct device_node *np_config;

/* CONFIG_OF enabled, p->dev not instantiated from DT */
if (!np) {
if (of_have_populated_dt())
dev_dbg(p->dev,
"no of_node; not parsing pinctrl DT\n");
return 0;
}

of_node_get(np); // 增加节点引用计数

for (state = 0; ; state++) {

propname = kasprintf(GFP_KERNEL, "pinctrl-%d", state);

// 通过 propname 获得对应设备树中的属性,pinctrl-0 属性的值为设备节点的引用,即为 phandle 属性。
prop = of_find_property(np, propname, &size);
kfree(propname);
if (!prop)
break;
list = prop->value; // 获取到属性值
size /= sizeof(*list); // 获取属性值的个数,即上面dts中的 <&gpio_lcm_pwr1v8_low> 的个数明显这里只有一个

// 通过 pinctrl-names, 获取对应的 state 的名字,一般情况下 state = 0 的名字为 default
// 这里可以看出,pinctrl-names 属性的值,和 pinctrl-* 是一一对应的。
ret = of_property_read_string_index(np, "pinctrl-names", state, &statename);

if (ret < 0) {
/* strlen("pinctrl-") == 8 */
statename = prop->name + 8;
}

for (config = 0; config < size; config++) { //
//将属性值转化为 pandle,只是保证数据的大小端一致性
phandle = be32_to_cpup(list++);

//通过 phandle 获取到其所在的设备节点 gpio_lcm_pwr1v8_low
np_config = of_find_node_by_phandle(phandle);
if (!np_config) {
dev_err(p->dev,
"prop %s index %i invalid phandle\n",
prop->name, config);
ret = -EINVAL;
goto err;
}

// 在 pinctrldev_list 中查找属于 gpio_lcm_pwr1v8_low 所在节点根节点的中的 pinctrl_dev,
// 然后调用 pctldev->desc->pctlops->dt_node_to_map(pctldev, np_config, &map, &num_maps); 函数, 创建出需要的 pinctrl_map
// 进一步初始化 pinctrl_map ,创建 pinctrl_dt_map 初始化之后 将,dt_map 挂接到所属的 pinctrl
// 检查 pinctrl_map 的合法性,动态创建一个 maps_node 初始化之后挂接到全局 pinctrl_maps
ret = dt_to_map_one_config(p, statename, np_config);
of_node_put(np_config);
if (ret < 0)
goto err;
}
}

return 0;

err:
pinctrl_dt_free_maps(p);
return ret;
}
dt_to_map_one_config
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// 在 pinctrldev_list 中查找属于 gpio_lcm_pwr1v8_low 所在节点根节点的中的 pinctrl_dev, 
// 然后调用 pctldev->desc->pctlops->dt_node_to_map(pctldev, np_config, &map, &num_maps); 函数, 创建出需要的 pinctrl_map
// 进一步初始化 pinctrl_map ,创建 pinctrl_dt_map 初始化之后 将,dt_map 挂接到所属的 pinctrl
// 检查 pinctrl_map 的合法性,动态创建一个 maps_node 初始化之后挂接到全局 pinctrl_maps
static int dt_to_map_one_config(struct pinctrl *p, const char *statename, struct device_node *np_config)
{
struct device_node *np_pctldev;
struct pinctrl_dev *pctldev;
const struct pinctrl_ops *ops;
int ret;
struct pinctrl_map *map;
unsigned num_maps;

/* 查找 pinctrl 的根节点 */
np_pctldev = of_node_get(np_config); //增加节点引用计数
for (;;) {
//获取 np_pctldev 所在的设备节点的父节点,即pinctrl-0 指向的设备节点 gpio_lcm_pwr1v8_low 的父节点,即 pintrl 根节点
np_pctldev = of_get_next_parent(np_pctldev);
if (!np_pctldev || of_node_is_root(np_pctldev)) {
dev_info(p->dev, "could not find pctldev for node %s, deferring probe\n",
np_config->full_name);
of_node_put(np_pctldev);
/* OK let's just assume this will appear later then */
return -EPROBE_DEFER;
}

//获取 pintrl 根节点的 pinctrl_dev
pctldev = get_pinctrl_dev_from_of_node(np_pctldev);
if (pctldev) //如果存在推出循环
break;
/* 如果 pinctrl 所在的节点和 dts 中的 pinctrl 根节点相同则 error */
if (np_pctldev == p->dev->of_node) {
of_node_put(np_pctldev);
return -ENODEV;
}
}
of_node_put(np_pctldev); //减少节点引用计数

//获取其 pinctrl_ops
ops = pctldev->desc->pctlops;
if (!ops->dt_node_to_map) {
dev_err(p->dev, "pctldev %s doesn't support DT\n",
dev_name(pctldev->dev));
return -ENODEV;
}
// 调用 dt_node_to_map 函数, 对于 gpio_lcm_pwr1v8_low 的所有子节点调用 mtk_pctrl_dt_subnode_to_map
// 从设备树中获取对应的配置,并创建对应的 pinctrl_map
ret = ops->dt_node_to_map(pctldev, np_config, &map, &num_maps);
if (ret < 0)
return ret;

// 进一步初始化 pinctrl_map ,创建 pinctrl_dt_map 初始化之后 将,dt_map 挂接到所属的 pinctrl
// 检查 pinctrl_map 的合法性,动态创建一个 maps_node 初始化之后挂接到全局 pinctrl_maps
return dt_remember_or_free_map(p, statename, pctldev, map, num_maps);
}

接下来是 mtk 平台的处理过程

mtk_pctrl_dt_node_to_map
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//对于 np_config(就是前面的 gpio_lcm_pwr1v8_low)的所有子节点调用 mtk_pctrl_dt_subnode_to_map, 从设备树中获取对应的配置,并创建对应的 pinctrl_map
static int mtk_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
struct device_node *np_config,
struct pinctrl_map **map, unsigned *num_maps)
{
struct device_node *np;
unsigned reserved_maps;
int ret;

*map = NULL;
*num_maps = 0; //表示 pinctrl_map 的数组下标
reserved_maps = 0;

/*
* 对于 gpio_lcm_pwr1v8_low 的所有子节点调用 mtk_pctrl_dt_subnode_to_map,
* 从设备树中获取对应的配置,并创建对应的 pinctrl_map
*/
for_each_child_of_node(np_config, np) {
ret = mtk_pctrl_dt_subnode_to_map(pctldev, np, map,
&reserved_maps, num_maps);
if (ret < 0) {
pinctrl_utils_dt_free_map(pctldev, *map, *num_maps);
return ret;
}
}

return 0;
}
mtk_pctrl_dt_subnode_to_map
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//从设备树中获取对应的配置,并创建对应的 pinctrl_map
static int mtk_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
struct device_node *node,
struct pinctrl_map **map,
unsigned *reserved_maps,
unsigned *num_maps)
{
struct property *pins;
u32 pinfunc, pin, func;
int num_pins, num_funcs, maps_per_pin;
unsigned long *configs;
unsigned int num_configs;
bool has_config = 0;
int i, err;
unsigned reserve = 0;
struct mtk_pinctrl_group *grp;
struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);

// 获取 pin 的属性,从这里可以知道 mtk 平台兼容两种 pin 属性的写法,
// 一种是 pinmux,一种是 pins
pins = of_find_property(node, "pinmux", NULL);
if (!pins) {
pins = of_find_property(node, "pins", NULL);
if (!pins) {
dev_err(pctl->dev, "missing pins property in node %s .\n",
node->name);
return -EINVAL;
}
}

// 在设备节点查找 dt_params 以及 pctldev->desc->custom_params 中的支持的 pinconfig
// 如果存在则按顺寻将 params 和 custom_params 可配置的 pinconfig 参数 pin_config_param
// 以及配置的默认状态 default_value 组合后,存入 configs 指向的内存空间, 并返回 configs 的长度
err = pinconf_generic_parse_dt_config(node, pctldev, &configs,
&num_configs);
if (err)
return err;

if (num_configs)
has_config = 1; //是否需要配置 configs

num_pins = pins->length / sizeof(u32); //获取 dts 配置的 pin 的数量
num_funcs = num_pins; //计算出 func 的数量
maps_per_pin = 0;
if (num_funcs)
maps_per_pin++; //
if (has_config && num_pins >= 1) //如果有配置的 config 以及需要配置的 pin >= 1
maps_per_pin++;

if (!num_pins || !maps_per_pin) {
err = -EINVAL;
goto exit;
}

reserve = num_pins * maps_per_pin; //计算需要的 pinctrl_map 的数量

// 重新申请一片大小为 *num_maps + reserve 的内存空间,并将 map 的值复制过去,
// reserved_maps 之后的内存空间初始化为 0, 同时更新 pinctrl_map 的数量 reserved_maps
// num_maps 表示有效的 pinctrl_map 的数量
err = pinctrl_utils_reserve_map(pctldev, map,
reserved_maps, num_maps, reserve);
if (err < 0)
goto exit;

for (i = 0; i < num_pins; i++) {
err = of_property_read_u32_index(node, "pinmux",
i, &pinfunc);
if (err) {
err = of_property_read_u32_index(node, "pins",
i, &pinfunc);
if (err)
goto exit;
}
pin = MTK_GET_PIN_NO(pinfunc); //获取配置的 pin 脚

// 获取该引脚对应的复用状态,复用状态在 include/dt-bindings/pinctrl/mt6771-pinfunc.h 文件中配置
func = MTK_GET_PIN_FUNC(pinfunc);

if (pin >= pctl->devdata->npins ||
func >= ARRAY_SIZE(mtk_gpio_functions)) {
dev_err(pctl->dev, "invalid pins value.\n");
err = -EINVAL;
goto exit;
}

//返回该 pin 所对应的 group
grp = mtk_pctrl_find_group_by_pin(pctl, pin);
if (!grp) {
dev_err(pctl->dev, "unable to match pin %d to group\n",
pin);
err = -EINVAL;
goto exit;
}
// 初始化 pinctrl_map 的 type 为 PIN_MAP_TYPE_MUX_GROUP,
// 初始化 data.mux.group 为 grp->name;
// 初始化 ata.mux.function 为 mtk_gpio_functions[fnum];
err = mtk_pctrl_dt_node_to_map_func(pctl, pin, func, grp, map,
reserved_maps, num_maps);
if (err < 0)
goto exit;

//如果有 config 则设置 config 对应的 pinctrl_map,
//因此 poinconfig 是对该节点的所有 pin 生效
if (has_config) {
err = pinctrl_utils_add_map_configs(pctldev, map,
reserved_maps, num_maps, grp->name,
configs, num_configs,
PIN_MAP_TYPE_CONFIGS_GROUP);
if (err < 0)
goto exit;
}
}

err = 0;

exit:
kfree(configs);
return err;
}

#define MTK_PIN_NO(x) ((x) << 8)
#define MTK_GET_PIN_NO(x) ((x) >> 8)
#define MTK_GET_PIN_FUNC(x) ((x) & 0xf)

#define PINMUX_GPIO0__FUNC_GPIO0 (MTK_PIN_NO(0) | 0)
#define PINMUX_GPIO0__FUNC_MRG_SYNC (MTK_PIN_NO(0) | 1)
#define PINMUX_GPIO0__FUNC_PCM0_SYNC (MTK_PIN_NO(0) | 2)
#define PINMUX_GPIO0__FUNC_TP_GPIO0_AO (MTK_PIN_NO(0) | 3)
#define PINMUX_GPIO0__FUNC_SRCLKENAI0 (MTK_PIN_NO(0) | 4)
#define PINMUX_GPIO0__FUNC_SCP_SPI2_CS (MTK_PIN_NO(0) | 5)
#define PINMUX_GPIO0__FUNC_I2S3_MCK (MTK_PIN_NO(0) | 6)
#define PINMUX_GPIO0__FUNC_SPI2_CSB (MTK_PIN_NO(0) | 7)
mtk_pctrl_dt_node_to_map_func
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 初始化 pinctrl_map 的 type 为 PIN_MAP_TYPE_MUX_GROUP,
// 初始化 data.mux.group 为 grp->name;
// 初始化 ata.mux.function 为 mtk_gpio_functions[fnum];
static int mtk_pctrl_dt_node_to_map_func(struct mtk_pinctrl *pctl,
u32 pin, u32 fnum, struct mtk_pinctrl_group *grp,
struct pinctrl_map **map, unsigned *reserved_maps,
unsigned *num_maps)
{
bool ret;

if (*num_maps == *reserved_maps)
return -ENOSPC;

(*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP; // 初始化 pinctrl_map 的 type
(*map)[*num_maps].data.mux.group = grp->name; //初始化 data.mux.group

//该 pin 的引脚复用 fnum 有效性检查
ret = mtk_pctrl_is_function_valid(pctl, pin, fnum);
if (!ret) {
dev_err(pctl->dev, "invalid function %d on pin %d .\n",
fnum, pin);
return -EINVAL;
}

//初始化对应 pin 脚复用的函数名
(*map)[*num_maps].data.mux.function = mtk_gpio_functions[fnum];
(*num_maps)++;

return 0;
}
mtk_pctrl_is_function_valid
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
//该 pin_num 的引脚复用 fnum 有效性检查
static bool mtk_pctrl_is_function_valid(struct mtk_pinctrl *pctl,
u32 pin_num, u32 fnum)
{
int i;

for (i = 0; i < pctl->devdata->npins; i++) {
const struct mtk_desc_pin *pin = pctl->devdata->pins + i;

if (pin->pin.number == pin_num) { 找到该 pin 对应的 mtk_desc_pin
const struct mtk_desc_function *func =
pin->functions; //获取到对应的 functions

while (func && func->name) { //查找对应的 functions 是否有对应的引脚复用 fnum
if (func->muxval == fnum)
return true;
func++;
}

break;
}
}

return false;
}

struct mtk_desc_function {
const char *name;
unsigned char muxval;
};

struct mtk_desc_pin {
struct pinctrl_pin_desc pin;
#ifdef CONFIG_MTK_EINT_MULTI_TRIGGER_DESIGN
struct mtk_desc_eint eint;
#else
const struct mtk_desc_eint eint;
#endif
const struct mtk_desc_function *functions;
};

struct mtk_desc_function {
const char *name;
unsigned char muxval;
};
pinctrl_utils_add_map_configs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//删除多余内存空间
int pinctrl_utils_add_map_configs(struct pinctrl_dev *pctldev,
struct pinctrl_map **map, unsigned *reserved_maps,
unsigned *num_maps, const char *group,
unsigned long *configs, unsigned num_configs,
enum pinctrl_map_type type)
{
unsigned long *dup_configs;

if (WARN_ON(*num_maps == *reserved_maps)) //防止数组越界
return -ENOSPC;

dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs),
GFP_KERNEL);
if (!dup_configs) {
dev_err(pctldev->dev, "kmemdup(configs) failed\n");
return -ENOMEM;
}

(*map)[*num_maps].type = type;
(*map)[*num_maps].data.configs.group_or_pin = group;
(*map)[*num_maps].data.configs.configs = dup_configs;
(*map)[*num_maps].data.configs.num_configs = num_configs;
(*num_maps)++;

return 0;
}
pinconf_generic_parse_dt_config
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
// 在设备节点 device_node 查找 dt_params 以及 pctldev->desc->custom_params 中的支持的引脚状态
// 如果存在则按顺寻将 params 和 custom_params 可配置的引脚状态参数 pin_config_param
// 以及配置的默认状态 default_value 组合后,存入 configs 指向的内存空间, 并返回 configs 的长度nconfigs
int pinconf_generic_parse_dt_config(struct device_node *np,
struct pinctrl_dev *pctldev,
unsigned long **configs,
unsigned int *nconfigs)
{
unsigned long *cfg;
unsigned int max_cfg, ncfg = 0;
int ret;

if (!np)
return -EINVAL;

/* allocate a temporary array big enough to hold one of each option */
//获取 dt_params 的中 config 的数量
max_cfg = ARRAY_SIZE(dt_params);

if (pctldev)
max_cfg += pctldev->desc->num_custom_params;

//每个 config 都由 unsigned long 表示,申请 max_cfg 个 unsigned long
cfg = kcalloc(max_cfg, sizeof(*cfg), GFP_KERNEL);
if (!cfg)
return -ENOMEM;

// 查询设备节点 np 中存在的 params[] 数组中的属性,
// 如果存在则按顺寻将该 params 可配置的引脚状态参数 pin_config_param
// 以及配置的默认状态 default_value 组合后,存入 cfg 指向的内存空间, ncfg 表示 cfg 的长度
parse_dt_cfg(np, dt_params, ARRAY_SIZE(dt_params), cfg, &ncfg);
if (pctldev && pctldev->desc->num_custom_params && pctldev->desc->custom_params)
//如果存在 custom_params 则同样查询该节点存在的属性,并返回其值
parse_dt_cfg(np, pctldev->desc->custom_params,
pctldev->desc->num_custom_params, cfg, &ncfg);

ret = 0;

//没有 configs 则推出
if (ncfg == 0) {
*configs = NULL;
*nconfigs = 0;
goto out;
}

//为了节省内存空间,这里将值复制到 configs 之后释放掉 cfg 所占的多余的内存空间
*configs = kmemdup(cfg, ncfg * sizeof(unsigned long), GFP_KERNEL);
if (!*configs) {
ret = -ENOMEM;
goto out;
}

*nconfigs = ncfg;

out:
kfree(cfg);
return ret;
}

struct pinconf_generic_params {
const char * const property;
enum pin_config_param param;
u32 default_value;
};

//文件中定义的全局变量,表示支持的引脚状态
static const struct pinconf_generic_params dt_params[] = {
// bias-bus-hold 属性名,在设备树中使用该名字,
// PIN_CONFIG_BIAS_BUS_HOLD 引脚的状态,
// 0 引脚状态的值
{ "bias-bus-hold", PIN_CONFIG_BIAS_BUS_HOLD, 0 },
{ "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
{ "bias-high-impedance", PIN_CONFIG_BIAS_HIGH_IMPEDANCE, 0 },
{ "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
{ "bias-pull-pin-default", PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, 1 },
{ "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
{ "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 },
{ "drive-open-source", PIN_CONFIG_DRIVE_OPEN_SOURCE, 0 },
{ "drive-push-pull", PIN_CONFIG_DRIVE_PUSH_PULL, 0 },
{ "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
{ "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE, 0 },
{ "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 },
{ "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 },
{ "input-schmitt", PIN_CONFIG_INPUT_SCHMITT, 0 },
{ "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 },
{ "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 },
{ "low-power-disable", PIN_CONFIG_LOW_POWER_MODE, 0 },
{ "low-power-enable", PIN_CONFIG_LOW_POWER_MODE, 1 },
{ "output-high", PIN_CONFIG_OUTPUT, 1, },
{ "output-low", PIN_CONFIG_OUTPUT, 0, },
{ "power-source", PIN_CONFIG_POWER_SOURCE, 0 },
{ "slew-rate", PIN_CONFIG_SLEW_RATE, 0 },
};
parse_dt_cfg
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 查询设备节点np中存在的  params[count] 数组中的属性,
// 如果存在则按顺寻将该 params 可配置的引脚状态参数 pin_config_param
// 以及配置的默认状态 default_value 组合后,存入 cfg 指向的内存空间, 之后 ncfg 等于 cfg 数组长度
static void parse_dt_cfg(struct device_node *np, const struct pinconf_generic_params *params, unsigned int count, unsigned long *cfg, unsigned int *ncfg)
{
int i;

for (i = 0; i < count; i++) {
u32 val;
int ret;
//获取 params 中的 pinconf_generic_params
const struct pinconf_generic_params *par = &params[i];

//从np节点中查询是存在该属性
ret = of_property_read_u32(np, par->property, &val);

//如果不存在结束本次循环
/* property not found */
if (ret == -EINVAL)
continue;

/* use default value, when no value is specified */
//如果存在这个属性则获取这个default属性的值
if (ret)
val = par->default_value;

pr_debug("found %s with value %u\n", par->property, val);
//将该params可配置的引脚状态参数 pin_config_param 以及配置的默认状态组合后写入到cfg所在的内存空间。
cfg[*ncfg] = pinconf_to_config_packed(par->param, val);
(*ncfg)++;
}
}

static inline unsigned long pinconf_to_config_packed(enum pin_config_param param,
u16 argument)
{
return PIN_CONF_PACKED(param, argument);
}

#define PIN_CONF_PACKED(p, a) ((a << 16) | ((unsigned long) p & 0xffffUL))
pinctrl_utils_reserve_map
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 重新申请一片大小为 *num_maps + reserve 的内存空间,并将 map 的值复制过去,
// reserved_maps 之后的内存空间初始化为 0, 同时更新 pinctrl_map 的数量 reserved_maps
int pinctrl_utils_reserve_map(struct pinctrl_dev *pctldev,
struct pinctrl_map **map, unsigned *reserved_maps,
unsigned *num_maps, unsigned reserve)
{
unsigned old_num = *reserved_maps; // 0
unsigned new_num = *num_maps + reserve; //
struct pinctrl_map *new_map;

if (old_num >= new_num)
return 0;

new_map = krealloc(*map, sizeof(*new_map) * new_num, GFP_KERNEL);
if (!new_map) {
dev_err(pctldev->dev, "krealloc(map) failed\n");
return -ENOMEM;
}

memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map));

*map = new_map;
*reserved_maps = new_num;
return 0;
}
mtk_pctrl_find_group_by_pin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//返回该 pin 脚所在的 group,mtk平台每一个 pin 就是一个 group
static struct mtk_pinctrl_group * mtk_pctrl_find_group_by_pin(struct mtk_pinctrl *pctl, u32 pin)
{
int i;

for (i = 0; i < pctl->ngroups; i++) {
struct mtk_pinctrl_group *grp = pctl->groups + i;

if (grp->pin == pin)
return grp;
}

return NULL;
}

struct mtk_pinctrl_group {
const char *name;
unsigned long config;
unsigned pin;
};
dt_remember_or_free_map
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//进一步初始化 pinctrl_map, 并创建对应的 pinctrl_dt_map 映射
static int dt_remember_or_free_map(struct pinctrl *p, const char *statename,
struct pinctrl_dev *pctldev,
struct pinctrl_map *map, unsigned num_maps)
{
int i;
struct pinctrl_dt_map *dt_map;

//初始化 dev_name 这个很重要,转化为 pinctrl_settings 时这个作为判断条件
for (i = 0; i < num_maps; i++) {
map[i].dev_name = dev_name(p->dev); //初始化 pinctrl_map 所属的 pinctrl 的 dev_name
map[i].name = statename; //初始化 name
if (pctldev)
map[i].ctrl_dev_name = dev_name(pctldev->dev); //设置所属的 pinctrl_dev 的 name
}

//创建 pinctrl_dt_map
dt_map = kzalloc(sizeof(*dt_map), GFP_KERNEL);
if (!dt_map) {
dev_err(p->dev, "failed to alloc struct pinctrl_dt_map\n");
dt_free_map(pctldev, map, num_maps);
return -ENOMEM;
}

// 初始化 pinctrl_dt_map
dt_map->pctldev = pctldev;
dt_map->map = map;
dt_map->num_maps = num_maps;
list_add_tail(&dt_map->node, &p->dt_maps); //将 dt_map 挂接到所属的 pinctrl

return pinctrl_register_map(map, num_maps, false);
}
pinctrl_register_map
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
//
int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
bool dup)
{
int i, ret;
struct pinctrl_maps *maps_node;

pr_debug("add %u pinctrl maps\n", num_maps);

//首先检测 map 的合法性
for (i = 0; i < num_maps; i++) {
if (!maps[i].dev_name) { //每一个 map 都要有所属的设备
pr_err("failed to register map %s (%d): no device given\n",
maps[i].name, i);
return -EINVAL;
}

if (!maps[i].name) { //每一个 map 都要有对应的 state
pr_err("failed to register map %d: no map name given\n",
i);
return -EINVAL;
}

//当 map 的类型不为 PIN_MAP_TYPE_DUMMY_STAT ,map 必须要有所属的 pinctl_dev
if (maps[i].type != PIN_MAP_TYPE_DUMMY_STATE &&
!maps[i].ctrl_dev_name) { E
pr_err("failed to register map %s (%d): no pin control device given\n",
maps[i].name, i);
return -EINVAL;
}

switch (maps[i].type) {
case PIN_MAP_TYPE_DUMMY_STATE:
break;
case PIN_MAP_TYPE_MUX_GROUP:
ret = pinmux_validate_map(&maps[i], i); //检查 map->data.mux.function 是否存在
if (ret < 0)
return ret;
break;
case PIN_MAP_TYPE_CONFIGS_PIN:
case PIN_MAP_TYPE_CONFIGS_GROUP:
ret = pinconf_validate_map(&maps[i], i);
if (ret < 0)
return ret;
break;
default:
pr_err("failed to register map %s (%d): invalid type given\n",
maps[i].name, i);
return -EINVAL;
}
}

//动态创建一个 maps_node 用于挂接 pinctrl_maps
maps_node = kzalloc(sizeof(*maps_node), GFP_KERNEL);
if (!maps_node) {
pr_err("failed to alloc struct pinctrl_maps\n");
return -ENOMEM;
}

maps_node->num_maps = num_maps;
if (dup) {
maps_node->maps = kmemdup(maps, sizeof(*maps) * num_maps,
GFP_KERNEL);
if (!maps_node->maps) {
pr_err("failed to duplicate mapping table\n");
kfree(maps_node);
return -ENOMEM;
}
} else {
maps_node->maps = maps; //跑这里
}

mutex_lock(&pinctrl_maps_mutex);
list_add_tail(&maps_node->node, &pinctrl_maps); //将 maps_node 链接到全局 pinctrl_maps
mutex_unlock(&pinctrl_maps_mutex);

return 0;
}
b. 将pinctrl_map转化为pinctrl_setting
add_setting
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
static int add_setting(struct pinctrl *p, struct pinctrl_map const *map)
{
struct pinctrl_state *state;
struct pinctrl_setting *setting;
int ret;

//获取对应的 state
state = find_state(p, map->name);
if (!state) // 如果没有 state 则创建
state = create_state(p, map->name);
if (IS_ERR(state))
return PTR_ERR(state);

if (map->type == PIN_MAP_TYPE_DUMMY_STATE)
return 0;

// 创建一个 pinctrl_setting
setting = kzalloc(sizeof(*setting), GFP_KERNEL);
if (setting == NULL) {
dev_err(p->dev,
"failed to alloc struct pinctrl_setting\n");
return -ENOMEM;
}

// 初始化 type
setting->type = map->type;

setting->pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name);
if (setting->pctldev == NULL) {
kfree(setting);
/* Do not defer probing of hogs (circular loop) */
if (!strcmp(map->ctrl_dev_name, map->dev_name))
return -ENODEV;
/*
* OK let us guess that the driver is not there yet, and
* let's defer obtaining this pinctrl handle to later...
*/
dev_info(p->dev, "unknown pinctrl device %s in map entry, deferring probe",
map->ctrl_dev_name);
return -EPROBE_DEFER;
}

setting->dev_name = map->dev_name;

switch (map->type) {
case PIN_MAP_TYPE_MUX_GROUP:
//转化引脚复用
ret = pinmux_map_to_setting(map, setting);
break;
case PIN_MAP_TYPE_CONFIGS_PIN:
case PIN_MAP_TYPE_CONFIGS_GROUP:
//转化pinconfig
ret = pinconf_map_to_setting(map, setting);
break;
default:
ret = -EINVAL;
break;
}
if (ret < 0) {
kfree(setting);
return ret;
}

list_add_tail(&setting->node, &state->settings);

return 0;
}
create_state
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
static struct pinctrl_state *create_state(struct pinctrl *p,
const char *name)
{
struct pinctrl_state *state;

//创建一个 state
state = kzalloc(sizeof(*state), GFP_KERNEL);
if (state == NULL) {
dev_err(p->dev,
"failed to alloc struct pinctrl_state\n");
return ERR_PTR(-ENOMEM);
}

state->name = name; //初始化 name
INIT_LIST_HEAD(&state->settings);

list_add_tail(&state->node, &p->states); //将其挂接到所属 pinctl 的states

return state;
}
pinmux_map_to_setting
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
int pinmux_map_to_setting(struct pinctrl_map const *map,
struct pinctrl_setting *setting)
{
struct pinctrl_dev *pctldev = setting->pctldev;
const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
char const * const *groups;
unsigned num_groups;
int ret;
const char *group;
int i;

if (!pmxops) {
dev_err(pctldev->dev, "does not support mux function\n");
return -EINVAL;
}

//返回 function所在数据结构的数组下标
ret = pinmux_func_name_to_selector(pctldev, map->data.mux.function);
if (ret < 0) {
dev_err(pctldev->dev, "invalid function %s in map table\n",
map->data.mux.function);
return ret;
}

//将其赋值给对应的 setting
setting->data.mux.func = ret;

//返回当前 function 结构中支持的 groups
ret = pmxops->get_function_groups(pctldev, setting->data.mux.func, &groups, &num_groups);
if (ret < 0) {
dev_err(pctldev->dev, "can't query groups for function %s\n",
map->data.mux.function);
return ret;
}
if (!num_groups) {
dev_err(pctldev->dev,
"function %s can't be selected on any group\n",
map->data.mux.function);
return -EINVAL;
}

if (map->data.mux.group) {
bool found = false;
group = map->data.mux.group;
for (i = 0; i < num_groups; i++) {
if (!strcmp(group, groups[i])) { //查看是否支持 data.mux.group
found = true;
break;
}
}
if (!found) {
dev_err(pctldev->dev,
"invalid group \"%s\" for function \"%s\"\n",
group, map->data.mux.function);
return -EINVAL;
}
} else {
group = groups[0]; //如果没有 map->data.mux.group 则使用 groups[0] 作为默认状态
}

//在所有的 group 中查找该 group 的下标,并用来初始化 map->data.mux.group
ret = pinctrl_get_group_selector(pctldev, group);
if (ret < 0) {
dev_err(pctldev->dev, "invalid group %s in map table\n",
map->data.mux.group);
return ret;
}
setting->data.mux.group = ret;

return 0;
}
pinmux_func_name_to_selector
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
static int pinmux_func_name_to_selector(struct pinctrl_dev *pctldev,
const char *function)
{
const struct pinmux_ops *ops = pctldev->desc->pmxops;
unsigned nfuncs = ops->get_functions_count(pctldev); //获取 functions 的数量
unsigned selector = 0;

//返回 function 所在数据结构的数组下标
while (selector < nfuncs) {
const char *fname = ops->get_function_name(pctldev, selector); //返回 selector 下标中的 func name

if (!strcmp(function, fname))
return selector; //返回数组下标

selector++;
}

dev_err(pctldev->dev, "function '%s' not supported\n", function);
return -EINVAL;
}
pinctrl_get_group_selector
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//在所有的 group 中查找该 group 的下标
int pinctrl_get_group_selector(struct pinctrl_dev *pctldev,
const char *pin_group)
{
const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
unsigned ngroups = pctlops->get_groups_count(pctldev); //返回 group 的大小
unsigned group_selector = 0;

while (group_selector < ngroups) {
const char *gname = pctlops->get_group_name(pctldev,
group_selector);
if (!strcmp(gname, pin_group)) {
dev_dbg(pctldev->dev,
"found group selector %u for %s\n",
group_selector,
pin_group);
return group_selector;
}

group_selector++;
}

dev_err(pctldev->dev, "does not have pin group %s\n",
pin_group);

return -EINVAL;
}
pinconf_map_to_setting
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
//pinconf_map_to_setting 将 conifg 对应的 map 转化为setting
int pinconf_map_to_setting(struct pinctrl_map const *map,
struct pinctrl_setting *setting)
{
struct pinctrl_dev *pctldev = setting->pctldev;
int pin;

switch (setting->type) {
case PIN_MAP_TYPE_CONFIGS_PIN:
// 对应的 pin 脚
pin = pin_get_from_name(pctldev,
map->data.configs.group_or_pin);
if (pin < 0) {
dev_err(pctldev->dev, "could not map pin config for \"%s\"",
map->data.configs.group_or_pin);
return pin;
}
setting->data.configs.group_or_pin = pin;
break;
case PIN_MAP_TYPE_CONFIGS_GROUP:
//返回对应的 group 的下标
pin = pinctrl_get_group_selector(pctldev,
map->data.configs.group_or_pin);
if (pin < 0) {
dev_err(pctldev->dev, "could not map group config for \"%s\"",
map->data.configs.group_or_pin);
return pin;
}
setting->data.configs.group_or_pin = pin;
break;
default:
return -EINVAL;
}

//config 的数量
setting->data.configs.num_configs = map->data.configs.num_configs;
//config
setting->data.configs.configs = map->data.configs.configs;

return 0;
}
pin_get_from_name
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//通过 name 返回对应的 pin 脚
int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name)
{
unsigned i, pin;

/* The pin number can be retrived from the pin controller descriptor */
for (i = 0; i < pctldev->desc->npins; i++) {
struct pin_desc *desc;

pin = pctldev->desc->pins[i].number;
desc = pin_desc_get(pctldev, pin);
/* Pin space may be sparse */
if (desc && !strcmp(name, desc->name))
return pin;
}

return -EINVAL;
}

四、pinctrl 子系统的使用

使用就比较简单了接口如下

1
2
3
4
5
6
7
8
//获取当前设备的 pinctrl 句柄
struct pinctrl *pinctrl_get(struct device *dev);

//获取我们需要设置的 state
struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *p, const char *name);

//设置为对应的state
int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state);

mtk 平台可以参考这篇文章 mtk-GPIO设置与应用