gpio子系统和pinctrl子系统(下)

情景分析

打算从两个角度来情景分析,先从bsp驱动工程师的角度,然后是驱动工程师的角度,下面以三星s3c6410 Pinctrl-samsung.c为例看看pinctrl输入参数的初始化过程(最开始的zynq平台的pin配置貌似是通过bitstreams来的,内核层没看到有关配置pin的代码,不过最新的zynq代码里加入了pinctrl,但我手上的恰好的较早其的zynq代码,所以这里以三星的代码为例子),不过这里贴的代码有点多(尽量将无关的代码删掉),耐心的看吧_

bsp驱动工程师的角度


   
   
  1. static int samsung_pinctrl_probe(struct platform_device *pdev)
  2. {
  3. ...
  4. ...
  5. ...
  6. //解析pinctrl信息,后面分析
  7. ctrl = samsung_pinctrl_get_soc_data(drvdata, pdev);
  8. drvdata->ctrl = ctrl;
  9. drvdata->dev = dev;
  10. ...
  11. ...
  12. ...
  13. //向gpio子系统注册(三星有用gpio子系统)
  14. ret = samsung_gpiolib_register(pdev, drvdata);
  15. if (ret)
  16. return ret;
  17. //向pinctrl子系统注册
  18. ret = samsung_pinctrl_register(pdev, drvdata);
  19. if (ret) {
  20. samsung_gpiolib_unregister(pdev, drvdata);
  21. return ret;
  22. }
  23. ...
  24. ...
  25. ...
  26. return 0;
  27. }

先贴下6410 pinctrl设备树信息(arch/arm/boot/dts/s3c64xx.dtsi):


   
   
  1. aliases {
  2. i2c0 = &i2c0;
  3. pinctrl0 = &pinctrl0;
  4. };
  5. pinctrl0: pinctrl@ 7f008000 {
  6. compatible = "samsung,s3c64xx-pinctrl";
  7. reg = < 0x7f008000 0x1000>;
  8. interrupt-parent = <&vic1>;
  9. interrupts = < 21>;
  10. pctrl_int_map: pinctrl-interrupt-map {
  11. interrupt-map = < 0 &vic0 0>,
  12. < 1 &vic0 1>,
  13. < 2 &vic1 0>,
  14. < 3 &vic1 1>;
  15. #address-cells = <0>;
  16. #size-cells = <0>;
  17. #interrupt-cells = <1>;
  18. };
  19. wakeup-interrupt-controller {
  20. compatible = "samsung,s3c64xx-wakeup-eint";
  21. interrupts = < 0>, < 1>, < 2>, < 3>;
  22. interrupt-parent = <&pctrl_int_map>;
  23. };
  24. };

