]>
Commit | Line | Data |
---|---|---|
606f7047 AA |
1 | /* |
2 | * LPC32xxGPIO driver | |
3 | * | |
4 | * (C) Copyright 2014 DENX Software Engineering GmbH | |
5 | * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr> | |
6 | * | |
7 | * SPDX-License-Identifier: GPL-2.0+ | |
8 | */ | |
9 | ||
4af0d7e8 | 10 | #include <common.h> |
606f7047 AA |
11 | #include <asm/io.h> |
12 | #include <asm/arch-lpc32xx/cpu.h> | |
13 | #include <asm/arch-lpc32xx/gpio.h> | |
14 | #include <asm-generic/gpio.h> | |
15 | #include <dm.h> | |
16 | ||
17 | /** | |
18 | * LPC32xx GPIOs work in banks but are non-homogeneous: | |
19 | * - each bank holds a different number of GPIOs | |
20 | * - some GPIOs are input/ouput, some input only, some output only; | |
21 | * - some GPIOs have different meanings as an input and as an output; | |
22 | * - some GPIOs are controlled on a given port and bit index, but | |
23 | * read on another one. | |
24 | * | |
25 | * In order to keep this code simple, GPIOS are considered here as | |
89983478 | 26 | * homogeneous and linear, from 0 to 159. |
606f7047 AA |
27 | * |
28 | * ** WARNING #1 ** | |
29 | * | |
30 | * Client code is responsible for properly using valid GPIO numbers, | |
31 | * including cases where a single physical GPIO has differing numbers | |
32 | * for setting its direction, reading it and/or writing to it. | |
33 | * | |
34 | * ** WARNING #2 ** | |
35 | * | |
36 | * Please read NOTE in description of lpc32xx_gpio_get_function(). | |
37 | */ | |
38 | ||
89983478 | 39 | #define LPC32XX_GPIOS 160 |
606f7047 | 40 | |
1f9e5e22 | 41 | struct lpc32xx_gpio_priv { |
606f7047 AA |
42 | struct gpio_regs *regs; |
43 | /* GPIO FUNCTION: SEE WARNING #2 */ | |
44 | signed char function[LPC32XX_GPIOS]; | |
45 | }; | |
46 | ||
47 | /** | |
48 | * We have 4 GPIO ports of 32 bits each | |
89983478 SL |
49 | * |
50 | * Port mapping offset (32 bits each): | |
51 | * - Port 0: 0 | |
52 | * - Port 1: 32 | |
53 | * - Port 2: 64 | |
54 | * - Port 3: GPO / GPIO (output): 96 | |
55 | * - Port 3: GPI: 128 | |
606f7047 AA |
56 | */ |
57 | ||
89983478 | 58 | #define MAX_GPIO 160 |
606f7047 | 59 | |
89983478 | 60 | #define GPIO_TO_PORT(gpio) ((gpio / 32) & 7) |
606f7047 AA |
61 | #define GPIO_TO_RANK(gpio) (gpio % 32) |
62 | #define GPIO_TO_MASK(gpio) (1 << (gpio % 32)) | |
63 | ||
64 | /** | |
65 | * Configure a GPIO number 'offset' as input | |
66 | */ | |
67 | ||
68 | static int lpc32xx_gpio_direction_input(struct udevice *dev, unsigned offset) | |
69 | { | |
70 | int port, mask; | |
1f9e5e22 AL |
71 | struct lpc32xx_gpio_priv *gpio_priv = dev_get_priv(dev); |
72 | struct gpio_regs *regs = gpio_priv->regs; | |
606f7047 AA |
73 | |
74 | port = GPIO_TO_PORT(offset); | |
75 | mask = GPIO_TO_MASK(offset); | |
76 | ||
77 | switch (port) { | |
78 | case 0: | |
79 | writel(mask, ®s->p0_dir_clr); | |
80 | break; | |
81 | case 1: | |
82 | writel(mask, ®s->p1_dir_clr); | |
83 | break; | |
84 | case 2: | |
85 | /* ports 2 and 3 share a common direction */ | |
606f7047 AA |
86 | writel(mask, ®s->p2_p3_dir_clr); |
87 | break; | |
89983478 SL |
88 | case 3: |
89 | /* Setup direction only for GPIO_xx. */ | |
90 | if ((mask >= 25) && (mask <= 30)) | |
91 | writel(mask, ®s->p2_p3_dir_clr); | |
92 | break; | |
93 | case 4: | |
94 | /* GPI_xx; nothing to do. */ | |
95 | break; | |
606f7047 AA |
96 | default: |
97 | return -1; | |
98 | } | |
99 | ||
100 | /* GPIO FUNCTION: SEE WARNING #2 */ | |
1f9e5e22 | 101 | gpio_priv->function[offset] = GPIOF_INPUT; |
606f7047 AA |
102 | |
103 | return 0; | |
104 | } | |
105 | ||
106 | /** | |
107 | * Get the value of a GPIO | |
108 | */ | |
109 | ||
110 | static int lpc32xx_gpio_get_value(struct udevice *dev, unsigned offset) | |
111 | { | |
112 | int port, rank, mask, value; | |
1f9e5e22 AL |
113 | struct lpc32xx_gpio_priv *gpio_priv = dev_get_priv(dev); |
114 | struct gpio_regs *regs = gpio_priv->regs; | |
606f7047 AA |
115 | |
116 | port = GPIO_TO_PORT(offset); | |
117 | ||
118 | switch (port) { | |
119 | case 0: | |
120 | value = readl(®s->p0_inp_state); | |
121 | break; | |
122 | case 1: | |
123 | value = readl(®s->p1_inp_state); | |
124 | break; | |
125 | case 2: | |
126 | value = readl(®s->p2_inp_state); | |
127 | break; | |
128 | case 3: | |
89983478 SL |
129 | /* Read GPO_xx and GPIO_xx (as output) using p3_outp_state. */ |
130 | value = readl(®s->p3_outp_state); | |
131 | break; | |
132 | case 4: | |
133 | /* Read GPI_xx and GPIO_xx (as input) using p3_inp_state. */ | |
606f7047 AA |
134 | value = readl(®s->p3_inp_state); |
135 | break; | |
136 | default: | |
137 | return -1; | |
138 | } | |
139 | ||
140 | rank = GPIO_TO_RANK(offset); | |
141 | mask = GPIO_TO_MASK(offset); | |
142 | ||
143 | return (value & mask) >> rank; | |
144 | } | |
145 | ||
146 | /** | |
147 | * Set a GPIO | |
148 | */ | |
149 | ||
150 | static int gpio_set(struct udevice *dev, unsigned gpio) | |
151 | { | |
152 | int port, mask; | |
1f9e5e22 AL |
153 | struct lpc32xx_gpio_priv *gpio_priv = dev_get_priv(dev); |
154 | struct gpio_regs *regs = gpio_priv->regs; | |
606f7047 AA |
155 | |
156 | port = GPIO_TO_PORT(gpio); | |
157 | mask = GPIO_TO_MASK(gpio); | |
158 | ||
159 | switch (port) { | |
160 | case 0: | |
161 | writel(mask, ®s->p0_outp_set); | |
162 | break; | |
163 | case 1: | |
164 | writel(mask, ®s->p1_outp_set); | |
165 | break; | |
166 | case 2: | |
167 | writel(mask, ®s->p2_outp_set); | |
168 | break; | |
169 | case 3: | |
170 | writel(mask, ®s->p3_outp_set); | |
171 | break; | |
89983478 SL |
172 | case 4: |
173 | /* GPI_xx; invalid. */ | |
606f7047 AA |
174 | default: |
175 | return -1; | |
176 | } | |
177 | return 0; | |
178 | } | |
179 | ||
180 | /** | |
181 | * Clear a GPIO | |
182 | */ | |
183 | ||
184 | static int gpio_clr(struct udevice *dev, unsigned gpio) | |
185 | { | |
186 | int port, mask; | |
1f9e5e22 AL |
187 | struct lpc32xx_gpio_priv *gpio_priv = dev_get_priv(dev); |
188 | struct gpio_regs *regs = gpio_priv->regs; | |
606f7047 AA |
189 | |
190 | port = GPIO_TO_PORT(gpio); | |
191 | mask = GPIO_TO_MASK(gpio); | |
192 | ||
193 | switch (port) { | |
194 | case 0: | |
195 | writel(mask, ®s->p0_outp_clr); | |
196 | break; | |
197 | case 1: | |
198 | writel(mask, ®s->p1_outp_clr); | |
199 | break; | |
200 | case 2: | |
201 | writel(mask, ®s->p2_outp_clr); | |
202 | break; | |
203 | case 3: | |
204 | writel(mask, ®s->p3_outp_clr); | |
205 | break; | |
89983478 SL |
206 | case 4: |
207 | /* GPI_xx; invalid. */ | |
606f7047 AA |
208 | default: |
209 | return -1; | |
210 | } | |
211 | return 0; | |
212 | } | |
213 | ||
214 | /** | |
215 | * Set the value of a GPIO | |
216 | */ | |
217 | ||
218 | static int lpc32xx_gpio_set_value(struct udevice *dev, unsigned offset, | |
219 | int value) | |
220 | { | |
221 | if (value) | |
222 | return gpio_set(dev, offset); | |
223 | else | |
224 | return gpio_clr(dev, offset); | |
225 | } | |
226 | ||
227 | /** | |
228 | * Configure a GPIO number 'offset' as output with given initial value. | |
229 | */ | |
230 | ||
231 | static int lpc32xx_gpio_direction_output(struct udevice *dev, unsigned offset, | |
232 | int value) | |
233 | { | |
234 | int port, mask; | |
1f9e5e22 AL |
235 | struct lpc32xx_gpio_priv *gpio_priv = dev_get_priv(dev); |
236 | struct gpio_regs *regs = gpio_priv->regs; | |
606f7047 AA |
237 | |
238 | port = GPIO_TO_PORT(offset); | |
239 | mask = GPIO_TO_MASK(offset); | |
240 | ||
241 | switch (port) { | |
242 | case 0: | |
243 | writel(mask, ®s->p0_dir_set); | |
244 | break; | |
245 | case 1: | |
246 | writel(mask, ®s->p1_dir_set); | |
247 | break; | |
248 | case 2: | |
249 | /* ports 2 and 3 share a common direction */ | |
606f7047 AA |
250 | writel(mask, ®s->p2_p3_dir_set); |
251 | break; | |
89983478 SL |
252 | case 3: |
253 | /* Setup direction only for GPIO_xx. */ | |
254 | if ((mask >= 25) && (mask <= 30)) | |
255 | writel(mask, ®s->p2_p3_dir_set); | |
256 | break; | |
257 | case 4: | |
258 | /* GPI_xx; invalid. */ | |
606f7047 AA |
259 | default: |
260 | return -1; | |
261 | } | |
262 | ||
263 | /* GPIO FUNCTION: SEE WARNING #2 */ | |
1f9e5e22 | 264 | gpio_priv->function[offset] = GPIOF_OUTPUT; |
606f7047 AA |
265 | |
266 | return lpc32xx_gpio_set_value(dev, offset, value); | |
267 | } | |
268 | ||
269 | /** | |
270 | * GPIO functions are supposed to be computed from their current | |
271 | * configuration, but that's way too complicated in LPC32XX. A simpler | |
272 | * approach is used, where the GPIO functions are cached in an array. | |
273 | * When the GPIO is in use, its function is either "input" or "output" | |
274 | * depending on its direction, otherwise its function is "unknown". | |
275 | * | |
276 | * ** NOTE ** | |
277 | * | |
278 | * THIS APPROACH WAS CHOSEN DU TO THE COMPLEX NATURE OF THE LPC32XX | |
279 | * GPIOS; DO NOT TAKE THIS AS AN EXAMPLE FOR NEW CODE. | |
280 | */ | |
281 | ||
282 | static int lpc32xx_gpio_get_function(struct udevice *dev, unsigned offset) | |
283 | { | |
1f9e5e22 AL |
284 | struct lpc32xx_gpio_priv *gpio_priv = dev_get_priv(dev); |
285 | return gpio_priv->function[offset]; | |
606f7047 AA |
286 | } |
287 | ||
288 | static const struct dm_gpio_ops gpio_lpc32xx_ops = { | |
289 | .direction_input = lpc32xx_gpio_direction_input, | |
290 | .direction_output = lpc32xx_gpio_direction_output, | |
291 | .get_value = lpc32xx_gpio_get_value, | |
292 | .set_value = lpc32xx_gpio_set_value, | |
293 | .get_function = lpc32xx_gpio_get_function, | |
294 | }; | |
295 | ||
296 | static int lpc32xx_gpio_probe(struct udevice *dev) | |
297 | { | |
1f9e5e22 | 298 | struct lpc32xx_gpio_priv *gpio_priv = dev_get_priv(dev); |
606f7047 AA |
299 | struct gpio_dev_priv *uc_priv = dev->uclass_priv; |
300 | ||
e160f7d4 | 301 | if (dev_of_offset(dev) == -1) { |
606f7047 AA |
302 | /* Tell the uclass how many GPIOs we have */ |
303 | uc_priv->gpio_count = LPC32XX_GPIOS; | |
304 | } | |
305 | ||
306 | /* set base address for GPIO registers */ | |
1f9e5e22 | 307 | gpio_priv->regs = (struct gpio_regs *)GPIO_BASE; |
606f7047 AA |
308 | |
309 | /* all GPIO functions are unknown until requested */ | |
310 | /* GPIO FUNCTION: SEE WARNING #2 */ | |
1f9e5e22 | 311 | memset(gpio_priv->function, GPIOF_UNKNOWN, sizeof(gpio_priv->function)); |
606f7047 AA |
312 | |
313 | return 0; | |
314 | } | |
315 | ||
316 | U_BOOT_DRIVER(gpio_lpc32xx) = { | |
317 | .name = "gpio_lpc32xx", | |
318 | .id = UCLASS_GPIO, | |
319 | .ops = &gpio_lpc32xx_ops, | |
320 | .probe = lpc32xx_gpio_probe, | |
1f9e5e22 | 321 | .priv_auto_alloc_size = sizeof(struct lpc32xx_gpio_priv), |
606f7047 | 322 | }; |