blob: d7f6a266e53c11c2e90ed6d774be2e98dcba4446 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Ian Campbellaf471472014-06-05 19:00:15 +01002/*
3 * (C) Copyright 2012 Henrik Nordstrom <henrik@henriknordstrom.net>
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 <tangliang@allwinnertech.com>
Ian Campbellaf471472014-06-05 19:00:15 +010010 */
11
12#include <common.h>
Simon Glass78304532014-10-30 20:25:49 -060013#include <dm.h>
14#include <errno.h>
15#include <fdtdec.h>
16#include <malloc.h>
Ian Campbellaf471472014-06-05 19:00:15 +010017#include <asm/io.h>
18#include <asm/gpio.h>
Chen-Yu Tsaif3aa2822016-07-22 16:12:59 +080019#include <dt-bindings/gpio/gpio.h>
Ian Campbellaf471472014-06-05 19:00:15 +010020
Andre Przywara82d307c2022-09-06 10:36:38 +010021/*
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
Andre Przywara82d307c2022-09-06 10:36:38 +010032#define GPIO_BANK(pin) ((pin) >> 5)
33#define GPIO_NUM(pin) ((pin) & 0x1f)
34
Andre Przywara841ebfb32022-09-05 18:12:39 +010035#define GPIO_CFG_REG_OFFSET 0x00
Andre Przywara82d307c2022-09-06 10:36:38 +010036#define GPIO_CFG_INDEX(pin) (((pin) & 0x1f) >> 3)
37#define GPIO_CFG_OFFSET(pin) ((((pin) & 0x1f) & 0x7) << 2)
38
Andre Przywara841ebfb32022-09-05 18:12:39 +010039#define GPIO_DAT_REG_OFFSET 0x10
40
41#define GPIO_DRV_REG_OFFSET 0x14
Andre Przywara82d307c2022-09-06 10:36:38 +010042#define GPIO_DRV_INDEX(pin) (((pin) & 0x1f) >> 4)
43#define GPIO_DRV_OFFSET(pin) ((((pin) & 0x1f) & 0xf) << 1)
44
Andre Przywara841ebfb32022-09-05 18:12:39 +010045#define GPIO_PULL_REG_OFFSET 0x1c
Andre Przywara82d307c2022-09-06 10:36:38 +010046#define GPIO_PULL_INDEX(pin) (((pin) & 0x1f) >> 4)
47#define GPIO_PULL_OFFSET(pin) ((((pin) & 0x1f) & 0xf) << 1)
48
Andre Przywara841ebfb32022-09-05 18:12:39 +010049static void* BANK_TO_GPIO(int bank)
50{
51 void *pio_base;
52
53 if (bank < SUNXI_GPIO_L) {
54 pio_base = (void *)(uintptr_t)SUNXI_PIO_BASE;
55 } else {
56 pio_base = (void *)(uintptr_t)SUNXI_R_PIO_BASE;
57 bank -= SUNXI_GPIO_L;
58 }
59
60 return pio_base + bank * SUNXI_PINCTRL_BANK_SIZE;
61}
62
63void sunxi_gpio_set_cfgbank(void *bank_base, int pin_offset, u32 val)
Andre Przywara82d307c2022-09-06 10:36:38 +010064{
Andre Przywara841ebfb32022-09-05 18:12:39 +010065 u32 index = GPIO_CFG_INDEX(pin_offset);
66 u32 offset = GPIO_CFG_OFFSET(pin_offset);
Andre Przywara82d307c2022-09-06 10:36:38 +010067
Andre Przywara841ebfb32022-09-05 18:12:39 +010068 clrsetbits_le32(bank_base + GPIO_CFG_REG_OFFSET + index * 4,
69 0xfU << offset, val << offset);
Andre Przywara82d307c2022-09-06 10:36:38 +010070}
71
72void sunxi_gpio_set_cfgpin(u32 pin, u32 val)
73{
74 u32 bank = GPIO_BANK(pin);
Andre Przywara841ebfb32022-09-05 18:12:39 +010075 void *pio = BANK_TO_GPIO(bank);
Andre Przywara82d307c2022-09-06 10:36:38 +010076
Andre Przywara841ebfb32022-09-05 18:12:39 +010077 sunxi_gpio_set_cfgbank(pio, GPIO_NUM(pin), val);
Andre Przywara82d307c2022-09-06 10:36:38 +010078}
79
Andre Przywara841ebfb32022-09-05 18:12:39 +010080int sunxi_gpio_get_cfgbank(void *bank_base, int pin_offset)
Andre Przywara82d307c2022-09-06 10:36:38 +010081{
Andre Przywara841ebfb32022-09-05 18:12:39 +010082 u32 index = GPIO_CFG_INDEX(pin_offset);
83 u32 offset = GPIO_CFG_OFFSET(pin_offset);
Andre Przywara82d307c2022-09-06 10:36:38 +010084 u32 cfg;
85
Andre Przywara841ebfb32022-09-05 18:12:39 +010086 cfg = readl(bank_base + GPIO_CFG_REG_OFFSET + index * 4);
Andre Przywara82d307c2022-09-06 10:36:38 +010087 cfg >>= offset;
88
89 return cfg & 0xf;
90}
91
92int sunxi_gpio_get_cfgpin(u32 pin)
93{
94 u32 bank = GPIO_BANK(pin);
Andre Przywara841ebfb32022-09-05 18:12:39 +010095 void *bank_base = BANK_TO_GPIO(bank);
Andre Przywara82d307c2022-09-06 10:36:38 +010096
Andre Przywara841ebfb32022-09-05 18:12:39 +010097 return sunxi_gpio_get_cfgbank(bank_base, GPIO_NUM(pin));
Andre Przywara82d307c2022-09-06 10:36:38 +010098}
99
Andre Przywara841ebfb32022-09-05 18:12:39 +0100100static void sunxi_gpio_set_value_bank(void *bank_base, int pin, bool set)
Andre Przywara6e632102022-09-06 10:07:18 +0100101{
102 u32 mask = 1U << pin;
103
Andre Przywara841ebfb32022-09-05 18:12:39 +0100104 clrsetbits_le32(bank_base + GPIO_DAT_REG_OFFSET,
105 set ? 0 : mask, set ? mask : 0);
Andre Przywara6e632102022-09-06 10:07:18 +0100106}
107
Andre Przywara841ebfb32022-09-05 18:12:39 +0100108static int sunxi_gpio_get_value_bank(void *bank_base, int pin)
Andre Przywara6e632102022-09-06 10:07:18 +0100109{
Andre Przywara841ebfb32022-09-05 18:12:39 +0100110 return !!(readl(bank_base + GPIO_DAT_REG_OFFSET) & (1U << pin));
Andre Przywara6e632102022-09-06 10:07:18 +0100111}
112
Andre Przywara82d307c2022-09-06 10:36:38 +0100113void sunxi_gpio_set_drv(u32 pin, u32 val)
114{
115 u32 bank = GPIO_BANK(pin);
Andre Przywara841ebfb32022-09-05 18:12:39 +0100116 void *bank_base = BANK_TO_GPIO(bank);
Andre Przywara82d307c2022-09-06 10:36:38 +0100117
Andre Przywara841ebfb32022-09-05 18:12:39 +0100118 sunxi_gpio_set_drv_bank(bank_base, GPIO_NUM(pin), val);
Andre Przywara82d307c2022-09-06 10:36:38 +0100119}
120
Andre Przywara841ebfb32022-09-05 18:12:39 +0100121void sunxi_gpio_set_drv_bank(void *bank_base, u32 pin_offset, u32 val)
Andre Przywara82d307c2022-09-06 10:36:38 +0100122{
Andre Przywara841ebfb32022-09-05 18:12:39 +0100123 u32 index = GPIO_DRV_INDEX(pin_offset);
124 u32 offset = GPIO_DRV_OFFSET(pin_offset);
Andre Przywara82d307c2022-09-06 10:36:38 +0100125
Andre Przywara841ebfb32022-09-05 18:12:39 +0100126 clrsetbits_le32(bank_base + GPIO_DRV_REG_OFFSET + index * 4,
127 0x3U << offset, val << offset);
Andre Przywara82d307c2022-09-06 10:36:38 +0100128}
129
130void sunxi_gpio_set_pull(u32 pin, u32 val)
131{
132 u32 bank = GPIO_BANK(pin);
Andre Przywara841ebfb32022-09-05 18:12:39 +0100133 void *bank_base = BANK_TO_GPIO(bank);
Andre Przywara82d307c2022-09-06 10:36:38 +0100134
Andre Przywara841ebfb32022-09-05 18:12:39 +0100135 sunxi_gpio_set_pull_bank(bank_base, GPIO_NUM(pin), val);
Andre Przywara82d307c2022-09-06 10:36:38 +0100136}
137
Andre Przywara841ebfb32022-09-05 18:12:39 +0100138void sunxi_gpio_set_pull_bank(void *bank_base, int pin_offset, u32 val)
Andre Przywara82d307c2022-09-06 10:36:38 +0100139{
Andre Przywara841ebfb32022-09-05 18:12:39 +0100140 u32 index = GPIO_PULL_INDEX(pin_offset);
141 u32 offset = GPIO_PULL_OFFSET(pin_offset);
Andre Przywara82d307c2022-09-06 10:36:38 +0100142
Andre Przywara841ebfb32022-09-05 18:12:39 +0100143 clrsetbits_le32(bank_base + GPIO_PULL_REG_OFFSET + index * 4,
144 0x3U << offset, val << offset);
Andre Przywara82d307c2022-09-06 10:36:38 +0100145}
146
147
148/* =========== Non-DM code, used by the SPL. ============ */
149
Simon Glassfa4689a2019-12-06 21:41:35 -0700150#if !CONFIG_IS_ENABLED(DM_GPIO)
Andre Przywara6e632102022-09-06 10:07:18 +0100151static void sunxi_gpio_set_value(u32 pin, bool set)
Ian Campbellaf471472014-06-05 19:00:15 +0100152{
Ian Campbellaf471472014-06-05 19:00:15 +0100153 u32 bank = GPIO_BANK(pin);
Andre Przywara841ebfb32022-09-05 18:12:39 +0100154 void *pio = BANK_TO_GPIO(bank);
Ian Campbellaf471472014-06-05 19:00:15 +0100155
Andre Przywara6e632102022-09-06 10:07:18 +0100156 sunxi_gpio_set_value_bank(pio, GPIO_NUM(pin), set);
Ian Campbellaf471472014-06-05 19:00:15 +0100157}
158
Andre Przywara6e632102022-09-06 10:07:18 +0100159static int sunxi_gpio_get_value(u32 pin)
Ian Campbellaf471472014-06-05 19:00:15 +0100160{
Ian Campbellaf471472014-06-05 19:00:15 +0100161 u32 bank = GPIO_BANK(pin);
Andre Przywara841ebfb32022-09-05 18:12:39 +0100162 void *pio = BANK_TO_GPIO(bank);
Ian Campbellaf471472014-06-05 19:00:15 +0100163
Andre Przywara6e632102022-09-06 10:07:18 +0100164 return sunxi_gpio_get_value_bank(pio, GPIO_NUM(pin));
Ian Campbellaf471472014-06-05 19:00:15 +0100165}
166
167int gpio_request(unsigned gpio, const char *label)
168{
169 return 0;
170}
171
172int gpio_free(unsigned gpio)
173{
174 return 0;
175}
176
177int gpio_direction_input(unsigned gpio)
178{
179 sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_INPUT);
180
Axel Lin06da3462014-12-20 11:41:25 +0800181 return 0;
Ian Campbellaf471472014-06-05 19:00:15 +0100182}
183
184int gpio_direction_output(unsigned gpio, int value)
185{
186 sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_OUTPUT);
Andre Przywara6e632102022-09-06 10:07:18 +0100187 sunxi_gpio_set_value(gpio, value);
Ian Campbellaf471472014-06-05 19:00:15 +0100188
Andre Przywara6e632102022-09-06 10:07:18 +0100189 return 0;
Ian Campbellaf471472014-06-05 19:00:15 +0100190}
191
192int gpio_get_value(unsigned gpio)
193{
Andre Przywara6e632102022-09-06 10:07:18 +0100194 return sunxi_gpio_get_value(gpio);
Ian Campbellaf471472014-06-05 19:00:15 +0100195}
196
197int gpio_set_value(unsigned gpio, int value)
198{
Andre Przywara6e632102022-09-06 10:07:18 +0100199 sunxi_gpio_set_value(gpio, value);
200
201 return 0;
Ian Campbellaf471472014-06-05 19:00:15 +0100202}
203
204int sunxi_name_to_gpio(const char *name)
205{
206 int group = 0;
207 int groupsize = 9 * 32;
208 long pin;
209 char *eptr;
Hans de Goede1fc9c4a2014-12-24 19:34:38 +0100210
Ian Campbellaf471472014-06-05 19:00:15 +0100211 if (*name == 'P' || *name == 'p')
212 name++;
213 if (*name >= 'A') {
214 group = *name - (*name > 'a' ? 'a' : 'A');
215 groupsize = 32;
216 name++;
217 }
218
219 pin = simple_strtol(name, &eptr, 10);
220 if (!*name || *eptr)
221 return -1;
222 if (pin < 0 || pin > groupsize || group >= 9)
223 return -1;
224 return group * 32 + pin;
225}
Andre Przywara82d307c2022-09-06 10:36:38 +0100226#endif /* !DM_GPIO */
227
228/* =========== DM code, used by U-Boot proper. ============ */
Simon Glass78304532014-10-30 20:25:49 -0600229
Simon Glassfa4689a2019-12-06 21:41:35 -0700230#if CONFIG_IS_ENABLED(DM_GPIO)
Simon Glass9754d932015-04-18 11:33:43 -0600231/* TODO(sjg@chromium.org): Remove this function and use device tree */
232int sunxi_name_to_gpio(const char *name)
233{
234 unsigned int gpio;
235 int ret;
Hans de Goede08607d12015-04-22 11:31:22 +0200236#if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO
237 char lookup[8];
Simon Glass9754d932015-04-18 11:33:43 -0600238
Samuel Holland5f9c8442023-01-22 17:46:22 -0600239 if (strcasecmp(name, "AXP0-VBUS-ENABLE") == 0) {
Hans de Goede08607d12015-04-22 11:31:22 +0200240 sprintf(lookup, SUNXI_GPIO_AXP0_PREFIX "%d",
241 SUNXI_GPIO_AXP0_VBUS_ENABLE);
242 name = lookup;
243 }
244#endif
Simon Glass9754d932015-04-18 11:33:43 -0600245 ret = gpio_lookup_name(name, NULL, NULL, &gpio);
246
247 return ret ? ret : gpio;
248}
249
Simon Glass78304532014-10-30 20:25:49 -0600250static int sunxi_gpio_get_value(struct udevice *dev, unsigned offset)
251{
Simon Glassb75b15b2020-12-03 16:55:23 -0700252 struct sunxi_gpio_plat *plat = dev_get_plat(dev);
Simon Glass78304532014-10-30 20:25:49 -0600253
Andre Przywara6e632102022-09-06 10:07:18 +0100254 return sunxi_gpio_get_value_bank(plat->regs, offset);
Simon Glass78304532014-10-30 20:25:49 -0600255}
256
Simon Glass78304532014-10-30 20:25:49 -0600257static int sunxi_gpio_get_function(struct udevice *dev, unsigned offset)
258{
Simon Glassb75b15b2020-12-03 16:55:23 -0700259 struct sunxi_gpio_plat *plat = dev_get_plat(dev);
Simon Glass78304532014-10-30 20:25:49 -0600260 int func;
261
262 func = sunxi_gpio_get_cfgbank(plat->regs, offset);
263 if (func == SUNXI_GPIO_OUTPUT)
264 return GPIOF_OUTPUT;
265 else if (func == SUNXI_GPIO_INPUT)
266 return GPIOF_INPUT;
267 else
268 return GPIOF_FUNC;
269}
270
Chen-Yu Tsaif3aa2822016-07-22 16:12:59 +0800271static int sunxi_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
Simon Glass12faa022017-05-18 20:09:18 -0600272 struct ofnode_phandle_args *args)
Chen-Yu Tsaif3aa2822016-07-22 16:12:59 +0800273{
274 int ret;
275
276 ret = device_get_child(dev, args->args[0], &desc->dev);
277 if (ret)
278 return ret;
279 desc->offset = args->args[1];
Samuel Hollandbfda9492021-10-20 23:52:56 -0500280 desc->flags = gpio_flags_xlate(args->args[2]);
281
282 return 0;
283}
284
285static int sunxi_gpio_set_flags(struct udevice *dev, unsigned int offset,
286 ulong flags)
287{
288 struct sunxi_gpio_plat *plat = dev_get_plat(dev);
289
290 if (flags & GPIOD_IS_OUT) {
291 u32 value = !!(flags & GPIOD_IS_OUT_ACTIVE);
Samuel Hollandbfda9492021-10-20 23:52:56 -0500292
Andre Przywara6e632102022-09-06 10:07:18 +0100293 sunxi_gpio_set_value_bank(plat->regs, offset, value);
Samuel Hollandbfda9492021-10-20 23:52:56 -0500294 sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_OUTPUT);
295 } else if (flags & GPIOD_IS_IN) {
296 u32 pull = 0;
297
298 if (flags & GPIOD_PULL_UP)
299 pull = 1;
300 else if (flags & GPIOD_PULL_DOWN)
301 pull = 2;
302 sunxi_gpio_set_pull_bank(plat->regs, offset, pull);
303 sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_INPUT);
304 }
Chen-Yu Tsaif3aa2822016-07-22 16:12:59 +0800305
306 return 0;
307}
308
Simon Glass78304532014-10-30 20:25:49 -0600309static const struct dm_gpio_ops gpio_sunxi_ops = {
Simon Glass78304532014-10-30 20:25:49 -0600310 .get_value = sunxi_gpio_get_value,
Simon Glass78304532014-10-30 20:25:49 -0600311 .get_function = sunxi_gpio_get_function,
Chen-Yu Tsaif3aa2822016-07-22 16:12:59 +0800312 .xlate = sunxi_gpio_xlate,
Samuel Hollandbfda9492021-10-20 23:52:56 -0500313 .set_flags = sunxi_gpio_set_flags,
Simon Glass78304532014-10-30 20:25:49 -0600314};
315
Simon Glass78304532014-10-30 20:25:49 -0600316static int gpio_sunxi_probe(struct udevice *dev)
317{
Simon Glassb75b15b2020-12-03 16:55:23 -0700318 struct sunxi_gpio_plat *plat = dev_get_plat(dev);
Simon Glassde0977b2015-03-05 12:25:20 -0700319 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
Simon Glass78304532014-10-30 20:25:49 -0600320
321 /* Tell the uclass how many GPIOs we have */
322 if (plat) {
Samuel Hollande3095022021-08-12 20:09:43 -0500323 uc_priv->gpio_count = SUNXI_GPIOS_PER_BANK;
Simon Glass78304532014-10-30 20:25:49 -0600324 uc_priv->bank_name = plat->bank_name;
325 }
326
327 return 0;
328}
Stephen Warrenb56989e2016-05-11 15:26:25 -0600329
Simon Glass78304532014-10-30 20:25:49 -0600330U_BOOT_DRIVER(gpio_sunxi) = {
331 .name = "gpio_sunxi",
332 .id = UCLASS_GPIO,
Simon Glass78304532014-10-30 20:25:49 -0600333 .probe = gpio_sunxi_probe,
Samuel Hollande3095022021-08-12 20:09:43 -0500334 .ops = &gpio_sunxi_ops,
Simon Glass78304532014-10-30 20:25:49 -0600335};
Simon Glassfa4689a2019-12-06 21:41:35 -0700336#endif /* DM_GPIO */