轉載地址: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()