转载地址:https://blog.csdn.net/chenliang0224/article/details/78777995
linux系统下采用pinctrl子系统管理所有的IO管脚,并对设备外围管脚(如串口、I2C、spi、LCD)都有相应的配置模式,本博客以pinctrl子系统细说该驱动架构。
1. 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管脚描述。
2. 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”结构体,下面将分析如何注册该结构体。
3. pinctrl_register()
直接上代码:
- 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);
- } 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”。
4. pinctrl_register_mappings()