Linux之pinctrl子系统与gpio


参考链接:
http://www.wowotech.net/sort/gpio_subsystem
在这里插入图片描述

pinctrl子系统文件列表

linux/drivers/pinctrl目录下的源文件列表

  • 源文件列表
文件名描述
core.c core.hpin control subsystem的core driver
pinctrl-utils.c pinctrl-utils.hpin control subsystem的一些utility接口函数
pinmux.c pinmux.hpin control subsystem的core driver(pin muxing部分的代码,也称为pinmux driver)
pinconf.c pinconf.hpin control subsystem的core driver(pin config部分的代码,也称为pin config driver)
devicetree.c devicetree.hpin control subsystem的device tree代码
pinctrl-xxxx.c各种pin controller的low level driver
  • 其他内核模块接口文件,很多内核的其他模块需要用到pin control subsystem的服务,这些头文件就定义了pin control subsystem的外部接口以及相关的数据结构
文件名描述
consumer.h其他的driver要使用pin control subsystem的接口:a、设置引脚复用功能 b、配置引脚的电气特性;需要include这个头文件
devinfo.h这是linux内核的驱动模型模块使用的接口。struct device中包括struct dev_pin_info *pins的成员,描述了该设备的引脚的初始状态信息,在probe之前,driver model中的core driver在调用driver的probe函数之前会先设定pin state
machine.hmachine模块的接口
  • Low level pin controller driver接口,提供给底层specific pin controller driver的头文件列表
文件名描述
pinconf-generic.h主要是提供给各种pin controller driver使用的,不是外部接口
pinconf.hpin configuration 接口
pinctrl-state.hpin control state状态定义
pinmux.hpin mux function接口

pinctrl主要数据结构

pinctrl_dev 是 pinctrl 子系统的根源结构体

struct pinctrl_dev {
	struct list_head node;
	struct pinctrl_desc *desc;
	struct radix_tree_root pin_desc_tree;
#ifdef CONFIG_GENERIC_PINCTRL_GROUPS
	struct radix_tree_root pin_group_tree;
	unsigned int num_groups;
#endif
#ifdef CONFIG_GENERIC_PINMUX_FUNCTIONS
	struct radix_tree_root pin_function_tree;
	unsigned int num_functions;
#endif
	struct list_head gpio_ranges;
	struct device *dev;
	struct module *owner;
	void *driver_data;
	struct pinctrl *p;
	struct pinctrl_state *hog_default;
	struct pinctrl_state *hog_sleep;
	struct mutex mutex;
#ifdef CONFIG_DEBUG_FS
	struct dentry *device_root;
#endif
};
  1. pinctrl_desc:这里包含了pinctrl 子系统三个最重要的结构体,有三个操作函数集,pinctrl_ops 包含了对 PIN 的操作函数集,pinmux_ops 包含了对 PIN 的复用函数集,pinconf_ops 包含了对 PIN 的配置函数
  • pin controller描述符。每一个特定的pin controller都用一个struct pinctrl_desc来抽象
  • pin controller描述符需要描述它可以控制多少个pin,每一个pin的信息。这两个成员就确定了一个pin controller所能控制的引脚的信息。
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/platform_device.h>

