]>
Commit | Line | Data |
---|---|---|
8d393b2c SB |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Pinctrl driver for Nexell SoCs | |
4 | * (C) Copyright 2016 Nexell | |
5 | * Bongyu, KOO <[email protected]> | |
6 | * | |
7 | * (C) Copyright 2019 Stefan Bosch <[email protected]> | |
8 | */ | |
9 | ||
10 | #include <common.h> | |
11 | #include <dm.h> | |
12 | #include <errno.h> | |
401d1c4f | 13 | #include <asm/global_data.h> |
8d393b2c SB |
14 | #include <asm/io.h> |
15 | #include <dm/pinctrl.h> | |
16 | #include <dm/root.h> | |
17 | #include "pinctrl-nexell.h" | |
18 | #include "pinctrl-s5pxx18.h" | |
19 | ||
20 | DECLARE_GLOBAL_DATA_PTR; | |
21 | ||
22 | static void nx_gpio_set_bit(u32 *value, u32 bit, int enable) | |
23 | { | |
24 | register u32 newvalue; | |
25 | ||
26 | newvalue = *value; | |
27 | newvalue &= ~(1ul << bit); | |
28 | newvalue |= (u32)enable << bit; | |
29 | writel(newvalue, value); | |
30 | } | |
31 | ||
32 | static void nx_gpio_set_bit2(u32 *value, u32 bit, u32 bit_value) | |
33 | { | |
34 | register u32 newvalue = *value; | |
35 | ||
36 | newvalue = (u32)(newvalue & ~(3ul << (bit * 2))); | |
37 | newvalue = (u32)(newvalue | (bit_value << (bit * 2))); | |
38 | ||
39 | writel(newvalue, value); | |
40 | } | |
41 | ||
42 | static int nx_gpio_open_module(void *base) | |
43 | { | |
44 | writel(0xFFFFFFFF, base + GPIOX_SLEW_DISABLE_DEFAULT); | |
45 | writel(0xFFFFFFFF, base + GPIOX_DRV1_DISABLE_DEFAULT); | |
46 | writel(0xFFFFFFFF, base + GPIOX_DRV0_DISABLE_DEFAULT); | |
47 | writel(0xFFFFFFFF, base + GPIOX_PULLSEL_DISABLE_DEFAULT); | |
48 | writel(0xFFFFFFFF, base + GPIOX_PULLENB_DISABLE_DEFAULT); | |
49 | return true; | |
50 | } | |
51 | ||
52 | static void nx_gpio_set_pad_function(void *base, u32 pin, u32 padfunc) | |
53 | { | |
54 | u32 reg = (pin / 16) ? GPIOX_ALTFN1 : GPIOX_ALTFN0; | |
55 | ||
56 | nx_gpio_set_bit2(base + reg, pin % 16, padfunc); | |
57 | } | |
58 | ||
59 | static void nx_gpio_set_drive_strength(void *base, u32 pin, u32 drv) | |
60 | { | |
61 | nx_gpio_set_bit(base + GPIOX_DRV1, pin, (int)(((u32)drv >> 0) & 0x1)); | |
62 | nx_gpio_set_bit(base + GPIOX_DRV0, pin, (int)(((u32)drv >> 1) & 0x1)); | |
63 | } | |
64 | ||
65 | static void nx_gpio_set_pull_mode(void *base, u32 pin, u32 mode) | |
66 | { | |
67 | if (mode == nx_gpio_pull_off) { | |
68 | nx_gpio_set_bit(base + GPIOX_PULLENB, pin, false); | |
69 | nx_gpio_set_bit(base + GPIOX_PULLSEL, pin, false); | |
70 | } else { | |
71 | nx_gpio_set_bit(base + GPIOX_PULLSEL, | |
72 | pin, (mode & 1 ? true : false)); | |
73 | nx_gpio_set_bit(base + GPIOX_PULLENB, pin, true); | |
74 | } | |
75 | } | |
76 | ||
77 | static void nx_alive_set_pullup(void *base, u32 pin, bool enable) | |
78 | { | |
79 | u32 PULLUP_MASK; | |
80 | ||
81 | PULLUP_MASK = (1UL << pin); | |
82 | if (enable) | |
83 | writel(PULLUP_MASK, base + ALIVE_PADPULLUPSET); | |
84 | else | |
85 | writel(PULLUP_MASK, base + ALIVE_PADPULLUPRST); | |
86 | } | |
87 | ||
88 | static int s5pxx18_pinctrl_gpio_init(struct udevice *dev) | |
89 | { | |
90 | struct nexell_pinctrl_priv *priv = dev_get_priv(dev); | |
91 | const struct nexell_pin_ctrl *ctrl = priv->pin_ctrl; | |
92 | unsigned long reg = priv->base; | |
93 | int i; | |
94 | ||
95 | for (i = 0; i < ctrl->nr_banks - 1; i++) /* except alive bank */ | |
96 | nx_gpio_open_module((void *)(reg + ctrl->pin_banks[i].offset)); | |
97 | ||
98 | return 0; | |
99 | } | |
100 | ||
101 | static int s5pxx18_pinctrl_alive_init(struct udevice *dev) | |
102 | { | |
103 | struct nexell_pinctrl_priv *priv = dev_get_priv(dev); | |
104 | const struct nexell_pin_ctrl *ctrl = priv->pin_ctrl; | |
105 | unsigned long reg = priv->base; | |
106 | ||
107 | reg += ctrl->pin_banks[ctrl->nr_banks - 1].offset; | |
108 | ||
109 | writel(1, reg + ALIVE_PWRGATE); | |
110 | return 0; | |
111 | } | |
112 | ||
113 | int s5pxx18_pinctrl_init(struct udevice *dev) | |
114 | { | |
115 | s5pxx18_pinctrl_gpio_init(dev); | |
116 | s5pxx18_pinctrl_alive_init(dev); | |
117 | ||
118 | return 0; | |
119 | } | |
120 | ||
121 | static int is_pin_alive(const char *name) | |
122 | { | |
123 | return !strncmp(name, "alive", 5); | |
124 | } | |
125 | ||
126 | /** | |
127 | * s5pxx18_pinctrl_set_state: configure a pin state. | |
128 | * dev: the pinctrl device to be configured. | |
129 | * config: the state to be configured. | |
130 | */ | |
131 | static int s5pxx18_pinctrl_set_state(struct udevice *dev, | |
132 | struct udevice *config) | |
133 | { | |
134 | unsigned int count, idx, pin; | |
135 | unsigned int pinfunc, pinpud, pindrv; | |
136 | unsigned long reg; | |
137 | const char *name; | |
138 | int ret; | |
139 | ||
140 | /* | |
141 | * refer to the following document for the pinctrl bindings | |
142 | * doc/device-tree-bindings/pinctrl/nexell,s5pxx18-pinctrl.txt | |
143 | */ | |
144 | count = dev_read_string_count(config, "pins"); | |
145 | ||
146 | if (count <= 0) | |
147 | return -EINVAL; | |
148 | ||
149 | pinfunc = dev_read_s32_default(config, "pin-function", -1); | |
150 | pinpud = dev_read_s32_default(config, "pin-pull", -1); | |
151 | pindrv = dev_read_s32_default(config, "pin-strength", -1); | |
152 | ||
153 | for (idx = 0; idx < count; idx++) { | |
154 | ret = dev_read_string_index(config, "pins", idx, &name); | |
155 | if (ret) | |
156 | return ret; | |
157 | if (!name) | |
158 | continue; | |
159 | reg = pin_to_bank_base(dev, name, &pin); | |
160 | ||
161 | if (is_pin_alive(name)) { | |
162 | /* pin pull up/down */ | |
163 | if (pinpud != -1) | |
164 | nx_alive_set_pullup((void *)reg, pin, | |
165 | pinpud & 1); | |
166 | continue; | |
167 | } | |
168 | ||
169 | /* pin function */ | |
170 | if (pinfunc != -1) | |
171 | nx_gpio_set_pad_function((void *)reg, pin, pinfunc); | |
172 | ||
173 | /* pin pull up/down/off */ | |
174 | if (pinpud != -1) | |
175 | nx_gpio_set_pull_mode((void *)reg, pin, pinpud); | |
176 | ||
177 | /* pin drive strength */ | |
178 | if (pindrv != -1) | |
179 | nx_gpio_set_drive_strength((void *)reg, pin, pindrv); | |
180 | } | |
181 | ||
182 | return 0; | |
183 | } | |
184 | ||
185 | static struct pinctrl_ops s5pxx18_pinctrl_ops = { | |
186 | .set_state = s5pxx18_pinctrl_set_state, | |
187 | }; | |
188 | ||
189 | /* pin banks of s5pxx18 pin-controller */ | |
190 | static const struct nexell_pin_bank_data s5pxx18_pin_banks[] = { | |
191 | NEXELL_PIN_BANK(32, 0xA000, "gpioa"), | |
192 | NEXELL_PIN_BANK(32, 0xB000, "gpiob"), | |
193 | NEXELL_PIN_BANK(32, 0xC000, "gpioc"), | |
194 | NEXELL_PIN_BANK(32, 0xD000, "gpiod"), | |
195 | NEXELL_PIN_BANK(32, 0xE000, "gpioe"), | |
196 | NEXELL_PIN_BANK(6, 0x0800, "alive"), | |
197 | }; | |
198 | ||
199 | const struct nexell_pin_ctrl s5pxx18_pin_ctrl[] = { | |
200 | { | |
201 | /* pin-controller data */ | |
202 | .pin_banks = s5pxx18_pin_banks, | |
203 | .nr_banks = ARRAY_SIZE(s5pxx18_pin_banks), | |
204 | }, | |
205 | }; | |
206 | ||
207 | static const struct udevice_id s5pxx18_pinctrl_ids[] = { | |
208 | { .compatible = "nexell,s5pxx18-pinctrl", | |
209 | .data = (ulong)s5pxx18_pin_ctrl }, | |
210 | { } | |
211 | }; | |
212 | ||
213 | U_BOOT_DRIVER(pinctrl_s5pxx18) = { | |
214 | .name = "pinctrl_s5pxx18", | |
215 | .id = UCLASS_PINCTRL, | |
216 | .of_match = s5pxx18_pinctrl_ids, | |
41575d8e | 217 | .priv_auto = sizeof(struct nexell_pinctrl_priv), |
8d393b2c SB |
218 | .ops = &s5pxx18_pinctrl_ops, |
219 | .probe = nexell_pinctrl_probe, | |
220 | .flags = DM_FLAG_PRE_RELOC | |
221 | }; |