blob: 2fa50f9f8d5d46336d65c0d2345de8dee37d0cae [file] [log] [blame]
Ian Campbellaf471472014-06-05 19:00:15 +01001/*
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>
Simon Glass78304532014-10-30 20:25:49 -060014#include <dm.h>
15#include <errno.h>
16#include <fdtdec.h>
17#include <malloc.h>
Ian Campbellaf471472014-06-05 19:00:15 +010018#include <asm/io.h>
19#include <asm/gpio.h>
Simon Glass78304532014-10-30 20:25:49 -060020#include <dm/device-internal.h>
Ian Campbellaf471472014-06-05 19:00:15 +010021
Simon Glass78304532014-10-30 20:25:49 -060022DECLARE_GLOBAL_DATA_PTR;
23
24#define SUNXI_GPIOS_PER_BANK SUNXI_GPIO_A_NR
25
26struct 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
Ian Campbellaf471472014-06-05 19:00:15 +010033static 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
51static 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
64int gpio_request(unsigned gpio, const char *label)
65{
66 return 0;
67}
68
69int gpio_free(unsigned gpio)
70{
71 return 0;
72}
73
74int gpio_direction_input(unsigned gpio)
75{
76 sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_INPUT);
77
Axel Lin06da3462014-12-20 11:41:25 +080078 return 0;
Ian Campbellaf471472014-06-05 19:00:15 +010079}
80
81int 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
88int gpio_get_value(unsigned gpio)
89{
90 return sunxi_gpio_input(gpio);
91}
92
93int gpio_set_value(unsigned gpio, int value)
94{
95 return sunxi_gpio_output(gpio, value);
96}
97
98int 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}
Simon Glass78304532014-10-30 20:25:49 -0600119#endif
120
121#ifdef CONFIG_DM_GPIO
122static 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
131static 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
143static 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
155static 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
165static 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
179static 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 */
195static 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
208static 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 */
225static 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
259static const struct udevice_id sunxi_gpio_ids[] = {
260 { .compatible = "allwinner,sun7i-a20-pinctrl" },
261 { }
262};
263
264U_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