]> Git Repo - u-boot.git/blob - drivers/gpio/sunxi_gpio.c
Restore patch series "arm: dts: am62-beagleplay: Fix Beagleplay Ethernet"
[u-boot.git] / drivers / gpio / sunxi_gpio.c
1 // SPDX-License-Identifier: GPL-2.0+
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]>
10  */
11
12 #include <dm.h>
13 #include <errno.h>
14 #include <fdtdec.h>
15 #include <malloc.h>
16 #include <asm/io.h>
17 #include <asm/gpio.h>
18 #include <dt-bindings/gpio/gpio.h>
19 #include <sunxi_gpio.h>
20
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
32 #define GPIO_BANK(pin)          ((pin) >> 5)
33 #define GPIO_NUM(pin)           ((pin) & 0x1f)
34
35 #define GPIO_CFG_REG_OFFSET     0x00
36 #define GPIO_CFG_INDEX(pin)     (((pin) & 0x1f) >> 3)
37 #define GPIO_CFG_OFFSET(pin)    ((((pin) & 0x1f) & 0x7) << 2)
38
39 #define GPIO_DAT_REG_OFFSET     0x10
40
41 #define GPIO_DRV_REG_OFFSET     0x14
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)
55
56 #define GPIO_PULL_REG_OFFSET    0x1c
57 #endif
58
59 #define GPIO_PULL_INDEX(pin)    (((pin) & 0x1f) >> 4)
60 #define GPIO_PULL_OFFSET(pin)   ((((pin) & 0x1f) & 0xf) << 1)
61
62 static 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
76 void sunxi_gpio_set_cfgbank(void *bank_base, int pin_offset, u32 val)
77 {
78         u32 index = GPIO_CFG_INDEX(pin_offset);
79         u32 offset = GPIO_CFG_OFFSET(pin_offset);
80
81         clrsetbits_le32(bank_base + GPIO_CFG_REG_OFFSET + index * 4,
82                         0xfU << offset, val << offset);
83 }
84
85 void sunxi_gpio_set_cfgpin(u32 pin, u32 val)
86 {
87         u32 bank = GPIO_BANK(pin);
88         void *pio = BANK_TO_GPIO(bank);
89
90         sunxi_gpio_set_cfgbank(pio, GPIO_NUM(pin), val);
91 }
92
93 int sunxi_gpio_get_cfgbank(void *bank_base, int pin_offset)
94 {
95         u32 index = GPIO_CFG_INDEX(pin_offset);
96         u32 offset = GPIO_CFG_OFFSET(pin_offset);
97         u32 cfg;
98
99         cfg = readl(bank_base + GPIO_CFG_REG_OFFSET + index * 4);
100         cfg >>= offset;
101
102         return cfg & 0xf;
103 }
104
105 int sunxi_gpio_get_cfgpin(u32 pin)
106 {
107         u32 bank = GPIO_BANK(pin);
108         void *bank_base = BANK_TO_GPIO(bank);
109
110         return sunxi_gpio_get_cfgbank(bank_base, GPIO_NUM(pin));
111 }
112
113 static void sunxi_gpio_set_value_bank(void *bank_base, int pin, bool set)
114 {
115         u32 mask = 1U << pin;
116
117         clrsetbits_le32(bank_base + GPIO_DAT_REG_OFFSET,
118                         set ? 0 : mask, set ? mask : 0);
119 }
120
121 static int sunxi_gpio_get_value_bank(void *bank_base, int pin)
122 {
123         return !!(readl(bank_base + GPIO_DAT_REG_OFFSET) & (1U << pin));
124 }
125
126 void sunxi_gpio_set_drv(u32 pin, u32 val)
127 {
128         u32 bank = GPIO_BANK(pin);
129         void *bank_base = BANK_TO_GPIO(bank);
130
131         sunxi_gpio_set_drv_bank(bank_base, GPIO_NUM(pin), val);
132 }
133
134 void sunxi_gpio_set_drv_bank(void *bank_base, u32 pin_offset, u32 val)
135 {
136         u32 index = GPIO_DRV_INDEX(pin_offset);
137         u32 offset = GPIO_DRV_OFFSET(pin_offset);
138
139         clrsetbits_le32(bank_base + GPIO_DRV_REG_OFFSET + index * 4,
140                         0x3U << offset, val << offset);
141 }
142
143 void sunxi_gpio_set_pull(u32 pin, u32 val)
144 {
145         u32 bank = GPIO_BANK(pin);
146         void *bank_base = BANK_TO_GPIO(bank);
147
148         sunxi_gpio_set_pull_bank(bank_base, GPIO_NUM(pin), val);
149 }
150
151 void sunxi_gpio_set_pull_bank(void *bank_base, int pin_offset, u32 val)
152 {
153         u32 index = GPIO_PULL_INDEX(pin_offset);
154         u32 offset = GPIO_PULL_OFFSET(pin_offset);
155
156         clrsetbits_le32(bank_base + GPIO_PULL_REG_OFFSET + index * 4,
157                         0x3U << offset, val << offset);
158 }
159
160
161 /* =========== Non-DM code, used by the SPL. ============ */
162
163 #if !CONFIG_IS_ENABLED(DM_GPIO)
164 static void sunxi_gpio_set_value(u32 pin, bool set)
165 {
166         u32 bank = GPIO_BANK(pin);
167         void *pio = BANK_TO_GPIO(bank);
168
169         sunxi_gpio_set_value_bank(pio, GPIO_NUM(pin), set);
170 }
171
172 static int sunxi_gpio_get_value(u32 pin)
173 {
174         u32 bank = GPIO_BANK(pin);
175         void *pio = BANK_TO_GPIO(bank);
176
177         return sunxi_gpio_get_value_bank(pio, GPIO_NUM(pin));
178 }
179
180 int gpio_request(unsigned gpio, const char *label)
181 {
182         return 0;
183 }
184
185 int gpio_free(unsigned gpio)
186 {
187         return 0;
188 }
189
190 int gpio_direction_input(unsigned gpio)
191 {
192         sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_INPUT);
193
194         return 0;
195 }
196
197 int gpio_direction_output(unsigned gpio, int value)
198 {
199         sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_OUTPUT);
200         sunxi_gpio_set_value(gpio, value);
201
202         return 0;
203 }
204
205 int gpio_get_value(unsigned gpio)
206 {
207         return sunxi_gpio_get_value(gpio);
208 }
209
210 int gpio_set_value(unsigned gpio, int value)
211 {
212         sunxi_gpio_set_value(gpio, value);
213
214         return 0;
215 }
216
217 int sunxi_name_to_gpio(const char *name)
218 {
219         int group = 0;
220         int groupsize = 9 * 32;
221         long pin;
222         char *eptr;
223
224         if (*name == 'P' || *name == 'p')
225                 name++;
226         if (*name >= 'A') {
227                 group = *name - (*name > 'a' ? 'a' : 'A');
228                 groupsize = 32;
229                 name++;
230         }
231
232         pin = simple_strtol(name, &eptr, 10);
233         if (!*name || *eptr)
234                 return -1;
235         if (pin < 0 || pin > groupsize || group >= 9)
236                 return -1;
237         return group * 32 + pin;
238 }
239 #endif /* !DM_GPIO */
240
241 /* =========== DM code, used by U-Boot proper. ============ */
242
243 #if CONFIG_IS_ENABLED(DM_GPIO)
244 /* TODO([email protected]): Remove this function and use device tree */
245 int sunxi_name_to_gpio(const char *name)
246 {
247         unsigned int gpio;
248         int ret;
249 #if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO
250         char lookup[8];
251
252         if (strcasecmp(name, "AXP0-VBUS-ENABLE") == 0) {
253                 sprintf(lookup, SUNXI_GPIO_AXP0_PREFIX "%d",
254                         SUNXI_GPIO_AXP0_VBUS_ENABLE);
255                 name = lookup;
256         }
257 #endif
258         ret = gpio_lookup_name(name, NULL, NULL, &gpio);
259
260         return ret ? ret : gpio;
261 }
262
263 static int sunxi_gpio_get_value(struct udevice *dev, unsigned offset)
264 {
265         struct sunxi_gpio_plat *plat = dev_get_plat(dev);
266
267         return sunxi_gpio_get_value_bank(plat->regs, offset);
268 }
269
270 static int sunxi_gpio_get_function(struct udevice *dev, unsigned offset)
271 {
272         struct sunxi_gpio_plat *plat = dev_get_plat(dev);
273         int func;
274
275         func = sunxi_gpio_get_cfgbank(plat->regs, offset);
276         if (func == SUNXI_GPIO_OUTPUT)
277                 return GPIOF_OUTPUT;
278         else if (func == SUNXI_GPIO_INPUT)
279                 return GPIOF_INPUT;
280         else
281                 return GPIOF_FUNC;
282 }
283
284 static int sunxi_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
285                             struct ofnode_phandle_args *args)
286 {
287         int ret;
288
289         ret = device_get_child(dev, args->args[0], &desc->dev);
290         if (ret)
291                 return ret;
292         desc->offset = args->args[1];
293         desc->flags = gpio_flags_xlate(args->args[2]);
294
295         return 0;
296 }
297
298 static int sunxi_gpio_set_flags(struct udevice *dev, unsigned int offset,
299                                 ulong flags)
300 {
301         struct sunxi_gpio_plat *plat = dev_get_plat(dev);
302
303         if (flags & GPIOD_IS_OUT) {
304                 u32 value = !!(flags & GPIOD_IS_OUT_ACTIVE);
305
306                 sunxi_gpio_set_value_bank(plat->regs, offset, value);
307                 sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_OUTPUT);
308         } else if (flags & GPIOD_IS_IN) {
309                 u32 pull = 0;
310
311                 if (flags & GPIOD_PULL_UP)
312                         pull = 1;
313                 else if (flags & GPIOD_PULL_DOWN)
314                         pull = 2;
315                 sunxi_gpio_set_pull_bank(plat->regs, offset, pull);
316                 sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_INPUT);
317         }
318
319         return 0;
320 }
321
322 static const struct dm_gpio_ops gpio_sunxi_ops = {
323         .get_value              = sunxi_gpio_get_value,
324         .get_function           = sunxi_gpio_get_function,
325         .xlate                  = sunxi_gpio_xlate,
326         .set_flags              = sunxi_gpio_set_flags,
327 };
328
329 static int gpio_sunxi_probe(struct udevice *dev)
330 {
331         struct sunxi_gpio_plat *plat = dev_get_plat(dev);
332         struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
333
334         /* Tell the uclass how many GPIOs we have */
335         if (plat) {
336                 uc_priv->gpio_count = SUNXI_GPIOS_PER_BANK;
337                 uc_priv->bank_name = plat->bank_name;
338         }
339
340         return 0;
341 }
342
343 U_BOOT_DRIVER(gpio_sunxi) = {
344         .name   = "gpio_sunxi",
345         .id     = UCLASS_GPIO,
346         .probe  = gpio_sunxi_probe,
347         .ops    = &gpio_sunxi_ops,
348 };
349 #endif /* DM_GPIO */
This page took 0.048612 seconds and 4 git commands to generate.