下面边看代码边对照上面的设备树描述,看看解析过程:


   
   
  1. static struct samsung_pin_ctrl * samsung_pinctrl_get_soc_data(
  2. struct samsung_pinctrl_drv_data *d,
  3. struct platform_device *pdev)
  4. {
  5. int id;
  6. const struct of_device_id *match;
  7. struct device_node *node = pdev->dev.of_node;
  8. struct device_node *np;
  9. struct samsung_pin_ctrl *ctrl;
  10. struct samsung_pin_bank *bank;
  11. int i;
  12. //获取pinctrl的alias id,其实就是上面的pinctrl0了
  13. id = of_alias_get_id(node, "pinctrl");
  14. if (id < 0) {
  15. dev_err(&pdev->dev, "failed to get alias id\n");
  16. return NULL;
  17. }
  18. //获取该节点对应的match
  19. match = of_match_node(samsung_pinctrl_dt_match, node);
  20. //通过id找到对应的pinctrl,因为三星的有些soc是存在多个pinctrl的,
  21. //也就是说pinctrl0,pinctrl1等等同时存在,这里就是获取第id个,对于6410,就一个
  22. //struct samsung_pin_ctrl s3c64xx_pin_ctrl[] = {
  23. // {
  24. // /* pin-controller instance 1 data */
  25. // .pin_banks = s3c64xx_pin_banks0,
  26. // .nr_banks = ARRAY_SIZE(s3c64xx_pin_banks0),
  27. // .eint_gpio_init = s3c64xx_eint_gpio_init,
  28. // .eint_wkup_init = s3c64xx_eint_eint0_init,
  29. // .label = "S3C64xx-GPIO",
  30. // },
  31. //};
  32. 对于exynos5420,就存在多个啦:
  33. //struct samsung_pin_ctrl exynos5420_pin_ctrl[] = {
  34. // {
  35. // /* pin-controller instance 0 data */
  36. // .pin_banks = exynos5420_pin_banks0,
  37. // .nr_banks = ARRAY_SIZE(exynos5420_pin_banks0),
  38. // .geint_con = EXYNOS_GPIO_ECON_OFFSET,
  39. // .geint_mask = EXYNOS_GPIO_EMASK_OFFSET,
  40. // .geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
  41. // .weint_con = EXYNOS_WKUP_ECON_OFFSET,
  42. // .weint_mask = EXYNOS_WKUP_EMASK_OFFSET,
  43. // .weint_pend = EXYNOS_WKUP_EPEND_OFFSET,
  44. // .svc = EXYNOS_SVC_OFFSET,
  45. // .eint_gpio_init = exynos_eint_gpio_init,
  46. // .eint_wkup_init = exynos_eint_wkup_init,
  47. // .label = "exynos5420-gpio-ctrl0",
  48. // }, {
  49. // /* pin-controller instance 1 data */
  50. // .pin_banks = exynos5420_pin_banks1,
  51. // .nr_banks = ARRAY_SIZE(exynos5420_pin_banks1),
  52. // .geint_con = EXYNOS_GPIO_ECON_OFFSET,
  53. // .geint_mask = EXYNOS_GPIO_EMASK_OFFSET,
  54. // .geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
  55. // .svc = EXYNOS_SVC_OFFSET,
  56. // .eint_gpio_init = exynos_eint_gpio_init,
  57. // .label = "exynos5420-gpio-ctrl1",
  58. // },
  59. // ...
  60. // ...
  61. // ...
  62. //};
  63. ctrl = ( struct samsung_pin_ctrl *)match->data + id;
  64. //提取pin ctrl里的banks信息,这里就是ARRAY_SIZE(s3c64xx_pin_banks0)
  65. bank = ctrl->pin_banks;
  66. //遍历每一个bank,填充相应的信息
  67. for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
  68. spin_lock_init(&bank->slock);
  69. bank->drvdata = d;
  70. //设置bank的pin base
  71. bank->pin_base = ctrl->nr_pins;
  72. //更新ctrl->nr_pins,即该pin ctrl的pin数量,在后面的注册时会用到该成员
  73. ctrl->nr_pins += bank->nr_pins;
  74. }
  75. //遍历该节点的每一个子节点,上面的s3c64xx.dtsi文件末尾有一个
  76. //#include "s3c64xx-pinctrl.dtsi" 语句,s3c64xx-pinctrl.dtsi里
  77. //的信息是对当前节点pinctrl0的补充,内容如下:
  78. //&pinctrl0 {
  79. ///*
  80. // * Pin banks
  81. // */
  82. //
  83. //gpa: gpa {
  84. // gpio-controller;
  85. // #gpio-cells = <2>;
  86. // interrupt-controller;
  87. // #interrupt-cells = <2>;
  88. //};
  89. //
  90. //gpb: gpb {
  91. // gpio-controller;
  92. // #gpio-cells = <2>;
  93. // interrupt-controller;
  94. // #interrupt-cells = <2>;
  95. //};
  96. //gpc: gpc {
  97. // gpio-controller;
  98. // #gpio-cells = <2>;
  99. // interrupt-controller;
  100. // #interrupt-cells = <2>;
  101. //};
  102. //...
  103. //...
  104. //...
  105. //hsi_bus: hsi-bus {
  106. // samsung,pins = "gpk-0", "gpk-1", "gpk-2", "gpk-3",
  107. // "gpk-4", "gpk-5", "gpk-6", "gpk-7";
  108. // samsung,pin-function = <3>;
  109. // samsung,pin-pud = <PIN_PULL_NONE>;
  110. //};
  111. //}
  112. //这里就是处理这些子节点
  113. for_each_child_of_node(node, np) {
  114. //如果该子节点没有gpio-controller属性,跳过处理,这里处理的是bank
  115. //只和gpio有关,所以跳过不关心的
  116. if (! of_find_property(np, "gpio-controller", NULL))
  117. continue;
  118. bank = ctrl->pin_banks;
  119. for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
  120. if (! strcmp(bank->name, np->name)) {
  121. //将bank对应到它自己的设备节点
  122. bank->of_node = np;
  123. break;
  124. }
  125. }
  126. }
  127. ctrl->base = pin_base;
  128. pin_base += ctrl->nr_pins;
  129. return ctrl;
  130. }

