xref: /openbmc/u-boot/drivers/gpio/sunxi_gpio.c (revision ed09a554)
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
326