xref: /openbsd/sys/arch/armv7/exynos/exgpio.c (revision fc61954a)
1 /* $OpenBSD: exgpio.c,v 1.4 2016/07/26 22:10:10 patrick Exp $ */
2 /*
3  * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
4  * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/queue.h>
22 #include <sys/device.h>
23 #include <sys/malloc.h>
24 #include <sys/evcount.h>
25 
26 #include <arm/cpufunc.h>
27 
28 #include <machine/bus.h>
29 #if NFDT > 0
30 #include <machine/fdt.h>
31 #endif
32 #include <machine/intr.h>
33 
34 #include <armv7/armv7/armv7var.h>
35 #include <armv7/exynos/exgpiovar.h>
36 
37 /* Exynos5 registers */
38 #define GPIO_BANK_SIZE		0x20
39 #define GPIO_BANK(x)		(GPIO_BANK_SIZE * ((x) / 8))
40 #define GPIO_CON(x)		(GPIO_BANK(x) + 0x00)
41 #define GPIO_DAT(x)		(GPIO_BANK(x) + 0x04)
42 #define GPIO_PULL(x)		(GPIO_BANK(x) + 0x08)
43 #define GPIO_DRV(x)		(GPIO_BANK(x) + 0x0c)
44 #define GPIO_PDN_CON(x)		(GPIO_BANK(x) + 0x10)
45 #define GPIO_PDN_PULL(x)	(GPIO_BANK(x) + 0x14)
46 
47 /* bits and bytes */
48 #define GPIO_PIN(x)		((x) % 8)
49 #define GPIO_CON_INPUT(x)	(0x0 << (GPIO_PIN(x) << 2))
50 #define GPIO_CON_OUTPUT(x)	(0x1 << (GPIO_PIN(x) << 2))
51 #define GPIO_CON_IRQ(x)		(0xf << (GPIO_PIN(x) << 2))
52 #define GPIO_CON_MASK(x)	(0xf << (GPIO_PIN(x) << 2))
53 #define GPIO_DAT_SET(x)		(0x1 << (GPIO_PIN(x) << 0))
54 #define GPIO_DAT_MASK(x)	(0x1 << (GPIO_PIN(x) << 0))
55 #define GPIO_PULL_NONE(x)	(0x0 << (GPIO_PIN(x) << 1))
56 #define GPIO_PULL_DOWN(x)	(0x1 << (GPIO_PIN(x) << 1))
57 #define GPIO_PULL_UP(x)		(0x3 << (GPIO_PIN(x) << 1))
58 #define GPIO_PULL_MASK(x)	(0x3 << (GPIO_PIN(x) << 1))
59 #define GPIO_DRV_1X(x)		(0x0 << (GPIO_PIN(x) << 1))
60 #define GPIO_DRV_2X(x)		(0x1 << (GPIO_PIN(x) << 1))
61 #define GPIO_DRV_3X(x)		(0x2 << (GPIO_PIN(x) << 1))
62 #define GPIO_DRV_4X(x)		(0x3 << (GPIO_PIN(x) << 1))
63 #define GPIO_DRV_MASK(x)	(0x3 << (GPIO_PIN(x) << 1))
64 
65 #define GPIO_PINS_PER_BANK	8
66 
67 struct exgpio_softc {
68 	struct device		sc_dev;
69 	bus_space_tag_t		sc_iot;
70 	bus_space_handle_t	sc_ioh;
71 	int			sc_ngpio;
72 	unsigned int (*sc_get_bit)(struct exgpio_softc *sc,
73 	    unsigned int gpio);
74 	void (*sc_set_bit)(struct exgpio_softc *sc,
75 	    unsigned int gpio);
76 	void (*sc_clear_bit)(struct exgpio_softc *sc,
77 	    unsigned int gpio);
78 	void (*sc_set_dir)(struct exgpio_softc *sc,
79 	    unsigned int gpio, unsigned int dir);
80 };
81 
82 int exgpio_match(struct device *parent, void *v, void *aux);
83 void exgpio_attach(struct device *parent, struct device *self, void *args);
84 
85 struct exgpio_softc *exgpio_pin_to_inst(unsigned int);
86 unsigned int exgpio_pin_to_offset(unsigned int);
87 unsigned int exgpio_v5_get_bit(struct exgpio_softc *, unsigned int);
88 void exgpio_v5_set_bit(struct exgpio_softc *, unsigned int);
89 void exgpio_v5_clear_bit(struct exgpio_softc *, unsigned int);
90 void exgpio_v5_set_dir(struct exgpio_softc *, unsigned int, unsigned int);
91 unsigned int exgpio_v5_get_dir(struct exgpio_softc *, unsigned int);
92 
93 
94 struct cfattach	exgpio_ca = {
95 	sizeof (struct exgpio_softc), NULL, exgpio_attach
96 };
97 struct cfattach	exgpio_fdt_ca = {
98 	sizeof (struct exgpio_softc), exgpio_match, exgpio_attach
99 };
100 
101 struct cfdriver exgpio_cd = {
102 	NULL, "exgpio", DV_DULL
103 };
104 
105 int
106 exgpio_match(struct device *parent, void *v, void *aux)
107 {
108 #if NFDT > 0
109 	struct armv7_attach_args *aa = aux;
110 
111 	if (fdt_node_compatible("samsung,exynos5250-pinctrl", aa->aa_node))
112 		return 1;
113 #endif
114 
115 	return 0;
116 }
117 
118 void
119 exgpio_attach(struct device *parent, struct device *self, void *args)
120 {
121 	struct armv7_attach_args *aa = args;
122 	struct exgpio_softc *sc = (struct exgpio_softc *) self;
123 	struct armv7mem mem;
124 
125 	sc->sc_iot = aa->aa_iot;
126 #if NFDT > 0
127 	if (aa->aa_node) {
128 		struct fdt_reg reg;
129 		if (fdt_get_reg(aa->aa_node, 0, &reg))
130 			panic("%s: could not extract memory data from FDT",
131 			    __func__);
132 		mem.addr = reg.addr;
133 		mem.size = reg.size;
134 	} else
135 #endif
136 	{
137 		mem.addr = aa->aa_dev->mem[0].addr;
138 		mem.size = aa->aa_dev->mem[0].size;
139 	}
140 	if (bus_space_map(sc->sc_iot, mem.addr, mem.size, 0, &sc->sc_ioh))
141 		panic("%s: bus_space_map failed!", __func__);
142 
143 	sc->sc_ngpio = (mem.size / GPIO_BANK_SIZE) * GPIO_PINS_PER_BANK;
144 
145 	sc->sc_get_bit  = exgpio_v5_get_bit;
146 	sc->sc_set_bit = exgpio_v5_set_bit;
147 	sc->sc_clear_bit = exgpio_v5_clear_bit;
148 	sc->sc_set_dir = exgpio_v5_set_dir;
149 
150 	printf("\n");
151 
152 	/* XXX - IRQ */
153 	/* XXX - SYSCONFIG */
154 	/* XXX - CTRL */
155 	/* XXX - DEBOUNCE */
156 }
157 
158 struct exgpio_softc *
159 exgpio_pin_to_inst(unsigned int gpio)
160 {
161 	int i;
162 
163 	for (i = 0; exgpio_cd.cd_devs[i] != NULL; i++)
164 	{
165 		struct exgpio_softc *sc = exgpio_cd.cd_devs[i];
166 		if (gpio < sc->sc_ngpio)
167 			return sc;
168 		else
169 			gpio -= sc->sc_ngpio;
170 	}
171 
172 	return NULL;
173 }
174 
175 unsigned int
176 exgpio_pin_to_offset(unsigned int gpio)
177 {
178 	int i;
179 
180 	for (i = 0; exgpio_cd.cd_devs[i] != NULL; i++)
181 	{
182 		struct exgpio_softc *sc = exgpio_cd.cd_devs[i];
183 		if (gpio < sc->sc_ngpio)
184 			return gpio;
185 		else
186 			gpio -= sc->sc_ngpio;
187 	}
188 
189 	return 0;
190 }
191 
192 unsigned int
193 exgpio_get_bit(unsigned int gpio)
194 {
195 	struct exgpio_softc *sc = exgpio_pin_to_inst(gpio);
196 
197 	return sc->sc_get_bit(sc, gpio);
198 }
199 
200 void
201 exgpio_set_bit(unsigned int gpio)
202 {
203 	struct exgpio_softc *sc = exgpio_pin_to_inst(gpio);
204 
205 	sc->sc_set_bit(sc, gpio);
206 }
207 
208 void
209 exgpio_clear_bit(unsigned int gpio)
210 {
211 	struct exgpio_softc *sc = exgpio_pin_to_inst(gpio);
212 
213 	sc->sc_clear_bit(sc, gpio);
214 }
215 void
216 exgpio_set_dir(unsigned int gpio, unsigned int dir)
217 {
218 	struct exgpio_softc *sc = exgpio_pin_to_inst(gpio);
219 
220 	sc->sc_set_dir(sc, gpio, dir);
221 }
222 
223 unsigned int
224 exgpio_v5_get_bit(struct exgpio_softc *sc, unsigned int gpio)
225 {
226 	u_int32_t val;
227 
228 	gpio = exgpio_pin_to_offset(gpio);
229 	val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio));
230 
231 	return !!(val & GPIO_DAT_SET(gpio));
232 }
233 
234 void
235 exgpio_v5_set_bit(struct exgpio_softc *sc, unsigned int gpio)
236 {
237 	u_int32_t val;
238 
239 	gpio = exgpio_pin_to_offset(gpio);
240 	val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio));
241 
242 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio),
243 		val | GPIO_DAT_SET(gpio));
244 }
245 
246 void
247 exgpio_v5_clear_bit(struct exgpio_softc *sc, unsigned int gpio)
248 {
249 	u_int32_t val;
250 
251 	gpio = exgpio_pin_to_offset(gpio);
252 	val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio));
253 
254 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio),
255 		val & ~GPIO_DAT_MASK(gpio));
256 }
257 
258 void
259 exgpio_v5_set_dir(struct exgpio_softc *sc, unsigned int gpio, unsigned int dir)
260 {
261 	int s;
262 	u_int32_t val;
263 
264 	gpio = exgpio_pin_to_offset(gpio);
265 	s = splhigh();
266 
267 	val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_CON(gpio));
268 	val &= ~GPIO_CON_OUTPUT(gpio);
269 	if (dir == EXGPIO_DIR_OUT)
270 		val |= GPIO_CON_OUTPUT(gpio);
271 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_CON(gpio), val);
272 
273 	splx(s);
274 }
275 
276 unsigned int
277 exgpio_v5_get_dir(struct exgpio_softc *sc, unsigned int gpio)
278 {
279 	int s;
280 	u_int32_t val;
281 
282 	gpio = exgpio_pin_to_offset(gpio);
283 	s = splhigh();
284 
285 	val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_CON(gpio));
286 	if (val & GPIO_CON_OUTPUT(gpio))
287 		val = EXGPIO_DIR_OUT;
288 	else
289 		val = EXGPIO_DIR_IN;
290 
291 	splx(s);
292 	return val;
293 }
294