填充完必要的信息,就开始注册了,先看pinctrl的注册吧!注意,传入的参数drvdata是已经经过前面的解析填入了很多信息的


   
   
  1. static int samsung_pinctrl_register(struct platform_device *pdev,
  2. struct samsung_pinctrl_drv_data *drvdata)
  3. {
  4. struct pinctrl_desc *ctrldesc = &drvdata->pctl;
  5. struct pinctrl_pin_desc *pindesc, *pdesc;
  6. struct samsung_pin_bank *pin_bank;
  7. char *pin_names;
  8. int pin, bank, ret;
  9. //初始化pinctrl_desc,register的时候要用
  10. ctrldesc->name = "samsung-pinctrl";
  11. ctrldesc->owner = THIS_MODULE;
  12. //这个ops是必须要的,里面的几个函数前面也都用到了,主要有
  13. //get_groups_count、dt_node_to_map、get_group_pins
  14. ctrldesc->pctlops = &samsung_pctrl_ops;
  15. //这个是pinctrl chip driver根据自己平台的特性,可选的支持的
  16. //主要有request、get_functions_count、get_function_groups、
  17. //enable,和gpio相关的还有额外几个gpio_request_enable、gpio_disable_free、gpio_set_direction
  18. ctrldesc->pmxops = &samsung_pinmux_ops;
  19. //这个是pinctrl chip driver根据自己平台的特性,可选的支持的
  20. //主要有pin_config_get、pin_config_set、pin_config_group_get、pin_config_group_set
  21. ctrldesc->confops = &samsung_pinconf_ops;
  22. //下面这部分也是pinctrl chip driver根据自己平台的特性必须填充的,用于表示该pinctrl chip
  23. //所有的pin信息
  24. pindesc = devm_kzalloc(&pdev->dev, sizeof(*pindesc) *
  25. drvdata->ctrl->nr_pins, GFP_KERNEL);
  26. if (!pindesc) {
  27. dev_err(&pdev->dev, "mem alloc for pin descriptors failed\n");
  28. return -ENOMEM;
  29. }
  30. ctrldesc->pins = pindesc;
  31. ctrldesc->npins = drvdata->ctrl->nr_pins; //该成员就是samsung_pin_ctrl填充的
  32. //填充pin号
  33. /* dynamically populate the pin number and pin name for pindesc */
  34. for (pin = 0, pdesc = pindesc; pin < ctrldesc->npins; pin++, pdesc++)
  35. pdesc->number = pin + drvdata->ctrl->base; //该成员也是由samsung_pin_ctrl填充的
  36. //分配空间,用于填充pin名字
  37. /*
  38. * allocate space for storing the dynamically generated names for all
  39. * the pins which belong to this pin-controller.
  40. */
  41. pin_names = devm_kzalloc(&pdev->dev, sizeof( char) * PIN_NAME_LENGTH *
  42. drvdata->ctrl->nr_pins, GFP_KERNEL);
  43. if (!pin_names) {
  44. dev_err(&pdev->dev, "mem alloc for pin names failed\n");
  45. return -ENOMEM;
  46. }
  47. /* for each pin, the name of the pin is pin-bank name + pin number */
  48. for (bank = 0; bank < drvdata->ctrl->nr_banks; bank++) {
  49. pin_bank = &drvdata->ctrl->pin_banks[bank];
  50. for (pin = 0; pin < pin_bank->nr_pins; pin++) {
  51. //填充pin的名字,注意这里的格式,设备树里的命名就得按照该格式,即bank名字+pin号
  52. sprintf(pin_names, "%s-%d", pin_bank->name, pin);
  53. pdesc = pindesc + pin_bank->pin_base + pin;
  54. pdesc->name = pin_names;
  55. pin_names += PIN_NAME_LENGTH;
  56. }
  57. }
  58. //到现在,离注册需要的条件就剩function和group的填充了,其实它们不是pinctrl子系统要求的,
  59. //但是回调函数的实现依赖这些,因此需要解析设备树信息来填充它们,后面会详细分析该函数
  60. ret = samsung_pinctrl_parse_dt(pdev, drvdata);
  61. if (ret)
  62. return ret;
  63. //一切准备好后,就注册了
  64. drvdata->pctl_dev = pinctrl_register(ctrldesc, &pdev->dev, drvdata);
  65. if (!drvdata->pctl_dev) {
  66. dev_err(&pdev->dev, "could not register pinctrl driver\n");
  67. return -EINVAL;
  68. }
  69. //
  70. for (bank = 0; bank < drvdata->ctrl->nr_banks; ++bank) {
  71. pin_bank = &drvdata->ctrl->pin_banks[bank];
  72. pin_bank->grange.name = pin_bank->name;
  73. pin_bank->grange.id = bank;
  74. pin_bank->grange.pin_base = pin_bank->pin_base;
  75. pin_bank->grange.base = pin_bank->gpio_chip.base;
  76. pin_bank->grange.npins = pin_bank->gpio_chip.ngpio;
  77. pin_bank->grange.gc = &pin_bank->gpio_chip;
  78. pinctrl_add_gpio_range(drvdata->pctl_dev, &pin_bank->grange);
  79. }
  80. return 0;
  81. }