struct pinctrl_desc {
	const char *name;
	//指向npins个pin描述符,每个描述符描述一个pin
	const struct pinctrl_pin_desc *pins;
	//该pin controller中有多少个可控的pin
	unsigned int npins;
	const struct pinctrl_ops *pctlops;
	const struct pinmux_ops *pmxops;
	const struct pinconf_ops *confops;
	struct module *owner;
#ifdef CONFIG_GENERIC_PINCONF
	unsigned int num_custom_params;
	const struct pinconf_generic_params *custom_params;
	const struct pin_config_item *custom_conf_items;
#endif
};
//对PIN的操作函数集
struct pinctrl_ops {
	//该pin controller支持多少个pin group
	//pin group的定义可以参考关于pin controller的功能规格中的描述。
	//注意不要把pin group和IO port的硬件分组搞混了。例如:S3C2416有138个I/O 端口,分成11组,分别是gpa~gpl,这个组并不叫pin group,而是叫做pin bank。pin group是和特定功能(例如SPI、I2C)相关的一组pin。
	int (*get_groups_count) (struct pinctrl_dev *pctldev);
	//给定一个selector(index),获取指定pin group的name
	const char *(*get_group_name) (struct pinctrl_dev *pctldev, unsigned selector);
	//给定一个selector(index),获取该pin group中pin的信息(该pin group包括多少个pin,每个pin的ID是什么)
	int (*get_group_pins) (struct pinctrl_dev *pctldev, unsigned selector, const unsigned **pins, unsigned *num_pins);
	//debug fs的callback接口
	void (*pin_dbg_show) (struct pinctrl_dev *pctldev, struct seq_file *s, unsigned offset);
	//分析一个pin configuration node并把分析的结果保存成mapping table entry,每一个entry表示一个setting(一个功能复用设定,或者电气特性设定)
	int (*dt_node_to_map) (struct pinctrl_dev *pctldev, struct device_node *np_config, struct pinctrl_map **map, unsigned *num_maps);
	//dt_node_to_map函数的逆函数
	void (*dt_free_map) (struct pinctrl_dev *pctldev, struct pinctrl_map *map, unsigned num_maps);
};
//对PIN的复用函数集
struct pinmux_ops {
	//pin control core进行具体的复用设定之前需要调用该函数,主要是用来底层的driver判断某个引脚的复用设定是否是OK的。
	int (*request) (struct pinctrl_dev *pctldev, unsigned offset);
	//是request的逆函数。调用request函数请求占用了某些pin的资源,调用free可以释放这些资源
	int (*free) (struct pinctrl_dev *pctldev, unsigned offset);
	//返回pin controller支持的function的数目
	int (*get_functions_count) (struct pinctrl_dev *pctldev);
	//给定一个selector(index),获取指定function的name
	const char *(*get_function_name) (struct pinctrl_dev *pctldev, unsigned selector);
	//给定一个selector(index),获取指定function的pin groups信息
	int (*get_function_groups) (struct pinctrl_dev *pctldev, unsigned selector, const char * const **groups, unsigned *num_groups);
	//
	int (*set_mux) (struct pinctrl_dev *pctldev, unsigned func_selector, unsigned group_selector);
	//request并且enable一个单独的gpio pin
	int (*gpio_request_enable) (struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset);
	//gpio_request_enable的逆函数
	void (*gpio_disable_free) (struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset);
	//设定GPIO方向的回调函数
	int (*gpio_set_direction) (struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset, bool input);
	bool strict;
};
//对PIN的配置函数
struct pinconf_ops {
#ifdef CONFIG_GENERIC_PINCONF
	bool is_generic;
#endif
	//给定一个pin ID以及config type ID,获取该引脚上指定type的配置
	int (*pin_config_get) (struct pinctrl_dev *pctldev, unsigned pin, unsigned long *config);
	//设定一个指定pin的配置
	int (*pin_config_set) (struct pinctrl_dev *pctldev, unsigned pin, unsigned long *configs, unsigned num_configs);
	//	以pin group为单位,获取pin上的配置信息
	int (*pin_config_group_get) (struct pinctrl_dev *pctldev, unsigned selector, unsigned long *config);
	//	以pin group为单位,设定pin group的特性配置
	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);
	//debug接口
	void (*pin_config_dbg_show) (struct pinctrl_dev *pctldev, struct seq_file *s, unsigned offset);
	//debug接口
	void (*pin_config_group_dbg_show) (struct pinctrl_dev *pctldev, struct seq_file *s, unsigned selector);
	//debug接口
	void (*pin_config_config_dbg_show) (struct pinctrl_dev *pctldev, struct seq_file *s, unsigned long config);
};
  1. pinctrl 结构体:这里包含了 PIN 控制器所控制 PIN 的状态 state,state 里面包含了setting,这个 setting 就是在设备树中对PIN的设置,设计理念如下:
  • 设置该设备的功能复用,一个是function,另外一个pin group。function是功能抽象,对应一个HW逻辑block,例如SPI0。虽然给定了具体的gunction name,并不能确定其使用的pins的情况。例如:芯片内部的SPI0的功能可能引出到pin group { A8, A7, A6, A5 },也可能引出到另外一个pin group{ G4, G3, G2, G1 },但是这两个pin group不能同时active, 因此,只有给出function selector(selector就是一个ID或者index)以及function的pin group selector才能进行function mux的设定。
  • 设定该device对应的那些pin的电气特性。由于电源管理的要求,某个device可能处于某个电源管理状态,如idle或者sleep,这时候,属于该device的所有的pin就会需要处于另外的状态。综合上述的需求,定义了pin control state的概念,也就是设备可能处于非常多的状态中的一个,device driver可以切换设备处于的状态。为了方便管理pin control state,提出了一个pin control state holder的概念,用来管理一个设备的所有的pin control状态
