]> Git Repo - J-u-boot.git/blame - drivers/gpio/sunxi_gpio.c
drivers: Use CONFIG_XPL_BUILD instead of CONFIG_SPL_BUILD
[J-u-boot.git] / drivers / gpio / sunxi_gpio.c
CommitLineData
83d290c5 1// SPDX-License-Identifier: GPL-2.0+
abce2c62
IC
2/*
3 * (C) Copyright 2012 Henrik Nordstrom <[email protected]>
4 *
5 * Based on earlier arch/arm/cpu/armv7/sunxi/gpio.c:
6 *
7 * (C) Copyright 2007-2011
8 * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
9 * Tom Cubie <[email protected]>
abce2c62
IC
10 */
11
7aa97485
SG
12#include <dm.h>
13#include <errno.h>
14#include <fdtdec.h>
15#include <malloc.h>
abce2c62
IC
16#include <asm/io.h>
17#include <asm/gpio.h>
4694dc56 18#include <dt-bindings/gpio/gpio.h>
207ed0a3 19#include <sunxi_gpio.h>
abce2c62 20
20b78c55
AP
21/*
22 * =======================================================================
23 * Low level GPIO/pin controller access functions, to be shared by non-DM
24 * SPL code and the DM pinctrl/GPIO drivers.
25 * The functions ending in "bank" take a base pointer to a GPIO bank, and
26 * the pin offset is relative to that bank.
27 * The functions without "bank" in their name take a linear GPIO number,
28 * covering all ports, and starting at 0 for PortA.
29 * =======================================================================
30 */
31
20b78c55
AP
32#define GPIO_BANK(pin) ((pin) >> 5)
33#define GPIO_NUM(pin) ((pin) & 0x1f)
34
30097ee3 35#define GPIO_CFG_REG_OFFSET 0x00
20b78c55
AP
36#define GPIO_CFG_INDEX(pin) (((pin) & 0x1f) >> 3)
37#define GPIO_CFG_OFFSET(pin) ((((pin) & 0x1f) & 0x7) << 2)
38
30097ee3
AP
39#define GPIO_DAT_REG_OFFSET 0x10
40
41#define GPIO_DRV_REG_OFFSET 0x14
452369cd
AP
42
43/* Newer SoCs use a slightly different register layout */
44#ifdef CONFIG_SUNXI_NEW_PINCTRL
45/* pin drive strength: 4 bits per pin */
46#define GPIO_DRV_INDEX(pin) ((pin) / 8)
47#define GPIO_DRV_OFFSET(pin) (((pin) % 8) * 4)
48
49#define GPIO_PULL_REG_OFFSET 0x24
50
51#else /* older generation pin controllers */
52/* pin drive strength: 2 bits per pin */
53#define GPIO_DRV_INDEX(pin) ((pin) / 16)
54#define GPIO_DRV_OFFSET(pin) (((pin) % 16) * 2)
20b78c55 55
30097ee3 56#define GPIO_PULL_REG_OFFSET 0x1c
452369cd
AP
57#endif
58
20b78c55
AP
59#define GPIO_PULL_INDEX(pin) (((pin) & 0x1f) >> 4)
60#define GPIO_PULL_OFFSET(pin) ((((pin) & 0x1f) & 0xf) << 1)
61
30097ee3
AP
62static void* BANK_TO_GPIO(int bank)
63{
64 void *pio_base;
65
66 if (bank < SUNXI_GPIO_L) {
67 pio_base = (void *)(uintptr_t)SUNXI_PIO_BASE;
68 } else {
69 pio_base = (void *)(uintptr_t)SUNXI_R_PIO_BASE;
70 bank -= SUNXI_GPIO_L;
71 }
72
73 return pio_base + bank * SUNXI_PINCTRL_BANK_SIZE;
74}
75
76void sunxi_gpio_set_cfgbank(void *bank_base, int pin_offset, u32 val)
20b78c55 77{
30097ee3
AP
78 u32 index = GPIO_CFG_INDEX(pin_offset);
79 u32 offset = GPIO_CFG_OFFSET(pin_offset);
20b78c55 80
30097ee3
AP
81 clrsetbits_le32(bank_base + GPIO_CFG_REG_OFFSET + index * 4,
82 0xfU << offset, val << offset);
20b78c55
AP
83}
84
85void sunxi_gpio_set_cfgpin(u32 pin, u32 val)
86{
87 u32 bank = GPIO_BANK(pin);
30097ee3 88 void *pio = BANK_TO_GPIO(bank);
20b78c55 89
30097ee3 90 sunxi_gpio_set_cfgbank(pio, GPIO_NUM(pin), val);
20b78c55
AP
91}
92
30097ee3 93int sunxi_gpio_get_cfgbank(void *bank_base, int pin_offset)
20b78c55 94{
30097ee3
AP
95 u32 index = GPIO_CFG_INDEX(pin_offset);
96 u32 offset = GPIO_CFG_OFFSET(pin_offset);
20b78c55
AP
97 u32 cfg;
98
30097ee3 99 cfg = readl(bank_base + GPIO_CFG_REG_OFFSET + index * 4);
20b78c55
AP
100 cfg >>= offset;
101
102 return cfg & 0xf;
103}
104
105int sunxi_gpio_get_cfgpin(u32 pin)
106{
107 u32 bank = GPIO_BANK(pin);
30097ee3 108 void *bank_base = BANK_TO_GPIO(bank);
20b78c55 109
30097ee3 110 return sunxi_gpio_get_cfgbank(bank_base, GPIO_NUM(pin));
20b78c55
AP
111}
112
30097ee3 113static void sunxi_gpio_set_value_bank(void *bank_base, int pin, bool set)
316ec7ff
AP
114{
115 u32 mask = 1U << pin;
116
30097ee3
AP
117 clrsetbits_le32(bank_base + GPIO_DAT_REG_OFFSET,
118 set ? 0 : mask, set ? mask : 0);
316ec7ff
AP
119}
120
30097ee3 121static int sunxi_gpio_get_value_bank(void *bank_base, int pin)
316ec7ff 122{
30097ee3 123 return !!(readl(bank_base + GPIO_DAT_REG_OFFSET) & (1U << pin));
316ec7ff
AP
124}
125
20b78c55
AP
126void sunxi_gpio_set_drv(u32 pin, u32 val)
127{
128 u32 bank = GPIO_BANK(pin);
30097ee3 129 void *bank_base = BANK_TO_GPIO(bank);
20b78c55 130
30097ee3 131 sunxi_gpio_set_drv_bank(bank_base, GPIO_NUM(pin), val);
20b78c55
AP
132}
133
30097ee3 134void sunxi_gpio_set_drv_bank(void *bank_base, u32 pin_offset, u32 val)
20b78c55 135{
30097ee3
AP
136 u32 index = GPIO_DRV_INDEX(pin_offset);
137 u32 offset = GPIO_DRV_OFFSET(pin_offset);
20b78c55 138
30097ee3
AP
139 clrsetbits_le32(bank_base + GPIO_DRV_REG_OFFSET + index * 4,
140 0x3U << offset, val << offset);
20b78c55
AP
141}
142
143void sunxi_gpio_set_pull(u32 pin, u32 val)
144{
145 u32 bank = GPIO_BANK(pin);
30097ee3 146 void *bank_base = BANK_TO_GPIO(bank);
20b78c55 147
30097ee3 148 sunxi_gpio_set_pull_bank(bank_base, GPIO_NUM(pin), val);
20b78c55
AP
149}
150
30097ee3 151void sunxi_gpio_set_pull_bank(void *bank_base, int pin_offset, u32 val)
20b78c55 152{
30097ee3
AP
153 u32 index = GPIO_PULL_INDEX(pin_offset);
154 u32 offset = GPIO_PULL_OFFSET(pin_offset);
20b78c55 155
30097ee3
AP
156 clrsetbits_le32(bank_base + GPIO_PULL_REG_OFFSET + index * 4,
157 0x3U << offset, val << offset);
20b78c55
AP
158}
159
20b78c55
AP
160/* =========== Non-DM code, used by the SPL. ============ */
161
bcee8d67 162#if !CONFIG_IS_ENABLED(DM_GPIO)
316ec7ff 163static void sunxi_gpio_set_value(u32 pin, bool set)
abce2c62 164{
abce2c62 165 u32 bank = GPIO_BANK(pin);
30097ee3 166 void *pio = BANK_TO_GPIO(bank);
abce2c62 167
316ec7ff 168 sunxi_gpio_set_value_bank(pio, GPIO_NUM(pin), set);
abce2c62
IC
169}
170
316ec7ff 171static int sunxi_gpio_get_value(u32 pin)
abce2c62 172{
abce2c62 173 u32 bank = GPIO_BANK(pin);
30097ee3 174 void *pio = BANK_TO_GPIO(bank);
abce2c62 175
316ec7ff 176 return sunxi_gpio_get_value_bank(pio, GPIO_NUM(pin));
abce2c62
IC
177}
178
179int gpio_request(unsigned gpio, const char *label)
180{
181 return 0;
182}
183
184int gpio_free(unsigned gpio)
185{
186 return 0;
187}
188
189int gpio_direction_input(unsigned gpio)
190{
191 sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_INPUT);
192
b0c4ae1a 193 return 0;
abce2c62
IC
194}
195
196int gpio_direction_output(unsigned gpio, int value)
197{
198 sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_OUTPUT);
316ec7ff 199 sunxi_gpio_set_value(gpio, value);
abce2c62 200
316ec7ff 201 return 0;
abce2c62
IC
202}
203
204int gpio_get_value(unsigned gpio)
205{
316ec7ff 206 return sunxi_gpio_get_value(gpio);
abce2c62
IC
207}
208
209int gpio_set_value(unsigned gpio, int value)
210{
316ec7ff
AP
211 sunxi_gpio_set_value(gpio, value);
212
213 return 0;
abce2c62
IC
214}
215
216int sunxi_name_to_gpio(const char *name)
217{
218 int group = 0;
219 int groupsize = 9 * 32;
220 long pin;
221 char *eptr;
6c727e09 222
abce2c62
IC
223 if (*name == 'P' || *name == 'p')
224 name++;
225 if (*name >= 'A') {
226 group = *name - (*name > 'a' ? 'a' : 'A');
227 groupsize = 32;
228 name++;
229 }
230
231 pin = simple_strtol(name, &eptr, 10);
232 if (!*name || *eptr)
233 return -1;
234 if (pin < 0 || pin > groupsize || group >= 9)
235 return -1;
236 return group * 32 + pin;
237}
20b78c55
AP
238#endif /* !DM_GPIO */
239
240/* =========== DM code, used by U-Boot proper. ============ */
7aa97485 241
bcee8d67 242#if CONFIG_IS_ENABLED(DM_GPIO)
a5ab8838
SG
243/* TODO([email protected]): Remove this function and use device tree */
244int sunxi_name_to_gpio(const char *name)
245{
246 unsigned int gpio;
247 int ret;
371dc068 248#if !defined CONFIG_XPL_BUILD && defined CONFIG_AXP_GPIO
f9b7a04b
HG
249 char lookup[8];
250
09cbd385 251 if (strcasecmp(name, "AXP0-VBUS-ENABLE") == 0) {
f9b7a04b
HG
252 sprintf(lookup, SUNXI_GPIO_AXP0_PREFIX "%d",
253 SUNXI_GPIO_AXP0_VBUS_ENABLE);
254 name = lookup;
255 }
256#endif
a5ab8838
SG
257 ret = gpio_lookup_name(name, NULL, NULL, &gpio);
258
259 return ret ? ret : gpio;
260}
261
7aa97485
SG
262static int sunxi_gpio_get_value(struct udevice *dev, unsigned offset)
263{
8a8d24bd 264 struct sunxi_gpio_plat *plat = dev_get_plat(dev);
7aa97485 265
316ec7ff 266 return sunxi_gpio_get_value_bank(plat->regs, offset);
7aa97485
SG
267}
268
7aa97485
SG
269static int sunxi_gpio_get_function(struct udevice *dev, unsigned offset)
270{
8a8d24bd 271 struct sunxi_gpio_plat *plat = dev_get_plat(dev);
7aa97485
SG
272 int func;
273
274 func = sunxi_gpio_get_cfgbank(plat->regs, offset);
275 if (func == SUNXI_GPIO_OUTPUT)
276 return GPIOF_OUTPUT;
277 else if (func == SUNXI_GPIO_INPUT)
278 return GPIOF_INPUT;
279 else
280 return GPIOF_FUNC;
281}
282
4694dc56 283static int sunxi_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
3a57123e 284 struct ofnode_phandle_args *args)
4694dc56
CYT
285{
286 int ret;
287
288 ret = device_get_child(dev, args->args[0], &desc->dev);
289 if (ret)
290 return ret;
291 desc->offset = args->args[1];
35ae126c
SH
292 desc->flags = gpio_flags_xlate(args->args[2]);
293
294 return 0;
295}
296
297static int sunxi_gpio_set_flags(struct udevice *dev, unsigned int offset,
298 ulong flags)
299{
300 struct sunxi_gpio_plat *plat = dev_get_plat(dev);
301
302 if (flags & GPIOD_IS_OUT) {
303 u32 value = !!(flags & GPIOD_IS_OUT_ACTIVE);
35ae126c 304
316ec7ff 305 sunxi_gpio_set_value_bank(plat->regs, offset, value);
35ae126c
SH
306 sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_OUTPUT);
307 } else if (flags & GPIOD_IS_IN) {
308 u32 pull = 0;
309
310 if (flags & GPIOD_PULL_UP)
311 pull = 1;
312 else if (flags & GPIOD_PULL_DOWN)
313 pull = 2;
314 sunxi_gpio_set_pull_bank(plat->regs, offset, pull);
315 sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_INPUT);
316 }
4694dc56
CYT
317
318 return 0;
319}
320
7aa97485 321static const struct dm_gpio_ops gpio_sunxi_ops = {
7aa97485 322 .get_value = sunxi_gpio_get_value,
7aa97485 323 .get_function = sunxi_gpio_get_function,
4694dc56 324 .xlate = sunxi_gpio_xlate,
35ae126c 325 .set_flags = sunxi_gpio_set_flags,
7aa97485
SG
326};
327
7aa97485
SG
328static int gpio_sunxi_probe(struct udevice *dev)
329{
8a8d24bd 330 struct sunxi_gpio_plat *plat = dev_get_plat(dev);
e564f054 331 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
7aa97485
SG
332
333 /* Tell the uclass how many GPIOs we have */
334 if (plat) {
b799eabc 335 uc_priv->gpio_count = SUNXI_GPIOS_PER_BANK;
7aa97485
SG
336 uc_priv->bank_name = plat->bank_name;
337 }
338
339 return 0;
340}
6f82fac2 341
7aa97485
SG
342U_BOOT_DRIVER(gpio_sunxi) = {
343 .name = "gpio_sunxi",
344 .id = UCLASS_GPIO,
7aa97485 345 .probe = gpio_sunxi_probe,
b799eabc 346 .ops = &gpio_sunxi_ops,
7aa97485 347};
bcee8d67 348#endif /* DM_GPIO */
This page took 0.472201 seconds and 4 git commands to generate.