samsung_pinctrl_parse_dt分析:


   
   
  1. static int samsung_pinctrl_parse_dt(struct platform_device *pdev,
  2. struct samsung_pinctrl_drv_data *drvdata)
  3. {
  4. ...
  5. //获取pinctrl设备的子节点数量,前面已经讲过有哪些子节点了,不再重复
  6. grp_cnt = of_get_child_count(dev_np);
  7. if (!grp_cnt)
  8. return -EINVAL;
  9. //根据获取的数量,分配空间,每个配置节点对应于一个group(pin的集合)
  10. groups = devm_kzalloc(dev, grp_cnt * sizeof(*groups), GFP_KERNEL);
  11. if (!groups) {
  12. dev_err(dev, "failed allocate memory for ping group list\n");
  13. return -EINVAL;
  14. }
  15. grp = groups;
  16. //根据获取的数量,分配空间,每个配置节点对应的功能
  17. functions = devm_kzalloc(dev, grp_cnt * sizeof(*functions), GFP_KERNEL);
  18. if (!functions) {
  19. dev_err(dev, "failed to allocate memory for function list\n");
  20. return -EINVAL;
  21. }
  22. func = functions;
  23. //遍历每一个子节点,一个个处理
  24. /*
  25. * Iterate over all the child nodes of the pin controller node
  26. * and create pin groups and pin function lists.
  27. */
  28. for_each_child_of_node(dev_np, cfg_np) {
  29. u32 function;
  30. //检查samsung,pins属性
  31. if (! of_find_property(cfg_np, "samsung,pins", NULL))
  32. continue;
  33. //将samsung,pins属性里面指定的名字列表转换为pin号列表
  34. //,这里面会用到前面samsung_pinctrl_get_soc_data填充的信息来匹配
  35. ret = samsung_pinctrl_parse_dt_pins(pdev, cfg_np,
  36. &drvdata->pctl, &pin_list, &npins);
  37. if (ret)
  38. return ret;
  39. //下面就是构成一个pin group了,注意pin组的名字
  40. //,是配置节点名+GROUP_SUFFIX,GROUP_SUFFIX为-grp
  41. /* derive pin group name from the node name */
  42. gname = devm_kzalloc(dev, strlen(cfg_np->name) + GSUFFIX_LEN,
  43. GFP_KERNEL);
  44. if (!gname) {
  45. dev_err(dev, "failed to alloc memory for group name\n");
  46. return -ENOMEM;
  47. }
  48. sprintf(gname, "%s%s", cfg_np->name, GROUP_SUFFIX);
  49. grp->name = gname;
  50. grp->pins = pin_list;
  51. grp->num_pins = npins;
  52. of_property_read_u32(cfg_np, "samsung,pin-function", &function);
  53. grp->func = function;
  54. grp++;
  55. if (! of_find_property(cfg_np, "samsung,pin-function", NULL))
  56. continue;
  57. //如果存在samsung,pin-function属性,那么构建一个功能名
  58. //,功能名组合方式是配置节点名+FUNCTION_SUFFIX,FUNCTION_SUFFIX为-mux
  59. /* derive function name from the node name */
  60. fname = devm_kzalloc(dev, strlen(cfg_np->name) + FSUFFIX_LEN,
  61. GFP_KERNEL);
  62. if (!fname) {
  63. dev_err(dev, "failed to alloc memory for func name\n");
  64. return -ENOMEM;
  65. }
  66. sprintf(fname, "%s%s", cfg_np->name, FUNCTION_SUFFIX);
  67. func->name = fname;
  68. func->groups = devm_kzalloc(dev, sizeof( char *), GFP_KERNEL);
  69. if (!func->groups) {
  70. dev_err(dev, "failed to alloc memory for group list "
  71. "in pin function");
  72. return -ENOMEM;
  73. }
  74. func->groups[ 0] = gname;
  75. func->num_groups = 1;
  76. func++;
  77. func_idx++;
  78. }
  79. //存储下解析的数据信息
  80. drvdata->pin_groups = groups;
  81. drvdata->nr_groups = grp_cnt;
  82. drvdata->pmx_functions = functions;
  83. drvdata->nr_functions = func_idx;
  84. return 0;
  85. }

下面通过分析各个ops,来进一步理解下上面几个函数所起的作用:


   
   
  1. static const struct pinctrl_ops samsung_pctrl_ops = {
  2. .get_groups_count = samsung_get_group_count,
  3. .get_group_name = samsung_get_group_name,
  4. .get_group_pins = samsung_get_group_pins,
  5. .dt_node_to_map = samsung_dt_node_to_map,
  6. .dt_free_map = samsung_dt_free_map,
  7. };
  8. static const struct pinmux_ops samsung_pinmux_ops = {
  9. .get_functions_count = samsung_get_functions_count,
  10. .get_function_name = samsung_pinmux_get_fname,
  11. .get_function_groups = samsung_pinmux_get_groups,
  12. .enable = samsung_pinmux_enable,
  13. .disable = samsung_pinmux_disable,
  14. //由pinmux_gpio_direction间接调用,最开始应该是gpio子系统
  15. //的gpio_pin_direction_input、gpio_pin_direction_output触发
  16. .gpio_set_direction = samsung_pinmux_gpio_set_direction,
  17. };
  18. static const struct pinconf_ops samsung_pinconf_ops = {
  19. .pin_config_get = samsung_pinconf_get,
  20. .pin_config_set = samsung_pinconf_set,
  21. .pin_config_group_get = samsung_pinconf_group_get,
  22. .pin_config_group_set = samsung_pinconf_group_set,
  23. };