struct pinctrl {
	struct list_head node;//系统中的所有device的pin control state holder被挂入到了一个全局链表中
	struct device *dev;//该pin control state holder对应的device
	struct list_head states;//该设备的所有的状态被挂入到这个链表中
	struct pinctrl_state *state;//当前的pin control state
	struct list_head dt_maps;//mapping table
	struct kref users;//引用计数
};
  • 通过create_pinctrl()函数来创建一个pinctrl,通过pinctrl_dt_to_map()来解析
  • 系统中的每一个需要和pin control subsystem进行交互的设备在进行设定之前都需要首先获取这个结构体指针。而属于该设备的所有的状态都是挂入到一个链表中,链表头就是pin control state holder的states成员,一个state的定义如下:
struct pinctrl_state {
    struct list_head node;//挂入链表头的节点
    const char *name;//该state的名字
    struct list_head settings;//属于该状态的所有的settings
};
//一个pin state包含若干个setting,所有的settings被挂入一个链表中,链表头就是pin state中的settings成员,定义如下:
struct pinctrl_setting {
    struct list_head node;
    enum pinctrl_map_type type;
    struct pinctrl_dev *pctldev;
    const char *dev_name;
    union {
        struct pinctrl_setting_mux mux;
        struct pinctrl_setting_configs configs;
    } data;
};
/*
当driver设定一个pin state的时候,pin control subsystem内部会遍历该state的settings链表,将一个一个的setting进行设定。这些settings有各种类型,定义如下:
*/
enum pinctrl_map_type {
    PIN_MAP_TYPE_INVALID,
    PIN_MAP_TYPE_DUMMY_STATE,
    PIN_MAP_TYPE_MUX_GROUP,//功能复用的setting
    PIN_MAP_TYPE_CONFIGS_PIN,//设定单一个pin的电气特性
    PIN_MAP_TYPE_CONFIGS_GROUP,//设定单pin group的电气特性
};
//有pin mux相关的设定(PIN_MAP_TYPE_MUX_GROUP),定义如下:
struct pinctrl_setting_mux {
    unsigned group;//该setting所对应的group selector
    unsigned func;//该setting所对应的function selector
};
//有了function selector以及属于该functiong的roup selector就可以进行该device和pin mux相关的设定了。设定电气特性的settings定义如下:
struct pinctrl_map_configs {
    const char *group_or_pin;//该pin或者pin group的名字
    unsigned long *configs;//要设定的值的列表。这个值被用来写入HW
    unsigned num_configs;//列表中值的个数
};
  1. gpio 相关的结构体gpio_chip,因 pinctrl 子系统和 gpio 子系统是耦合的
struct gpio_chip {
	const char *label;
	struct gpio_device	*gpiodev;
	struct device *parent;
	struct module *owner;

	int (*request)(struct gpio_chip *chip, unsigned offset);
	void (*free)(struct gpio_chip *chip, unsigned offset);
	int (*get_direction)(struct gpio_chip *chip, unsigned offset);
	int (*direction_input)(struct gpio_chip *chip, unsigned offset);
	int (*direction_output)(struct gpio_chip *chip, unsigned offset, int value);
	int (*get)(struct gpio_chip *chip, unsigned offset);
	void (*set)(struct gpio_chip *chip, unsigned offset, int value);
	void (*set_multiple)(struct gpio_chip *chip, unsigned long *mask, unsigned long *bits);
	int (*set_config)(struct gpio_chip *chip, unsigned offset, unsigned long config);
	int (*to_irq)(struct gpio_chip *chip, unsigned offset);

