Merge branch 'buildman' of git://git.denx.de/u-boot-x86
[oweals/u-boot.git] / drivers / gpio / sunxi_gpio.c
1 /*
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>
14 #include <dm.h>
15 #include <errno.h>
16 #include <fdtdec.h>
17 #include <malloc.h>
18 #include <asm/io.h>
19 #include <asm/gpio.h>
20 #include <dm/device-internal.h>
21 #ifdef CONFIG_AXP209_POWER
22 #include <axp209.h>
23 #endif
24 #ifdef CONFIG_AXP221_POWER
25 #include <axp221.h>
26 #endif
27
28 DECLARE_GLOBAL_DATA_PTR;
29
30 #define SUNXI_GPIOS_PER_BANK    SUNXI_GPIO_A_NR
31
32 struct 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
39 static 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
57 static 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
70 int gpio_request(unsigned gpio, const char *label)
71 {
72         return 0;
73 }
74
75 int gpio_free(unsigned gpio)
76 {
77         return 0;
78 }
79
80 int gpio_direction_input(unsigned gpio)
81 {
82 #ifdef AXP_GPIO
83         if (gpio >= SUNXI_GPIO_AXP0_START)
84                 return axp_gpio_direction_input(gpio - SUNXI_GPIO_AXP0_START);
85 #endif
86         sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_INPUT);
87
88         return 0;
89 }
90
91 int gpio_direction_output(unsigned gpio, int value)
92 {
93 #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
98         sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_OUTPUT);
99
100         return sunxi_gpio_output(gpio, value);
101 }
102
103 int gpio_get_value(unsigned gpio)
104 {
105 #ifdef AXP_GPIO
106         if (gpio >= SUNXI_GPIO_AXP0_START)
107                 return axp_gpio_get_value(gpio - SUNXI_GPIO_AXP0_START);
108 #endif
109         return sunxi_gpio_input(gpio);
110 }
111
112 int gpio_set_value(unsigned gpio, int value)
113 {
114 #ifdef AXP_GPIO
115         if (gpio >= SUNXI_GPIO_AXP0_START)
116                 return axp_gpio_set_value(gpio - SUNXI_GPIO_AXP0_START, value);
117 #endif
118         return sunxi_gpio_output(gpio, value);
119 }
120
121 int sunxi_name_to_gpio_bank(const char *name)
122 {
123         int group = 0;
124
125         if (*name == 'P' || *name == 'p')
126                 name++;
127         if (*name >= 'A') {
128                 group = *name - (*name > 'a' ? 'a' : 'A');
129                 return group;
130         }
131
132         return -1;
133 }
134
135 int sunxi_name_to_gpio(const char *name)
136 {
137         int group = 0;
138         int groupsize = 9 * 32;
139         long pin;
140         char *eptr;
141
142 #ifdef AXP_GPIO
143         if (strncasecmp(name, "AXP0-", 5) == 0) {
144                 name += 5;
145                 if (strcmp(name, "VBUS-DETECT") == 0)
146                         return SUNXI_GPIO_AXP0_START +
147                                 SUNXI_GPIO_AXP0_VBUS_DETECT;
148                 if (strcmp(name, "VBUS-ENABLE") == 0)
149                         return SUNXI_GPIO_AXP0_START +
150                                 SUNXI_GPIO_AXP0_VBUS_ENABLE;
151                 pin = simple_strtol(name, &eptr, 10);
152                 if (!*name || *eptr)
153                         return -1;
154                 return SUNXI_GPIO_AXP0_START + pin;
155         }
156 #endif
157         if (*name == 'P' || *name == 'p')
158                 name++;
159         if (*name >= 'A') {
160                 group = *name - (*name > 'a' ? 'a' : 'A');
161                 groupsize = 32;
162                 name++;
163         }
164
165         pin = simple_strtol(name, &eptr, 10);
166         if (!*name || *eptr)
167                 return -1;
168         if (pin < 0 || pin > groupsize || group >= 9)
169                 return -1;
170         return group * 32 + pin;
171 }
172 #endif
173
174 #ifdef CONFIG_DM_GPIO
175 static int sunxi_gpio_direction_input(struct udevice *dev, unsigned offset)
176 {
177         struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
178
179         sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_INPUT);
180
181         return 0;
182 }
183
184 static int sunxi_gpio_direction_output(struct udevice *dev, unsigned offset,
185                                        int value)
186 {
187         struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
188         u32 num = GPIO_NUM(offset);
189
190         sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_OUTPUT);
191         clrsetbits_le32(&plat->regs->dat, 1 << num, value ? (1 << num) : 0);
192
193         return 0;
194 }
195
196 static int sunxi_gpio_get_value(struct udevice *dev, unsigned offset)
197 {
198         struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
199         u32 num = GPIO_NUM(offset);
200         unsigned dat;
201
202         dat = readl(&plat->regs->dat);
203         dat >>= num;
204
205         return dat & 0x1;
206 }
207
208 static int sunxi_gpio_set_value(struct udevice *dev, unsigned offset,
209                                 int value)
210 {
211         struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
212         u32 num = GPIO_NUM(offset);
213
214         clrsetbits_le32(&plat->regs->dat, 1 << num, value ? (1 << num) : 0);
215         return 0;
216 }
217
218 static int sunxi_gpio_get_function(struct udevice *dev, unsigned offset)
219 {
220         struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
221         int func;
222
223         func = sunxi_gpio_get_cfgbank(plat->regs, offset);
224         if (func == SUNXI_GPIO_OUTPUT)
225                 return GPIOF_OUTPUT;
226         else if (func == SUNXI_GPIO_INPUT)
227                 return GPIOF_INPUT;
228         else
229                 return GPIOF_FUNC;
230 }
231
232 static const struct dm_gpio_ops gpio_sunxi_ops = {
233         .direction_input        = sunxi_gpio_direction_input,
234         .direction_output       = sunxi_gpio_direction_output,
235         .get_value              = sunxi_gpio_get_value,
236         .set_value              = sunxi_gpio_set_value,
237         .get_function           = sunxi_gpio_get_function,
238 };
239
240 /**
241  * Returns the name of a GPIO bank
242  *
243  * GPIO banks are named A, B, C, ...
244  *
245  * @bank:       Bank number (0, 1..n-1)
246  * @return allocated string containing the name
247  */
248 static char *gpio_bank_name(int bank)
249 {
250         char *name;
251
252         name = malloc(2);
253         if (name) {
254                 name[0] = 'A' + bank;
255                 name[1] = '\0';
256         }
257
258         return name;
259 }
260
261 static int gpio_sunxi_probe(struct udevice *dev)
262 {
263         struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
264         struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
265
266         /* Tell the uclass how many GPIOs we have */
267         if (plat) {
268                 uc_priv->gpio_count = plat->gpio_count;
269                 uc_priv->bank_name = plat->bank_name;
270         }
271
272         return 0;
273 }
274 /**
275  * We have a top-level GPIO device with no actual GPIOs. It has a child
276  * device for each Sunxi bank.
277  */
278 static int gpio_sunxi_bind(struct udevice *parent)
279 {
280         struct sunxi_gpio_platdata *plat = parent->platdata;
281         struct sunxi_gpio_reg *ctlr;
282         int bank;
283         int ret;
284
285         /* If this is a child device, there is nothing to do here */
286         if (plat)
287                 return 0;
288
289         ctlr = (struct sunxi_gpio_reg *)fdtdec_get_addr(gd->fdt_blob,
290                                                    parent->of_offset, "reg");
291         for (bank = 0; bank < SUNXI_GPIO_BANKS; bank++) {
292                 struct sunxi_gpio_platdata *plat;
293                 struct udevice *dev;
294
295                 plat = calloc(1, sizeof(*plat));
296                 if (!plat)
297                         return -ENOMEM;
298                 plat->regs = &ctlr->gpio_bank[bank];
299                 plat->bank_name = gpio_bank_name(bank);
300                 plat->gpio_count = SUNXI_GPIOS_PER_BANK;
301
302                 ret = device_bind(parent, parent->driver,
303                                         plat->bank_name, plat, -1, &dev);
304                 if (ret)
305                         return ret;
306                 dev->of_offset = parent->of_offset;
307         }
308
309         return 0;
310 }
311
312 static const struct udevice_id sunxi_gpio_ids[] = {
313         { .compatible = "allwinner,sun7i-a20-pinctrl" },
314         { }
315 };
316
317 U_BOOT_DRIVER(gpio_sunxi) = {
318         .name   = "gpio_sunxi",
319         .id     = UCLASS_GPIO,
320         .ops    = &gpio_sunxi_ops,
321         .of_match = sunxi_gpio_ids,
322         .bind   = gpio_sunxi_bind,
323         .probe  = gpio_sunxi_probe,
324 };
325 #endif