从上面一路分析下路来,我们应该知道dt_node_to_map是最先调用的,其次是get_functions_countget_function_nameget_function_groupsget_groups_countget_group_nameget_group_pinsrequest(三星pinmux_ops没有实现它)、enablepin_config_setpin_config_group_set所以我打算就按这个顺序进行分析。

调用dt_node_to_map的时候,从前文应该很清楚了吧,就是在某一个设备(pinctrl本身也算是一个设备,不过从前文贴出来的pinctrl0里,我没发现有pinctrl-xxx的属性,也就是说不需要对它做任何pin ctrl)用pinctrl_get请求解析自己设备树信息的时候,说的更准确点的话,就是解析该设备里某一个状态的某一个配置(一个状态可能需要多个配置来完成)的时候。下面用某一个子设备的设备树信息为例子,对应文件s3c6410-smdk6410.dts


   
   
  1. #define PIN_PULL_NONE 0
  2. &uart0 {
  3. pinctrl-names = "default";
  4. pinctrl -0 = <&uart0_data>, <&uart0_fctl>;
  5. status = "okay";
  6. };
  7. uart0_data: uart0-data {
  8. samsung,pins = "gpa-0", "gpa-1";
  9. samsung,pin-function = < 2>;
  10. samsung,pin-pud = <PIN_PULL_NONE>;
  11. };
  12. uart0_fctl: uart0-fctl {
  13. samsung,pins = "gpa-2", "gpa-3";
  14. samsung,pin-function = < 2>;
  15. samsung,pin-pud = <PIN_PULL_NONE>;
  16. };
  17. //下面部分是uart0的其他信息,和本文关心的pinctrl无关,之所以也列出来,只是不想让读者对这部分有误解
  18. uart0: serial@ 7f005000 {
  19. compatible = "samsung,s3c6400-uart";
  20. reg = < 0x7f005000 0x100>;
  21. interrupt-parent = <&vic1>;
  22. interrupts = < 5>;
  23. clock-names = "uart", "clk_uart_baud2",
  24. "clk_uart_baud3";
  25. clocks = <&clocks PCLK_UART0>, <&clocks PCLK_UART0>,
  26. <&clocks SCLK_UART>;
  27. status = "disabled";
  28. };

