xref: /rk3399_rockchip-uboot/drivers/gpio/sunxi_gpio.c (revision f9b7a04bc8aae9b1ffe35c8cc90e1a59f618a9ab)
1abce2c62SIan Campbell /*
2abce2c62SIan Campbell  * (C) Copyright 2012 Henrik Nordstrom <henrik@henriknordstrom.net>
3abce2c62SIan Campbell  *
4abce2c62SIan Campbell  * Based on earlier arch/arm/cpu/armv7/sunxi/gpio.c:
5abce2c62SIan Campbell  *
6abce2c62SIan Campbell  * (C) Copyright 2007-2011
7abce2c62SIan Campbell  * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
8abce2c62SIan Campbell  * Tom Cubie <tangliang@allwinnertech.com>
9abce2c62SIan Campbell  *
10abce2c62SIan Campbell  * SPDX-License-Identifier:	GPL-2.0+
11abce2c62SIan Campbell  */
12abce2c62SIan Campbell 
13abce2c62SIan Campbell #include <common.h>
147aa97485SSimon Glass #include <dm.h>
157aa97485SSimon Glass #include <errno.h>
167aa97485SSimon Glass #include <fdtdec.h>
177aa97485SSimon Glass #include <malloc.h>
182fcf033dSHans de Goede #include <asm/arch/gpio.h>
19abce2c62SIan Campbell #include <asm/io.h>
20abce2c62SIan Campbell #include <asm/gpio.h>
217aa97485SSimon Glass #include <dm/device-internal.h>
22abce2c62SIan Campbell 
237aa97485SSimon Glass DECLARE_GLOBAL_DATA_PTR;
247aa97485SSimon Glass 
257aa97485SSimon Glass #define SUNXI_GPIOS_PER_BANK	SUNXI_GPIO_A_NR
267aa97485SSimon Glass 
277aa97485SSimon Glass struct sunxi_gpio_platdata {
287aa97485SSimon Glass 	struct sunxi_gpio *regs;
297aa97485SSimon Glass 	const char *bank_name;	/* Name of bank, e.g. "B" */
307aa97485SSimon Glass 	int gpio_count;
317aa97485SSimon Glass };
327aa97485SSimon Glass 
337aa97485SSimon Glass #ifndef CONFIG_DM_GPIO
34abce2c62SIan Campbell static int sunxi_gpio_output(u32 pin, u32 val)
35abce2c62SIan Campbell {
36abce2c62SIan Campbell 	u32 dat;
37abce2c62SIan Campbell 	u32 bank = GPIO_BANK(pin);
38abce2c62SIan Campbell 	u32 num = GPIO_NUM(pin);
39abce2c62SIan Campbell 	struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
40abce2c62SIan Campbell 
41abce2c62SIan Campbell 	dat = readl(&pio->dat);
42abce2c62SIan Campbell 	if (val)
43abce2c62SIan Campbell 		dat |= 0x1 << num;
44abce2c62SIan Campbell 	else
45abce2c62SIan Campbell 		dat &= ~(0x1 << num);
46abce2c62SIan Campbell 
47abce2c62SIan Campbell 	writel(dat, &pio->dat);
48abce2c62SIan Campbell 
49abce2c62SIan Campbell 	return 0;
50abce2c62SIan Campbell }
51abce2c62SIan Campbell 
52abce2c62SIan Campbell static int sunxi_gpio_input(u32 pin)
53abce2c62SIan Campbell {
54abce2c62SIan Campbell 	u32 dat;
55abce2c62SIan Campbell 	u32 bank = GPIO_BANK(pin);
56abce2c62SIan Campbell 	u32 num = GPIO_NUM(pin);
57abce2c62SIan Campbell 	struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
58abce2c62SIan Campbell 
59abce2c62SIan Campbell 	dat = readl(&pio->dat);
60abce2c62SIan Campbell 	dat >>= num;
61abce2c62SIan Campbell 
62abce2c62SIan Campbell 	return dat & 0x1;
63abce2c62SIan Campbell }
64abce2c62SIan Campbell 
65abce2c62SIan Campbell int gpio_request(unsigned gpio, const char *label)
66abce2c62SIan Campbell {
67abce2c62SIan Campbell 	return 0;
68abce2c62SIan Campbell }
69abce2c62SIan Campbell 
70abce2c62SIan Campbell int gpio_free(unsigned gpio)
71abce2c62SIan Campbell {
72abce2c62SIan Campbell 	return 0;
73abce2c62SIan Campbell }
74abce2c62SIan Campbell 
75abce2c62SIan Campbell int gpio_direction_input(unsigned gpio)
76abce2c62SIan Campbell {
772fcf033dSHans de Goede #if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO
786c727e09SHans de Goede 	if (gpio >= SUNXI_GPIO_AXP0_START)
7912ce1553SHans de Goede 		return axp_gpio_direction_input(NULL, gpio - SUNXI_GPIO_AXP0_START);
806c727e09SHans de Goede #endif
81abce2c62SIan Campbell 	sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_INPUT);
82abce2c62SIan Campbell 
83b0c4ae1aSAxel Lin 	return 0;
84abce2c62SIan Campbell }
85abce2c62SIan Campbell 
86abce2c62SIan Campbell int gpio_direction_output(unsigned gpio, int value)
87abce2c62SIan Campbell {
882fcf033dSHans de Goede #if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO
896c727e09SHans de Goede 	if (gpio >= SUNXI_GPIO_AXP0_START)
9012ce1553SHans de Goede 		return axp_gpio_direction_output(NULL, gpio - SUNXI_GPIO_AXP0_START,
916c727e09SHans de Goede 						 value);
926c727e09SHans de Goede #endif
93abce2c62SIan Campbell 	sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_OUTPUT);
94abce2c62SIan Campbell 
95abce2c62SIan Campbell 	return sunxi_gpio_output(gpio, value);
96abce2c62SIan Campbell }
97abce2c62SIan Campbell 
98abce2c62SIan Campbell int gpio_get_value(unsigned gpio)
99abce2c62SIan Campbell {
1002fcf033dSHans de Goede #if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO
1016c727e09SHans de Goede 	if (gpio >= SUNXI_GPIO_AXP0_START)
10212ce1553SHans de Goede 		return axp_gpio_get_value(NULL, gpio - SUNXI_GPIO_AXP0_START);
1036c727e09SHans de Goede #endif
104abce2c62SIan Campbell 	return sunxi_gpio_input(gpio);
105abce2c62SIan Campbell }
106abce2c62SIan Campbell 
107abce2c62SIan Campbell int gpio_set_value(unsigned gpio, int value)
108abce2c62SIan Campbell {
1092fcf033dSHans de Goede #if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO
1106c727e09SHans de Goede 	if (gpio >= SUNXI_GPIO_AXP0_START)
11112ce1553SHans de Goede 		return axp_gpio_set_value(NULL, gpio - SUNXI_GPIO_AXP0_START, value);
1126c727e09SHans de Goede #endif
113abce2c62SIan Campbell 	return sunxi_gpio_output(gpio, value);
114abce2c62SIan Campbell }
115abce2c62SIan Campbell 
116abce2c62SIan Campbell int sunxi_name_to_gpio(const char *name)
117abce2c62SIan Campbell {
118abce2c62SIan Campbell 	int group = 0;
119abce2c62SIan Campbell 	int groupsize = 9 * 32;
120abce2c62SIan Campbell 	long pin;
121abce2c62SIan Campbell 	char *eptr;
1226c727e09SHans de Goede 
1232fcf033dSHans de Goede #if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO
1246c727e09SHans de Goede 	if (strncasecmp(name, "AXP0-", 5) == 0) {
1256c727e09SHans de Goede 		name += 5;
126f7c7ab63SPaul Kocialkowski 		if (strcmp(name, "VBUS-DETECT") == 0)
127f7c7ab63SPaul Kocialkowski 			return SUNXI_GPIO_AXP0_START +
128f7c7ab63SPaul Kocialkowski 				SUNXI_GPIO_AXP0_VBUS_DETECT;
129f7c7ab63SPaul Kocialkowski 		if (strcmp(name, "VBUS-ENABLE") == 0)
130f7c7ab63SPaul Kocialkowski 			return SUNXI_GPIO_AXP0_START +
131f7c7ab63SPaul Kocialkowski 				SUNXI_GPIO_AXP0_VBUS_ENABLE;
1326c727e09SHans de Goede 		pin = simple_strtol(name, &eptr, 10);
1336c727e09SHans de Goede 		if (!*name || *eptr)
1346c727e09SHans de Goede 			return -1;
1356c727e09SHans de Goede 		return SUNXI_GPIO_AXP0_START + pin;
1366c727e09SHans de Goede 	}
1376c727e09SHans de Goede #endif
138abce2c62SIan Campbell 	if (*name == 'P' || *name == 'p')
139abce2c62SIan Campbell 		name++;
140abce2c62SIan Campbell 	if (*name >= 'A') {
141abce2c62SIan Campbell 		group = *name - (*name > 'a' ? 'a' : 'A');
142abce2c62SIan Campbell 		groupsize = 32;
143abce2c62SIan Campbell 		name++;
144abce2c62SIan Campbell 	}
145abce2c62SIan Campbell 
146abce2c62SIan Campbell 	pin = simple_strtol(name, &eptr, 10);
147abce2c62SIan Campbell 	if (!*name || *eptr)
148abce2c62SIan Campbell 		return -1;
149abce2c62SIan Campbell 	if (pin < 0 || pin > groupsize || group >= 9)
150abce2c62SIan Campbell 		return -1;
151abce2c62SIan Campbell 	return group * 32 + pin;
152abce2c62SIan Campbell }
1537aa97485SSimon Glass #endif
1547aa97485SSimon Glass 
155746c087bSHans de Goede int sunxi_name_to_gpio_bank(const char *name)
156746c087bSHans de Goede {
157746c087bSHans de Goede 	int group = 0;
158746c087bSHans de Goede 
159746c087bSHans de Goede 	if (*name == 'P' || *name == 'p')
160746c087bSHans de Goede 		name++;
161746c087bSHans de Goede 	if (*name >= 'A') {
162746c087bSHans de Goede 		group = *name - (*name > 'a' ? 'a' : 'A');
163746c087bSHans de Goede 		return group;
164746c087bSHans de Goede 	}
165746c087bSHans de Goede 
166746c087bSHans de Goede 	return -1;
167746c087bSHans de Goede }
168746c087bSHans de Goede 
1697aa97485SSimon Glass #ifdef CONFIG_DM_GPIO
170a5ab8838SSimon Glass /* TODO(sjg@chromium.org): Remove this function and use device tree */
171a5ab8838SSimon Glass int sunxi_name_to_gpio(const char *name)
172a5ab8838SSimon Glass {
173a5ab8838SSimon Glass 	unsigned int gpio;
174a5ab8838SSimon Glass 	int ret;
175*f9b7a04bSHans de Goede #if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO
176*f9b7a04bSHans de Goede 	char lookup[8];
177a5ab8838SSimon Glass 
178*f9b7a04bSHans de Goede 	if (strcasecmp(name, "AXP0-VBUS-DETECT") == 0) {
179*f9b7a04bSHans de Goede 		sprintf(lookup, SUNXI_GPIO_AXP0_PREFIX "%d",
180*f9b7a04bSHans de Goede 			SUNXI_GPIO_AXP0_VBUS_DETECT);
181*f9b7a04bSHans de Goede 		name = lookup;
182*f9b7a04bSHans de Goede 	} else if (strcasecmp(name, "AXP0-VBUS-ENABLE") == 0) {
183*f9b7a04bSHans de Goede 		sprintf(lookup, SUNXI_GPIO_AXP0_PREFIX "%d",
184*f9b7a04bSHans de Goede 			SUNXI_GPIO_AXP0_VBUS_ENABLE);
185*f9b7a04bSHans de Goede 		name = lookup;
186*f9b7a04bSHans de Goede 	}
187*f9b7a04bSHans de Goede #endif
188a5ab8838SSimon Glass 	ret = gpio_lookup_name(name, NULL, NULL, &gpio);
189a5ab8838SSimon Glass 
190a5ab8838SSimon Glass 	return ret ? ret : gpio;
191a5ab8838SSimon Glass }
192a5ab8838SSimon Glass 
1937aa97485SSimon Glass static int sunxi_gpio_direction_input(struct udevice *dev, unsigned offset)
1947aa97485SSimon Glass {
1957aa97485SSimon Glass 	struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
1967aa97485SSimon Glass 
1977aa97485SSimon Glass 	sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_INPUT);
1987aa97485SSimon Glass 
1997aa97485SSimon Glass 	return 0;
2007aa97485SSimon Glass }
2017aa97485SSimon Glass 
2027aa97485SSimon Glass static int sunxi_gpio_direction_output(struct udevice *dev, unsigned offset,
2037aa97485SSimon Glass 				       int value)
2047aa97485SSimon Glass {
2057aa97485SSimon Glass 	struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
2067aa97485SSimon Glass 	u32 num = GPIO_NUM(offset);
2077aa97485SSimon Glass 
2087aa97485SSimon Glass 	sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_OUTPUT);
2097aa97485SSimon Glass 	clrsetbits_le32(&plat->regs->dat, 1 << num, value ? (1 << num) : 0);
2107aa97485SSimon Glass 
2117aa97485SSimon Glass 	return 0;
2127aa97485SSimon Glass }
2137aa97485SSimon Glass 
2147aa97485SSimon Glass static int sunxi_gpio_get_value(struct udevice *dev, unsigned offset)
2157aa97485SSimon Glass {
2167aa97485SSimon Glass 	struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
2177aa97485SSimon Glass 	u32 num = GPIO_NUM(offset);
2187aa97485SSimon Glass 	unsigned dat;
2197aa97485SSimon Glass 
2207aa97485SSimon Glass 	dat = readl(&plat->regs->dat);
2217aa97485SSimon Glass 	dat >>= num;
2227aa97485SSimon Glass 
2237aa97485SSimon Glass 	return dat & 0x1;
2247aa97485SSimon Glass }
2257aa97485SSimon Glass 
2267aa97485SSimon Glass static int sunxi_gpio_set_value(struct udevice *dev, unsigned offset,
2277aa97485SSimon Glass 				int value)
2287aa97485SSimon Glass {
2297aa97485SSimon Glass 	struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
2307aa97485SSimon Glass 	u32 num = GPIO_NUM(offset);
2317aa97485SSimon Glass 
2327aa97485SSimon Glass 	clrsetbits_le32(&plat->regs->dat, 1 << num, value ? (1 << num) : 0);
2337aa97485SSimon Glass 	return 0;
2347aa97485SSimon Glass }
2357aa97485SSimon Glass 
2367aa97485SSimon Glass static int sunxi_gpio_get_function(struct udevice *dev, unsigned offset)
2377aa97485SSimon Glass {
2387aa97485SSimon Glass 	struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
2397aa97485SSimon Glass 	int func;
2407aa97485SSimon Glass 
2417aa97485SSimon Glass 	func = sunxi_gpio_get_cfgbank(plat->regs, offset);
2427aa97485SSimon Glass 	if (func == SUNXI_GPIO_OUTPUT)
2437aa97485SSimon Glass 		return GPIOF_OUTPUT;
2447aa97485SSimon Glass 	else if (func == SUNXI_GPIO_INPUT)
2457aa97485SSimon Glass 		return GPIOF_INPUT;
2467aa97485SSimon Glass 	else
2477aa97485SSimon Glass 		return GPIOF_FUNC;
2487aa97485SSimon Glass }
2497aa97485SSimon Glass 
2507aa97485SSimon Glass static const struct dm_gpio_ops gpio_sunxi_ops = {
2517aa97485SSimon Glass 	.direction_input	= sunxi_gpio_direction_input,
2527aa97485SSimon Glass 	.direction_output	= sunxi_gpio_direction_output,
2537aa97485SSimon Glass 	.get_value		= sunxi_gpio_get_value,
2547aa97485SSimon Glass 	.set_value		= sunxi_gpio_set_value,
2557aa97485SSimon Glass 	.get_function		= sunxi_gpio_get_function,
2567aa97485SSimon Glass };
2577aa97485SSimon Glass 
2587aa97485SSimon Glass /**
2597aa97485SSimon Glass  * Returns the name of a GPIO bank
2607aa97485SSimon Glass  *
2617aa97485SSimon Glass  * GPIO banks are named A, B, C, ...
2627aa97485SSimon Glass  *
2637aa97485SSimon Glass  * @bank:	Bank number (0, 1..n-1)
2647aa97485SSimon Glass  * @return allocated string containing the name
2657aa97485SSimon Glass  */
2667aa97485SSimon Glass static char *gpio_bank_name(int bank)
2677aa97485SSimon Glass {
2687aa97485SSimon Glass 	char *name;
2697aa97485SSimon Glass 
27007ce60f3SSimon Glass 	name = malloc(3);
2717aa97485SSimon Glass 	if (name) {
27207ce60f3SSimon Glass 		name[0] = 'P';
27307ce60f3SSimon Glass 		name[1] = 'A' + bank;
27407ce60f3SSimon Glass 		name[2] = '\0';
2757aa97485SSimon Glass 	}
2767aa97485SSimon Glass 
2777aa97485SSimon Glass 	return name;
2787aa97485SSimon Glass }
2797aa97485SSimon Glass 
2807aa97485SSimon Glass static int gpio_sunxi_probe(struct udevice *dev)
2817aa97485SSimon Glass {
2827aa97485SSimon Glass 	struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
283e564f054SSimon Glass 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
2847aa97485SSimon Glass 
2857aa97485SSimon Glass 	/* Tell the uclass how many GPIOs we have */
2867aa97485SSimon Glass 	if (plat) {
2877aa97485SSimon Glass 		uc_priv->gpio_count = plat->gpio_count;
2887aa97485SSimon Glass 		uc_priv->bank_name = plat->bank_name;
2897aa97485SSimon Glass 	}
2907aa97485SSimon Glass 
2917aa97485SSimon Glass 	return 0;
2927aa97485SSimon Glass }
2937aa97485SSimon Glass /**
2947aa97485SSimon Glass  * We have a top-level GPIO device with no actual GPIOs. It has a child
2957aa97485SSimon Glass  * device for each Sunxi bank.
2967aa97485SSimon Glass  */
2977aa97485SSimon Glass static int gpio_sunxi_bind(struct udevice *parent)
2987aa97485SSimon Glass {
2997aa97485SSimon Glass 	struct sunxi_gpio_platdata *plat = parent->platdata;
3007aa97485SSimon Glass 	struct sunxi_gpio_reg *ctlr;
3017aa97485SSimon Glass 	int bank;
3027aa97485SSimon Glass 	int ret;
3037aa97485SSimon Glass 
3047aa97485SSimon Glass 	/* If this is a child device, there is nothing to do here */
3057aa97485SSimon Glass 	if (plat)
3067aa97485SSimon Glass 		return 0;
3077aa97485SSimon Glass 
3087aa97485SSimon Glass 	ctlr = (struct sunxi_gpio_reg *)fdtdec_get_addr(gd->fdt_blob,
3097aa97485SSimon Glass 						   parent->of_offset, "reg");
3107aa97485SSimon Glass 	for (bank = 0; bank < SUNXI_GPIO_BANKS; bank++) {
3117aa97485SSimon Glass 		struct sunxi_gpio_platdata *plat;
3127aa97485SSimon Glass 		struct udevice *dev;
3137aa97485SSimon Glass 
3147aa97485SSimon Glass 		plat = calloc(1, sizeof(*plat));
3157aa97485SSimon Glass 		if (!plat)
3167aa97485SSimon Glass 			return -ENOMEM;
3177aa97485SSimon Glass 		plat->regs = &ctlr->gpio_bank[bank];
3187aa97485SSimon Glass 		plat->bank_name = gpio_bank_name(bank);
3197aa97485SSimon Glass 		plat->gpio_count = SUNXI_GPIOS_PER_BANK;
3207aa97485SSimon Glass 
3217aa97485SSimon Glass 		ret = device_bind(parent, parent->driver,
3227aa97485SSimon Glass 					plat->bank_name, plat, -1, &dev);
3237aa97485SSimon Glass 		if (ret)
3247aa97485SSimon Glass 			return ret;
3257aa97485SSimon Glass 		dev->of_offset = parent->of_offset;
3267aa97485SSimon Glass 	}
3277aa97485SSimon Glass 
3287aa97485SSimon Glass 	return 0;
3297aa97485SSimon Glass }
3307aa97485SSimon Glass 
3317aa97485SSimon Glass static const struct udevice_id sunxi_gpio_ids[] = {
33211d52a9dSHans de Goede 	{ .compatible = "allwinner,sun4i-a10-pinctrl" },
33311d52a9dSHans de Goede 	{ .compatible = "allwinner,sun5i-a10s-pinctrl" },
33411d52a9dSHans de Goede 	{ .compatible = "allwinner,sun5i-a13-pinctrl" },
33511d52a9dSHans de Goede 	{ .compatible = "allwinner,sun6i-a31-pinctrl" },
33611d52a9dSHans de Goede 	{ .compatible = "allwinner,sun6i-a31s-pinctrl" },
3377aa97485SSimon Glass 	{ .compatible = "allwinner,sun7i-a20-pinctrl" },
33811d52a9dSHans de Goede 	{ .compatible = "allwinner,sun8i-a23-pinctrl" },
33911d52a9dSHans de Goede 	{ .compatible = "allwinner,sun9i-a80-pinctrl" },
3407aa97485SSimon Glass 	{ }
3417aa97485SSimon Glass };
3427aa97485SSimon Glass 
3437aa97485SSimon Glass U_BOOT_DRIVER(gpio_sunxi) = {
3447aa97485SSimon Glass 	.name	= "gpio_sunxi",
3457aa97485SSimon Glass 	.id	= UCLASS_GPIO,
3467aa97485SSimon Glass 	.ops	= &gpio_sunxi_ops,
3477aa97485SSimon Glass 	.of_match = sunxi_gpio_ids,
3487aa97485SSimon Glass 	.bind	= gpio_sunxi_bind,
3497aa97485SSimon Glass 	.probe	= gpio_sunxi_probe,
3507aa97485SSimon Glass };
3517aa97485SSimon Glass #endif
352