blob: 29301c43d092a9e70de35c817cc41bab127f4877 [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
Paul Kocialkowski8deacca2015-03-22 18:12:23 +0100121int 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
Ian Campbellabce2c62014-06-05 19:00:15 +0100135int sunxi_name_to_gpio(const char *name)
136{
137 int group = 0;
138 int groupsize = 9 * 32;
139 long pin;
140 char *eptr;
Hans de Goede6c727e02014-12-24 19:34:38 +0100141
142#ifdef AXP_GPIO
143 if (strncasecmp(name, "AXP0-", 5) == 0) {
144 name += 5;
Paul Kocialkowskif7c7ab62015-03-22 18:07:09 +0100145 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;
Hans de Goede6c727e02014-12-24 19:34:38 +0100151 pin = simple_strtol(name, &eptr, 10);
152 if (!*name || *eptr)
153 return -1;
154 return SUNXI_GPIO_AXP0_START + pin;
155 }
156#endif
Ian Campbellabce2c62014-06-05 19:00:15 +0100157 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}
Simon Glass7aa97482014-10-30 20:25:49 -0600172#endif
173
174#ifdef CONFIG_DM_GPIO
175static 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
184static 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
196static 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
208static 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
218static 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
232static 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 */
248static char *gpio_bank_name(int bank)
249{
250 char *name;
251
Simon Glass07ce60f2015-04-18 11:33:44 -0600252 name = malloc(3);
Simon Glass7aa97482014-10-30 20:25:49 -0600253 if (name) {
Simon Glass07ce60f2015-04-18 11:33:44 -0600254 name[0] = 'P';
255 name[1] = 'A' + bank;
256 name[2] = '\0';
Simon Glass7aa97482014-10-30 20:25:49 -0600257 }
258
259 return name;
260}
261
262static int gpio_sunxi_probe(struct udevice *dev)
263{
264 struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
Simon Glasse564f052015-03-05 12:25:20 -0700265 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
Simon Glass7aa97482014-10-30 20:25:49 -0600266
267 /* Tell the uclass how many GPIOs we have */
268 if (plat) {
269 uc_priv->gpio_count = plat->gpio_count;
270 uc_priv->bank_name = plat->bank_name;
271 }
272
273 return 0;
274}
275/**
276 * We have a top-level GPIO device with no actual GPIOs. It has a child
277 * device for each Sunxi bank.
278 */
279static int gpio_sunxi_bind(struct udevice *parent)
280{
281 struct sunxi_gpio_platdata *plat = parent->platdata;
282 struct sunxi_gpio_reg *ctlr;
283 int bank;
284 int ret;
285
286 /* If this is a child device, there is nothing to do here */
287 if (plat)
288 return 0;
289
290 ctlr = (struct sunxi_gpio_reg *)fdtdec_get_addr(gd->fdt_blob,
291 parent->of_offset, "reg");
292 for (bank = 0; bank < SUNXI_GPIO_BANKS; bank++) {
293 struct sunxi_gpio_platdata *plat;
294 struct udevice *dev;
295
296 plat = calloc(1, sizeof(*plat));
297 if (!plat)
298 return -ENOMEM;
299 plat->regs = &ctlr->gpio_bank[bank];
300 plat->bank_name = gpio_bank_name(bank);
301 plat->gpio_count = SUNXI_GPIOS_PER_BANK;
302
303 ret = device_bind(parent, parent->driver,
304 plat->bank_name, plat, -1, &dev);
305 if (ret)
306 return ret;
307 dev->of_offset = parent->of_offset;
308 }
309
310 return 0;
311}
312
313static const struct udevice_id sunxi_gpio_ids[] = {
314 { .compatible = "allwinner,sun7i-a20-pinctrl" },
315 { }
316};
317
318U_BOOT_DRIVER(gpio_sunxi) = {
319 .name = "gpio_sunxi",
320 .id = UCLASS_GPIO,
321 .ops = &gpio_sunxi_ops,
322 .of_match = sunxi_gpio_ids,
323 .bind = gpio_sunxi_bind,
324 .probe = gpio_sunxi_probe,
325};
326#endif