对应的解析代码如下,从前文描述应该清楚,期望回调函数返回该设备该状态该配置下的所有设置信息(可能只存在mux设置,也可能同时存在mux和conf设置),而上面的设备树里的uart0只有一个状态,default,对应的配置有两个,一个是uart0_data,一个是uart0_fctl,它们都是对配置节点的引用,配置节点都是pinctrl节点下的子节点,下面看代码吧:


   
   
  1. static int samsung_dt_node_to_map(struct pinctrl_dev *pctldev,
  2. struct device_node *np, struct pinctrl_map **maps,
  3. unsigned *nmaps)
  4. {
  5. ...
  6. //检查该节点(第一次调用应该是uart0_data节点,第二次调用应该是uart0_fctl节点啦)
  7. //含有多少个自己定义的属性,包括:
  8. //{ "samsung,pin-pud", PINCFG_TYPE_PUD },
  9. //{ "samsung,pin-drv", PINCFG_TYPE_DRV },
  10. //{ "samsung,pin-con-pdn", PINCFG_TYPE_CON_PDN },
  11. //{ "samsung,pin-pud-pdn", PINCFG_TYPE_PUD_PDN },
  12. /* count the number of config options specfied in the node */
  13. for (idx = 0; idx < ARRAY_SIZE(pcfgs); idx++) {
  14. if ( of_find_property(np, pcfgs[idx].prop_cfg, NULL))
  15. cfg_cnt++;
  16. }
  17. /*
  18. * Find out the number of map entries to create. All the config options
  19. * can be accomadated into a single config map entry.
  20. */
  21. //如果有,那么说明需要继续后面的conf操作
  22. if (cfg_cnt)
  23. map_cnt = 1;
  24. //如果存在samsung,pin-function属性,那么不仅要做后面的操作,还需要额外做一些mux操作
  25. if ( of_find_property(np, "samsung,pin-function", NULL))
  26. map_cnt++;
  27. if (!map_cnt) {
  28. dev_err(dev, "node %s does not have either config or function "
  29. "configurations\n", np->name);
  30. return -EINVAL;
  31. }
  32. //分配空间
  33. /* Allocate memory for pin-map entries */
  34. map = kzalloc( sizeof(*map) * map_cnt, GFP_KERNEL);
  35. if (!map) {
  36. dev_err(dev, "could not alloc memory for pin-maps\n");
  37. return -ENOMEM;
  38. }
  39. *nmaps = 0;
  40. //从前面的分析应该清楚了组名的格式,下面就是根据配置节点名构建一个格式,然后到系统
  41. //里找对应的信息
  42. /*
  43. * Allocate memory for pin group name. The pin group name is derived
  44. * from the node name from which these map entries are be created.
  45. */
  46. gname = kzalloc( strlen(np->name) + GSUFFIX_LEN, GFP_KERNEL);
  47. if (!gname) {
  48. dev_err(dev, "failed to alloc memory for group name\n");
  49. goto free_map;
  50. }
  51. sprintf(gname, "%s%s", np->name, GROUP_SUFFIX);
  52. /*
  53. * don't have config options? then skip over to creating function
  54. * map entries.
  55. */
  56. if (!cfg_cnt)
  57. goto skip_cfgs;
  58. //根据前面获取的数量来分配配置节点空间
  59. /* Allocate memory for config entries */
  60. cfg = kzalloc( sizeof(*cfg) * cfg_cnt, GFP_KERNEL);
  61. if (!cfg) {
  62. dev_err(dev, "failed to alloc memory for configs\n");
  63. goto free_gname;
  64. }
  65. //将已经定义的,属于自己定义列表里面的属性值提取出来,对应于我们这里,都是PIN_PULL_NONE
  66. /* Prepare a list of config settings */
  67. for (idx = 0, cfg_cnt = 0; idx < ARRAY_SIZE(pcfgs); idx++) {
  68. u32 value;
  69. if (! of_property_read_u32(np, pcfgs[idx].prop_cfg, &value))
  70. cfg[cfg_cnt++] =
  71. PINCFG_PACK(pcfgs[idx].cfg_type, value);
  72. }
  73. //创建设置信息,如设置名字,类型,以及多少个conf操作,每一个conf值
  74. /* create the config map entry */
  75. map[*nmaps].data.configs.group_or_pin = gname;
  76. map[*nmaps].data.configs.configs = cfg;
  77. map[*nmaps].data.configs.num_configs = cfg_cnt;
  78. map[*nmaps].type = PIN_MAP_TYPE_CONFIGS_GROUP;
  79. *nmaps += 1;
  80. skip_cfgs:
  81. /* create the function map entry */
  82. if ( of_find_property(np, "samsung,pin-function", NULL)) {
  83. //如果存在samsung,pin-function属性,说明有mux的需求,处理它
  84. //这里是构建功能名,和前面初始化的时候一致
  85. fname = kzalloc( strlen(np->name) + FSUFFIX_LEN, GFP_KERNEL);
  86. if (!fname) {
  87. dev_err(dev, "failed to alloc memory for func name\n");
  88. goto free_cfg;
  89. }
  90. sprintf(fname, "%s%s", np->name, FUNCTION_SUFFIX);
  91. //填充mux操作需要的信息,如哪一个设备,哪一个功能
  92. map[*nmaps].data.mux.group = gname;
  93. map[*nmaps].data.mux.function = fname;
  94. map[*nmaps].type = PIN_MAP_TYPE_MUX_GROUP;
  95. *nmaps += 1;
  96. }
  97. *maps = map;
  98. return 0;
  99. ...
  100. }

