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