1/*
2 * @TAG(OTHER_GPL)
3 */
4
5/*
6 * Copyright (C) 2009
7 * Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de>
8 *
9 * Copyright (C) 2011
10 * Stefano Babic, DENX Software Engineering, <sbabic@denx.de>
11 *
12 * See file CREDITS for list of people who contributed to this
13 * project.
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License as
17 * published by the Free Software Foundation; either version 2 of
18 * the License, or (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
28 * MA 02111-1307 USA
29 */
30#include "common.h"
31#include "imx-regs.h"
32#include "gpio.h"
33#include "../io.h"
34#include "../unimplemented.h"
35
36enum mxc_gpio_direction {
37    MXC_GPIO_DIRECTION_IN,
38    MXC_GPIO_DIRECTION_OUT,
39};
40
41#define GPIO_TO_PORT(n)     (n / 32)
42
43#define GPIO_SIZE 0x4000
44
45/* GPIO port description */
46
47#ifdef CONFIG_PLAT_IMX6
48static unsigned long gpio_ports[] = {
49    [0] = 0,
50    [1] = 0,
51    [2] = 0,
52    [3] = 0,
53    [4] = 0,
54    [5] = 0,
55    [6] = 0,
56};
57
58static unsigned long gpio_paddr[] = {
59    [0] = GPIO1_BASE_ADDR,
60    [1] = GPIO2_BASE_ADDR,
61    [2] = GPIO3_BASE_ADDR, /* Used by ethernet */
62    [3] = GPIO4_BASE_ADDR,
63    [4] = GPIO5_BASE_ADDR,
64    [5] = GPIO6_BASE_ADDR,
65    [6] = GPIO7_BASE_ADDR,
66};
67#endif
68#ifdef CONFIG_PLAT_IMX8MQ_EVK
69static unsigned long gpio_ports[] = {
70    [0] = 0,
71    [1] = 0,
72    [2] = 0,
73    [3] = 0,
74    [4] = 0,
75};
76
77static unsigned long gpio_paddr[] = {
78    [0] = 0x30200000,
79    [1] = 0x30210000,
80    [2] = 0x30220000,
81    [3] = 0x30230000,
82    [4] = 0x30240000,
83};
84#endif
85
86static int mxc_gpio_direction(unsigned int gpio,
87                              enum mxc_gpio_direction direction, ps_io_ops_t *io_ops)
88{
89    unsigned int port = GPIO_TO_PORT(gpio);
90    struct gpio_regs *regs;
91    uint32_t l;
92
93    if (port >= ARRAY_SIZE(gpio_ports)) {
94        return -1;
95    }
96
97    gpio &= 0x1f;
98
99    if (gpio_ports[port] == 0) {
100        uintptr_t gpio_phys = (uintptr_t)gpio_paddr[port];
101        gpio_ports[port] = (unsigned long)ps_io_map(&io_ops->io_mapper, gpio_phys, GPIO_SIZE, 0, PS_MEM_NORMAL);
102        if (gpio_ports[port] == 0) {
103            LOG_ERROR("Warning: No map for GPIO %d. Assuming that it is already configured\n", port);
104            return 0;
105        }
106    }
107
108    regs = (struct gpio_regs *)gpio_ports[port];
109    l = readl(&regs->gpio_dir);
110
111    switch (direction) {
112    case MXC_GPIO_DIRECTION_OUT:
113        l |= 1 << gpio;
114        break;
115    case MXC_GPIO_DIRECTION_IN:
116        l &= ~(BIT(gpio));
117    }
118    writel(l, &regs->gpio_dir);
119
120    return 0;
121}
122
123int gpio_set_value(unsigned gpio, int value)
124{
125    unsigned int port = GPIO_TO_PORT(gpio);
126    struct gpio_regs *regs;
127    uint32_t l;
128
129    if (port >= ARRAY_SIZE(gpio_ports)) {
130        return -1;
131    }
132
133    gpio &= 0x1f;
134
135    regs = (struct gpio_regs *)gpio_ports[port];
136
137    l = readl(&regs->gpio_dr);
138    if (value) {
139        l |= 1 << gpio;
140    } else {
141        l &= ~(BIT(gpio));
142    }
143    writel(l, &regs->gpio_dr);
144
145    return 0;
146}
147
148int gpio_get_value(unsigned gpio)
149{
150    unsigned int port = GPIO_TO_PORT(gpio);
151    struct gpio_regs *regs;
152    uint32_t val;
153
154    if (port >= ARRAY_SIZE(gpio_ports)) {
155        return -1;
156    }
157
158    gpio &= 0x1f;
159
160    regs = (struct gpio_regs *)gpio_ports[port];
161
162    val = (readl(&regs->gpio_psr) >> gpio) & 0x01;
163
164    return val;
165}
166
167int gpio_request(unsigned gpio, const char *label)
168{
169    unsigned int port = GPIO_TO_PORT(gpio);
170    if (port >= ARRAY_SIZE(gpio_ports)) {
171        return -1;
172    }
173    return 0;
174}
175
176int gpio_free(unsigned gpio)
177{
178    return 0;
179}
180
181int gpio_direction_input(unsigned gpio, ps_io_ops_t *io_ops)
182{
183    return mxc_gpio_direction(gpio, MXC_GPIO_DIRECTION_IN, io_ops);
184}
185
186int gpio_direction_output(unsigned gpio, int value, ps_io_ops_t *io_ops)
187{
188    int ret = mxc_gpio_direction(gpio, MXC_GPIO_DIRECTION_OUT, io_ops);
189
190    if (ret < 0) {
191        return ret;
192    }
193
194    return gpio_set_value(gpio, value);
195}
196