转自:http://www.cnblogs.com/kevinhwang/p/5703192.html
pinctrl框架是linux系统为统一各SOC厂家pin管理,目的是为了减少SOC厂家系统移植工作量。
通常通过设备树初始化pinctrl,并提供调用io接口,以下为全志A64平台的实例:
在drivers/pinctrl/sunxi/pinctrl-sun50iw1p1.c:
1 static const struct sunxi_desc_pin sun50iw1p1_pins[] = {
2 SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 0),
3 SUNXI_FUNCTION(0x0, "gpio_in"),
4 SUNXI_FUNCTION(0x1, "gpio_out"),
5 SUNXI_FUNCTION(0x2, "uart2"), /*TX*/
6 SUNXI_FUNCTION(0x3, "vdevice"), /*vdevice for test */
7 SUNXI_FUNCTION(0x4, "jtag0"), /*MS0*/
8 SUNXI_FUNCTION(0x7, "io_disabled"),
9 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 0)), /*PB_EINT0 */
10 SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 1),
11 SUNXI_FUNCTION(0x0, "gpio_in"),
12 SUNXI_FUNCTION(0x1, "gpio_out"),
13 SUNXI_FUNCTION(0x2, "uart2"), /*RX*/
14 SUNXI_FUNCTION(0x3, "vdevice"), /*vdevice for test */
15 SUNXI_FUNCTION(0x4, "jtag0"), /*CK0*/
16 SUNXI_FUNCTION(0x5, "sim0"), /*PWREN*/
17 SUNXI_FUNCTION(0x7, "io_disabled"),
18 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 1)), /*PB_EINT1 */
19 ......
20 ......
21 ......
22 };
23
24 static const struct sunxi_pinctrl_desc sun50iw1p1_pinctrl_data = {
25 .pins = sun50iw1p1_pins,
26 .npins = ARRAY_SIZE(sun50iw1p1_pins),
27 .irq_banks = 3,
28 };
29
30 static int sun50iw1p1_pinctrl_probe(struct platform_device *pdev)
31 {
32 pr_warn("[%s][%d]
", __func__, __LINE__);
33 return sunxi_pinctrl_init(pdev,
34 &sun50iw1p1_pinctrl_data);
35 }
36
37 static struct of_device_id sun50iw1p1_pinctrl_match[] = {
38 { .compatible = "allwinner,sun50i-pinctrl", },
39 {}
40 };
41 MODULE_DEVICE_TABLE(of, sun50iw1p1_pinctrl_match);
42
43 static struct platform_driver sun50iw1p1_pinctrl_driver = {
44 .probe = sun50iw1p1_pinctrl_probe,
45 .driver = {
46 .name = "sun50i-pinctrl",
47 .owner = THIS_MODULE,
48 .of_match_table = sun50iw1p1_pinctrl_match,
49 },
50 };
51 static int __init sun50iw1p1_pio_init(void)
52 {
53 int ret;
54 ret = platform_driver_register(&sun50iw1p1_pinctrl_driver);
55 if (IS_ERR_VALUE(ret)) {
56 pr_debug("register sun50i pio controller failed
");
57 return -EINVAL;
58 }
59 return 0;
60 }
61 postcore_initcall(sun50iw1p1_pio_init);
start_kernel----rest_init----kernel_init----kernel_init_freeable----do_basic_setup----do_initcalls调用postcore_initcall。
注册平台驱动,匹配设备最后调用sunxi_pinctrl_init(pdev, &sun50iw1p1_pinctrl_data);
sun50iw1p1_pins为全志平台的PIN IO和IRQ的定义,里面定义引脚名字name,复用功能muxval,中断号irqnum。
忽略部分代码的drivers/pinctrl/sunxi/pinctrl-sunxi.c:
1 int sunxi_pinctrl_init(struct platform_device *pdev,
2 const struct sunxi_pinctrl_desc *desc)
3 {
4 struct device_node *node = pdev->dev.of_node;
5 struct pinctrl_desc *pctrl_desc;
6 struct pinctrl_pin_desc *pins;
7 struct sunxi_pinctrl *pctl;
8 struct resource *res;
9 int i, ret, last_pin;
10 struct clk *clk;
11 pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
12
13 platform_set_drvdata(pdev, pctl);
14
15 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
16 pctl->membase = devm_ioremap_resource(&pdev->dev, res); //返回设备的MEM资源的虚拟地址
17
18
19 pctl->dev = &pdev->dev;
20 pctl->desc = desc;
21
22 pctl->irq_array = devm_kcalloc(&pdev->dev, IRQ_PER_BANK * pctl->desc->irq_banks,
23 sizeof(*pctl->irq_array), GFP_KERNEL);
24
25 //把sunxi_pinctrl_desc的内容全部映射到sunxi_pinctrl的成员(sunxi_pinctrl_group、irq_array和sunxi_pinctrl_function)
26 ret = sunxi_pinctrl_build_state(pdev);
27
28 pins = devm_kzalloc(&pdev->dev, pctl->desc->npins * sizeof(*pins), GFP_KERNEL);
29
30 for (i = 0; i < pctl->desc->npins; i++)
31 pins[i] = pctl->desc->pins[i].pin;
32
33 //注册pctldev,这里把平台硬件相关函数向上映射到pinctrl子系统
34 pctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*pctrl_desc), GFP_KERNEL);
35
36 //confops、pctlops和pmxops都是直接和硬件相关,新设备配置PIN需要用到
37 pctrl_desc->name = dev_name(&pdev->dev);
38 pctrl_desc->owner = THIS_MODULE;
39 pctrl_desc->pins = pins;
40 pctrl_desc->npins = pctl->desc->npins;
41 pctrl_desc->confops = &sunxi_pconf_ops; //pin config operations vtable
42 pctrl_desc->pctlops = &sunxi_pctrl_ops; //pin control operation vtable
43 pctrl_desc->pmxops = &sunxi_pmx_ops; //pinmux operations vtable
44
45 //把描述表的name和number加入radix_tree,分配pinctrl_dev并把加入双链表,这里没有创建新的pinctrl设备,也没有state
46 pctl->pctl_dev = pinctrl_register(pctrl_desc, &pdev->dev, pctl);
47
48 //注册gpio子系统,把平台硬件相关函数向上映射到gpio子系统
49 pctl->chip = devm_kzalloc(&pdev->dev, sizeof(*pctl->chip), GFP_KERNEL);
50
51 last_pin = pctl->desc->pins[pctl->desc->npins - 1].pin.number;
52 pctl->chip->owner = THIS_MODULE;
53 pctl->chip->request = sunxi_pinctrl_gpio_request,
54 pctl->chip->free = sunxi_pinctrl_gpio_free,
55 pctl->chip->direction_input = sunxi_pinctrl_gpio_direction_input,
56 pctl->chip->direction_output = sunxi_pinctrl_gpio_direction_output,
57 pctl->chip->get = sunxi_pinctrl_gpio_get,
58 pctl->chip->set = sunxi_pinctrl_gpio_set,
59 pctl->chip->set_debounce = sunxi_pinctrl_gpio_set_debounce,
60 pctl->chip->of_xlate = sunxi_pinctrl_gpio_of_xlate,
61 pctl->chip->to_irq = sunxi_pinctrl_gpio_to_irq,
62 pctl->chip->of_gpio_n_cells = 6,
63 pctl->chip->can_sleep = false,
64 pctl->chip->ngpio = round_up(last_pin + 1, PINS_PER_BANK) - pctl->desc->pin_base;
65 pctl->chip->label = dev_name(&pdev->dev);
66 pctl->chip->dev = &pdev->dev;
67 pctl->chip->base = pctl->desc->pin_base;
68
69 ret = gpiochip_add(pctl->chip); //把gpio_chip(A64有两个chip)加入双链表
70
71 for (i = 0; i < pctl->desc->npins; i++) {
72 const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
73 //注册gpio_ranges,并加入双链表
74 ret = gpiochip_add_pin_range(pctl->chip, dev_name(&pdev->dev),
75 pin->pin.number - pctl->desc->pin_base,
76 pin->pin.number, 1);
77 }
78
79 clk = devm_clk_get(&pdev->dev, NULL);
80
81 ret = clk_prepare_enable(clk);
82 if (ret)
83 goto gpiochip_error;
84
85 pctl->irq = devm_kcalloc(&pdev->dev,
86 pctl->desc->irq_banks,
87 sizeof(*pctl->irq),
88 GFP_KERNEL);
89
90 for (i = 0; i < pctl->desc->irq_banks; i++) {
91 pctl->irq[i] = platform_get_irq(pdev, i); //获取中断资源
92 }
93
94 pctl->domain = irq_domain_add_linear(node, pctl->desc->irq_banks * IRQ_PER_BANK,
95 &irq_domain_simple_ops, NULL); //把pinctrl加入线性中断域,pin中断都域中搜索
96
97
98 for (i = 0; i < (pctl->desc->irq_banks * IRQ_PER_BANK); i++) {
99 int irqno = irq_create_mapping(pctl->domain, i); //获取线性中断域的irq号
100
101 irq_set_chip_and_handler(irqno, &sunxi_pinctrl_edge_irq_chip,
102 handle_edge_irq); //sunxi_pinctrl_edge_irq_chip为全志底层irq_chip操作
103 irq_set_chip_data(irqno, pctl);
104 };
105
106 for (i = 0; i < pctl->desc->irq_banks; i++) {
107 /* Mask and clear all IRQs before registering a handler */
108 writel(0, pctl->membase + sunxi_irq_ctrl_reg_from_bank(i));
109 writel(0xffffffff, pctl->membase + sunxi_irq_status_reg_from_bank(i));
110 if(pctl->desc->pin_base >= PL_BASE){
111 ret = devm_request_irq(&pdev->dev, pctl->irq[i], sunxi_pinctrl_irq_handler,
112 IRQF_SHARED | IRQF_NO_SUSPEND, "PIN_GRP", pctl);
113 //同一个bank的gpio中断均共享一个中断,在sunxi_pinctrl_irq_handler通过gpio的中断号
114 //启动对应generic_handle_irq
115 }else{
116 ret = devm_request_irq(&pdev->dev, pctl->irq[i], sunxi_pinctrl_irq_handler,
117 IRQF_SHARED, "PIN_GRP", pctl); //同上
118 }
119 }
120
121 return 0;
122 }
在设备树实例(一)中的:
1 soc@01c00000 {
2 compatible = "simple-bus";
3 #address-cells = <0x2>;
4 #size-cells = <0x2>;
5 ranges;
6 device_type = "soc";
7
8 pinctrl@01c20800 {
9 compatible = "allwinner,sun50i-pinctrl";
10 reg = <0x0 0x1c20800 0x0 0x400>;
11 interrupts = <0x0 0xb 0x4 0x0 0x11 0x4 0x0 0x15 0x4>;
12 device_type = "pio";
13 clocks = <0xa>;
14 gpio-controller;
15 interrupt-controller;
16 #interrupt-cells = <0x2>;
17 #size-cells = <0x0>;
18 #gpio-cells = <0x6>;
19 linux,phandle = <0x30>;
20 phandle = <0x30>;
21
22 uart0@0 {
23 allwinner,pins = "PB8", "PB9";
24 allwinner,pname = "uart0_tx", "uart0_rx";
25 allwinner,function = "uart0";
26 allwinner,muxsel = <0x4>;
27 allwinner,drive = <0x1>;
28 allwinner,pull = <0x1>;
29 linux,phandle = <0x19>;
30 phandle = <0x19>;
31 };
32
33 uart0@1 {
34 allwinner,pins = "PB8", "PB9";
35 allwinner,function = "io_disabled";
36 allwinner,muxsel = <0x7>;
37 allwinner,drive = <0x1>;
38 allwinner,pull = <0x1>;
39 linux,phandle = <0x1a>;
40 phandle = <0x1a>;
41 };
42
43 ......
44 ......
45 ......
46 };
47
48 uart@01c28000 {
49 compatible = "allwinner,sun50i-uart";
50 device_type = "uart0";
51 reg = <0x0 0x1c28000 0x0 0x400>;
52 interrupts = <0x0 0x0 0x4>;
53 clocks = <0x18>;
54 pinctrl-names = "default", "sleep";
55 pinctrl-0 = <0x19>;
56 pinctrl-1 = <0x1a>;
57 uart0_port = <0x0>;
58 uart0_type = <0x2>;
59 status = "disabled";
60 };
pinctrl-names = "default", "sleep";的两种状态的phandle对应于pinctrl-0(uart0@0)和pinctrl-1(uart0@1),uart0@0里面的配置是全志硬件平台相关,跟confops、pctlops和pmxops相关。
如何开启设备树对应的pin配置?
一般在driver程序里面调用devm_pinctrl_get_select_default就可以。
定义在linux3-10/include/pintrl/consumer.h:
1 static inline struct pinctrl * __must_check devm_pinctrl_get_select(
2 struct device *dev, const char *name)
3 {
4 struct pinctrl *p;
5 struct pinctrl_state *s;
6 int ret;
7
8 //通过device获取phandle,若是新设备则会调用创建head_list,找到pinctrl父设备sun50i-pinctrl ,解析设备树,
9 //创建states,获取硬件相关配置,最后add devices。
10 p = devm_pinctrl_get(dev);
11 if (IS_ERR(p))
12 return p;
13
14 s = pinctrl_lookup_state(p, name);
15 if (IS_ERR(s)) {
16 devm_pinctrl_put(p);
17 return ERR_CAST(s);
18 }
19 //设置state(默认是DEFAULT)从设备树对应的配置
20 ret = pinctrl_select_state(p, s);
21 if (ret < 0) {
22 devm_pinctrl_put(p);
23 return ERR_PTR(ret);
24 }
25
26 return p;
27 }
调用IO口或者中断可以参考linux-3.10/drivers/pinctrl/sunxi/pinctrl-sunxi-test.c
1 #include <linux/io.h>
2 #include <linux/clk.h>
3 #include <linux/gpio.h>
4 #include <linux/interrupt.h>
5 #include <linux/module.h>
6 #include <linux/of.h>
7 #include <linux/of_platform.h>
8 #include <linux/of_address.h>
9 #include <linux/of_device.h>
10 #include <linux/of_gpio.h>
11 #include <linux/pinctrl/consumer.h>
12 #include <linux/platform_device.h>
13 #include <linux/slab.h>
14 #include <linux/sys_config.h>
15 #include <linux/string.h>
16
17 static struct of_device_id sunxi_pinctrl_test_match[] = {
18 { .compatible = "allwinner,sun50i-vdevice"},
19 }; //这里要在dts文件建立compatible = "allwinner,sun50i-vdevice"的node才能匹配driver
20
21 static irqreturn_t test_sunxi_pinctrl_irq_handler(int irq, void *dev_id)
22 {
23 pr_warn("[%s] handler for test pinctrl eint api.
", __func__);
24 disable_irq_nosync(irq);
25 return IRQ_HANDLED;
26
27 }
28
29
30 static int sunxi_pinctrl_test_probe(struct platform_device *pdev)
31 {
32 struct gpio_config config;
33 unsigned int ret;
34 struct device_node *node;
35
36 int req_irq_status;
37 int req_status;
38 int virq;
39
40 node=of_find_node_by_type(NULL, "vdevice"); //通过属性device_type = "vdevice"找到设备树节点
41 if(!node){
42 printk("find node
");
43 }
44 ret = of_get_named_gpio_flags(node, "test-gpios", 0, (enum of_gpio_flags *)&config);
45 //找到设备树属性test-gpios,解析GPIO配置,这步是重点(不同硬件平台不一定相同)
46 if (!gpio_is_valid(ret)) {
47 return -EINVAL;
48 }
49 printk("config: gpio=%d mul=%d drive=%d pull=%d data=%d
"
50 , config.gpio
51 , config.mul_sel
52 , config.drv_level
53 , config.pull
54 , config.data);
55 req_status = gpio_request(config.gpio, NULL);
56 if (0 != req_status)
57 return -EINVAL;
58 virq = gpio_to_irq(config.gpio);
59 if (IS_ERR_VALUE(virq)) {
60 pr_warn("gpio[%d]get virq[%d] failed!
", config.gpio, virq);
61 return -EINVAL;
62 }
63 req_irq_status = devm_request_irq(&pdev->dev, virq,
64 test_sunxi_pinctrl_irq_handler,
65 IRQF_TRIGGER_LOW, "GPIO_EINT", NULL);
66 if (IS_ERR_VALUE(req_irq_status)) {
67 pr_warn("request irq failed !
");
68 return -EINVAL;
69 }
70 return 0;
71 }
72
73 static struct platform_driver sunxi_pinctrl_test_driver = {
74 .probe = sunxi_pinctrl_test_probe,
75 .driver = {
76 .name = "vdevice",
77 .owner = THIS_MODULE,
78 .of_match_table = sunxi_pinctrl_test_match,
79 },
80 };
81
82 static int __init sunxi_pinctrl_test_init(void)
83 {
84 int ret;
85 ret = platform_driver_register(&sunxi_pinctrl_test_driver);
86 if (IS_ERR_VALUE(ret)) {
87 pr_warn("register sunxi pinctrl platform driver failed
");
88 return -EINVAL;
89 }
90 return 0;
91 }
92 late_initcall(sunxi_pinctrl_test_init);
93
94 MODULE_AUTHOR("Huangshr<huangshr@allwinnertech.com");
95 MODULE_DESCRIPTION("Allwinner SUNXI Pinctrl driver test");
96 MODULE_LICENSE("GPL");
一般应用是