xref: /openbmc/u-boot/drivers/gpio/sunxi_gpio.c (revision 4bf225aa)
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/arch/gpio.h>
19 #include <asm/io.h>
20 #include <asm/gpio.h>
21 #include <dm/device-internal.h>
22 #include <dt-bindings/gpio/gpio.h>
23 
24 #define SUNXI_GPIOS_PER_BANK	SUNXI_GPIO_A_NR
25 
26 struct sunxi_gpio_platdata {
27 	struct sunxi_gpio *regs;
28 	const char *bank_name;	/* Name of bank, e.g. "B" */
29 	int gpio_count;
30 };
31 
32 #ifndef CONFIG_DM_GPIO
33 static int sunxi_gpio_output(u32 pin, u32 val)
34 {
35 	u32 dat;
36 	u32 bank = GPIO_BANK(pin);
37 	u32 num = GPIO_NUM(pin);
38 	struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
39 
40 	dat = readl(&pio->dat);
41 	if (val)
42 		dat |= 0x1 << num;
43 	else
44 		dat &= ~(0x1 << num);
45 
46 	writel(dat, &pio->dat);
47 
48 	return 0;
49 }
50 
51 static int sunxi_gpio_input(u32 pin)
52 {
53 	u32 dat;
54 	u32 bank = GPIO_BANK(pin);
55 	u32 num = GPIO_NUM(pin);
56 	struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
57 
58 	dat = readl(&pio->dat);
59 	dat >>= num;
60 
61 	return dat & 0x1;
62 }
63 
64 int gpio_request(unsigned gpio, const char *label)
65 {
66 	return 0;
67 }
68 
69 int gpio_free(unsigned gpio)
70 {
71 	return 0;
72 }
73 
74 int gpio_direction_input(unsigned gpio)
75 {
76 	sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_INPUT);
77 
78 	return 0;
79 }
80 
81 int gpio_direction_output(unsigned gpio, int value)
82 {
83 	sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_OUTPUT);
84 
85 	return sunxi_gpio_output(gpio, value);
86 }
87 
88 int gpio_get_value(unsigned gpio)
89 {
90 	return sunxi_gpio_input(gpio);
91 }
92 
93 int gpio_set_value(unsigned gpio, int value)
94 {
95 	return sunxi_gpio_output(gpio, value);
96 }
97 
98 int sunxi_name_to_gpio(const char *name)
99 {
100 	int group = 0;
101 	int groupsize = 9 * 32;
102 	long pin;
103 	char *eptr;
104 
105 	if (*name == 'P' || *name == 'p')
106 		name++;
107 	if (*name >= 'A') {
108 		group = *name - (*name > 'a' ? 'a' : 'A');
109 		groupsize = 32;
110 		name++;
111 	}
112 
113 	pin = simple_strtol(name, &eptr, 10);
114 	if (!*name || *eptr)
115 		return -1;
116 	if (pin < 0 || pin > groupsize || group >= 9)
117 		return -1;
118 	return group * 32 + pin;
119 }
120 #endif
121 
122 int sunxi_name_to_gpio_bank(const char *name)
123 {
124 	int group = 0;
125 
126 	if (*name == 'P' || *name == 'p')
127 		name++;
128 	if (*name >= 'A') {
129 		group = *name - (*name > 'a' ? 'a' : 'A');
130 		return group;
131 	}
132 
133 	return -1;
134 }
135 
136 #ifdef CONFIG_DM_GPIO
137 /* TODO(sjg@chromium.org): Remove this function and use device tree */
138 int sunxi_name_to_gpio(const char *name)
139 {
140 	unsigned int gpio;
141 	int ret;
142 #if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO
143 	char lookup[8];
144 
145 	if (strcasecmp(name, "AXP0-VBUS-DETECT") == 0) {
146 		sprintf(lookup, SUNXI_GPIO_AXP0_PREFIX "%d",
147 			SUNXI_GPIO_AXP0_VBUS_DETECT);
148 		name = lookup;
149 	} else if (strcasecmp(name, "AXP0-VBUS-ENABLE") == 0) {
150 		sprintf(lookup, SUNXI_GPIO_AXP0_PREFIX "%d",
151 			SUNXI_GPIO_AXP0_VBUS_ENABLE);
152 		name = lookup;
153 	}
154 #endif
155 	ret = gpio_lookup_name(name, NULL, NULL, &gpio);
156 
157 	return ret ? ret : gpio;
158 }
159 
160 static int sunxi_gpio_direction_input(struct udevice *dev, unsigned offset)
161 {
162 	struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
163 
164 	sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_INPUT);
165 
166 	return 0;
167 }
168 
169 static int sunxi_gpio_direction_output(struct udevice *dev, unsigned offset,
170 				       int value)
171 {
172 	struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
173 	u32 num = GPIO_NUM(offset);
174 
175 	sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_OUTPUT);
176 	clrsetbits_le32(&plat->regs->dat, 1 << num, value ? (1 << num) : 0);
177 
178 	return 0;
179 }
180 
181 static int sunxi_gpio_get_value(struct udevice *dev, unsigned offset)
182 {
183 	struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
184 	u32 num = GPIO_NUM(offset);
185 	unsigned dat;
186 
187 	dat = readl(&plat->regs->dat);
188 	dat >>= num;
189 
190 	return dat & 0x1;
191 }
192 
193 static int sunxi_gpio_set_value(struct udevice *dev, unsigned offset,
194 				int value)
195 {
196 	struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
197 	u32 num = GPIO_NUM(offset);
198 
199 	clrsetbits_le32(&plat->regs->dat, 1 << num, value ? (1 << num) : 0);
200 	return 0;
201 }
202 
203 static int sunxi_gpio_get_function(struct udevice *dev, unsigned offset)
204 {
205 	struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
206 	int func;
207 
208 	func = sunxi_gpio_get_cfgbank(plat->regs, offset);
209 	if (func == SUNXI_GPIO_OUTPUT)
210 		return GPIOF_OUTPUT;
211 	else if (func == SUNXI_GPIO_INPUT)
212 		return GPIOF_INPUT;
213 	else
214 		return GPIOF_FUNC;
215 }
216 
217 static int sunxi_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
218 			    struct ofnode_phandle_args *args)
219 {
220 	int ret;
221 
222 	ret = device_get_child(dev, args->args[0], &desc->dev);
223 	if (ret)
224 		return ret;
225 	desc->offset = args->args[1];
226 	desc->flags = args->args[2] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
227 
228 	return 0;
229 }
230 
231 static const struct dm_gpio_ops gpio_sunxi_ops = {
232 	.direction_input	= sunxi_gpio_direction_input,
233 	.direction_output	= sunxi_gpio_direction_output,
234 	.get_value		= sunxi_gpio_get_value,
235 	.set_value		= sunxi_gpio_set_value,
236 	.get_function		= sunxi_gpio_get_function,
237 	.xlate			= sunxi_gpio_xlate,
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(3);
253 	if (name) {
254 		name[0] = 'P';
255 		name[1] = 'A' + bank;
256 		name[2] = '\0';
257 	}
258 
259 	return name;
260 }
261 
262 static int gpio_sunxi_probe(struct udevice *dev)
263 {
264 	struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
265 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
266 
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 struct sunxi_gpio_soc_data {
277 	int start;
278 	int no_banks;
279 };
280 
281 /**
282  * We have a top-level GPIO device with no actual GPIOs. It has a child
283  * device for each Sunxi bank.
284  */
285 static int gpio_sunxi_bind(struct udevice *parent)
286 {
287 	struct sunxi_gpio_soc_data *soc_data =
288 		(struct sunxi_gpio_soc_data *)dev_get_driver_data(parent);
289 	struct sunxi_gpio_platdata *plat = parent->platdata;
290 	struct sunxi_gpio_reg *ctlr;
291 	int bank, ret;
292 
293 	/* If this is a child device, there is nothing to do here */
294 	if (plat)
295 		return 0;
296 
297 	ctlr = (struct sunxi_gpio_reg *)devfdt_get_addr(parent);
298 	for (bank = 0; bank < soc_data->no_banks; bank++) {
299 		struct sunxi_gpio_platdata *plat;
300 		struct udevice *dev;
301 
302 		plat = calloc(1, sizeof(*plat));
303 		if (!plat)
304 			return -ENOMEM;
305 		plat->regs = &ctlr->gpio_bank[bank];
306 		plat->bank_name = gpio_bank_name(soc_data->start + bank);
307 		plat->gpio_count = SUNXI_GPIOS_PER_BANK;
308 
309 		ret = device_bind(parent, parent->driver,
310 					plat->bank_name, plat, -1, &dev);
311 		if (ret)
312 			return ret;
313 		dev_set_of_offset(dev, dev_of_offset(parent));
314 	}
315 
316 	return 0;
317 }
318 
319 static const struct sunxi_gpio_soc_data soc_data_a_all = {
320 	.start = 0,
321 	.no_banks = SUNXI_GPIO_BANKS,
322 };
323 
324 static const struct sunxi_gpio_soc_data soc_data_l_1 = {
325 	.start = 'L' - 'A',
326 	.no_banks = 1,
327 };
328 
329 static const struct sunxi_gpio_soc_data soc_data_l_2 = {
330 	.start = 'L' - 'A',
331 	.no_banks = 2,
332 };
333 
334 static const struct sunxi_gpio_soc_data soc_data_l_3 = {
335 	.start = 'L' - 'A',
336 	.no_banks = 3,
337 };
338 
339 #define ID(_compat_, _soc_data_) \
340 	{ .compatible = _compat_, .data = (ulong)&soc_data_##_soc_data_ }
341 
342 static const struct udevice_id sunxi_gpio_ids[] = {
343 	ID("allwinner,sun4i-a10-pinctrl",	a_all),
344 	ID("allwinner,sun5i-a10s-pinctrl",	a_all),
345 	ID("allwinner,sun5i-a13-pinctrl",	a_all),
346 	ID("allwinner,sun50i-h5-pinctrl",	a_all),
347 	ID("allwinner,sun6i-a31-pinctrl",	a_all),
348 	ID("allwinner,sun6i-a31s-pinctrl",	a_all),
349 	ID("allwinner,sun7i-a20-pinctrl",	a_all),
350 	ID("allwinner,sun8i-a23-pinctrl",	a_all),
351 	ID("allwinner,sun8i-a33-pinctrl",	a_all),
352 	ID("allwinner,sun8i-a83t-pinctrl",	a_all),
353 	ID("allwinner,sun8i-h3-pinctrl",	a_all),
354 	ID("allwinner,sun8i-r40-pinctrl",	a_all),
355 	ID("allwinner,sun8i-v3s-pinctrl",	a_all),
356 	ID("allwinner,sun9i-a80-pinctrl",	a_all),
357 	ID("allwinner,sun50i-a64-pinctrl",	a_all),
358 	ID("allwinner,sun6i-a31-r-pinctrl",	l_2),
359 	ID("allwinner,sun8i-a23-r-pinctrl",	l_1),
360 	ID("allwinner,sun8i-a83t-r-pinctrl",	l_1),
361 	ID("allwinner,sun8i-h3-r-pinctrl",	l_1),
362 	ID("allwinner,sun9i-a80-r-pinctrl",	l_3),
363 	ID("allwinner,sun50i-a64-r-pinctrl",	l_1),
364 	{ }
365 };
366 
367 U_BOOT_DRIVER(gpio_sunxi) = {
368 	.name	= "gpio_sunxi",
369 	.id	= UCLASS_GPIO,
370 	.ops	= &gpio_sunxi_ops,
371 	.of_match = sunxi_gpio_ids,
372 	.bind	= gpio_sunxi_bind,
373 	.probe	= gpio_sunxi_probe,
374 };
375 #endif
376