blob: 670af0c383c5d981043873be9a9348e5613c7e6f [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
160#ifdef CONFIG_DM_GPIO
161static int sunxi_gpio_direction_input(struct udevice *dev, unsigned offset)
162{
163 struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
164
165 sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_INPUT);
166
167 return 0;
168}
169
170static int sunxi_gpio_direction_output(struct udevice *dev, unsigned offset,
171 int value)
172{
173 struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
174 u32 num = GPIO_NUM(offset);
175
176 sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_OUTPUT);
177 clrsetbits_le32(&plat->regs->dat, 1 << num, value ? (1 << num) : 0);
178
179 return 0;
180}
181
182static int sunxi_gpio_get_value(struct udevice *dev, unsigned offset)
183{
184 struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
185 u32 num = GPIO_NUM(offset);
186 unsigned dat;
187
188 dat = readl(&plat->regs->dat);
189 dat >>= num;
190
191 return dat & 0x1;
192}
193
194static int sunxi_gpio_set_value(struct udevice *dev, unsigned offset,
195 int value)
196{
197 struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
198 u32 num = GPIO_NUM(offset);
199
200 clrsetbits_le32(&plat->regs->dat, 1 << num, value ? (1 << num) : 0);
201 return 0;
202}
203
204static int sunxi_gpio_get_function(struct udevice *dev, unsigned offset)
205{
206 struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
207 int func;
208
209 func = sunxi_gpio_get_cfgbank(plat->regs, offset);
210 if (func == SUNXI_GPIO_OUTPUT)
211 return GPIOF_OUTPUT;
212 else if (func == SUNXI_GPIO_INPUT)
213 return GPIOF_INPUT;
214 else
215 return GPIOF_FUNC;
216}
217
218static const struct dm_gpio_ops gpio_sunxi_ops = {
219 .direction_input = sunxi_gpio_direction_input,
220 .direction_output = sunxi_gpio_direction_output,
221 .get_value = sunxi_gpio_get_value,
222 .set_value = sunxi_gpio_set_value,
223 .get_function = sunxi_gpio_get_function,
224};
225
226/**
227 * Returns the name of a GPIO bank
228 *
229 * GPIO banks are named A, B, C, ...
230 *
231 * @bank: Bank number (0, 1..n-1)
232 * @return allocated string containing the name
233 */
234static char *gpio_bank_name(int bank)
235{
236 char *name;
237
238 name = malloc(2);
239 if (name) {
240 name[0] = 'A' + bank;
241 name[1] = '\0';
242 }
243
244 return name;
245}
246
247static int gpio_sunxi_probe(struct udevice *dev)
248{
249 struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
250 struct gpio_dev_priv *uc_priv = dev->uclass_priv;
251
252 /* Tell the uclass how many GPIOs we have */
253 if (plat) {
254 uc_priv->gpio_count = plat->gpio_count;
255 uc_priv->bank_name = plat->bank_name;
256 }
257
258 return 0;
259}
260/**
261 * We have a top-level GPIO device with no actual GPIOs. It has a child
262 * device for each Sunxi bank.
263 */
264static int gpio_sunxi_bind(struct udevice *parent)
265{
266 struct sunxi_gpio_platdata *plat = parent->platdata;
267 struct sunxi_gpio_reg *ctlr;
268 int bank;
269 int ret;
270
271 /* If this is a child device, there is nothing to do here */
272 if (plat)
273 return 0;
274
275 ctlr = (struct sunxi_gpio_reg *)fdtdec_get_addr(gd->fdt_blob,
276 parent->of_offset, "reg");
277 for (bank = 0; bank < SUNXI_GPIO_BANKS; bank++) {
278 struct sunxi_gpio_platdata *plat;
279 struct udevice *dev;
280
281 plat = calloc(1, sizeof(*plat));
282 if (!plat)
283 return -ENOMEM;
284 plat->regs = &ctlr->gpio_bank[bank];
285 plat->bank_name = gpio_bank_name(bank);
286 plat->gpio_count = SUNXI_GPIOS_PER_BANK;
287
288 ret = device_bind(parent, parent->driver,
289 plat->bank_name, plat, -1, &dev);
290 if (ret)
291 return ret;
292 dev->of_offset = parent->of_offset;
293 }
294
295 return 0;
296}
297
298static const struct udevice_id sunxi_gpio_ids[] = {
299 { .compatible = "allwinner,sun7i-a20-pinctrl" },
300 { }
301};
302
303U_BOOT_DRIVER(gpio_sunxi) = {
304 .name = "gpio_sunxi",
305 .id = UCLASS_GPIO,
306 .ops = &gpio_sunxi_ops,
307 .of_match = sunxi_gpio_ids,
308 .bind = gpio_sunxi_bind,
309 .probe = gpio_sunxi_probe,
310};
311#endif