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