xref: /openbsd/sys/arch/armv7/exynos/exgpio.c (revision 07829fe8)
1 /* $OpenBSD: exgpio.c,v 1.1 2015/01/26 02:48:24 bmercer 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 #include <machine/fdt.h>
30 #include <machine/intr.h>
31 
32 #include <armv7/armv7/armv7var.h>
33 #include <armv7/exynos/exgpiovar.h>
34 
35 /* Exynos5 registers */
36 #define GPIO_BANK_SIZE		0x20
37 #define GPIO_BANK(x)		(GPIO_BANK_SIZE * ((x) / 8))
38 #define GPIO_CON(x)		(GPIO_BANK(x) + 0x00)
39 #define GPIO_DAT(x)		(GPIO_BANK(x) + 0x04)
40 #define GPIO_PULL(x)		(GPIO_BANK(x) + 0x08)
41 #define GPIO_DRV(x)		(GPIO_BANK(x) + 0x0c)
42 #define GPIO_PDN_CON(x)		(GPIO_BANK(x) + 0x10)
43 #define GPIO_PDN_PULL(x)	(GPIO_BANK(x) + 0x14)
44 
45 /* bits and bytes */
46 #define GPIO_PIN(x)		((x) % 8)
47 #define GPIO_CON_INPUT(x)	(0x0 << (GPIO_PIN(x) << 2))
48 #define GPIO_CON_OUTPUT(x)	(0x1 << (GPIO_PIN(x) << 2))
49 #define GPIO_CON_IRQ(x)		(0xf << (GPIO_PIN(x) << 2))
50 #define GPIO_CON_MASK(x)	(0xf << (GPIO_PIN(x) << 2))
51 #define GPIO_DAT_SET(x)		(0x1 << (GPIO_PIN(x) << 0))
52 #define GPIO_DAT_MASK(x)	(0x1 << (GPIO_PIN(x) << 0))
53 #define GPIO_PULL_NONE(x)	(0x0 << (GPIO_PIN(x) << 1))
54 #define GPIO_PULL_DOWN(x)	(0x1 << (GPIO_PIN(x) << 1))
55 #define GPIO_PULL_UP(x)		(0x3 << (GPIO_PIN(x) << 1))
56 #define GPIO_PULL_MASK(x)	(0x3 << (GPIO_PIN(x) << 1))
57 #define GPIO_DRV_1X(x)		(0x0 << (GPIO_PIN(x) << 1))
58 #define GPIO_DRV_2X(x)		(0x1 << (GPIO_PIN(x) << 1))
59 #define GPIO_DRV_3X(x)		(0x2 << (GPIO_PIN(x) << 1))
60 #define GPIO_DRV_4X(x)		(0x3 << (GPIO_PIN(x) << 1))
61 #define GPIO_DRV_MASK(x)	(0x3 << (GPIO_PIN(x) << 1))
62 
63 #define GPIO_PINS_PER_BANK	8
64 
65 struct exgpio_softc {
66 	struct device		sc_dev;
67 	bus_space_tag_t		sc_iot;
68 	bus_space_handle_t	sc_ioh;
69 	int			sc_ngpio;
70 	unsigned int (*sc_get_bit)(struct exgpio_softc *sc,
71 	    unsigned int gpio);
72 	void (*sc_set_bit)(struct exgpio_softc *sc,
73 	    unsigned int gpio);
74 	void (*sc_clear_bit)(struct exgpio_softc *sc,
75 	    unsigned int gpio);
76 	void (*sc_set_dir)(struct exgpio_softc *sc,
77 	    unsigned int gpio, unsigned int dir);
78 };
79 
80 int exgpio_match(struct device *parent, void *v, void *aux);
81 void exgpio_attach(struct device *parent, struct device *self, void *args);
82 
83 struct exgpio_softc *exgpio_pin_to_inst(unsigned int);
84 unsigned int exgpio_pin_to_offset(unsigned int);
85 unsigned int exgpio_v5_get_bit(struct exgpio_softc *, unsigned int);
86 void exgpio_v5_set_bit(struct exgpio_softc *, unsigned int);
87 void exgpio_v5_clear_bit(struct exgpio_softc *, unsigned int);
88 void exgpio_v5_set_dir(struct exgpio_softc *, unsigned int, unsigned int);
89 unsigned int exgpio_v5_get_dir(struct exgpio_softc *, unsigned int);
90 
91 
92 struct cfattach	exgpio_ca = {
93 	sizeof (struct exgpio_softc), NULL, exgpio_attach
94 };
95 struct cfattach	exgpio_fdt_ca = {
96 	sizeof (struct exgpio_softc), exgpio_match, exgpio_attach
97 };
98 
99 struct cfdriver exgpio_cd = {
100 	NULL, "exgpio", DV_DULL
101 };
102 
103 int
104 exgpio_match(struct device *parent, void *v, void *aux)
105 {
106 	struct armv7_attach_args *aa = aux;
107 
108 	if (fdt_node_compatible("samsung,exynos5250-pinctrl", aa->aa_node))
109 		return 1;
110 
111 	return 0;
112 }
113 
114 void
115 exgpio_attach(struct device *parent, struct device *self, void *args)
116 {
117 	struct armv7_attach_args *aa = args;
118 	struct exgpio_softc *sc = (struct exgpio_softc *) self;
119 	struct fdt_memory mem;
120 
121 	sc->sc_iot = aa->aa_iot;
122 	if (aa->aa_node) {
123 		if (fdt_get_memory_address(aa->aa_node, 0, &mem))
124 			panic("%s: could not extract memory data from FDT",
125 			    __func__);
126 	} else {
127 		mem.addr = aa->aa_dev->mem[0].addr;
128 		mem.size = aa->aa_dev->mem[0].size;
129 	}
130 	if (bus_space_map(sc->sc_iot, mem.addr, mem.size, 0, &sc->sc_ioh))
131 		panic("%s: bus_space_map failed!", __func__);
132 
133 	sc->sc_ngpio = (mem.size / GPIO_BANK_SIZE) * GPIO_PINS_PER_BANK;
134 
135 	sc->sc_get_bit  = exgpio_v5_get_bit;
136 	sc->sc_set_bit = exgpio_v5_set_bit;
137 	sc->sc_clear_bit = exgpio_v5_clear_bit;
138 	sc->sc_set_dir = exgpio_v5_set_dir;
139 
140 	printf("\n");
141 
142 	/* XXX - IRQ */
143 	/* XXX - SYSCONFIG */
144 	/* XXX - CTRL */
145 	/* XXX - DEBOUNCE */
146 }
147 
148 struct exgpio_softc *
149 exgpio_pin_to_inst(unsigned int gpio)
150 {
151 	int i;
152 
153 	for (i = 0; exgpio_cd.cd_devs[i] != NULL; i++)
154 	{
155 		struct exgpio_softc *sc = exgpio_cd.cd_devs[i];
156 		if (gpio < sc->sc_ngpio)
157 			return sc;
158 		else
159 			gpio -= sc->sc_ngpio;
160 	}
161 
162 	return NULL;
163 }
164 
165 unsigned int
166 exgpio_pin_to_offset(unsigned int gpio)
167 {
168 	int i;
169 
170 	for (i = 0; exgpio_cd.cd_devs[i] != NULL; i++)
171 	{
172 		struct exgpio_softc *sc = exgpio_cd.cd_devs[i];
173 		if (gpio < sc->sc_ngpio)
174 			return gpio;
175 		else
176 			gpio -= sc->sc_ngpio;
177 	}
178 
179 	return 0;
180 }
181 
182 unsigned int
183 exgpio_get_bit(unsigned int gpio)
184 {
185 	struct exgpio_softc *sc = exgpio_pin_to_inst(gpio);
186 
187 	return sc->sc_get_bit(sc, gpio);
188 }
189 
190 void
191 exgpio_set_bit(unsigned int gpio)
192 {
193 	struct exgpio_softc *sc = exgpio_pin_to_inst(gpio);
194 
195 	sc->sc_set_bit(sc, gpio);
196 }
197 
198 void
199 exgpio_clear_bit(unsigned int gpio)
200 {
201 	struct exgpio_softc *sc = exgpio_pin_to_inst(gpio);
202 
203 	sc->sc_clear_bit(sc, gpio);
204 }
205 void
206 exgpio_set_dir(unsigned int gpio, unsigned int dir)
207 {
208 	struct exgpio_softc *sc = exgpio_pin_to_inst(gpio);
209 
210 	sc->sc_set_dir(sc, gpio, dir);
211 }
212 
213 unsigned int
214 exgpio_v5_get_bit(struct exgpio_softc *sc, unsigned int gpio)
215 {
216 	u_int32_t val;
217 
218 	gpio = exgpio_pin_to_offset(gpio);
219 	val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio));
220 
221 	return !!(val & GPIO_DAT_SET(gpio));
222 }
223 
224 void
225 exgpio_v5_set_bit(struct exgpio_softc *sc, unsigned int gpio)
226 {
227 	u_int32_t val;
228 
229 	gpio = exgpio_pin_to_offset(gpio);
230 	val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio));
231 
232 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio),
233 		val | GPIO_DAT_SET(gpio));
234 }
235 
236 void
237 exgpio_v5_clear_bit(struct exgpio_softc *sc, unsigned int gpio)
238 {
239 	u_int32_t val;
240 
241 	gpio = exgpio_pin_to_offset(gpio);
242 	val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio));
243 
244 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio),
245 		val & ~GPIO_DAT_MASK(gpio));
246 }
247 
248 void
249 exgpio_v5_set_dir(struct exgpio_softc *sc, unsigned int gpio, unsigned int dir)
250 {
251 	int s;
252 	u_int32_t val;
253 
254 	gpio = exgpio_pin_to_offset(gpio);
255 	s = splhigh();
256 
257 	val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_CON(gpio));
258 	val &= ~GPIO_CON_OUTPUT(gpio);
259 	if (dir == EXGPIO_DIR_OUT)
260 		val |= GPIO_CON_OUTPUT(gpio);
261 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_CON(gpio), val);
262 
263 	splx(s);
264 }
265 
266 unsigned int
267 exgpio_v5_get_dir(struct exgpio_softc *sc, unsigned int gpio)
268 {
269 	int s;
270 	u_int32_t val;
271 
272 	gpio = exgpio_pin_to_offset(gpio);
273 	s = splhigh();
274 
275 	val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_CON(gpio));
276 	if (val & GPIO_CON_OUTPUT(gpio))
277 		val = EXGPIO_DIR_OUT;
278 	else
279 		val = EXGPIO_DIR_IN;
280 
281 	splx(s);
282 	return val;
283 }
284