	void (*dbg_show)(struct seq_file *s, struct gpio_chip *chip);
	int base;
	u16 ngpio;
	const char *const *names;
	bool can_sleep;

#if IS_ENABLED(CONFIG_GPIO_GENERIC)
	unsigned long (*read_reg)(void __iomem *reg);
	void (*write_reg)(void __iomem *reg, unsigned long data);
	unsigned long (*pin2mask)(struct gpio_chip *gc, unsigned int pin);
	void __iomem *reg_dat;
	void __iomem *reg_set;
	void __iomem *reg_clr;
	void __iomem *reg_dir;
	int bgpio_bits;
	spinlock_t bgpio_lock;
	unsigned long bgpio_data;
	unsigned long bgpio_dir;
#endif

#ifdef CONFIG_GPIOLIB_IRQCHIP
	/*
	 * With CONFIG_GPIOLIB_IRQCHIP we get an irqchip inside the gpiolib
	 * to handle IRQs for most practical cases.
	 */
	struct irq_chip		*irqchip;
	struct irq_domain	*irqdomain;
	unsigned int		irq_base;
	irq_flow_handler_t	irq_handler;
	unsigned int		irq_default_type;
	unsigned int		irq_chained_parent;
	bool			irq_nested;
	bool			irq_need_valid_mask;
	unsigned long		*irq_valid_mask;
	struct lock_class_key	*lock_key;
#endif

#if defined(CONFIG_OF_GPIO)
	/*
	 * If CONFIG_OF is enabled, then all GPIO controllers described in the
	 * device tree automatically may have an OF translation
	 */

	/*Pointer to a device tree node representing this GPIO controller.*/
	struct device_node *of_node;

	/* Number of cells used to form the GPIO specifier.*/
	unsigned int of_gpio_n_cells;

	/**
	 * Callback to translate a device tree GPIO specifier into a chip-
	 * relative GPIO number and flags.
	 */
	int (*of_xlate)(struct gpio_chip *gc, const struct of_phandle_args *gpiospec, u32 *flags);
#endif
};
  • 根据GPIO ID找到该ID对应的pin control device(struct pinctrl_dev)和GPIO rang(pinctrl_gpio_range)。在core driver中,每个low level的pin controller device都被映射成一个struct pinctrl_dev,并形成链表,链表头就是pinctrldev_list。由于实际的硬件设计(例如GPIO block被分成若干个GPIO 的bank,每个bank就对应一个HW GPIO Controller Block),一个pin control device要管理的GPIO ID是分成区域的,每个区域用struct pinctrl_gpio_range来抽象,在low level 的pin controller初始化的时候(具体参考samsung_pinctrl_register的代码),会调用pinctrl_add_gpio_range将每个GPIO bank表示的gpio range挂入到pin control device的range list中(gpio_ranges成员)。pinctrl_gpio_range 的定义如下:
struct pinctrl_gpio_range {
    struct list_head node;
    const char *name;
    unsigned int id;//GPIO chip ID
    unsigned int base;//该range中的起始GPIO IDD
    unsigned int pin_base;//在线性映射的情况下,这是起始的pin base
    unsigned const *pins;//在非线性映射的时候,这是table是pin到GPIO的lookup table
    unsigned int npins;//这个range有多少个GPIO引脚
    struct gpio_chip *gc;-//每个GPIO bank都是一个gpio chip,对应一个GPIO range
};
  • pin ID和GPIO ID有两种映射关系,一种是线性映射(这时候pin_base有效),对于这个GPIO range,GPIO base ID是a,pin ID base是b,那么a<—>b,a+1<—>b+1,a+2<—>b+2,以此类推。对于非线性映射(pin_base无效,pins是有效的),需要建立一个lookup table,以GPIO ID为索引,可以找到对于的pin ID。

