]>
Commit | Line | Data |
---|---|---|
b30de3cc GL |
1 | /* |
2 | * Copyright (C) 2009 | |
3 | * Guennadi Liakhovetski, DENX Software Engineering, <[email protected]> | |
4 | * | |
d8e0ca85 SB |
5 | * Copyright (C) 2011 |
6 | * Stefano Babic, DENX Software Engineering, <[email protected]> | |
7 | * | |
1a459660 | 8 | * SPDX-License-Identifier: GPL-2.0+ |
b30de3cc GL |
9 | */ |
10 | #include <common.h> | |
441d0cff SG |
11 | #include <errno.h> |
12 | #include <dm.h> | |
13 | #include <malloc.h> | |
c4ea1424 | 14 | #include <asm/arch/imx-regs.h> |
d8e0ca85 | 15 | #include <asm/gpio.h> |
c4ea1424 | 16 | #include <asm/io.h> |
b30de3cc | 17 | |
d8e0ca85 SB |
18 | enum mxc_gpio_direction { |
19 | MXC_GPIO_DIRECTION_IN, | |
20 | MXC_GPIO_DIRECTION_OUT, | |
21 | }; | |
22 | ||
441d0cff SG |
23 | #define GPIO_PER_BANK 32 |
24 | ||
25 | struct mxc_gpio_plat { | |
637a7693 | 26 | int bank_index; |
441d0cff SG |
27 | struct gpio_regs *regs; |
28 | }; | |
29 | ||
30 | struct mxc_bank_info { | |
441d0cff SG |
31 | struct gpio_regs *regs; |
32 | }; | |
33 | ||
34 | #ifndef CONFIG_DM_GPIO | |
8d28c211 | 35 | #define GPIO_TO_PORT(n) (n / 32) |
d8e0ca85 | 36 | |
b30de3cc GL |
37 | /* GPIO port description */ |
38 | static unsigned long gpio_ports[] = { | |
c4ea1424 SB |
39 | [0] = GPIO1_BASE_ADDR, |
40 | [1] = GPIO2_BASE_ADDR, | |
41 | [2] = GPIO3_BASE_ADDR, | |
e71c39de | 42 | #if defined(CONFIG_MX25) || defined(CONFIG_MX27) || defined(CONFIG_MX51) || \ |
26dd3464 | 43 | defined(CONFIG_MX53) || defined(CONFIG_MX6) || \ |
8953d866 | 44 | defined(CONFIG_MX7) || defined(CONFIG_MX8M) |
c4ea1424 SB |
45 | [3] = GPIO4_BASE_ADDR, |
46 | #endif | |
26dd3464 | 47 | #if defined(CONFIG_MX27) || defined(CONFIG_MX53) || defined(CONFIG_MX6) || \ |
8953d866 | 48 | defined(CONFIG_MX7) || defined(CONFIG_MX8M) |
01643ec1 | 49 | [4] = GPIO5_BASE_ADDR, |
8953d866 | 50 | #if !(defined(CONFIG_MX6UL) || defined(CONFIG_MX6ULL) || defined(CONFIG_MX8M)) |
01643ec1 | 51 | [5] = GPIO6_BASE_ADDR, |
e71c39de | 52 | #endif |
f2753b06 | 53 | #endif |
26dd3464 | 54 | #if defined(CONFIG_MX53) || defined(CONFIG_MX6) || defined(CONFIG_MX7) |
290e7cfd | 55 | #if !(defined(CONFIG_MX6UL) || defined(CONFIG_MX6ULL)) |
01643ec1 LHR |
56 | [6] = GPIO7_BASE_ADDR, |
57 | #endif | |
f2753b06 | 58 | #endif |
b30de3cc GL |
59 | }; |
60 | ||
d8e0ca85 SB |
61 | static int mxc_gpio_direction(unsigned int gpio, |
62 | enum mxc_gpio_direction direction) | |
b30de3cc | 63 | { |
be282554 | 64 | unsigned int port = GPIO_TO_PORT(gpio); |
c4ea1424 | 65 | struct gpio_regs *regs; |
b30de3cc GL |
66 | u32 l; |
67 | ||
68 | if (port >= ARRAY_SIZE(gpio_ports)) | |
365d6070 | 69 | return -1; |
b30de3cc GL |
70 | |
71 | gpio &= 0x1f; | |
72 | ||
c4ea1424 SB |
73 | regs = (struct gpio_regs *)gpio_ports[port]; |
74 | ||
75 | l = readl(®s->gpio_dir); | |
76 | ||
b30de3cc | 77 | switch (direction) { |
c4ea1424 | 78 | case MXC_GPIO_DIRECTION_OUT: |
b30de3cc GL |
79 | l |= 1 << gpio; |
80 | break; | |
c4ea1424 | 81 | case MXC_GPIO_DIRECTION_IN: |
b30de3cc GL |
82 | l &= ~(1 << gpio); |
83 | } | |
c4ea1424 | 84 | writel(l, ®s->gpio_dir); |
b30de3cc GL |
85 | |
86 | return 0; | |
87 | } | |
88 | ||
365d6070 | 89 | int gpio_set_value(unsigned gpio, int value) |
b30de3cc | 90 | { |
be282554 | 91 | unsigned int port = GPIO_TO_PORT(gpio); |
c4ea1424 | 92 | struct gpio_regs *regs; |
b30de3cc GL |
93 | u32 l; |
94 | ||
95 | if (port >= ARRAY_SIZE(gpio_ports)) | |
365d6070 | 96 | return -1; |
b30de3cc GL |
97 | |
98 | gpio &= 0x1f; | |
99 | ||
c4ea1424 SB |
100 | regs = (struct gpio_regs *)gpio_ports[port]; |
101 | ||
102 | l = readl(®s->gpio_dr); | |
b30de3cc GL |
103 | if (value) |
104 | l |= 1 << gpio; | |
105 | else | |
106 | l &= ~(1 << gpio); | |
c4ea1424 | 107 | writel(l, ®s->gpio_dr); |
365d6070 JH |
108 | |
109 | return 0; | |
b30de3cc | 110 | } |
7d27cd08 | 111 | |
365d6070 | 112 | int gpio_get_value(unsigned gpio) |
7d27cd08 | 113 | { |
be282554 | 114 | unsigned int port = GPIO_TO_PORT(gpio); |
c4ea1424 | 115 | struct gpio_regs *regs; |
365d6070 | 116 | u32 val; |
7d27cd08 SB |
117 | |
118 | if (port >= ARRAY_SIZE(gpio_ports)) | |
365d6070 | 119 | return -1; |
7d27cd08 SB |
120 | |
121 | gpio &= 0x1f; | |
122 | ||
c4ea1424 SB |
123 | regs = (struct gpio_regs *)gpio_ports[port]; |
124 | ||
5dafa454 | 125 | val = (readl(®s->gpio_psr) >> gpio) & 0x01; |
7d27cd08 | 126 | |
365d6070 | 127 | return val; |
7d27cd08 | 128 | } |
d8e0ca85 | 129 | |
365d6070 | 130 | int gpio_request(unsigned gpio, const char *label) |
d8e0ca85 | 131 | { |
be282554 | 132 | unsigned int port = GPIO_TO_PORT(gpio); |
d8e0ca85 | 133 | if (port >= ARRAY_SIZE(gpio_ports)) |
365d6070 | 134 | return -1; |
d8e0ca85 SB |
135 | return 0; |
136 | } | |
137 | ||
365d6070 | 138 | int gpio_free(unsigned gpio) |
d8e0ca85 | 139 | { |
365d6070 | 140 | return 0; |
d8e0ca85 SB |
141 | } |
142 | ||
365d6070 | 143 | int gpio_direction_input(unsigned gpio) |
d8e0ca85 | 144 | { |
365d6070 | 145 | return mxc_gpio_direction(gpio, MXC_GPIO_DIRECTION_IN); |
d8e0ca85 SB |
146 | } |
147 | ||
365d6070 | 148 | int gpio_direction_output(unsigned gpio, int value) |
d8e0ca85 | 149 | { |
04c79cbd | 150 | int ret = gpio_set_value(gpio, value); |
d8e0ca85 SB |
151 | |
152 | if (ret < 0) | |
153 | return ret; | |
154 | ||
04c79cbd | 155 | return mxc_gpio_direction(gpio, MXC_GPIO_DIRECTION_OUT); |
d8e0ca85 | 156 | } |
441d0cff SG |
157 | #endif |
158 | ||
159 | #ifdef CONFIG_DM_GPIO | |
99c0ae16 | 160 | #include <fdtdec.h> |
441d0cff SG |
161 | static int mxc_gpio_is_output(struct gpio_regs *regs, int offset) |
162 | { | |
163 | u32 val; | |
164 | ||
165 | val = readl(®s->gpio_dir); | |
166 | ||
167 | return val & (1 << offset) ? 1 : 0; | |
168 | } | |
169 | ||
170 | static void mxc_gpio_bank_direction(struct gpio_regs *regs, int offset, | |
171 | enum mxc_gpio_direction direction) | |
172 | { | |
173 | u32 l; | |
174 | ||
175 | l = readl(®s->gpio_dir); | |
176 | ||
177 | switch (direction) { | |
178 | case MXC_GPIO_DIRECTION_OUT: | |
179 | l |= 1 << offset; | |
180 | break; | |
181 | case MXC_GPIO_DIRECTION_IN: | |
182 | l &= ~(1 << offset); | |
183 | } | |
184 | writel(l, ®s->gpio_dir); | |
185 | } | |
186 | ||
187 | static void mxc_gpio_bank_set_value(struct gpio_regs *regs, int offset, | |
188 | int value) | |
189 | { | |
190 | u32 l; | |
191 | ||
192 | l = readl(®s->gpio_dr); | |
193 | if (value) | |
194 | l |= 1 << offset; | |
195 | else | |
196 | l &= ~(1 << offset); | |
197 | writel(l, ®s->gpio_dr); | |
198 | } | |
199 | ||
200 | static int mxc_gpio_bank_get_value(struct gpio_regs *regs, int offset) | |
201 | { | |
202 | return (readl(®s->gpio_psr) >> offset) & 0x01; | |
203 | } | |
204 | ||
441d0cff SG |
205 | /* set GPIO pin 'gpio' as an input */ |
206 | static int mxc_gpio_direction_input(struct udevice *dev, unsigned offset) | |
207 | { | |
208 | struct mxc_bank_info *bank = dev_get_priv(dev); | |
441d0cff SG |
209 | |
210 | /* Configure GPIO direction as input. */ | |
211 | mxc_gpio_bank_direction(bank->regs, offset, MXC_GPIO_DIRECTION_IN); | |
212 | ||
213 | return 0; | |
214 | } | |
215 | ||
216 | /* set GPIO pin 'gpio' as an output, with polarity 'value' */ | |
217 | static int mxc_gpio_direction_output(struct udevice *dev, unsigned offset, | |
218 | int value) | |
219 | { | |
220 | struct mxc_bank_info *bank = dev_get_priv(dev); | |
441d0cff SG |
221 | |
222 | /* Configure GPIO output value. */ | |
223 | mxc_gpio_bank_set_value(bank->regs, offset, value); | |
224 | ||
225 | /* Configure GPIO direction as output. */ | |
226 | mxc_gpio_bank_direction(bank->regs, offset, MXC_GPIO_DIRECTION_OUT); | |
227 | ||
228 | return 0; | |
229 | } | |
230 | ||
231 | /* read GPIO IN value of pin 'gpio' */ | |
232 | static int mxc_gpio_get_value(struct udevice *dev, unsigned offset) | |
233 | { | |
234 | struct mxc_bank_info *bank = dev_get_priv(dev); | |
441d0cff SG |
235 | |
236 | return mxc_gpio_bank_get_value(bank->regs, offset); | |
237 | } | |
238 | ||
239 | /* write GPIO OUT value to pin 'gpio' */ | |
240 | static int mxc_gpio_set_value(struct udevice *dev, unsigned offset, | |
241 | int value) | |
242 | { | |
243 | struct mxc_bank_info *bank = dev_get_priv(dev); | |
441d0cff SG |
244 | |
245 | mxc_gpio_bank_set_value(bank->regs, offset, value); | |
246 | ||
247 | return 0; | |
248 | } | |
249 | ||
441d0cff SG |
250 | static int mxc_gpio_get_function(struct udevice *dev, unsigned offset) |
251 | { | |
252 | struct mxc_bank_info *bank = dev_get_priv(dev); | |
253 | ||
441d0cff SG |
254 | /* GPIOF_FUNC is not implemented yet */ |
255 | if (mxc_gpio_is_output(bank->regs, offset)) | |
256 | return GPIOF_OUTPUT; | |
257 | else | |
258 | return GPIOF_INPUT; | |
259 | } | |
260 | ||
261 | static const struct dm_gpio_ops gpio_mxc_ops = { | |
441d0cff SG |
262 | .direction_input = mxc_gpio_direction_input, |
263 | .direction_output = mxc_gpio_direction_output, | |
264 | .get_value = mxc_gpio_get_value, | |
265 | .set_value = mxc_gpio_set_value, | |
266 | .get_function = mxc_gpio_get_function, | |
441d0cff SG |
267 | }; |
268 | ||
441d0cff SG |
269 | static int mxc_gpio_probe(struct udevice *dev) |
270 | { | |
271 | struct mxc_bank_info *bank = dev_get_priv(dev); | |
272 | struct mxc_gpio_plat *plat = dev_get_platdata(dev); | |
e564f054 | 273 | struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); |
441d0cff SG |
274 | int banknum; |
275 | char name[18], *str; | |
276 | ||
637a7693 | 277 | banknum = plat->bank_index; |
441d0cff SG |
278 | sprintf(name, "GPIO%d_", banknum + 1); |
279 | str = strdup(name); | |
280 | if (!str) | |
281 | return -ENOMEM; | |
282 | uc_priv->bank_name = str; | |
283 | uc_priv->gpio_count = GPIO_PER_BANK; | |
284 | bank->regs = plat->regs; | |
285 | ||
286 | return 0; | |
287 | } | |
288 | ||
99c0ae16 PF |
289 | static int mxc_gpio_bind(struct udevice *dev) |
290 | { | |
291 | struct mxc_gpio_plat *plat = dev->platdata; | |
292 | fdt_addr_t addr; | |
293 | ||
294 | /* | |
295 | * If platdata already exsits, directly return. | |
296 | * Actually only when DT is not supported, platdata | |
297 | * is statically initialized in U_BOOT_DEVICES.Here | |
298 | * will return. | |
299 | */ | |
300 | if (plat) | |
301 | return 0; | |
302 | ||
a821c4af | 303 | addr = devfdt_get_addr(dev); |
99c0ae16 | 304 | if (addr == FDT_ADDR_T_NONE) |
7c84319a | 305 | return -EINVAL; |
99c0ae16 PF |
306 | |
307 | /* | |
308 | * TODO: | |
309 | * When every board is converted to driver model and DT is supported, | |
310 | * this can be done by auto-alloc feature, but not using calloc | |
311 | * to alloc memory for platdata. | |
4d686041 SG |
312 | * |
313 | * For example mxc_plat below uses platform data rather than device | |
314 | * tree. | |
315 | * | |
316 | * NOTE: DO NOT COPY this code if you are using device tree. | |
99c0ae16 PF |
317 | */ |
318 | plat = calloc(1, sizeof(*plat)); | |
319 | if (!plat) | |
320 | return -ENOMEM; | |
321 | ||
322 | plat->regs = (struct gpio_regs *)addr; | |
323 | plat->bank_index = dev->req_seq; | |
324 | dev->platdata = plat; | |
325 | ||
326 | return 0; | |
327 | } | |
328 | ||
329 | static const struct udevice_id mxc_gpio_ids[] = { | |
330 | { .compatible = "fsl,imx35-gpio" }, | |
331 | { } | |
332 | }; | |
333 | ||
441d0cff SG |
334 | U_BOOT_DRIVER(gpio_mxc) = { |
335 | .name = "gpio_mxc", | |
336 | .id = UCLASS_GPIO, | |
337 | .ops = &gpio_mxc_ops, | |
338 | .probe = mxc_gpio_probe, | |
339 | .priv_auto_alloc_size = sizeof(struct mxc_bank_info), | |
99c0ae16 PF |
340 | .of_match = mxc_gpio_ids, |
341 | .bind = mxc_gpio_bind, | |
342 | }; | |
343 | ||
0f925822 | 344 | #if !CONFIG_IS_ENABLED(OF_CONTROL) |
99c0ae16 PF |
345 | static const struct mxc_gpio_plat mxc_plat[] = { |
346 | { 0, (struct gpio_regs *)GPIO1_BASE_ADDR }, | |
347 | { 1, (struct gpio_regs *)GPIO2_BASE_ADDR }, | |
348 | { 2, (struct gpio_regs *)GPIO3_BASE_ADDR }, | |
349 | #if defined(CONFIG_MX25) || defined(CONFIG_MX27) || defined(CONFIG_MX51) || \ | |
8953d866 PF |
350 | defined(CONFIG_MX53) || defined(CONFIG_MX6) || \ |
351 | defined(CONFIG_MX8M) | |
99c0ae16 PF |
352 | { 3, (struct gpio_regs *)GPIO4_BASE_ADDR }, |
353 | #endif | |
8953d866 PF |
354 | #if defined(CONFIG_MX27) || defined(CONFIG_MX53) || defined(CONFIG_MX6) || \ |
355 | defined(CONFIG_MX8M) | |
99c0ae16 | 356 | { 4, (struct gpio_regs *)GPIO5_BASE_ADDR }, |
8953d866 | 357 | #ifndef CONFIG_MX8M |
99c0ae16 PF |
358 | { 5, (struct gpio_regs *)GPIO6_BASE_ADDR }, |
359 | #endif | |
8953d866 | 360 | #endif |
99c0ae16 PF |
361 | #if defined(CONFIG_MX53) || defined(CONFIG_MX6) |
362 | { 6, (struct gpio_regs *)GPIO7_BASE_ADDR }, | |
363 | #endif | |
441d0cff SG |
364 | }; |
365 | ||
366 | U_BOOT_DEVICES(mxc_gpios) = { | |
367 | { "gpio_mxc", &mxc_plat[0] }, | |
368 | { "gpio_mxc", &mxc_plat[1] }, | |
369 | { "gpio_mxc", &mxc_plat[2] }, | |
370 | #if defined(CONFIG_MX25) || defined(CONFIG_MX27) || defined(CONFIG_MX51) || \ | |
8953d866 PF |
371 | defined(CONFIG_MX53) || defined(CONFIG_MX6) || \ |
372 | defined(CONFIG_MX8M) | |
441d0cff SG |
373 | { "gpio_mxc", &mxc_plat[3] }, |
374 | #endif | |
8953d866 PF |
375 | #if defined(CONFIG_MX27) || defined(CONFIG_MX53) || defined(CONFIG_MX6) || \ |
376 | defined(CONFIG_MX8M) | |
441d0cff | 377 | { "gpio_mxc", &mxc_plat[4] }, |
8953d866 | 378 | #ifndef CONFIG_MX8M |
441d0cff SG |
379 | { "gpio_mxc", &mxc_plat[5] }, |
380 | #endif | |
8953d866 | 381 | #endif |
441d0cff SG |
382 | #if defined(CONFIG_MX53) || defined(CONFIG_MX6) |
383 | { "gpio_mxc", &mxc_plat[6] }, | |
384 | #endif | |
385 | }; | |
386 | #endif | |
99c0ae16 | 387 | #endif |