]> git.ipfire.org Git - people/ms/u-boot.git/blame - drivers/gpio/sunxi_gpio.c
fastboot: add support for "oem format" command
[people/ms/u-boot.git] / drivers / gpio / sunxi_gpio.c
CommitLineData
abce2c62
IC
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>
7aa97485
SG
14#include <dm.h>
15#include <errno.h>
16#include <fdtdec.h>
17#include <malloc.h>
abce2c62
IC
18#include <asm/io.h>
19#include <asm/gpio.h>
7aa97485 20#include <dm/device-internal.h>
6c727e09
HG
21#ifdef CONFIG_AXP209_POWER
22#include <axp209.h>
23#endif
abce2c62 24
7aa97485
SG
25DECLARE_GLOBAL_DATA_PTR;
26
27#define SUNXI_GPIOS_PER_BANK SUNXI_GPIO_A_NR
28
29struct sunxi_gpio_platdata {
30 struct sunxi_gpio *regs;
31 const char *bank_name; /* Name of bank, e.g. "B" */
32 int gpio_count;
33};
34
35#ifndef CONFIG_DM_GPIO
abce2c62
IC
36static int sunxi_gpio_output(u32 pin, u32 val)
37{
38 u32 dat;
39 u32 bank = GPIO_BANK(pin);
40 u32 num = GPIO_NUM(pin);
41 struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
42
43 dat = readl(&pio->dat);
44 if (val)
45 dat |= 0x1 << num;
46 else
47 dat &= ~(0x1 << num);
48
49 writel(dat, &pio->dat);
50
51 return 0;
52}
53
54static int sunxi_gpio_input(u32 pin)
55{
56 u32 dat;
57 u32 bank = GPIO_BANK(pin);
58 u32 num = GPIO_NUM(pin);
59 struct sunxi_gpio *pio = BANK_TO_GPIO(bank);
60
61 dat = readl(&pio->dat);
62 dat >>= num;
63
64 return dat & 0x1;
65}
66
67int gpio_request(unsigned gpio, const char *label)
68{
69 return 0;
70}
71
72int gpio_free(unsigned gpio)
73{
74 return 0;
75}
76
77int gpio_direction_input(unsigned gpio)
78{
6c727e09
HG
79#ifdef AXP_GPIO
80 if (gpio >= SUNXI_GPIO_AXP0_START)
81 return axp_gpio_direction_input(gpio - SUNXI_GPIO_AXP0_START);
82#endif
abce2c62
IC
83 sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_INPUT);
84
b0c4ae1a 85 return 0;
abce2c62
IC
86}
87
88int gpio_direction_output(unsigned gpio, int value)
89{
6c727e09
HG
90#ifdef AXP_GPIO
91 if (gpio >= SUNXI_GPIO_AXP0_START)
92 return axp_gpio_direction_output(gpio - SUNXI_GPIO_AXP0_START,
93 value);
94#endif
abce2c62
IC
95 sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_OUTPUT);
96
97 return sunxi_gpio_output(gpio, value);
98}
99
100int gpio_get_value(unsigned gpio)
101{
6c727e09
HG
102#ifdef AXP_GPIO
103 if (gpio >= SUNXI_GPIO_AXP0_START)
104 return axp_gpio_get_value(gpio - SUNXI_GPIO_AXP0_START);
105#endif
abce2c62
IC
106 return sunxi_gpio_input(gpio);
107}
108
109int gpio_set_value(unsigned gpio, int value)
110{
6c727e09
HG
111#ifdef AXP_GPIO
112 if (gpio >= SUNXI_GPIO_AXP0_START)
113 return axp_gpio_set_value(gpio - SUNXI_GPIO_AXP0_START, value);
114#endif
abce2c62
IC
115 return sunxi_gpio_output(gpio, value);
116}
117
118int sunxi_name_to_gpio(const char *name)
119{
120 int group = 0;
121 int groupsize = 9 * 32;
122 long pin;
123 char *eptr;
6c727e09
HG
124
125#ifdef AXP_GPIO
126 if (strncasecmp(name, "AXP0-", 5) == 0) {
127 name += 5;
128 pin = simple_strtol(name, &eptr, 10);
129 if (!*name || *eptr)
130 return -1;
131 return SUNXI_GPIO_AXP0_START + pin;
132 }
133#endif
abce2c62
IC
134 if (*name == 'P' || *name == 'p')
135 name++;
136 if (*name >= 'A') {
137 group = *name - (*name > 'a' ? 'a' : 'A');
138 groupsize = 32;
139 name++;
140 }
141
142 pin = simple_strtol(name, &eptr, 10);
143 if (!*name || *eptr)
144 return -1;
145 if (pin < 0 || pin > groupsize || group >= 9)
146 return -1;
147 return group * 32 + pin;
148}
7aa97485
SG
149#endif
150
151#ifdef CONFIG_DM_GPIO
152static int sunxi_gpio_direction_input(struct udevice *dev, unsigned offset)
153{
154 struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
155
156 sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_INPUT);
157
158 return 0;
159}
160
161static int sunxi_gpio_direction_output(struct udevice *dev, unsigned offset,
162 int value)
163{
164 struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
165 u32 num = GPIO_NUM(offset);
166
167 sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_OUTPUT);
168 clrsetbits_le32(&plat->regs->dat, 1 << num, value ? (1 << num) : 0);
169
170 return 0;
171}
172
173static int sunxi_gpio_get_value(struct udevice *dev, unsigned offset)
174{
175 struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
176 u32 num = GPIO_NUM(offset);
177 unsigned dat;
178
179 dat = readl(&plat->regs->dat);
180 dat >>= num;
181
182 return dat & 0x1;
183}
184
185static int sunxi_gpio_set_value(struct udevice *dev, unsigned offset,
186 int value)
187{
188 struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
189 u32 num = GPIO_NUM(offset);
190
191 clrsetbits_le32(&plat->regs->dat, 1 << num, value ? (1 << num) : 0);
192 return 0;
193}
194
195static int sunxi_gpio_get_function(struct udevice *dev, unsigned offset)
196{
197 struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
198 int func;
199
200 func = sunxi_gpio_get_cfgbank(plat->regs, offset);
201 if (func == SUNXI_GPIO_OUTPUT)
202 return GPIOF_OUTPUT;
203 else if (func == SUNXI_GPIO_INPUT)
204 return GPIOF_INPUT;
205 else
206 return GPIOF_FUNC;
207}
208
209static const struct dm_gpio_ops gpio_sunxi_ops = {
210 .direction_input = sunxi_gpio_direction_input,
211 .direction_output = sunxi_gpio_direction_output,
212 .get_value = sunxi_gpio_get_value,
213 .set_value = sunxi_gpio_set_value,
214 .get_function = sunxi_gpio_get_function,
215};
216
217/**
218 * Returns the name of a GPIO bank
219 *
220 * GPIO banks are named A, B, C, ...
221 *
222 * @bank: Bank number (0, 1..n-1)
223 * @return allocated string containing the name
224 */
225static char *gpio_bank_name(int bank)
226{
227 char *name;
228
229 name = malloc(2);
230 if (name) {
231 name[0] = 'A' + bank;
232 name[1] = '\0';
233 }
234
235 return name;
236}
237
238static int gpio_sunxi_probe(struct udevice *dev)
239{
240 struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
241 struct gpio_dev_priv *uc_priv = dev->uclass_priv;
242
243 /* Tell the uclass how many GPIOs we have */
244 if (plat) {
245 uc_priv->gpio_count = plat->gpio_count;
246 uc_priv->bank_name = plat->bank_name;
247 }
248
249 return 0;
250}
251/**
252 * We have a top-level GPIO device with no actual GPIOs. It has a child
253 * device for each Sunxi bank.
254 */
255static int gpio_sunxi_bind(struct udevice *parent)
256{
257 struct sunxi_gpio_platdata *plat = parent->platdata;
258 struct sunxi_gpio_reg *ctlr;
259 int bank;
260 int ret;
261
262 /* If this is a child device, there is nothing to do here */
263 if (plat)
264 return 0;
265
266 ctlr = (struct sunxi_gpio_reg *)fdtdec_get_addr(gd->fdt_blob,
267 parent->of_offset, "reg");
268 for (bank = 0; bank < SUNXI_GPIO_BANKS; bank++) {
269 struct sunxi_gpio_platdata *plat;
270 struct udevice *dev;
271
272 plat = calloc(1, sizeof(*plat));
273 if (!plat)
274 return -ENOMEM;
275 plat->regs = &ctlr->gpio_bank[bank];
276 plat->bank_name = gpio_bank_name(bank);
277 plat->gpio_count = SUNXI_GPIOS_PER_BANK;
278
279 ret = device_bind(parent, parent->driver,
280 plat->bank_name, plat, -1, &dev);
281 if (ret)
282 return ret;
283 dev->of_offset = parent->of_offset;
284 }
285
286 return 0;
287}
288
289static const struct udevice_id sunxi_gpio_ids[] = {
290 { .compatible = "allwinner,sun7i-a20-pinctrl" },
291 { }
292};
293
294U_BOOT_DRIVER(gpio_sunxi) = {
295 .name = "gpio_sunxi",
296 .id = UCLASS_GPIO,
297 .ops = &gpio_sunxi_ops,
298 .of_match = sunxi_gpio_ids,
299 .bind = gpio_sunxi_bind,
300 .probe = gpio_sunxi_probe,
301};
302#endif