函数调用逻辑

  1. 在文件 drivers/pinctrl/freescale/pinctrl-xxx.c中,驱动的入口是 arch_initcall 中声明的函数
  2. pinctrl 子系统的驱动也是一个标准的 platform 驱动框架,分为:驱动、设备、总线。platform 虚拟总线会按照 of_device_id 结构体中的 compatible 属性去匹配 pinctrl 驱动和设备
  3. of_device_id 定义的数组,最后一个是空元素,这是必须的,原因是 platform 本身的 match 函数中需要判断是否达到末尾,of_device_id 定义的 compatible 经常不止一个,系统需要知道是否匹配到最后一个元素
  4. probe 函数后面的调用中,调用 pinctrl_register 函数,向 Linux 内核注册一个 PIN 控制器
struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc, struct device *dev, void *driver_data)

设备树实例

  1. pin controller 的DTS结构
  • 每个pin configuration都是pin controller的child node,描述了client device要使用到的一组pin的配置信息
  • 各个device可以通过自己节点的属性来指向pin controller的某个child node,也就是pin configuration
  1. DTS的PIN属性
  • actions,groups的属性用于表示Mux Group的名字数组
  • actions,pins的属性用于表示该组pin的名字数组
  • actions,function的属性表示该组Mux Group使用功能的名字
  • actions,paddrv的属性表示该组Dirve Group所代表的pin的驱动能力
  • actions,pull的属性表述该组的pin需要配置的上下拉状态
pinctrl@56000000 { 
        //定义S3C2416 pin controller自己的属性
        reg = <0x56000000 0x1000="">;
        compatible = "samsung,s3c2416-pinctrl";
        ...
        //定义pin bank
        gpf {
        	//gpio-controller属性,说明该device node是一个GPIO controller
            gpio-controller;
            //#gpio-cells属性是一个GPIO controller的必须定义的属性,描述了需要多少个cell来具体描述一个GPIO(这是和具体的GPIO controller相关的)
            #gpio-cells = <0x2>;
            interrupt-controller;
            #interrupt-cells = <0x2>;
            //phandle(linux,phandle这个属性和phandle是一样的,只不过linux,phandle是old-style,多定义一个属性是为了兼容)定义了一个句柄,当其他的device node想要引用这个node的时候就可以使用该句柄
            linux,phandle = <0xc>;
            phandle = <0xc>;
        };
        ...
        //定义功能复用配置
        uart0-data {
        //samsung,pins这个属性定义了一个pin configuration所涉及到的引脚定义
        //对于uart0-data这个node,该配置涉及了gph bank中的第一个和第二个GPIO pin
        //一旦选择功能,amsung,pins定义的引脚需要做功能设定,这就是samsung,pin-function定义的内容。而具体设定需要去查阅datasheet
    	samsung,pins = "gph-0", "gph-1";
    	samsung,pin-function = <0x2>;
    	linux,phandle = <0x2>;
    	phandle = <0x2>;
		};

		uart0-fctl {
    	samsung,pins = "gph-8", "gph-9";
    	samsung,pin-function = <0x2>;
    	linux,phandle = <0x3>;
    	phandle = <0x3>;
		};
		...
}
//client device的DTS
device-node-name { 
    //定义该device自己的属性  
	...
	//pinctrl-names定义了一个pin state列表
	//state有两种,标识,一种就是pinctrl-names定义的字符串列表,另外一种就是ID,ID从0开始,依次加
    pinctrl-names = "sleep", "active";
    //pinctrl-x的定义。pinctrl-x是一个句柄(phandle)列表,每个句柄指向一个pin configuration。
    //有时候,一个state对应多个pin configure。例如I2C功能有两种配置,一是pin ID{7,8}引出,另一是pin ID{69,103}引出
    pinctrl-0 = <pin-config-0-a>;
    pinctrl-1 = <pin-config-1-a pin-config-1-b>;        
};
//例如
serial@50000000 { 
	……
	pinctrl-names = "default";
	pinctrl-0 = <0x2 0x3>;//或 pinctrl-0 = <&uart0-data &uart0-fctl>
};

驱动使用pinctrl

//设备驱动模块获取对应的pinctrl
struct pinctrl *devm_pinctrl_get(struct device *dev);
struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *p, const char *name);

