xref: /openbmc/u-boot/drivers/gpio/sunxi_gpio.c (revision b616d9b0)
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 
23 DECLARE_GLOBAL_DATA_PTR;
24 
25 #define SUNXI_GPIOS_PER_BANK	SUNXI_GPIO_A_NR
26 
27 struct sunxi_gpio_platdata {
28 	struct sunxi_gpio *regs;
29 	const char *bank_name;	/* Name of bank, e.g. "B" */
30 	int gpio_count;
31 };
32 
33 #ifndef CONFIG_DM_GPIO
34 static int sunxi_gpio_output(u32 pin, u32 val)
35 {
36 	u32 dat;
37 	u32 bank = GPIO_BANK(pin);
38 	u32 num = GPIO_NUM(pin);
39 	struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
40 
41 	dat = readl(&pio->dat);
42 	if (val)
43 		dat |= 0x1 << num;
44 	else
45 		dat &= ~(0x1 << num);
46 
47 	writel(dat, &pio->dat);
48 
49 	return 0;
50 }
51 
52 static int sunxi_gpio_input(u32 pin)
53 {
54 	u32 dat;
55 	u32 bank = GPIO_BANK(pin);
56 	u32 num = GPIO_NUM(pin);
57 	struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
58 
59 	dat = readl(&pio->dat);
60 	dat >>= num;
61 
62 	return dat & 0x1;
63 }
64 
65 int gpio_request(unsigned gpio, const char *label)
66 {
67 	return 0;
68 }
69 
70 int gpio_free(unsigned gpio)
71 {
72 	return 0;
73 }
74 
75 int gpio_direction_input(unsigned gpio)
76 {
77 	sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_INPUT);
78 
79 	return 0;
80 }
81 
82 int gpio_direction_output(unsigned gpio, int value)
83 {
84 	sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_OUTPUT);
85 
86 	return sunxi_gpio_output(gpio, value);
87 }
88 
89 int gpio_get_value(unsigned gpio)
90 {
91 	return sunxi_gpio_input(gpio);
92 }
93 
94 int gpio_set_value(unsigned gpio, int value)
95 {
96 	return sunxi_gpio_output(gpio, value);
97 }
98 
99 int sunxi_name_to_gpio(const char *name)
100 {
101 	int group = 0;
102 	int groupsize = 9 * 32;
103 	long pin;
104 	char *eptr;
105 
106 	if (*name == 'P' || *name == 'p')
107 		name++;
108 	if (*name >= 'A') {
109 		group = *name - (*name > 'a' ? 'a' : 'A');
110 		groupsize = 32;
111 		name++;
112 	}
113 
114 	pin = simple_strtol(name, &eptr, 10);
115 	if (!*name || *eptr)
116 		return -1;
117 	if (pin < 0 || pin > groupsize || group >= 9)
118 		return -1;
119 	return group * 32 + pin;
120 }
121 #endif
122 
123 int sunxi_name_to_gpio_bank(const char *name)
124 {
125 	int group = 0;
126 
127 	if (*name == 'P' || *name == 'p')
128 		name++;
129 	if (*name >= 'A') {
130 		group = *name - (*name > 'a' ? 'a' : 'A');
131 		return group;
132 	}
133 
134 	return -1;
135 }
136 
137 #ifdef CONFIG_DM_GPIO
138 /* TODO(sjg@chromium.org): Remove this function and use device tree */
139 int sunxi_name_to_gpio(const char *name)
140 {
141 	unsigned int gpio;
142 	int ret;
143 #if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO
144 	char lookup[8];
145 
146 	if (strcasecmp(name, "AXP0-VBUS-DETECT") == 0) {
147 		sprintf(lookup, SUNXI_GPIO_AXP0_PREFIX "%d",
148 			SUNXI_GPIO_AXP0_VBUS_DETECT);
149 		name = lookup;
150 	} else if (strcasecmp(name, "AXP0-VBUS-ENABLE") == 0) {
151 		sprintf(lookup, SUNXI_GPIO_AXP0_PREFIX "%d",
152 			SUNXI_GPIO_AXP0_VBUS_ENABLE);
153 		name = lookup;
154 	}
155 #endif
156 	ret = gpio_lookup_name(name, NULL, NULL, &gpio);
157 
158 	return ret ? ret : gpio;
159 }
160 
161 static 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 
170 static 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 
182 static 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 
194 static 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 
204 static 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 
218 static 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  */
234 static char *gpio_bank_name(int bank)
235 {
236 	char *name;
237 
238 	name = malloc(3);
239 	if (name) {
240 		name[0] = 'P';
241 		name[1] = 'A' + bank;
242 		name[2] = '\0';
243 	}
244 
245 	return name;
246 }
247 
248 static int gpio_sunxi_probe(struct udevice *dev)
249 {
250 	struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
251 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
252 
253 	/* Tell the uclass how many GPIOs we have */
254 	if (plat) {
255 		uc_priv->gpio_count = plat->gpio_count;
256 		uc_priv->bank_name = plat->bank_name;
257 	}
258 
259 	return 0;
260 }
261 
262 struct sunxi_gpio_soc_data {
263 	int start;
264 	int no_banks;
265 };
266 
267 /**
268  * We have a top-level GPIO device with no actual GPIOs. It has a child
269  * device for each Sunxi bank.
270  */
271 static int gpio_sunxi_bind(struct udevice *parent)
272 {
273 	struct sunxi_gpio_soc_data *soc_data =
274 		(struct sunxi_gpio_soc_data *)dev_get_driver_data(parent);
275 	struct sunxi_gpio_platdata *plat = parent->platdata;
276 	struct sunxi_gpio_reg *ctlr;
277 	int bank, ret;
278 
279 	/* If this is a child device, there is nothing to do here */
280 	if (plat)
281 		return 0;
282 
283 	ctlr = (struct sunxi_gpio_reg *)dev_get_addr(parent);
284 	for (bank = 0; bank < soc_data->no_banks; bank++) {
285 		struct sunxi_gpio_platdata *plat;
286 		struct udevice *dev;
287 
288 		plat = calloc(1, sizeof(*plat));
289 		if (!plat)
290 			return -ENOMEM;
291 		plat->regs = &ctlr->gpio_bank[bank];
292 		plat->bank_name = gpio_bank_name(soc_data->start + bank);
293 		plat->gpio_count = SUNXI_GPIOS_PER_BANK;
294 
295 		ret = device_bind(parent, parent->driver,
296 					plat->bank_name, plat, -1, &dev);
297 		if (ret)
298 			return ret;
299 		dev->of_offset = parent->of_offset;
300 	}
301 
302 	return 0;
303 }
304 
305 static const struct sunxi_gpio_soc_data soc_data_a_all = {
306 	.start = 0,
307 	.no_banks = SUNXI_GPIO_BANKS,
308 };
309 
310 static const struct sunxi_gpio_soc_data soc_data_l_1 = {
311 	.start = 'L' - 'A',
312 	.no_banks = 1,
313 };
314 
315 static const struct sunxi_gpio_soc_data soc_data_l_2 = {
316 	.start = 'L' - 'A',
317 	.no_banks = 2,
318 };
319 
320 static const struct sunxi_gpio_soc_data soc_data_l_3 = {
321 	.start = 'L' - 'A',
322 	.no_banks = 3,
323 };
324 
325 #define ID(_compat_, _soc_data_) \
326 	{ .compatible = _compat_, .data = (ulong)&soc_data_##_soc_data_ }
327 
328 static const struct udevice_id sunxi_gpio_ids[] = {
329 	ID("allwinner,sun4i-a10-pinctrl",	a_all),
330 	ID("allwinner,sun5i-a10s-pinctrl",	a_all),
331 	ID("allwinner,sun5i-a13-pinctrl",	a_all),
332 	ID("allwinner,sun6i-a31-pinctrl",	a_all),
333 	ID("allwinner,sun6i-a31s-pinctrl",	a_all),
334 	ID("allwinner,sun7i-a20-pinctrl",	a_all),
335 	ID("allwinner,sun8i-a23-pinctrl",	a_all),
336 	ID("allwinner,sun8i-a33-pinctrl",	a_all),
337 	ID("allwinner,sun8i-a83t-pinctrl",	a_all),
338 	ID("allwinner,sun8i-h3-pinctrl",	a_all),
339 	ID("allwinner,sun9i-a80-pinctrl",	a_all),
340 	ID("allwinner,sun6i-a31-r-pinctrl",	l_2),
341 	ID("allwinner,sun8i-a23-r-pinctrl",	l_1),
342 	ID("allwinner,sun8i-a83t-r-pinctrl",	l_1),
343 	ID("allwinner,sun8i-h3-r-pinctrl",	l_1),
344 	ID("allwinner,sun9i-a80-r-pinctrl",	l_3),
345 	{ }
346 };
347 
348 U_BOOT_DRIVER(gpio_sunxi) = {
349 	.name	= "gpio_sunxi",
350 	.id	= UCLASS_GPIO,
351 	.ops	= &gpio_sunxi_ops,
352 	.of_match = sunxi_gpio_ids,
353 	.bind	= gpio_sunxi_bind,
354 	.probe	= gpio_sunxi_probe,
355 };
356 #endif
357