samsung_get_functions_count,它用于获取功能的总数量drvdata->nr_functions,前面已经分析过初始化这个的过程,所以这里就不再分析。samsung_pinmux_get_fname从已经初始化的数据结构里拿出对应索引上的name,name就是由配置节点名+-mux后缀构成。pinctrl_get的过程(pinmux_map_to_setting),会以map->data.mux.function为参数调用samsung_pinmux_get_fname获取该功能对应的索引来初始化setting->data.mux.func,然后在用samsung_pinmux_get_groups获取的组信息里,用前面解析出来的map[*nmaps].data.mux.group作为输入参数,获取该组的索引来初始化setting->data.mux.group。最后在pinctrl_select_state的时候,会通过上面的信息并结合最开始初始化的一些数据结构进行mux和conf操作。pinconf_map_to_setting的操作类似,不再重复。在pinctrl_select_state的时候samsung_pinmux_enablesamsung_pinconf_set有可能会触发,这里就不再继续分析了,但还是贴出代码吧!


   
   
  1. /* enable a specified pinmux by writing to registers */
  2. static int samsung_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector,
  3. unsigned group)
  4. {
  5. samsung_pinmux_setup(pctldev, selector, group, true);
  6. return 0;
  7. }
  8. static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector,
  9. unsigned group, bool enable)
  10. {
  11. struct samsung_pinctrl_drv_data *drvdata;
  12. const unsigned int *pins;
  13. struct samsung_pin_bank *bank;
  14. void __iomem *reg;
  15. u32 mask, shift, data, pin_offset, cnt;
  16. unsigned long flags;
  17. drvdata = pinctrl_dev_get_drvdata(pctldev);
  18. pins = drvdata->pin_groups[group].pins;
  19. /*
  20. * for each pin in the pin group selected, program the correspoding pin
  21. * pin function number in the config register.
  22. */
  23. for (cnt = 0; cnt < drvdata->pin_groups[group].num_pins; cnt++) {
  24. struct samsung_pin_bank_type *type;
  25. pin_to_reg_bank(drvdata, pins[cnt] - drvdata->ctrl->base,
  26. &reg, &pin_offset, &bank);
  27. type = bank->type;
  28. mask = ( 1 << type->fld_width[PINCFG_TYPE_FUNC]) - 1;
  29. shift = pin_offset * type->fld_width[PINCFG_TYPE_FUNC];
  30. if (shift >= 32) {
  31. /* Some banks have two config registers */
  32. shift -= 32;
  33. reg += 4;
  34. }
  35. spin_lock_irqsave(&bank->slock, flags);
  36. data = readl(reg + type->reg_offset[PINCFG_TYPE_FUNC]);
  37. data &= ~(mask << shift);
  38. if (enable)
  39. data |= drvdata->pin_groups[group].func << shift;
  40. writel(data, reg + type->reg_offset[PINCFG_TYPE_FUNC]);
  41. spin_unlock_irqrestore(&bank->slock, flags);
  42. }
  43. }

   
   
  1. /* set the pin config settings for a specified pin */
  2. static int samsung_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
  3. unsigned long *configs, unsigned num_configs)
  4. {
  5. int i, ret;
  6. for (i = 0; i < num_configs; i++) {
  7. ret = samsung_pinconf_rw(pctldev, pin, &configs[i], true);
  8. if (ret < 0)
  9. return ret;
  10. } /* for each config */
  11. return 0;
  12. }
  13. /* set or get the pin config settings for a specified pin */
  14. static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin,
  15. unsigned long *config, bool set)
  16. {
  17. struct samsung_pinctrl_drv_data *drvdata;
  18. struct samsung_pin_bank_type *type;
  19. struct samsung_pin_bank *bank;
  20. void __iomem *reg_base;
  21. enum pincfg_type cfg_type = PINCFG_UNPACK_TYPE(*config);
  22. u32 data, width, pin_offset, mask, shift;
  23. u32 cfg_value, cfg_reg;
  24. unsigned long flags;
  25. drvdata = pinctrl_dev_get_drvdata(pctldev);
  26. pin_to_reg_bank(drvdata, pin - drvdata->ctrl->base, &reg_base,
  27. &pin_offset, &bank);
  28. type = bank->type;
  29. if (cfg_type >= PINCFG_TYPE_NUM || !type->fld_width[cfg_type])
  30. return -EINVAL;
  31. width = type->fld_width[cfg_type];
  32. cfg_reg = type->reg_offset[cfg_type];
  33. spin_lock_irqsave(&bank->slock, flags);
  34. mask = ( 1 << width) - 1;
  35. shift = pin_offset * width;
  36. data = readl(reg_base + cfg_reg);
  37. if (set) {
  38. cfg_value = PINCFG_UNPACK_VALUE(*config);
  39. data &= ~(mask << shift);
  40. data |= (cfg_value << shift);
  41. writel(data, reg_base + cfg_reg);
  42. } else {
  43. data >>= shift;
  44. data &= mask;
  45. *config = PINCFG_PACK(cfg_type, data);
  46. }
  47. spin_unlock_irqrestore(&bank->slock, flags);
  48. return 0;
  49. }

   
   
  1. /* set the pin config settings for a specified pin group */
  2. static int samsung_pinconf_group_set(struct pinctrl_dev *pctldev,
  3. unsigned group, unsigned long *configs,
  4. unsigned num_configs)
  5. {
  6. struct samsung_pinctrl_drv_data *drvdata;
  7. const unsigned int *pins;
  8. unsigned int cnt;
  9. drvdata = pinctrl_dev_get_drvdata(pctldev);
  10. pins = drvdata->pin_groups[group].pins;
  11. for (cnt = 0; cnt < drvdata->pin_groups[group].num_pins; cnt++)
  12. samsung_pinconf_set(pctldev, pins[cnt], configs, num_configs);
  13. return 0;
  14. }

驱动工程师的角度

一般会用到的接口:
devm_pinctrl_get
pinctrl_lookup_state
pinctrl_select_state

