Prepare v2023.10
[platform/kernel/u-boot.git] / drivers / gpio / sunxi_gpio.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
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>
10  */
11
12 #include <common.h>
13 #include <dm.h>
14 #include <errno.h>
15 #include <fdtdec.h>
16 #include <malloc.h>
17 #include <asm/io.h>
18 #include <asm/gpio.h>
19 #include <dt-bindings/gpio/gpio.h>
20
21 #if !CONFIG_IS_ENABLED(DM_GPIO)
22 static int sunxi_gpio_output(u32 pin, u32 val)
23 {
24         u32 dat;
25         u32 bank = GPIO_BANK(pin);
26         u32 num = GPIO_NUM(pin);
27         struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
28
29         dat = readl(&pio->dat);
30         if (val)
31                 dat |= 0x1 << num;
32         else
33                 dat &= ~(0x1 << num);
34
35         writel(dat, &pio->dat);
36
37         return 0;
38 }
39
40 static int sunxi_gpio_input(u32 pin)
41 {
42         u32 dat;
43         u32 bank = GPIO_BANK(pin);
44         u32 num = GPIO_NUM(pin);
45         struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
46
47         dat = readl(&pio->dat);
48         dat >>= num;
49
50         return dat & 0x1;
51 }
52
53 int gpio_request(unsigned gpio, const char *label)
54 {
55         return 0;
56 }
57
58 int gpio_free(unsigned gpio)
59 {
60         return 0;
61 }
62
63 int gpio_direction_input(unsigned gpio)
64 {
65         sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_INPUT);
66
67         return 0;
68 }
69
70 int gpio_direction_output(unsigned gpio, int value)
71 {
72         sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_OUTPUT);
73
74         return sunxi_gpio_output(gpio, value);
75 }
76
77 int gpio_get_value(unsigned gpio)
78 {
79         return sunxi_gpio_input(gpio);
80 }
81
82 int gpio_set_value(unsigned gpio, int value)
83 {
84         return sunxi_gpio_output(gpio, value);
85 }
86
87 int sunxi_name_to_gpio(const char *name)
88 {
89         int group = 0;
90         int groupsize = 9 * 32;
91         long pin;
92         char *eptr;
93
94         if (*name == 'P' || *name == 'p')
95                 name++;
96         if (*name >= 'A') {
97                 group = *name - (*name > 'a' ? 'a' : 'A');
98                 groupsize = 32;
99                 name++;
100         }
101
102         pin = simple_strtol(name, &eptr, 10);
103         if (!*name || *eptr)
104                 return -1;
105         if (pin < 0 || pin > groupsize || group >= 9)
106                 return -1;
107         return group * 32 + pin;
108 }
109 #endif /* DM_GPIO */
110
111 #if CONFIG_IS_ENABLED(DM_GPIO)
112 /* TODO(sjg@chromium.org): Remove this function and use device tree */
113 int sunxi_name_to_gpio(const char *name)
114 {
115         unsigned int gpio;
116         int ret;
117 #if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO
118         char lookup[8];
119
120         if (strcasecmp(name, "AXP0-VBUS-ENABLE") == 0) {
121                 sprintf(lookup, SUNXI_GPIO_AXP0_PREFIX "%d",
122                         SUNXI_GPIO_AXP0_VBUS_ENABLE);
123                 name = lookup;
124         }
125 #endif
126         ret = gpio_lookup_name(name, NULL, NULL, &gpio);
127
128         return ret ? ret : gpio;
129 }
130
131 static int sunxi_gpio_get_value(struct udevice *dev, unsigned offset)
132 {
133         struct sunxi_gpio_plat *plat = dev_get_plat(dev);
134         u32 num = GPIO_NUM(offset);
135         unsigned dat;
136
137         dat = readl(&plat->regs->dat);
138         dat >>= num;
139
140         return dat & 0x1;
141 }
142
143 static int sunxi_gpio_get_function(struct udevice *dev, unsigned offset)
144 {
145         struct sunxi_gpio_plat *plat = dev_get_plat(dev);
146         int func;
147
148         func = sunxi_gpio_get_cfgbank(plat->regs, offset);
149         if (func == SUNXI_GPIO_OUTPUT)
150                 return GPIOF_OUTPUT;
151         else if (func == SUNXI_GPIO_INPUT)
152                 return GPIOF_INPUT;
153         else
154                 return GPIOF_FUNC;
155 }
156
157 static int sunxi_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
158                             struct ofnode_phandle_args *args)
159 {
160         int ret;
161
162         ret = device_get_child(dev, args->args[0], &desc->dev);
163         if (ret)
164                 return ret;
165         desc->offset = args->args[1];
166         desc->flags = gpio_flags_xlate(args->args[2]);
167
168         return 0;
169 }
170
171 static int sunxi_gpio_set_flags(struct udevice *dev, unsigned int offset,
172                                 ulong flags)
173 {
174         struct sunxi_gpio_plat *plat = dev_get_plat(dev);
175
176         if (flags & GPIOD_IS_OUT) {
177                 u32 value = !!(flags & GPIOD_IS_OUT_ACTIVE);
178                 u32 num = GPIO_NUM(offset);
179
180                 clrsetbits_le32(&plat->regs->dat, 1 << num, value << num);
181                 sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_OUTPUT);
182         } else if (flags & GPIOD_IS_IN) {
183                 u32 pull = 0;
184
185                 if (flags & GPIOD_PULL_UP)
186                         pull = 1;
187                 else if (flags & GPIOD_PULL_DOWN)
188                         pull = 2;
189                 sunxi_gpio_set_pull_bank(plat->regs, offset, pull);
190                 sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_INPUT);
191         }
192
193         return 0;
194 }
195
196 static const struct dm_gpio_ops gpio_sunxi_ops = {
197         .get_value              = sunxi_gpio_get_value,
198         .get_function           = sunxi_gpio_get_function,
199         .xlate                  = sunxi_gpio_xlate,
200         .set_flags              = sunxi_gpio_set_flags,
201 };
202
203 static int gpio_sunxi_probe(struct udevice *dev)
204 {
205         struct sunxi_gpio_plat *plat = dev_get_plat(dev);
206         struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
207
208         /* Tell the uclass how many GPIOs we have */
209         if (plat) {
210                 uc_priv->gpio_count = SUNXI_GPIOS_PER_BANK;
211                 uc_priv->bank_name = plat->bank_name;
212         }
213
214         return 0;
215 }
216
217 U_BOOT_DRIVER(gpio_sunxi) = {
218         .name   = "gpio_sunxi",
219         .id     = UCLASS_GPIO,
220         .probe  = gpio_sunxi_probe,
221         .ops    = &gpio_sunxi_ops,
222 };
223 #endif /* DM_GPIO */