blob: 91af1a54ec50afa0953cf498befe70df019ec3c2 [file] [log] [blame]
Ian Campbellabce2c62014-06-05 19:00:15 +01001/*
2 * (C) Copyright 2012 Henrik Nordstrom <henrik@henriknordstrom.net>
3 *
4 * Based on earlier arch/arm/cpu/armv7/sunxi/gpio.c:
5 *
6 * (C) Copyright 2007-2011
7 * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
8 * Tom Cubie <tangliang@allwinnertech.com>
9 *
10 * SPDX-License-Identifier: GPL-2.0+
11 */
12
13#include <common.h>
Simon Glass7aa97482014-10-30 20:25:49 -060014#include <dm.h>
15#include <errno.h>
16#include <fdtdec.h>
17#include <malloc.h>
Ian Campbellabce2c62014-06-05 19:00:15 +010018#include <asm/io.h>
19#include <asm/gpio.h>
Simon Glass7aa97482014-10-30 20:25:49 -060020#include <dm/device-internal.h>
Hans de Goede6c727e02014-12-24 19:34:38 +010021#ifdef CONFIG_AXP209_POWER
22#include <axp209.h>
23#endif
Paul Kocialkowskif7c7ab62015-03-22 18:07:09 +010024#ifdef CONFIG_AXP221_POWER
25#include <axp221.h>
26#endif
Ian Campbellabce2c62014-06-05 19:00:15 +010027
Simon Glass7aa97482014-10-30 20:25:49 -060028DECLARE_GLOBAL_DATA_PTR;
29
30#define SUNXI_GPIOS_PER_BANK SUNXI_GPIO_A_NR
31
32struct sunxi_gpio_platdata {
33 struct sunxi_gpio *regs;
34 const char *bank_name; /* Name of bank, e.g. "B" */
35 int gpio_count;
36};
37
38#ifndef CONFIG_DM_GPIO
Ian Campbellabce2c62014-06-05 19:00:15 +010039static int sunxi_gpio_output(u32 pin, u32 val)
40{
41 u32 dat;
42 u32 bank = GPIO_BANK(pin);
43 u32 num = GPIO_NUM(pin);
44 struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
45
46 dat = readl(&pio->dat);
47 if (val)
48 dat |= 0x1 << num;
49 else
50 dat &= ~(0x1 << num);
51
52 writel(dat, &pio->dat);
53
54 return 0;
55}
56
57static int sunxi_gpio_input(u32 pin)
58{
59 u32 dat;
60 u32 bank = GPIO_BANK(pin);
61 u32 num = GPIO_NUM(pin);
62 struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
63
64 dat = readl(&pio->dat);
65 dat >>= num;
66
67 return dat & 0x1;
68}
69
70int gpio_request(unsigned gpio, const char *label)
71{
72 return 0;
73}
74
75int gpio_free(unsigned gpio)
76{
77 return 0;
78}
79
80int gpio_direction_input(unsigned gpio)
81{
Hans de Goede6c727e02014-12-24 19:34:38 +010082#ifdef AXP_GPIO
83 if (gpio >= SUNXI_GPIO_AXP0_START)
84 return axp_gpio_direction_input(gpio - SUNXI_GPIO_AXP0_START);
85#endif
Ian Campbellabce2c62014-06-05 19:00:15 +010086 sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_INPUT);
87
Axel Linb0c4ae12014-12-20 11:41:25 +080088 return 0;
Ian Campbellabce2c62014-06-05 19:00:15 +010089}
90
91int gpio_direction_output(unsigned gpio, int value)
92{
Hans de Goede6c727e02014-12-24 19:34:38 +010093#ifdef AXP_GPIO
94 if (gpio >= SUNXI_GPIO_AXP0_START)
95 return axp_gpio_direction_output(gpio - SUNXI_GPIO_AXP0_START,
96 value);
97#endif
Ian Campbellabce2c62014-06-05 19:00:15 +010098 sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_OUTPUT);
99
100 return sunxi_gpio_output(gpio, value);
101}
102
103int gpio_get_value(unsigned gpio)
104{
Hans de Goede6c727e02014-12-24 19:34:38 +0100105#ifdef AXP_GPIO
106 if (gpio >= SUNXI_GPIO_AXP0_START)
107 return axp_gpio_get_value(gpio - SUNXI_GPIO_AXP0_START);
108#endif
Ian Campbellabce2c62014-06-05 19:00:15 +0100109 return sunxi_gpio_input(gpio);
110}
111
112int gpio_set_value(unsigned gpio, int value)
113{
Hans de Goede6c727e02014-12-24 19:34:38 +0100114#ifdef AXP_GPIO
115 if (gpio >= SUNXI_GPIO_AXP0_START)
116 return axp_gpio_set_value(gpio - SUNXI_GPIO_AXP0_START, value);
117#endif
Ian Campbellabce2c62014-06-05 19:00:15 +0100118 return sunxi_gpio_output(gpio, value);
119}
120
121int sunxi_name_to_gpio(const char *name)
122{
123 int group = 0;
124 int groupsize = 9 * 32;
125 long pin;
126 char *eptr;
Hans de Goede6c727e02014-12-24 19:34:38 +0100127
128#ifdef AXP_GPIO
129 if (strncasecmp(name, "AXP0-", 5) == 0) {
130 name += 5;
Paul Kocialkowskif7c7ab62015-03-22 18:07:09 +0100131 if (strcmp(name, "VBUS-DETECT") == 0)
132 return SUNXI_GPIO_AXP0_START +
133 SUNXI_GPIO_AXP0_VBUS_DETECT;
134 if (strcmp(name, "VBUS-ENABLE") == 0)
135 return SUNXI_GPIO_AXP0_START +
136 SUNXI_GPIO_AXP0_VBUS_ENABLE;
Hans de Goede6c727e02014-12-24 19:34:38 +0100137 pin = simple_strtol(name, &eptr, 10);
138 if (!*name || *eptr)
139 return -1;
140 return SUNXI_GPIO_AXP0_START + pin;
141 }
142#endif
Ian Campbellabce2c62014-06-05 19:00:15 +0100143 if (*name == 'P' || *name == 'p')
144 name++;
145 if (*name >= 'A') {
146 group = *name - (*name > 'a' ? 'a' : 'A');
147 groupsize = 32;
148 name++;
149 }
150
151 pin = simple_strtol(name, &eptr, 10);
152 if (!*name || *eptr)
153 return -1;
154 if (pin < 0 || pin > groupsize || group >= 9)
155 return -1;
156 return group * 32 + pin;
157}
Simon Glass7aa97482014-10-30 20:25:49 -0600158#endif
159
Hans de Goede746c0872015-04-22 17:59:01 +0200160int sunxi_name_to_gpio_bank(const char *name)
161{
162 int group = 0;
163
164 if (*name == 'P' || *name == 'p')
165 name++;
166 if (*name >= 'A') {
167 group = *name - (*name > 'a' ? 'a' : 'A');
168 return group;
169 }
170
171 return -1;
172}
173
Simon Glass7aa97482014-10-30 20:25:49 -0600174#ifdef CONFIG_DM_GPIO
Simon Glassa5ab8832015-04-18 11:33:43 -0600175/* TODO(sjg@chromium.org): Remove this function and use device tree */
176int sunxi_name_to_gpio(const char *name)
177{
178 unsigned int gpio;
179 int ret;
180
181 ret = gpio_lookup_name(name, NULL, NULL, &gpio);
182
183 return ret ? ret : gpio;
184}
185
Simon Glass7aa97482014-10-30 20:25:49 -0600186static int sunxi_gpio_direction_input(struct udevice *dev, unsigned offset)
187{
188 struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
189
190 sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_INPUT);
191
192 return 0;
193}
194
195static int sunxi_gpio_direction_output(struct udevice *dev, unsigned offset,
196 int value)
197{
198 struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
199 u32 num = GPIO_NUM(offset);
200
201 sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_OUTPUT);
202 clrsetbits_le32(&plat->regs->dat, 1 << num, value ? (1 << num) : 0);
203
204 return 0;
205}
206
207static int sunxi_gpio_get_value(struct udevice *dev, unsigned offset)
208{
209 struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
210 u32 num = GPIO_NUM(offset);
211 unsigned dat;
212
213 dat = readl(&plat->regs->dat);
214 dat >>= num;
215
216 return dat & 0x1;
217}
218
219static int sunxi_gpio_set_value(struct udevice *dev, unsigned offset,
220 int value)
221{
222 struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
223 u32 num = GPIO_NUM(offset);
224
225 clrsetbits_le32(&plat->regs->dat, 1 << num, value ? (1 << num) : 0);
226 return 0;
227}
228
229static int sunxi_gpio_get_function(struct udevice *dev, unsigned offset)
230{
231 struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
232 int func;
233
234 func = sunxi_gpio_get_cfgbank(plat->regs, offset);
235 if (func == SUNXI_GPIO_OUTPUT)
236 return GPIOF_OUTPUT;
237 else if (func == SUNXI_GPIO_INPUT)
238 return GPIOF_INPUT;
239 else
240 return GPIOF_FUNC;
241}
242
243static const struct dm_gpio_ops gpio_sunxi_ops = {
244 .direction_input = sunxi_gpio_direction_input,
245 .direction_output = sunxi_gpio_direction_output,
246 .get_value = sunxi_gpio_get_value,
247 .set_value = sunxi_gpio_set_value,
248 .get_function = sunxi_gpio_get_function,
249};
250
251/**
252 * Returns the name of a GPIO bank
253 *
254 * GPIO banks are named A, B, C, ...
255 *
256 * @bank: Bank number (0, 1..n-1)
257 * @return allocated string containing the name
258 */
259static char *gpio_bank_name(int bank)
260{
261 char *name;
262
Simon Glass07ce60f2015-04-18 11:33:44 -0600263 name = malloc(3);
Simon Glass7aa97482014-10-30 20:25:49 -0600264 if (name) {
Simon Glass07ce60f2015-04-18 11:33:44 -0600265 name[0] = 'P';
266 name[1] = 'A' + bank;
267 name[2] = '\0';
Simon Glass7aa97482014-10-30 20:25:49 -0600268 }
269
270 return name;
271}
272
273static int gpio_sunxi_probe(struct udevice *dev)
274{
275 struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
Simon Glasse564f052015-03-05 12:25:20 -0700276 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
Simon Glass7aa97482014-10-30 20:25:49 -0600277
278 /* Tell the uclass how many GPIOs we have */
279 if (plat) {
280 uc_priv->gpio_count = plat->gpio_count;
281 uc_priv->bank_name = plat->bank_name;
282 }
283
284 return 0;
285}
286/**
287 * We have a top-level GPIO device with no actual GPIOs. It has a child
288 * device for each Sunxi bank.
289 */
290static int gpio_sunxi_bind(struct udevice *parent)
291{
292 struct sunxi_gpio_platdata *plat = parent->platdata;
293 struct sunxi_gpio_reg *ctlr;
294 int bank;
295 int ret;
296
297 /* If this is a child device, there is nothing to do here */
298 if (plat)
299 return 0;
300
301 ctlr = (struct sunxi_gpio_reg *)fdtdec_get_addr(gd->fdt_blob,
302 parent->of_offset, "reg");
303 for (bank = 0; bank < SUNXI_GPIO_BANKS; bank++) {
304 struct sunxi_gpio_platdata *plat;
305 struct udevice *dev;
306
307 plat = calloc(1, sizeof(*plat));
308 if (!plat)
309 return -ENOMEM;
310 plat->regs = &ctlr->gpio_bank[bank];
311 plat->bank_name = gpio_bank_name(bank);
312 plat->gpio_count = SUNXI_GPIOS_PER_BANK;
313
314 ret = device_bind(parent, parent->driver,
315 plat->bank_name, plat, -1, &dev);
316 if (ret)
317 return ret;
318 dev->of_offset = parent->of_offset;
319 }
320
321 return 0;
322}
323
324static const struct udevice_id sunxi_gpio_ids[] = {
Hans de Goede11d52a92015-04-22 11:29:38 +0200325 { .compatible = "allwinner,sun4i-a10-pinctrl" },
326 { .compatible = "allwinner,sun5i-a10s-pinctrl" },
327 { .compatible = "allwinner,sun5i-a13-pinctrl" },
328 { .compatible = "allwinner,sun6i-a31-pinctrl" },
329 { .compatible = "allwinner,sun6i-a31s-pinctrl" },
Simon Glass7aa97482014-10-30 20:25:49 -0600330 { .compatible = "allwinner,sun7i-a20-pinctrl" },
Hans de Goede11d52a92015-04-22 11:29:38 +0200331 { .compatible = "allwinner,sun8i-a23-pinctrl" },
332 { .compatible = "allwinner,sun9i-a80-pinctrl" },
Simon Glass7aa97482014-10-30 20:25:49 -0600333 { }
334};
335
336U_BOOT_DRIVER(gpio_sunxi) = {
337 .name = "gpio_sunxi",
338 .id = UCLASS_GPIO,
339 .ops = &gpio_sunxi_ops,
340 .of_match = sunxi_gpio_ids,
341 .bind = gpio_sunxi_bind,
342 .probe = gpio_sunxi_probe,
343};
344#endif