xref: /rk3399_rockchip-uboot/drivers/gpio/sunxi_gpio.c (revision 1d624a4f08d3a478e38ceb1a048c3da4982021df)
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(NULL, 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(NULL, 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(NULL, 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(NULL, gpio - SUNXI_GPIO_AXP0_START, value);
117 #endif
118 	return sunxi_gpio_output(gpio, value);
119 }
120 
121 int sunxi_name_to_gpio(const char *name)
122 {
123 	int group = 0;
124 	int groupsize = 9 * 32;
125 	long pin;
126 	char *eptr;
127 
128 #ifdef AXP_GPIO
129 	if (strncasecmp(name, "AXP0-", 5) == 0) {
130 		name += 5;
131 		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;
137 		pin = simple_strtol(name, &eptr, 10);
138 		if (!*name || *eptr)
139 			return -1;
140 		return SUNXI_GPIO_AXP0_START + pin;
141 	}
142 #endif
143 	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 }
158 #endif
159 
160 int sunxi_name_to_gpio_bank(const char *name)
161 {
162 	int group = 0;
163 
164 	if (*name == 'P' || *name == 'p')
165 		name++;
166 	if (*name >= 'A') {
167 		group = *name - (*name > 'a' ? 'a' : 'A');
168 		return group;
169 	}
170 
171 	return -1;
172 }
173 
174 #ifdef CONFIG_DM_GPIO
175 /* TODO(sjg@chromium.org): Remove this function and use device tree */
176 int sunxi_name_to_gpio(const char *name)
177 {
178 	unsigned int gpio;
179 	int ret;
180 
181 	ret = gpio_lookup_name(name, NULL, NULL, &gpio);
182 
183 	return ret ? ret : gpio;
184 }
185 
186 static int sunxi_gpio_direction_input(struct udevice *dev, unsigned offset)
187 {
188 	struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
189 
190 	sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_INPUT);
191 
192 	return 0;
193 }
194 
195 static int sunxi_gpio_direction_output(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 	sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_OUTPUT);
202 	clrsetbits_le32(&plat->regs->dat, 1 << num, value ? (1 << num) : 0);
203 
204 	return 0;
205 }
206 
207 static int sunxi_gpio_get_value(struct udevice *dev, unsigned offset)
208 {
209 	struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
210 	u32 num = GPIO_NUM(offset);
211 	unsigned dat;
212 
213 	dat = readl(&plat->regs->dat);
214 	dat >>= num;
215 
216 	return dat & 0x1;
217 }
218 
219 static int sunxi_gpio_set_value(struct udevice *dev, unsigned offset,
220 				int value)
221 {
222 	struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
223 	u32 num = GPIO_NUM(offset);
224 
225 	clrsetbits_le32(&plat->regs->dat, 1 << num, value ? (1 << num) : 0);
226 	return 0;
227 }
228 
229 static int sunxi_gpio_get_function(struct udevice *dev, unsigned offset)
230 {
231 	struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
232 	int func;
233 
234 	func = sunxi_gpio_get_cfgbank(plat->regs, offset);
235 	if (func == SUNXI_GPIO_OUTPUT)
236 		return GPIOF_OUTPUT;
237 	else if (func == SUNXI_GPIO_INPUT)
238 		return GPIOF_INPUT;
239 	else
240 		return GPIOF_FUNC;
241 }
242 
243 static const struct dm_gpio_ops gpio_sunxi_ops = {
244 	.direction_input	= sunxi_gpio_direction_input,
245 	.direction_output	= sunxi_gpio_direction_output,
246 	.get_value		= sunxi_gpio_get_value,
247 	.set_value		= sunxi_gpio_set_value,
248 	.get_function		= sunxi_gpio_get_function,
249 };
250 
251 /**
252  * Returns the name of a GPIO bank
253  *
254  * GPIO banks are named A, B, C, ...
255  *
256  * @bank:	Bank number (0, 1..n-1)
257  * @return allocated string containing the name
258  */
259 static char *gpio_bank_name(int bank)
260 {
261 	char *name;
262 
263 	name = malloc(3);
264 	if (name) {
265 		name[0] = 'P';
266 		name[1] = 'A' + bank;
267 		name[2] = '\0';
268 	}
269 
270 	return name;
271 }
272 
273 static int gpio_sunxi_probe(struct udevice *dev)
274 {
275 	struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
276 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
277 
278 	/* Tell the uclass how many GPIOs we have */
279 	if (plat) {
280 		uc_priv->gpio_count = plat->gpio_count;
281 		uc_priv->bank_name = plat->bank_name;
282 	}
283 
284 	return 0;
285 }
286 /**
287  * We have a top-level GPIO device with no actual GPIOs. It has a child
288  * device for each Sunxi bank.
289  */
290 static int gpio_sunxi_bind(struct udevice *parent)
291 {
292 	struct sunxi_gpio_platdata *plat = parent->platdata;
293 	struct sunxi_gpio_reg *ctlr;
294 	int bank;
295 	int ret;
296 
297 	/* If this is a child device, there is nothing to do here */
298 	if (plat)
299 		return 0;
300 
301 	ctlr = (struct sunxi_gpio_reg *)fdtdec_get_addr(gd->fdt_blob,
302 						   parent->of_offset, "reg");
303 	for (bank = 0; bank < SUNXI_GPIO_BANKS; bank++) {
304 		struct sunxi_gpio_platdata *plat;
305 		struct udevice *dev;
306 
307 		plat = calloc(1, sizeof(*plat));
308 		if (!plat)
309 			return -ENOMEM;
310 		plat->regs = &ctlr->gpio_bank[bank];
311 		plat->bank_name = gpio_bank_name(bank);
312 		plat->gpio_count = SUNXI_GPIOS_PER_BANK;
313 
314 		ret = device_bind(parent, parent->driver,
315 					plat->bank_name, plat, -1, &dev);
316 		if (ret)
317 			return ret;
318 		dev->of_offset = parent->of_offset;
319 	}
320 
321 	return 0;
322 }
323 
324 static const struct udevice_id sunxi_gpio_ids[] = {
325 	{ .compatible = "allwinner,sun4i-a10-pinctrl" },
326 	{ .compatible = "allwinner,sun5i-a10s-pinctrl" },
327 	{ .compatible = "allwinner,sun5i-a13-pinctrl" },
328 	{ .compatible = "allwinner,sun6i-a31-pinctrl" },
329 	{ .compatible = "allwinner,sun6i-a31s-pinctrl" },
330 	{ .compatible = "allwinner,sun7i-a20-pinctrl" },
331 	{ .compatible = "allwinner,sun8i-a23-pinctrl" },
332 	{ .compatible = "allwinner,sun9i-a80-pinctrl" },
333 	{ }
334 };
335 
336 U_BOOT_DRIVER(gpio_sunxi) = {
337 	.name	= "gpio_sunxi",
338 	.id	= UCLASS_GPIO,
339 	.ops	= &gpio_sunxi_ops,
340 	.of_match = sunxi_gpio_ids,
341 	.bind	= gpio_sunxi_bind,
342 	.probe	= gpio_sunxi_probe,
343 };
344 #endif
345