操作gpio时,会用到的接口:
pinctrl_request_gpio
pinctrl_gpio_direction_input
pinctrl_gpio_direction_output

还有一些额外变体,懒得贴了

下面以gpio方式的api为例子继续分析,这样也好与文章最开始的gpio子系统结合起来理解!pinctrl_request_gpio在驱动里,主要有两类会用到它,一类是gpio子系统的实现者,即gpio-xxx.c那些文件,另一类是pinctrl的实现者,即pinctrl-xxx.c那些文件。它们在注册gpio chip时,将pinctrl_request_gpio作为gpio chip里request,这样间接将pinctrl操作交给gpio子系统自动完成。从gpio子系统分析可知,request的调用是在gpio_request或者gpiod_get间接触发。看一下pinctrl_request_gpio做了些什么:


   
   
  1. int pinctrl_request_gpio(unsigned gpio)
  2. {
  3. struct pinctrl_dev *pctldev;
  4. struct pinctrl_gpio_range *range;
  5. int ret;
  6. int pin;
  7. //这里会通过gpio来取得该gpio对应的pctldev和range,还记得分析gpiochip_add时的
  8. //of_gpiochip_add_pin_range吧,这里就用到了它add的信息
  9. ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
  10. if (ret) {
  11. if ( pinctrl_ready_for_gpio_range(gpio))
  12. ret = 0;
  13. return ret;
  14. }
  15. mutex_lock(&pctldev->mutex);
  16. /* Convert to the pin controllers number space */
  17. //有了range就好办了啦,它里面有gpio与pin号的对应关系,当然这关系是最开始从设备树里解析过来的
  18. pin = gpio_to_pin(range, gpio);
  19. //有了所有信息调用pinmux_request_gpio进一步request吧
  20. ret = pinmux_request_gpio(pctldev, range, pin, gpio);
  21. mutex_unlock(&pctldev->mutex);
  22. return ret;
  23. }

继续pinmux_request_gpio


   
   
  1. int pinmux_request_gpio(struct pinctrl_dev *pctldev,
  2. struct pinctrl_gpio_range *range,
  3. unsigned pin, unsigned gpio)
  4. {
  5. const char *owner;
  6. int ret;
  7. /* Conjure some name stating what chip and pin this is taken by */
  8. owner = kasprintf(GFP_KERNEL, "%s:%d", range->name, gpio);
  9. if (!owner)
  10. return -EINVAL;
  11. //pin_request之前分析的时候有看到调用过,不过这次gpio的时候会传入range,导致它的
  12. //调用流程会有所不同,里面会触发pinmux_ops的gpio_request_enable回调,而不是request回调
  13. ret = pin_request(pctldev, pin, owner, range);
  14. if (ret < 0)
  15. kfree(owner);
  16. return ret;
  17. }

最后看看设备驱动模型中pinctrl的影子,在bus_probe_device的时候,会调用device_attach,而device_attach里会调用__device_attach去attach,在匹配成功后,会调用driver_probe_device,它会导致really_probe的调用来进行驱动的probe,最终会导致pinctrl_bind_pins调用,这个函数会pinctrl_get并设置设备的初始状态,这个过程不需要驱动额外做任何事情,多么巧妙啊 


   
   
  1. int pinctrl_bind_pins(struct device *dev)
  2. {
  3. int ret;
  4. dev->pins = devm_kzalloc(dev, sizeof(*(dev->pins)), GFP_KERNEL);
  5. if (!dev->pins)
  6. return -ENOMEM;
  7. dev->pins->p = devm_pinctrl_get(dev);
  8. if ( IS_ERR(dev->pins->p)) {
  9. dev_dbg(dev, "no pinctrl handle\n");
  10. ret = PTR_ERR(dev->pins->p);
  11. goto cleanup_alloc;
  12. }
  13. dev->pins->default_state = pinctrl_lookup_state(dev->pins->p,
  14. PINCTRL_STATE_DEFAULT);
  15. if ( IS_ERR(dev->pins->default_state)) {
  16. dev_dbg(dev, "no default pinctrl state\n");
  17. ret = 0;
  18. goto cleanup_get;
  19. }
  20. ret = pinctrl_select_state(dev->pins->p, dev->pins->default_state);
  21. if (ret) {
  22. dev_dbg(dev, "failed to activate default pinctrl state\n");
  23. goto cleanup_get;
  24. }
  25. ...
  26. }

总结

通过对gpio子系统和pinctrl子系统的分析,应该对这两个系统有了大致的概念了吧_ gpio子系统让驱动工程师不用关心底层gpio chip的具体实现,让bsp工程师不用关心上层驱动工程师的使用方式。pinctrl子系统帮我们管理了pin信息,包括了pin的mux和conf,同时也透明的处理了与gpio子系统的关联以及设备模型的关联。

完!
2015年7月

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值