xref: /openbmc/u-boot/drivers/gpio/sunxi_gpio.c (revision 7bf38161)
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 
22 DECLARE_GLOBAL_DATA_PTR;
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 sunxi_gpio_input(gpio);
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 	if (*name == 'P' || *name == 'p')
105 		name++;
106 	if (*name >= 'A') {
107 		group = *name - (*name > 'a' ? 'a' : 'A');
108 		groupsize = 32;
109 		name++;
110 	}
111 
112 	pin = simple_strtol(name, &eptr, 10);
113 	if (!*name || *eptr)
114 		return -1;
115 	if (pin < 0 || pin > groupsize || group >= 9)
116 		return -1;
117 	return group * 32 + pin;
118 }
119 #endif
120 
121 #ifdef CONFIG_DM_GPIO
122 static int sunxi_gpio_direction_input(struct udevice *dev, unsigned offset)
123 {
124 	struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
125 
126 	sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_INPUT);
127 
128 	return 0;
129 }
130 
131 static int sunxi_gpio_direction_output(struct udevice *dev, unsigned offset,
132 				       int value)
133 {
134 	struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
135 	u32 num = GPIO_NUM(offset);
136 
137 	sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_OUTPUT);
138 	clrsetbits_le32(&plat->regs->dat, 1 << num, value ? (1 << num) : 0);
139 
140 	return 0;
141 }
142 
143 static int sunxi_gpio_get_value(struct udevice *dev, unsigned offset)
144 {
145 	struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
146 	u32 num = GPIO_NUM(offset);
147 	unsigned dat;
148 
149 	dat = readl(&plat->regs->dat);
150 	dat >>= num;
151 
152 	return dat & 0x1;
153 }
154 
155 static int sunxi_gpio_set_value(struct udevice *dev, unsigned offset,
156 				int value)
157 {
158 	struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
159 	u32 num = GPIO_NUM(offset);
160 
161 	clrsetbits_le32(&plat->regs->dat, 1 << num, value ? (1 << num) : 0);
162 	return 0;
163 }
164 
165 static int sunxi_gpio_get_function(struct udevice *dev, unsigned offset)
166 {
167 	struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
168 	int func;
169 
170 	func = sunxi_gpio_get_cfgbank(plat->regs, offset);
171 	if (func == SUNXI_GPIO_OUTPUT)
172 		return GPIOF_OUTPUT;
173 	else if (func == SUNXI_GPIO_INPUT)
174 		return GPIOF_INPUT;
175 	else
176 		return GPIOF_FUNC;
177 }
178 
179 static const struct dm_gpio_ops gpio_sunxi_ops = {
180 	.direction_input	= sunxi_gpio_direction_input,
181 	.direction_output	= sunxi_gpio_direction_output,
182 	.get_value		= sunxi_gpio_get_value,
183 	.set_value		= sunxi_gpio_set_value,
184 	.get_function		= sunxi_gpio_get_function,
185 };
186 
187 /**
188  * Returns the name of a GPIO bank
189  *
190  * GPIO banks are named A, B, C, ...
191  *
192  * @bank:	Bank number (0, 1..n-1)
193  * @return allocated string containing the name
194  */
195 static char *gpio_bank_name(int bank)
196 {
197 	char *name;
198 
199 	name = malloc(2);
200 	if (name) {
201 		name[0] = 'A' + bank;
202 		name[1] = '\0';
203 	}
204 
205 	return name;
206 }
207 
208 static int gpio_sunxi_probe(struct udevice *dev)
209 {
210 	struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
211 	struct gpio_dev_priv *uc_priv = dev->uclass_priv;
212 
213 	/* Tell the uclass how many GPIOs we have */
214 	if (plat) {
215 		uc_priv->gpio_count = plat->gpio_count;
216 		uc_priv->bank_name = plat->bank_name;
217 	}
218 
219 	return 0;
220 }
221 /**
222  * We have a top-level GPIO device with no actual GPIOs. It has a child
223  * device for each Sunxi bank.
224  */
225 static int gpio_sunxi_bind(struct udevice *parent)
226 {
227 	struct sunxi_gpio_platdata *plat = parent->platdata;
228 	struct sunxi_gpio_reg *ctlr;
229 	int bank;
230 	int ret;
231 
232 	/* If this is a child device, there is nothing to do here */
233 	if (plat)
234 		return 0;
235 
236 	ctlr = (struct sunxi_gpio_reg *)fdtdec_get_addr(gd->fdt_blob,
237 						   parent->of_offset, "reg");
238 	for (bank = 0; bank < SUNXI_GPIO_BANKS; bank++) {
239 		struct sunxi_gpio_platdata *plat;
240 		struct udevice *dev;
241 
242 		plat = calloc(1, sizeof(*plat));
243 		if (!plat)
244 			return -ENOMEM;
245 		plat->regs = &ctlr->gpio_bank[bank];
246 		plat->bank_name = gpio_bank_name(bank);
247 		plat->gpio_count = SUNXI_GPIOS_PER_BANK;
248 
249 		ret = device_bind(parent, parent->driver,
250 					plat->bank_name, plat, -1, &dev);
251 		if (ret)
252 			return ret;
253 		dev->of_offset = parent->of_offset;
254 	}
255 
256 	return 0;
257 }
258 
259 static const struct udevice_id sunxi_gpio_ids[] = {
260 	{ .compatible = "allwinner,sun7i-a20-pinctrl" },
261 	{ }
262 };
263 
264 U_BOOT_DRIVER(gpio_sunxi) = {
265 	.name	= "gpio_sunxi",
266 	.id	= UCLASS_GPIO,
267 	.ops	= &gpio_sunxi_ops,
268 	.of_match = sunxi_gpio_ids,
269 	.bind	= gpio_sunxi_bind,
270 	.probe	= gpio_sunxi_probe,
271 };
272 #endif
273