PINCTRL: stm32f7: add pin control driver
[platform/kernel/u-boot.git] / drivers / pinctrl / pinctrl_stm32.c
1 #include <common.h>
2 #include <asm/arch/gpio.h>
3 #include <dm.h>
4 #include <dm/pinctrl.h>
5
6 DECLARE_GLOBAL_DATA_PTR;
7
8 static int prep_gpio_dsc(struct stm32_gpio_dsc *gpio_dsc, u32 port_pin)
9 {
10         gpio_dsc->port = (port_pin & 0xF000) >> 12;
11         gpio_dsc->pin = (port_pin & 0x0F00) >> 8;
12         debug("%s: GPIO:port= %d, pin= %d\n", __func__, gpio_dsc->port,
13               gpio_dsc->pin);
14
15         return 0;
16 }
17
18 static int prep_gpio_ctl(struct stm32_gpio_ctl *gpio_ctl, u32 gpio_fn, int node)
19 {
20         gpio_fn &= 0x00FF;
21
22         switch (gpio_fn) {
23         case 0:
24                 gpio_ctl->mode = STM32_GPIO_MODE_IN;
25                 break;
26         case 1 ... 16:
27                 gpio_ctl->mode = STM32_GPIO_MODE_AF;
28                 gpio_ctl->af = gpio_fn - 1;
29                 break;
30         case 17:
31                 gpio_ctl->mode = STM32_GPIO_MODE_AN;
32                 break;
33         default:
34                 gpio_ctl->mode = STM32_GPIO_MODE_OUT;
35                 break;
36         }
37
38         gpio_ctl->speed = fdtdec_get_int(gd->fdt_blob, node, "slew-rate", 0);
39
40         if (fdtdec_get_bool(gd->fdt_blob, node, "drive-open-drain"))
41                 gpio_ctl->otype = STM32_GPIO_OTYPE_OD;
42         else
43                 gpio_ctl->otype = STM32_GPIO_OTYPE_PP;
44
45         if (fdtdec_get_bool(gd->fdt_blob, node, "bias-pull-up"))
46                 gpio_ctl->pupd = STM32_GPIO_PUPD_UP;
47         else if (fdtdec_get_bool(gd->fdt_blob, node, "bias-pull-down"))
48                 gpio_ctl->pupd = STM32_GPIO_PUPD_DOWN;
49         else
50                 gpio_ctl->pupd = STM32_GPIO_PUPD_NO;
51
52         debug("%s: gpio fn= %d, slew-rate= %x, op type= %x, pull-upd is = %x\n",
53               __func__,  gpio_fn, gpio_ctl->speed, gpio_ctl->otype,
54              gpio_ctl->pupd);
55
56         return 0;
57 }
58
59 static int stm32_pinctrl_set_state_simple(struct udevice *dev,
60                                           struct udevice *periph)
61 {
62         u32 pin_mux[50];
63         struct fdtdec_phandle_args args;
64         int rv, len;
65
66         /* Get node pinctrl-0 */
67         rv = fdtdec_parse_phandle_with_args(gd->fdt_blob, periph->of_offset,
68                                            "pinctrl-0", 0, 0, 0, &args);
69         if (rv)
70                 return rv;
71         /*
72          * check for "pinmux" property in each subnode (e.g. pins1 and pins2 for
73          * usart1) of pin controller phandle "pinctrl-0"
74          * */
75         fdt_for_each_subnode(args.node, gd->fdt_blob, args.node) {
76                 struct stm32_gpio_dsc gpio_dsc;
77                 struct stm32_gpio_ctl gpio_ctl;
78                 int i;
79
80                 len = fdtdec_get_int_array_count(gd->fdt_blob, args.node,
81                                                  "pinmux", pin_mux,
82                                                  ARRAY_SIZE(pin_mux));
83                 debug("%s: periph->name = %s, no of pinmux entries= %d\n",
84                       __func__, periph->name, len);
85                 if (len < 0)
86                         return -EINVAL;
87                 for (i = 0; i < len; i++) {
88                         debug("%s: pinmux = %x\n", __func__, *(pin_mux + i));
89                         prep_gpio_dsc(&gpio_dsc, *(pin_mux + i));
90                         prep_gpio_ctl(&gpio_ctl, *(pin_mux + i), args.node);
91
92                         rv = stm32_gpio_config(&gpio_dsc, &gpio_ctl);
93                         debug("%s: rv = %d\n\n", __func__, rv);
94                         if (rv)
95                                 return rv;
96                 }
97         }
98
99         return 0;
100 }
101
102 static struct pinctrl_ops stm32_pinctrl_ops = {
103         .set_state_simple       = stm32_pinctrl_set_state_simple,
104 };
105
106 static const struct udevice_id stm32_pinctrl_ids[] = {
107         { .compatible = "st,stm32f746-pinctrl" },
108         { }
109 };
110
111 U_BOOT_DRIVER(pinctrl_stm32) = {
112         .name           = "pinctrl_stm32",
113         .id             = UCLASS_PINCTRL,
114         .of_match       = stm32_pinctrl_ids,
115         .ops            = &stm32_pinctrl_ops,
116         .bind           = dm_scan_fdt_dev,
117 };