struct pinctrl *pinctrl_get_select_default(struct device *dev);
struct pinctrl *devm_pinctrl_get_select(struct device *dev, const char *name);
int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state);
//pinctrl子系统申请GPIO
int pinctrl_request_gpio(unsigned gpio);
void pinctrl_free_gpio(unsigned gpio);
int pinctrl_gpio_direction_input(unsigned gpio);
int pinctrl_gpio_direction_output(unsigned gpio);
//GPIO子系统申请GPIO
#include <linux/gpio.h> //里面声明io口的操作函数
int gpio_request(unsigned gpio, const char *label);//每个io只能被请求一次,可防止多个驱动来控制同一个IO口 
void gpio_free(unsigned gpio); //释放已请求的io口 
int gpio_direction_input(unsigned gpio); //把指定的IO口作输入功能, gpio用于指定具体哪个io口 
int gpio_direction_output(unsigned gpio, int value); //作输出功能,并根据value的值输出高低电平 
int gpio_get_value(unsigned gpio); //获取指定IO口的电平 
void gpio_set_value(unsigned gpio, int value); //设置IO口的电平为value(0/1)
int gpio_to_irq(unsigned gpio); //根据io口,获取到它对应的中断号(io口大都有外部中断功能)

与驱动模型的接口

  • 与其写代码调用devm_pinctrl_get、pinctrl_lookup_state、pinctrl_select_state等pin control subsystem的接口函数,最好是让统一设备驱动模型(Driver model)来处理pin 的各种设定。
  • linux kernel中的驱动模型提供了driver和device的绑定机制,一旦匹配会调用probe函数如下:
static int really_probe(struct device *dev, struct device_driver *drv)
{
    ……
    ret = pinctrl_bind_pins(dev);//对该device涉及的pin进行pin control相关设定
    ……

    if (dev->bus->probe) {//下面是真正的probe过程
        ret = dev->bus->probe(dev);
        if (ret)
            goto probe_failed;
    } else if (drv->probe) {
        ret = drv->probe(dev);
        if (ret)
            goto probe_failed;
    }

……

}
//pinctrl_bind_pins的代码如下:
int pinctrl_bind_pins(struct device *dev)
{
    int ret;
    dev->pins = devm_kzalloc(dev, sizeof(*(dev->pins)), GFP_KERNEL);
    dev->pins->p = devm_pinctrl_get(dev);//调用devm_pinctrl_get获取该device对应的 pin control state holder句柄
    //搜索default state,sleep state,idle state并记录在本device中
    dev->pins->default_state = pinctrl_lookup_state(dev->pins->p, PINCTRL_STATE_DEFAULT);
    ret = pinctrl_select_state(dev->pins->p, dev->pins->default_state);//将该设备设定为pin default state
    dev->pins->sleep_state = pinctrl_lookup_state(dev->pins->p, PINCTRL_STATE_SLEEP);//(3)
    dev->pins->idle_state = pinctrl_lookup_state(dev->pins->p, PINCTRL_STATE_IDLE);//(3)
    return 0;
}
//struct device数据结构有一个pins的成员,它描述了和该设备相关的pin control的信息,定义如下:
struct dev_pin_info {
    struct pinctrl *p;//该device对应的pin control state holder
    struct pinctrl_state *default_state;//缺省状态
    struct pinctrl_state *sleep_state;//电源管理相关的状态
    struct pinctrl_state *idle_state;//电源管理相关的状态
};

和device tree或者machine driver相关的接口

  • device tree或者machine driver这两个模块主要是为 pin control subsystem提供pin mapping database的支持。这个database的每个entry用下面的数据结构表示:
struct pinctrl_map {
    const char *dev_name;//使用这个mapping entry的设备名
    const char *name;//该名字表示了该mapping entry
    enum pinctrl_map_type type;//这个entry的mapping type
    const char *ctrl_dev_name;//pin controller这个设备的名字
    union {
        struct pinctrl_map_mux mux;
        struct pinctrl_map_configs configs;
    } data;
};
  • 通过machine driver静态定义的数据来建立pin mapping database,machine driver定义一个巨大的mapping table,描述,然后在machine初始化的时候,调用pinctrl_register_mappings将该table注册到pin control subsystem中。
  • 通过device tree来建立pin mapping database,pin mapping信息定义在dts中,主要包括两个部分,一个是定义在各个具体的device node中,另外一处是定义在pin controller的device node中。
