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