前言:
linux系统下采用pinctrl子系统管理所有的IO管脚,并对设备外围管脚(如串口、I2C、spi、LCD)都有相应的配置模式,本博客以pinctrl子系统细说该驱动架构。
static int __init nuc970_pinctrl_init(void)
{
return platform_driver_register(&nuc970_pinctrl_driver);
}
arch_initcall(nuc970_pinctrl_init);
static void __exit nuc970_pinctrl_exit(void)
{
platform_driver_unregister(&nuc970_pinctrl_driver);
}
module_exit(nuc970_pinctrl_exit);
static struct platform_driver nuc970_pinctrl_driver = {
.driver = {
.name = "pinctrl-nuc970",
.owner = THIS_MODULE,
},
.probe = nuc970_pinctrl_probe,
.remove = nuc970_pinctrl_remove,
};
static int nuc970_pinctrl_probe(struct platform_device *pdev)
{
struct pinctrl_dev *pctl;
pctl = pinctrl_register(&nuc970_pinctrl_desc, &pdev->dev, NULL);
if (IS_ERR(pctl))
pr_err("could not register NUC970 pin driver\n");
platform_set_drvdata(pdev, pctl);
return pinctrl_register_mappings(nuc970_pinmap, ARRAY_SIZE(nuc970_pinmap));
}
platform平台驱动设备的注册流程都是类似,具体注册流程可参考:点击打开链接,而arch_initcall(...)系统接口函数将注册该驱动,函数路径:inux-3.10.x\include\linux\init.h。现在我们主要分析下结构体struct nuc970_pinctrl_desc管脚描述。
先看下struct pinctrl_desc结构体定义的具体内容:
struct pinctrl_desc {
const char *name; //管脚控制名字
struct pinctrl_pin_desc const *pins; //管脚描述,包括管脚编号和管脚字符串描述,见下面!
unsigned int npins; //管脚个数
const struct pinctrl_ops *pctlops; //管脚控制操作,见下面!
const struct pinmux_ops *pmxops; //管脚复用操作,见下面!
const struct pinconf_ops *confops; //管脚配置操作,见下面!
struct module *owner;
};
管脚描述符控制结构体:
struct pinctrl_pin_desc {
unsigned number; //pin管脚值 如:PA01=0x00
const char *name; //pin管脚名字 如:PA01="PA0"
};
管脚操作结构体:
struct pinctrl_ops {
int (*get_groups_count) (struct pinctrl_dev *pctldev); //一个驱动控制器由哪些管脚构成,这里表示获取多少个控制器设备,见结构体nuc970_pinctrl_groups[]!
const char *(*get_group_name) (struct pinctrl_dev *pctldev,
unsigned selector); //每一组控制器都有对应的名字,如下面nuc970_pinctrl_groups[]结构体中第一个成员控制器的名字为“emac0_grp”
int (*get_group_pins) (struct pinctrl_dev *pctldev,
unsigned selector,
const unsigned **pins,
unsigned *num_pins); //获取一个驱动控制器由哪些外围管脚构成和管脚的个数,如"emac0_grp"是由“emac0_pins[]”数组构成
void (*pin_dbg_show) (struct pinctrl_dev *pctldev, struct seq_file *s,
unsigned offset);
int (*dt_node_to_map) (struct pinctrl_dev *pctldev,
struct device_node *np_config,
struct pinctrl_map **map, unsigned *num_maps);
void (*dt_free_map) (struct pinctrl_dev *pctldev,
struct pinctrl_map *map, unsigned num_maps);
};
由于一个控制器设备存在复用管脚,如nuc972 nandflash设备有两路管脚选择,所以我们在实际使用过程中需要选择任意一路,而struct pinmux就是对控制器设备复用选择操作:
struct pinmux_ops {
int (*request) (struct pinctrl_dev *pctldev, unsigned offset);
int (*free) (struct pinctrl_dev *pctldev, unsigned offset);
int (*get_functions_count) (struct pinctrl_dev *pctldev); //获取管脚复用个数
const char *(*get_function_name) (struct pinctrl_dev *pctldev,
unsigned selector); //获取管脚复用名字,如“emac0”
int (*get_function_groups) (struct pinctrl_dev *pctldev,
unsigned selector,
const char * const **groups,
unsigned * const num_groups); //获取控制器有多少个复用,我们还是以“emac0”为例,它只对应一个,即“emac0_grp”
int (*enable) (struct pinctrl_dev *pctldev, unsigned func_selector,
unsigned group_selector); //使能控制器,即配置控制器如果存在管脚复用,在实际使用中需选择一路来运用,下面会介绍
void (*disable) (struct pinctrl_dev *pctldev, unsigned func_selector,
unsigned group_selector); //释放管脚
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);
};
管脚配置操作结构体:
struct pinconf_ops {
#ifdef CONFIG_GENERIC_PINCONF
bool is_generic;
#endif
int (*pin_config_get) (struct pinctrl_dev *pctldev,
unsigned pin,
unsigned long *config);
int (*pin_config_set) (struct pinctrl_dev *pctldev,
unsigned pin,
unsigned long config);
int (*pin_config_group_get) (struct pinctrl_dev *pctldev,
unsigned selector,
unsigned long *config);
int (*pin_config_group_set) (struct pinctrl_dev *pctldev,
unsigned selector,
unsigned long config);
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);
};
上面主要介绍需要用到的结构体,下面我们将一步步分析pinctrl配置:
static struct pinctrl_desc nuc970_pinctrl_desc = {
.name = "nuc970-pinctrl_desc", //见下面
.pins = nuc970_pins,
.npins = ARRAY_SIZE(nuc970_pins),
.pctlops = &nuc970_pctrl_ops, //见下面
.pmxops = &nuc970_pmxops,
.owner = THIS_MODULE,
};
"nuc970_pins"管脚映射结构体:
const struct pinctrl_pin_desc nuc970_pins[] = {
PINCTRL_PIN(0x00, "PA0"),
PINCTRL_PIN(0x01, "PA1"),
//......
PINCTRL_PIN(0x40, "PE0"),
PINCTRL_PIN(0x41, "PE1"),
PINCTRL_PIN(0x42, "PE2"),
PINCTRL_PIN(0x43, "PE3"),
PINCTRL_PIN(0x44, "PE4"),
PINCTRL_PIN(0x45, "PE5"),
PINCTRL_PIN(0x46, "PE6"),
PINCTRL_PIN(0x47, "PE7"),
PINCTRL_PIN(0x48, "PE8"),
PINCTRL_PIN(0x49, "PE9"),
PINCTRL_PIN(0x4A, "PE10"),
PINCTRL_PIN(0x4B, "PE11"),
PINCTRL_PIN(0x4C, "PE12"),
PINCTRL_PIN(0x4D, "PE13"),
PINCTRL_PIN(0x4E, "PE14"),
PINCTRL_PIN(0x4F, "PE15"),
PINCTRL_PIN(0x50, "PF0"),
PINCTRL_PIN(0x51, "PF1"),
PINCTRL_PIN(0x52, "PF2"),
PINCTRL_PIN(0x53, "PF3"),
PINCTRL_PIN(0x54, "PF4"),
PINCTRL_PIN(0x55, "PF5"),
PINCTRL_PIN(0x56, "PF6"),
PINCTRL_PIN(0x57, "PF7"),
PINCTRL_PIN(0x58, "PF8"),
PINCTRL_PIN(0x59, "PF9"),
PINCTRL_PIN(0x5A, "PF10"),
PINCTRL_PIN(0x5B, "PF11"),
PINCTRL_PIN(0x5C, "PF12"),
PINCTRL_PIN(0x5D, "PF13"),
PINCTRL_PIN(0x5E, "PF14"),
PINCTRL_PIN(0x5F, "PF15"),
//......
};
static struct pinctrl_ops nuc970_pctrl_ops = {
.get_groups_count = nuc970_get_groups_count,
.get_group_name = nuc970_get_group_name,
.get_group_pins = nuc970_get_group_pins,
};
结构体的函数比较简单,如下:
static int nuc970_get_groups_count(struct pinctrl_dev *pctldev)
{
return ARRAY_SIZE(nuc970_pinctrl_groups);
}
static const char *nuc970_get_group_name(struct pinctrl_dev *pctldev,
unsigned selector)
{;
return nuc970_pinctrl_groups[selector].name;
}
static int nuc970_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
const unsigned ** pins,
unsigned * num_pins)
{
*pins = (unsigned *) nuc970_pinctrl_groups[selector].pins;
*num_pins = nuc970_pinctrl_groups[selector].num_pins;
return 0;
}
这里主要分析上面折几个函数内部调用的“nuc970_pinctrl_groups”结构体,这里已“emac0_grp”为例:
static const struct nuc970_pinctrl_group nuc970_pinctrl_groups[] = {
{
.name = "emac0_grp",
.pins = emac0_pins,
.num_pins = ARRAY_SIZE(emac0_pins),
.func = 0x1, //通过查看datasheet “emac0_pins”中的管脚是复用管脚,0x01表示选择选择emac0,如下截图!
},
{
.name = "emac1_grp",
.pins = emac1_pins,
.num_pins = ARRAY_SIZE(emac1_pins),
.func = 0x1,
},
//......
}
这里以“emac0_pins”举例,我们看如下的定义:
static const unsigned emac0_pins[] = {0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59}; // Port F
emac0_pins数组中内容16进制数表示对应的管脚,通过上面nuc970_pins结构体可以找到对应关系 0x50~0x59对用port F0~F7管脚。
emac0_pins结构体成员“.func=0x1”表示设置该管脚的寄存器值为1,通过查看下面的截图中红框部分得知它们为emac0的配置!
到这里就分析完了“nuc970_pctrl_ops”结构体,接下来我们继续回到“struct nuc970_pinctrl_desc”结构体来分析管脚复用成员“struct nuc970_pmxops”:
struct pinmux_ops nuc970_pmxops = {
.get_functions_count = nuc970_get_functions_count,
.get_function_name = nuc970_get_fname,
.get_function_groups = nuc970_get_groups,
.enable = nuc970_enable,
.disable = nuc970_disable,
};
nuc970_pmxops结构体中成员函数如下:
int nuc970_get_functions_count(struct pinctrl_dev *pctldev)
{
return ARRAY_SIZE(nuc970_functions);
}
const char *nuc970_get_fname(struct pinctrl_dev *pctldev, unsigned selector)
{
return nuc970_functions[selector].name;
}
static int nuc970_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
const char * const **groups,
unsigned * const num_groups)
{
*groups = nuc970_functions[selector].groups;
*num_groups = nuc970_functions[selector].num_groups;
return 0;
}
/*
* selector = data.nux.func, which is entry number in nuc970_functions,
* and group = data.mux.group, which is entry number in nuc970_pmx_func
* group is not used since some function use different setting between
* different ports. for example UART....
*/
int nuc970_enable(struct pinctrl_dev *pctldev, unsigned selector, unsigned group) { unsigned int i, j; unsigned int reg, offset; //printk("enable =>%x %x\n", selector, group); for(i = 0; i < nuc970_pinctrl_groups[group].num_pins; i++) { j = nuc970_pinctrl_groups[group].pins[i]; /* offset值要分两层意思理解: 1. (j >> 4) * 8 表示j/16*8,我们知道管脚PA0~PA15=0x00~0x0f,PB0~PB15=0x10~0x1f,.... 所以,(j >> 4)表示j属于哪一组管脚,如j=0x08,即是PA,j=0x12,即是PB, 而*8呢?通过下面GPA_L,GPA_H,GPB_L,GPB_H可知,GPAL与GPAH相差0x4,而 GPAL与GPBL相差0x08,所以这里的(j >> 4) * 8表示的是当前j属于PA还是PB... #define REG_MFP_GPA_L (GCR_BA+0x070) #define REG_MFP_GPA_H (GCR_BA+0x074) #define REG_MFP_GPB_L (GCR_BA+0x078) #define REG_MFP_GPB_H (GCR_BA+0x07C) 2. ((j & 0x8) ? 4 : 0) 由1.分析可知(j >> 4) * 8表示属于哪类管脚(PA\PB\PC...), 而((j & 0x8) ? 4 : 0) 表示的是哪类管脚(PA\PB\PC...)的高低字节,即PA_L\PA_H,PB_L\PB_H, PC_L\PC_H 所以,通过(j >> 4) * 8 + ((j & 0x8) ? 4 : 0)我们可以计算出当前的j是位于哪个管脚配置 寄存器EG_MFP_Px_y的哪种功能! */ offset = (j >> 4) * 8 + ((j & 0x8) ? 4 : 0); reg = __raw_readl(REG_MFP_GPA_L + offset); reg = (reg & ~(0xF << ((j & 0x7) * 4))) | (nuc970_pinctrl_groups[group].func << ((j & 0x7) * 4)); __raw_writel(reg, REG_MFP_GPA_L + offset); } /* SD0 pin value is 0x6, SD1 PI pin value is 0x4, should set the correct value */ if (strcmp(nuc970_pinctrl_groups[group].name, "sd01_0_grp") == 0) { for(i = 8; i < nuc970_pinctrl_groups[group].num_pins; i++) { j = nuc970_pinctrl_groups[group].pins[i]; offset = (j >> 4) * 8 + ((j & 0x8) ? 4 : 0); reg = __raw_readl(REG_MFP_GPA_L + offset); reg = (reg & ~(0xF << ((j & 0x7) * 4))) | (0x4 << ((j & 0x7) * 4)); __raw_writel(reg, REG_MFP_GPA_L + offset); } } return 0; }
/*
* By disable a function, we'll switch it back to GPIO
*/
void nuc970_disable(struct pinctrl_dev *pctldev, unsigned selector,
unsigned group)
{
unsigned int i, j;
unsigned int reg, offset;
//printk("disable =>%x %x\n", selector, group);
for(i = 0; i < nuc970_pinctrl_groups[group].num_pins; i++) {
j = nuc970_pinctrl_groups[group].pins[i];
offset = (j >> 4) * 8 + ((j & 0x8) ? 4 : 0); //获取寄存器偏移位置
reg = __raw_readl(REG_MFP_GPA_L + offset);
reg &= ~(0xF << ((j & 0x7) * 4));
__raw_writel(reg, REG_MFP_GPA_L + offset);
}
return;
}
这里我们主要分析上面函数中“struct nuc970_functions”结构体的作用, 这里还是以“emac0”为例:
static const struct nuc970_pmx_func nuc970_functions[] = {
{
.name = "emac0",
.groups = emac0_groups,
.num_groups = ARRAY_SIZE(emac0_groups),
},
{
.name = "emac1",
.groups = emac1_groups,
.num_groups = ARRAY_SIZE(emac1_groups),
},
//.......
}
static const char * const emac0_groups[] = {"emac0_grp"};
可以看到emac0_groups中内容为“emac0_grp”,这个就是对应我们上面分析到结构体nuc970_pinctrl_groups中的“emac0”,由于我们的“emac0”只有1个,所以emac0_groups中定义“emac0_grp”,例如nandflash有两路,所以就会定义两个,如下:
static const char * const nand_groups[] = {"nand_0_grp", "nand_1_grp"};
到这里就介绍完了“nuc970_pinctrl_desc”结构体,下面将分析如何注册该结构体。
直接上代码:
static int nuc970_pinctrl_probe(struct platform_device *pdev)
{
struct pinctrl_dev *pctl;
pctl = pinctrl_register(&nuc970_pinctrl_desc, &pdev->dev, NULL);
if (IS_ERR(pctl))
pr_err("could not register NUC970 pin driver\n");
platform_set_drvdata(pdev, pctl);
return pinctrl_register_mappings(nuc970_pinmap, ARRAY_SIZE(nuc970_pinmap));
}
管脚注册:
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; //将pctrldesc与管脚控制设备绑定
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);
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); //pinctrldev_list为全局链表,这里将pctrldev设备以节点的形式加入到链表pinctrldev_list中
mutex_unlock(&pinctrldev_list_mutex);
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");
}
pinctrl_init_device_debugfs(pctldev);
return pctldev;
out_err:
mutex_destroy(&pctldev->mutex);
kfree(pctldev);
return NULL;
}
static int pinctrl_register_pins(struct pinctrl_dev *pctldev,
struct pinctrl_pin_desc const *pins,
unsigned num_descs)
{
unsigned i;
int ret = 0;
for (i = 0; i < num_descs; i++) {
ret = pinctrl_register_one_pin(pctldev,
pins[i].number, pins[i].name);
if (ret)
return ret;
}
return 0;
}
static int pinctrl_register_one_pin(struct pinctrl_dev *pctldev,
unsigned number, const char *name)
{
struct pin_desc *pindesc;
pindesc = pin_desc_get(pctldev, number); //��δ���忴?????add by cl 20170411 23:41
if (pindesc != NULL) {
pr_err("pin %d already registered on %s\n", number,
pctldev->desc->name);
return -EINVAL;
}
pindesc = kzalloc(sizeof(*pindesc), GFP_KERNEL);
if (pindesc == NULL) {
dev_err(pctldev->dev, "failed to alloc struct pin_desc\n");
return -ENOMEM;
}
/* Set owner */
pindesc->pctldev = pctldev;
/* Copy basic pin info */
if (name) {
pindesc->name = name;
} else {
pindesc->name = kasprintf(GFP_KERNEL, "PIN%u", number);
if (pindesc->name == NULL) {
kfree(pindesc);
return -ENOMEM;
}
pindesc->dynamic_name = true;
}
radix_tree_insert(&pctldev->pin_desc_tree, number, pindesc); //将管脚值和管脚名称加入到“基数数”里面
pr_debug("registered pin %d (%s) on %s\n",
number, pindesc->name, pctldev->desc->name);
return 0;
}
至此就完成了管脚的注册,接下来分析管脚的映射“pinctrl_register_mappings”。
return pinctrl_register_mappings(nuc970_pinmap, ARRAY_SIZE(nuc970_pinmap));
这里我们主要分析nuc970_pinmap[]这个结构体,先来看下这个结构体内部都有哪些成员:
enum pinctrl_map_type {
PIN_MAP_TYPE_INVALID,
PIN_MAP_TYPE_DUMMY_STATE,
PIN_MAP_TYPE_MUX_GROUP,
PIN_MAP_TYPE_CONFIGS_PIN,
PIN_MAP_TYPE_CONFIGS_GROUP,
};
/**
* struct pinctrl_map_mux - mapping table content for MAP_TYPE_MUX_GROUP
* @group: the name of the group whose mux function is to be configured. This
* field may be left NULL, and the first applicable group for the function
* will be used.
* @function: the mux function to select for the group
*/
struct pinctrl_map_mux {
const char *group;
const char *function;
};
/**
* struct pinctrl_map_configs - mapping table content for MAP_TYPE_CONFIGS_*
* @group_or_pin: the name of the pin or group whose configuration parameters
* are to be configured.
* @configs: a pointer to an array of config parameters/values to program into
* hardware. Each individual pin controller defines the format and meaning
* of config parameters.
* @num_configs: the number of entries in array @configs
*/
struct pinctrl_map_configs {
const char *group_or_pin;
unsigned long *configs;
unsigned num_configs;
};
/**
* struct pinctrl_map - boards/machines shall provide this map for devices
* @dev_name: the name of the device using this specific mapping, the name
* must be the same as in your struct device*. If this name is set to the
* same name as the pin controllers own dev_name(), the map entry will be
* hogged by the driver itself upon registration
* @name: the name of this specific map entry for the particular machine.
* This is the parameter passed to pinmux_lookup_state()
* @type: the type of mapping table entry
* @ctrl_dev_name: the name of the device controlling this specific mapping,
* the name must be the same as in your struct device*. This field is not
* used for PIN_MAP_TYPE_DUMMY_STATE
* @data: Data specific to the mapping type
*/
struct pinctrl_map {
const char *dev_name;
const char *name;
enum pinctrl_map_type type;
const char *ctrl_dev_name;
union {
struct pinctrl_map_mux mux;
struct pinctrl_map_configs configs;
} data;
};
我们在来看下nuc970_pinmap[]这个结构体的成员:
static const struct pinctrl_map nuc970_pinmap[] = {
{
.dev_name = "nuc970-emac0", //设备驱动名称
.name = PINCTRL_STATE_DEFAULT,
.type = PIN_MAP_TYPE_MUX_GROUP,
.ctrl_dev_name = "pinctrl-nuc970",//控制设备名称
.data.mux.function = "emac0", //管脚复用功能名称,对应上面分析到的nuc970_functions[]结构体
.data.mux.group = "emac0_grp", //管脚复用所属组,对应上面分析到的nuc970_pinctrl_groups[]结构体
},
{
.dev_name = "nuc970-emac1",
.name = PINCTRL_STATE_DEFAULT,
.type = PIN_MAP_TYPE_MUX_GROUP,
.ctrl_dev_name = "pinctrl-nuc970",
.data.mux.function = "emac1",
.data.mux.group = "emac1_grp",
},
{
.dev_name = "nuc970-emac0",
.name = "pps0",
.type = PIN_MAP_TYPE_MUX_GROUP,
.ctrl_dev_name = "pinctrl-nuc970",
.data.mux.function = "pps0",
.data.mux.group = "pps0_grp",
},
{
.dev_name = "nuc970-emac1",
.name = "pps1",
.type = PIN_MAP_TYPE_MUX_GROUP,
.ctrl_dev_name = "pinctrl-nuc970",
.data.mux.function = "pps1",
.data.mux.group = "pps1_grp",
},
//......
}
再回到“pinctrl_register_mappings”函数,源码如下:
int pinctrl_register_mappings(struct pinctrl_map const *maps,
unsigned num_maps)
{
return pinctrl_register_map(maps, num_maps, true, false);
}
int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
bool dup, bool locked)
{
int i, ret;
struct pinctrl_maps *maps_node;
pr_debug("add %d pinmux maps\n", num_maps);
/* First sanity check the new mapping */
for (i = 0; i < num_maps; i++) {
if (!maps[i].dev_name) {
pr_err("failed to register map %s (%d): no device given\n",
maps[i].name, i);
return -EINVAL;
}
if (!maps[i].name) {
pr_err("failed to register map %d: no map name given\n",
i);
return -EINVAL;
}
if (maps[i].type != PIN_MAP_TYPE_DUMMY_STATE &&
!maps[i].ctrl_dev_name) {
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);
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 = 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;
}
if (!locked)
mutex_lock(&pinctrl_maps_mutex);
list_add_tail(&maps_node->node, &pinctrl_maps); //将管脚映射加入到链表pinctrl_maps中
if (!locked)
mutex_unlock(&pinctrl_maps_mutex);
return 0;
}
到这里就完成了管脚映射加入到内核链表中的操作,下面我们以UART2为例的说明驱动在注册时是如何获取到对应的管脚及管脚的寄存器的配置。
以下是截取nuc970_pinmap[]、nuc970_pinctrl_groups[]结构体的部分内容:
static const struct pinctrl_map nuc970_pinmap[] = {
{
.dev_name = "nuc970-uart.2",//驱动名称,由串口驱动程序注册时自动添加串口编号nuc970serial_driver.driver.name="nuc970-uart"
.name = "uart2_fc", //UART串口驱动注册时内部调用 devm_pinctrl_get_select(&pdev->dev, "uart2_fc");
.type = PIN_MAP_TYPE_MUX_GROUP,
.ctrl_dev_name = "pinctrl-nuc970",
.data.mux.function = "uart2",
.data.mux.group = "uart2_0_grp",
},
{
.dev_name = "nuc970-uart.2",
.name = "uart2_fc",
.type = PIN_MAP_TYPE_MUX_GROUP,
.ctrl_dev_name = "pinctrl-nuc970",
.data.mux.function = "uart2_fc",
.data.mux.group = "uart2_1_grp",
},
}
static const unsigned uart2_0_pins[] = {0x5B, 0x5C}; // tx, rx
static const unsigned uart2_1_pins[] = {0x5D, 0x5E}; // rts, cts
static const struct nuc970_pinctrl_group nuc970_pinctrl_groups[] = {
{
.name = "uart2_0_grp",
.pins = uart2_0_pins,
.num_pins = ARRAY_SIZE(uart2_0_pins),
.func = 0x9,
},
{
.name = "uart2_1_grp",
.pins = uart2_1_pins,
.num_pins = ARRAY_SIZE(uart2_1_pins),
.func = 0x9,
},
}
static const char * const uart2_groups[] = {"uart2_0_grp"};
static const char * const uart2_fc_groups[] = {"uart2_1_grp"};
static const struct nuc970_pmx_func nuc970_functions[] = {
{
.name = "uart2",
.groups = uart2_groups,
.num_groups = ARRAY_SIZE(uart2_groups),
},
{
.name = "uart2_fc",
.groups = uart2_fc_groups,
.num_groups = ARRAY_SIZE(uart2_fc_groups),
},
}
static const struct pinctrl_map nuc970_pinmap[] = {
{
.dev_name = "nuc970-uart.2",
.name = "uart2",
.type = PIN_MAP_TYPE_MUX_GROUP,
.ctrl_dev_name = "pinctrl-nuc970",
.data.mux.function = "uart2",
.data.mux.group = "uart2_0_grp",
},
{
.dev_name = "nuc970-uart.2",
.name = "uart2_fc",
.type = PIN_MAP_TYPE_MUX_GROUP,
.ctrl_dev_name = "pinctrl-nuc970",
.data.mux.function = "uart2",
.data.mux.group = "uart2_0_grp",
},
{
.dev_name = "nuc970-uart.2",
.name = "uart2_fc",
.type = PIN_MAP_TYPE_MUX_GROUP,
.ctrl_dev_name = "pinctrl-nuc970",
.data.mux.function = "uart2_fc",
.data.mux.group = "uart2_1_grp",
},
}
直接上源码:
devm_pinctrl_get_select(&pdev->dev, "uart2_fc");
static inline struct pinctrl * __must_check devm_pinctrl_get_select(
struct device *dev, const char *name)
{
struct pinctrl *p;
struct pinctrl_state *s;
int ret;
p = devm_pinctrl_get(dev); //获取pinctrl,见下面分析
if (IS_ERR(p))
return p;
s = pinctrl_lookup_state(p, name);
if (IS_ERR(s)) {
devm_pinctrl_put(p);
return ERR_CAST(s);
}
ret = pinctrl_select_state(p, s);
if (ret < 0) {
devm_pinctrl_put(p);
return ERR_PTR(ret);
}
return p;
}
struct pinctrl *devm_pinctrl_get(struct device *dev)
{
struct pinctrl **ptr, *p;
ptr = devres_alloc(devm_pinctrl_release, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return ERR_PTR(-ENOMEM);
p = pinctrl_get(dev); //获取管脚
if (!IS_ERR(p)) {
*ptr = p;
devres_add(dev, ptr);
} else {
devres_free(ptr);
}
return p;
}
struct pinctrl *pinctrl_get(struct device *dev)
{
struct pinctrl *p;
if (WARN_ON(!dev))
return ERR_PTR(-EINVAL);
/*
* See if somebody else (such as the device core) has already
* obtained a handle to the pinctrl for this device. In that case,
* return another pointer to it.
*/
//如果已经有其他模块get了,那么pinctrl肯定已经创建好了,直接返回吧,函数内部会遍历pinctrl_list链表,比对该设备(uart)的管脚控制是否已经配置?
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用于管理该设备本身的pin信息
return create_pinctrl(dev); //见下面的分析!
}
static struct pinctrl *find_pinctrl(struct device *dev)
{
struct pinctrl *p;
mutex_lock(&pinctrl_list_mutex);
list_for_each_entry(p, &pinctrl_list, node) //确定当前UART-2设备是否已经加入到pinctrl_list链表中,有就返回对应的pinctrl指向pinctrl_list链表指针
if (p->dev == dev) {
mutex_unlock(&pinctrl_list_mutex);
return p;
}
mutex_unlock(&pinctrl_list_mutex);
return NULL;
}
create_pinctrl()函数内嵌套太深,这里只给出函数嵌套路径,由于水平有限,仅贴出关键源代码:
static struct pinctrl *create_pinctrl(struct device *dev)
{
struct pinctrl *p;
const char *devname;
struct pinctrl_maps *maps_node;
int i;
struct pinctrl_map const *map;
int ret;
/*
* create the state cookie holder struct pinctrl for each
* mapping, this is what consumers will get when requesting
* a pin control handle with pinctrl_get()
*/
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;
INIT_LIST_HEAD(&p->states);
INIT_LIST_HEAD(&p->dt_maps);
ret = pinctrl_dt_to_map(p); //很重要,见下面的分析
if (ret < 0) {
kfree(p);
return ERR_PTR(ret);
}
devname = dev_name(dev);
mutex_lock(&pinctrl_maps_mutex);
/* Iterate over the pin control maps to locate the right ones */
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); //很重要,见下面分析
/*
* At this point the adding of a setting may:
*
* - Defer, if the pinctrl device is not yet available
* - Fail, if the pinctrl device is not yet available,
* AND the setting is a hog. We cannot defer that, since
* the hog will kick in immediately after the device
* is registered.
*
* If the error returned was not -EPROBE_DEFER then we
* accumulate the errors to see if we end up with
* an -EPROBE_DEFER later, as that is the worst case.
*/
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);
/* Add the pinctrl handle to the global list */
mutex_lock(&pinctrl_list_mutex);
list_add_tail(&p->node, &pinctrl_list);
mutex_unlock(&pinctrl_list_mutex);
return p;
}
//管脚到设备树的映射
int pinctrl_dt_to_map(struct pinctrl *p)
{
struct device_node *np = p->dev->of_node; //关联的设备树节点,这里应该是pinctrl-nuc970注册时绑定的???
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) {
dev_dbg(p->dev, "no of_node; not parsing pinctrl DT\n");
return 0;
}
/* We may store pointers to property names within the node */
of_node_get(np);
/* For each defined state ID */
for (state = 0; ; state++) {
/* Retrieve the pinctrl-* property */
propname = kasprintf(GFP_KERNEL, "pinctrl-%d", state);
prop = of_find_property(np, propname, &size); //匹配pinctrl-x名称
kfree(propname);
if (!prop)
break;
list = prop->value;
size /= sizeof(*list);
/* Determine whether pinctrl-names property names the state */
ret = of_property_read_string_index(np, "pinctrl-names",
state, &statename);
/*
* If not, statename is just the integer state ID. But rather
* than dynamically allocate it and have to free it later,
* just point part way into the property name for the string.
*/
if (ret < 0) {
/* strlen("pinctrl-") == 8 */
statename = prop->name + 8;
}
/* For every referenced pin configuration node in it */
for (config = 0; config < size; config++) {
phandle = be32_to_cpup(list++);
/* Look up the pin configuration node */
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;
}
/* Parse the node */
ret = dt_to_map_one_config(p, statename, np_config); //很重要!!!
of_node_put(np_config);
if (ret < 0)
goto err;
}
/* No entries in DT? Generate a dummy state table entry */
if (!size) {
ret = dt_remember_dummy_state(p, statename);
if (ret < 0)
goto err;
}
}
return 0;
err:
pinctrl_dt_free_maps(p);
return ret;
}
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;
/* Find the pin controller containing np_config */
np_pctldev = of_node_get(np_config);
for (;;) {
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;
}
//这个函数很重要,内部会遍历pinctrldev_list全局链表,而这个链表就是我们在pinctrl-nuc970.c设备驱动里注册的管脚!!!
pctldev = get_pinctrl_dev_from_of_node(np_pctldev);
if (pctldev)
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;
if (!ops->dt_node_to_map) {
dev_err(p->dev, "pctldev %s doesn't support DT\n",
dev_name(pctldev->dev));
return -ENODEV;
}
ret = ops->dt_node_to_map(pctldev, np_config, &map, &num_maps);//返回map映射个数汗操作函数,这里应该是对应nuc970_pinmap[]
if (ret < 0)
return ret;
/* Stash the mapping table chunk away for later use */
return dt_remember_or_free_map(p, statename, pctldev, map, num_maps); //很重要,见下面分析
}
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;
/* Initialize common mapping table entry fields */
for (i = 0; i < num_maps; i++) {
map[i].dev_name = dev_name(p->dev);
map[i].name = statename;
if (pctldev)
map[i].ctrl_dev_name = dev_name(pctldev->dev);
}
/* Remember the converted mapping table entries */
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;
}
dt_map->pctldev = pctldev;
dt_map->map = map;
dt_map->num_maps = num_maps;
list_add_tail(&dt_map->node, &p->dt_maps);
return pinctrl_register_map(map, num_maps, false, true); //很重要,见下面
}
这里要理解一点,maps[i]就是指向nuc970_pinmap[]结构体:
int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
bool dup, bool locked)
{
int i, ret;
struct pinctrl_maps *maps_node;
pr_debug("add %d pinmux maps\n", num_maps);
/* First sanity check the new mapping */
for (i = 0; i < num_maps; i++) { //遍历nuc970_pinmap[]成员个数
if (!maps[i].dev_name) {
pr_err("failed to register map %s (%d): no device given\n",
maps[i].name, i);
return -EINVAL;
}
if (!maps[i].name) {
pr_err("failed to register map %d: no map name given\n",
i);
return -EINVAL;
}
if (maps[i].type != PIN_MAP_TYPE_DUMMY_STATE &&
!maps[i].ctrl_dev_name) {
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); //判读复用功能是否有效
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 = 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;
}
if (!locked)
mutex_lock(&pinctrl_maps_mutex);
list_add_tail(&maps_node->node, &pinctrl_maps); //加入到全局链表中pinctrl_maps中,这里很重要,下面会用到!又见链表!!!
if (!locked)
mutex_unlock(&pinctrl_maps_mutex);
return 0;
}
到现在我们在回到create_pinctrl(...)函数:
static struct pinctrl *create_pinctrl(struct device *dev)
{
struct pinctrl *p;
const char *devname;
struct pinctrl_maps *maps_node;
int i;
struct pinctrl_map const *map;
int ret;
/*
* create the state cookie holder struct pinctrl for each
* mapping, this is what consumers will get when requesting
* a pin control handle with pinctrl_get()
*/
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;
INIT_LIST_HEAD(&p->states);
INIT_LIST_HEAD(&p->dt_maps);
ret = pinctrl_dt_to_map(p); //从设备树device tree设备找到对应的映射,上面已简单分析,水太深,我也还没有完全理解!!!!
if (ret < 0) {
kfree(p);
return ERR_PTR(ret);
}
devname = dev_name(dev);
mutex_lock(&pinctrl_maps_mutex);
/* Iterate over the pin control maps to locate the right ones */
//for_each_maps(...)遍历的是上面分析到的pinctrl_maps链表,所以下面的操作就明白了,就是
//查找与链表中相同的设备名字,而devname="nuc970-uart.2",在结构体nuc970_pinmap[]中有三个
//"nuc970-uart.2"相同的成员,这里是如何选择一个还没有找到原因?
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); //很重要,管脚功能选择、配置就是通过该函数,见下面!!
/*
* At this point the adding of a setting may:
*
* - Defer, if the pinctrl device is not yet available
* - Fail, if the pinctrl device is not yet available,
* AND the setting is a hog. We cannot defer that, since
* the hog will kick in immediately after the device
* is registered.
*
* If the error returned was not -EPROBE_DEFER then we
* accumulate the errors to see if we end up with
* an -EPROBE_DEFER later, as that is the worst case.
*/
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);
/* Add the pinctrl handle to the global list */
mutex_lock(&pinctrl_list_mutex);
list_add_tail(&p->node, &pinctrl_list);
mutex_unlock(&pinctrl_list_mutex);
return p;
}
static int add_setting(struct pinctrl *p, struct pinctrl_map const *map)
{
struct pinctrl_state *state;
struct pinctrl_setting *setting;
int ret;
//确定串口名字是否有相同, map->name="uart2"或“uart2-fc”
state = find_state(p, map->name);
if (!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;
setting = kzalloc(sizeof(*setting), GFP_KERNEL);
if (setting == NULL) {
dev_err(p->dev,
"failed to alloc struct pinctrl_setting\n");
return -ENOMEM;
}
setting->type = map->type;
//函数会遍历全局链表pinctrldev_list,而pinctrl-nuc970.c管脚是加入到了该链表中。
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:
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;
}
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; //获取nuc970_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;
}
//1. 在nuc970_functions[]中查找与“uart2_fc”匹配的成员,同时返回该成员在nuc970_functions[]的偏移位置!!!
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->data.mux.func = ret;
//2. 由1.中返回的索引,确定“uart2_fc”有多少组复用的管脚配置,这里uart2_fc_groups[] = {"uart2_1_grp"}
// 即只有一组,同时返回uart2_fc_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])) { //确定组名“uart2_1_grp”是否匹配!!!
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];
}
//3. 根据选中的组名“uart2_1_grp”,确定“uart2_1_grp”对应的管家选择,这里返回“uart2_1_grp”在
// nuc970_pinctrl_groups[]中的偏移!!!
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;
}
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_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:
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;
}
setting->data.configs.num_configs = map->data.configs.num_configs;
setting->data.configs.configs = map->data.configs.configs;
return 0;
}
再次回到devm_pinctrl_get_select(...)函数,
static inline struct pinctrl * __must_check devm_pinctrl_get_select(
struct device *dev, const char *name)
{
struct pinctrl *p;
struct pinctrl_state *s;
int ret;
p = devm_pinctrl_get(dev); //获取pinctrl
if (IS_ERR(p))
return p;
//查找管脚的状态setting,已在devm_pinctrl_get(...)函数内部有提到
s = pinctrl_lookup_state(p, name);
if (IS_ERR(s)) {
devm_pinctrl_put(p);
return ERR_CAST(s);
}
//根据管脚控制,选择一种状态,即使能“uart-fs”串口的配置
ret = pinctrl_select_state(p, s);
if (ret < 0) {
devm_pinctrl_put(p);
return ERR_PTR(ret);
}
return p;
}
int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)
{
struct pinctrl_setting *setting, *setting2;
struct pinctrl_state *old_state = p->state;
int ret;
if (p->state == state)
return 0;
if (p->state) {
/*
* The set of groups with a mux configuration in the old state
* may not be identical to the set of groups with a mux setting
* in the new state. While this might be unusual, it's entirely
* possible for the "user"-supplied mapping table to be written
* that way. For each group that was configured in the old state
* but not in the new state, this code puts that group into a
* safe/disabled state.
*/
list_for_each_entry(setting, &p->state->settings, node) {
bool found = false;
if (setting->type != PIN_MAP_TYPE_MUX_GROUP)
continue;
list_for_each_entry(setting2, &state->settings, node) {
if (setting2->type != PIN_MAP_TYPE_MUX_GROUP)
continue;
if (setting2->data.mux.group ==
setting->data.mux.group) {
found = true;
break;
}
}
if (!found)
pinmux_disable_setting(setting);
}
}
p->state = NULL;
/* Apply all the settings for the new state */
//到这里,终于看到了对pin管脚的操作函数,真的不容易!!!!
list_for_each_entry(setting, &state->settings, node) {
switch (setting->type) {
case PIN_MAP_TYPE_MUX_GROUP:
ret = pinmux_enable_setting(setting); //见下面
break;
case PIN_MAP_TYPE_CONFIGS_PIN:
case PIN_MAP_TYPE_CONFIGS_GROUP:
ret = pinconf_apply_setting(setting); //见下面
break;
default:
ret = -EINVAL;
break;
}
if (ret < 0) {
goto unapply_new_state;
}
}
p->state = state;
return 0;
unapply_new_state:
dev_err(p->dev, "Error applying setting, reverse things back\n");
list_for_each_entry(setting2, &state->settings, node) {
if (&setting2->node == &setting->node)
break;
/*
* All we can do here is pinmux_disable_setting.
* That means that some pins are muxed differently now
* than they were before applying the setting (We can't
* "unmux a pin"!), but it's not a big deal since the pins
* are free to be muxed by another apply_setting.
*/
if (setting2->type == PIN_MAP_TYPE_MUX_GROUP)
pinmux_disable_setting(setting2);
}
/* There's no infinite recursive loop here because p->state is NULL */
if (old_state)
pinctrl_select_state(p, old_state);
return ret;
}
int pinmux_enable_setting(struct pinctrl_setting const *setting)
{
struct pinctrl_dev *pctldev = setting->pctldev;
const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
const struct pinmux_ops *ops = pctldev->desc->pmxops;
int ret;
const unsigned *pins;
unsigned num_pins;
int i;
struct pin_desc *desc;
//获取管脚的数量和数组,即“uart-fs”的配置管脚
ret = pctlops->get_group_pins(pctldev, setting->data.mux.group,
&pins, &num_pins);
if (ret) {
/* errors only affect debug data, so just warn */
dev_warn(pctldev->dev,
"could not get pins for group selector %d\n",
setting->data.mux.group);
num_pins = 0;
}
//申请管脚使用,即“uart-fs”的配置管脚
/* Try to allocate all pins in this group, one by one */
for (i = 0; i < num_pins; i++) {
ret = pin_request(pctldev, pins[i], setting->dev_name, NULL);
if (ret) {
dev_err(pctldev->dev,
"could not request pin %d on device %s\n",
pins[i], pinctrl_dev_get_name(pctldev));
goto err_pin_request;
}
}
/* Now that we have acquired the pins, encode the mux setting */
for (i = 0; i < num_pins; i++) {
desc = pin_desc_get(pctldev, pins[i]);
if (desc == NULL) {
dev_warn(pctldev->dev,
"could not get pin desc for pin %d\n",
pins[i]);
continue;
}
desc->mux_setting = &(setting->data.mux);
}
//使能管脚,到这里就是我们最终要找的根源,到这里也就完成了管脚的选择、配置!!!
ret = ops->enable(pctldev, setting->data.mux.func,
setting->data.mux.group);
if (ret)
goto err_enable;
return 0;
err_enable:
for (i = 0; i < num_pins; i++) {
desc = pin_desc_get(pctldev, pins[i]);
if (desc)
desc->mux_setting = NULL;
}
err_pin_request:
/* On error release all taken pins */
while (--i >= 0)
pin_free(pctldev, pins[i], NULL);
return ret;
}
int pinconf_apply_setting(struct pinctrl_setting const *setting)
{
struct pinctrl_dev *pctldev = setting->pctldev;
const struct pinconf_ops *ops = pctldev->desc->confops;
int i, ret;
if (!ops) {
dev_err(pctldev->dev, "missing confops\n");
return -EINVAL;
}
switch (setting->type) {
case PIN_MAP_TYPE_CONFIGS_PIN:
if (!ops->pin_config_set) {
dev_err(pctldev->dev, "missing pin_config_set op\n");
return -EINVAL;
}
for (i = 0; i < setting->data.configs.num_configs; i++) {
ret = ops->pin_config_set(pctldev,
setting->data.configs.group_or_pin,
setting->data.configs.configs[i]);
if (ret < 0) {
dev_err(pctldev->dev,
"pin_config_set op failed for pin %d config %08lx\n",
setting->data.configs.group_or_pin,
setting->data.configs.configs[i]);
return ret;
}
}
break;
case PIN_MAP_TYPE_CONFIGS_GROUP:
if (!ops->pin_config_group_set) {
dev_err(pctldev->dev,
"missing pin_config_group_set op\n");
return -EINVAL;
}
for (i = 0; i < setting->data.configs.num_configs; i++) {
ret = ops->pin_config_group_set(pctldev,
setting->data.configs.group_or_pin,
setting->data.configs.configs[i]);
if (ret < 0) {
dev_err(pctldev->dev,
"pin_config_group_set op failed for group %d config %08lx\n",
setting->data.configs.group_or_pin,
setting->data.configs.configs[i]);
return ret;
}
}
break;
default:
return -EINVAL;
}
return 0;
}
ret = ops->enable(pctldev, setting->data.mux.func, setting->data.mux.group);这里调用的是结构体nuc970_pmxops中的成员nuc970_enable函数,至此上面讲了一大推的铺垫也就是为了找到这个管脚配置的源头!!!