//一个典型的device tree中的外设node定义如下
device-node-name { 
        //定义该device自己的属性  
        pinctrl-names = "sleep", "default";
        pinctrl-0 = ;
        pinctrl-1 = ;        
    };
  • 对普通device的dts分析在函数pinctrl_dt_to_map中,代码如下:
int pinctrl_dt_to_map(struct pinctrl *p)
{  
    of_node_get(np); 
    //pinctrl-0 pinctrl-1……表示了该设备的一个个的状态,这里定义了两个pinctrl-0和pinctrl-1分别对应sleep和default状态。这里每次循环分析一个pin state。
    for (state = 0; ; state++) {
        /* Retrieve the pinctrl-* property */
        propname = kasprintf(GFP_KERNEL, "pinctrl-%d", state);
        prop = of_find_property(np, propname, &size); 
        kfree(propname);
        if (!prop)
            break;
		//size和list分别保存了该pin state中所涉及pin configuration phandle的数目以及phandle的列表
		//list指向pinctrl-x,size等于pinctrl-x=<...>元素个数
        list = prop->value;
        size /= sizeof(*list);
        //读取从pinctrl-names属性中获取对应的state name,如:sleep 或 default
        ret = of_property_read_string_index(np, "pinctrl-names", state, &statename);
        if (ret < 0) {
            //如果没有定义pinctrl-names属性,那么我们将pinctrl-0 pinctrl-1……中的那个ID取出来作为state name
            /* strlen("pinctrl-") == 8 */
            statename = prop->name + 8;
        }
        //遍历一个pin state中的pin configuration list,即pinctrl-x=<...>对应的pin configuration,实际应该是pin controler device node中的sub node,用指针phandle标识
        for (config = 0; config < size; config++) {
            phandle = be32_to_cpup(list++);
            //用phandle作为索引,在device tree中找他该phandle表示的那个pin configuration
            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;
			}
            //分析一个pin configuration
            ret = dt_to_map_one_config(p, statename, np_config);
            of_node_put(np_config);
            if (ret < 0)
                goto err;
        }

        //如果该设备没有定义pin configuration,那么也要创建一个dummy的pin state
        if (!size) {
            ret = dt_remember_dummy_state(p, statename);
            if (ret < 0)
                goto err;
        }
    }
    return 0;
err:
    pinctrl_dt_free_maps(p);
    return ret;
}
  • 对普通device的dts分析在函数dt_to_map_one_config中,代码如下:
//statename,对应的pinctrl-x的pinctrl-names属性名字,或ID
//np_config,指向pinctrl-x=<...>其中的一个节点
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;

    /* 增加节点np_config的引用 */
    np_pctldev = of_node_get(np_config);
    for (;;) {
    //首先找到该pin configuration node对应的parent node(也就是pin controler对应的node,如device-node-name),如果找不到或者是root node,则进入出错处理。
        np_pctldev = of_get_next_parent(np_pctldev);
        if (!np_pctldev || of_node_is_root(np_pctldev)) {
            of_node_put(np_pctldev);
            return -EPROBE_DEFER;
        }
        //获取pin control class device,也就是底层注册的pinctrl_dev
        pctldev = get_pinctrl_dev_from_of_node(np_pctldev);
        if (pctldev)
        	//一旦找到pin control class device则跳出for循环
            break;
        /* Do not defer probing of hogs (circular loop) */
        if (np_pctldev == p->dev->of_node) {
            of_node_put(np_pctldev);
            return -ENODEV;
        }
    }
    of_node_put(np_pctldev);

    /*
     * Call pinctrl driver to parse device tree node, and
     * generate mapping table entries
     */
    ops = pctldev->desc->pctlops;
    //调用底层的callback函数处理pin configuration node
    ret = ops->dt_node_to_map(pctldev, np_config, &map, &num_maps);
    if (ret < 0)
        return ret;

    /* Stash the mapping table chunk away for later use */
    //将该pin configuration node的mapping entry信息注册到系统中
    return dt_remember_or_free_map(p, statename, pctldev, map, num_maps);
}