Deleted Added
full compact
exynos5_pad.c (273799) exynos5_pad.c (274670)
1/*-
2 * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27/*
28 * Samsung Exynos 5 Pad Control
29 * Chapter 4, Exynos 5 Dual User's Manual Public Rev 1.00
30 */
31
32#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27/*
28 * Samsung Exynos 5 Pad Control
29 * Chapter 4, Exynos 5 Dual User's Manual Public Rev 1.00
30 */
31
32#include <sys/cdefs.h>
33__FBSDID("$FreeBSD: head/sys/arm/samsung/exynos/exynos5_pad.c 273799 2014-10-28 18:33:59Z loos $");
33__FBSDID("$FreeBSD: head/sys/arm/samsung/exynos/exynos5_pad.c 274670 2014-11-18 17:22:08Z loos $");
34
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/bus.h>
38#include <sys/kernel.h>
39#include <sys/module.h>
40#include <sys/malloc.h>
41#include <sys/rman.h>
42#include <sys/timeet.h>
43#include <sys/timetc.h>
44#include <sys/watchdog.h>
45#include <sys/mutex.h>
46#include <sys/gpio.h>
47
48#include <dev/ofw/openfirm.h>
49#include <dev/ofw/ofw_bus.h>
50#include <dev/ofw/ofw_bus_subr.h>
51
52#include <machine/bus.h>
53#include <machine/cpu.h>
54#include <machine/intr.h>
55
56#include "gpio_if.h"
57
58#include <arm/samsung/exynos/exynos5_combiner.h>
59#include <arm/samsung/exynos/exynos5_pad.h>
60
61#define GPIO_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
62#define GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
63
64#define DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)
65
66#define MAX_PORTS 5
67#define MAX_NGPIO 253
68
69#define N_EXT_INTS 16
70
71#define EXYNOS5250 1
72#define EXYNOS5420 2
73
74#define PIN_IN 0
75#define PIN_OUT 1
76
77#define READ4(_sc, _port, _reg) \
78 bus_space_read_4(_sc->bst[_port], _sc->bsh[_port], _reg)
79#define WRITE4(_sc, _port, _reg, _val) \
80 bus_space_write_4(_sc->bst[_port], _sc->bsh[_port], _reg, _val)
81
82/*
83 * GPIO interface
84 */
85static int pad_pin_max(device_t, int *);
86static int pad_pin_getcaps(device_t, uint32_t, uint32_t *);
87static int pad_pin_getname(device_t, uint32_t, char *);
88static int pad_pin_getflags(device_t, uint32_t, uint32_t *);
89static int pad_pin_setflags(device_t, uint32_t, uint32_t);
90static int pad_pin_set(device_t, uint32_t, unsigned int);
91static int pad_pin_get(device_t, uint32_t, unsigned int *);
92static int pad_pin_toggle(device_t, uint32_t pin);
93
94struct gpio_bank {
95 char *name;
96 uint32_t port;
97 uint32_t con;
98 uint32_t ngpio;
99 uint32_t ext_con;
100 uint32_t ext_flt_con;
101 uint32_t mask;
102 uint32_t pend;
103};
104
105struct pad_softc {
106 struct resource *res[MAX_PORTS * 2];
107 bus_space_tag_t bst[MAX_PORTS];
108 bus_space_handle_t bsh[MAX_PORTS];
109 struct mtx sc_mtx;
110 int gpio_npins;
111 struct gpio_pin gpio_pins[MAX_NGPIO];
112 void *gpio_ih[MAX_PORTS];
113 device_t dev;
114 int model;
115 struct resource_spec *pad_spec;
116 struct gpio_bank *gpio_map;
117 struct interrupt_entry *interrupt_table;
118 int nports;
119};
120
121struct pad_softc *gpio_sc;
122
123static struct resource_spec pad_spec_5250[] = {
124 { SYS_RES_MEMORY, 0, RF_ACTIVE },
125 { SYS_RES_MEMORY, 1, RF_ACTIVE },
126 { SYS_RES_MEMORY, 2, RF_ACTIVE },
127 { SYS_RES_MEMORY, 3, RF_ACTIVE },
128 { SYS_RES_IRQ, 0, RF_ACTIVE },
129 { SYS_RES_IRQ, 1, RF_ACTIVE },
130 { SYS_RES_IRQ, 2, RF_ACTIVE },
131 { SYS_RES_IRQ, 3, RF_ACTIVE },
132 { -1, 0 }
133};
134
135static struct resource_spec pad_spec_5420[] = {
136 { SYS_RES_MEMORY, 0, RF_ACTIVE },
137 { SYS_RES_MEMORY, 1, RF_ACTIVE },
138 { SYS_RES_MEMORY, 2, RF_ACTIVE },
139 { SYS_RES_MEMORY, 3, RF_ACTIVE },
140 { SYS_RES_MEMORY, 4, RF_ACTIVE },
141 { SYS_RES_IRQ, 0, RF_ACTIVE },
142 { SYS_RES_IRQ, 1, RF_ACTIVE },
143 { SYS_RES_IRQ, 2, RF_ACTIVE },
144 { SYS_RES_IRQ, 3, RF_ACTIVE },
145 { SYS_RES_IRQ, 4, RF_ACTIVE },
146 { -1, 0 }
147};
148
149static struct ofw_compat_data compat_data[] = {
150 {"samsung,exynos5420-padctrl", EXYNOS5420},
151 {"samsung,exynos5250-padctrl", EXYNOS5250},
152 {NULL, 0}
153};
154
155struct pad_intr {
156 uint32_t enabled;
157 void (*ih) (void *);
158 void *ih_user;
159};
160
161static struct pad_intr intr_map[MAX_NGPIO];
162
163struct interrupt_entry {
164 int gpio_number;
165 char *combiner_source_name;
166};
167
168struct interrupt_entry interrupt_table_5250[N_EXT_INTS] = {
169 { 147, "EINT[15]" },
170 { 146, "EINT[14]" },
171 { 145, "EINT[13]" },
172 { 144, "EINT[12]" },
173 { 143, "EINT[11]" },
174 { 142, "EINT[10]" },
175 { 141, "EINT[9]" },
176 { 140, "EINT[8]" },
177 { 139, "EINT[7]" },
178 { 138, "EINT[6]" },
179 { 137, "EINT[5]" },
180 { 136, "EINT[4]" },
181 { 135, "EINT[3]" },
182 { 134, "EINT[2]" },
183 { 133, "EINT[1]" },
184 { 132, "EINT[0]" },
185};
186
187struct interrupt_entry interrupt_table_5420[N_EXT_INTS] = {
188 { 23, "EINT[15]" },
189 { 22, "EINT[14]" },
190 { 21, "EINT[13]" },
191 { 20, "EINT[12]" },
192 { 19, "EINT[11]" },
193 { 18, "EINT[10]" },
194 { 17, "EINT[9]" },
195 { 16, "EINT[8]" },
196 { 15, "EINT[7]" },
197 { 14, "EINT[6]" },
198 { 13, "EINT[5]" },
199 { 12, "EINT[4]" },
200 { 11, "EINT[3]" },
201 { 10, "EINT[2]" },
202 { 9, "EINT[1]" },
203 { 8, "EINT[0]" },
204};
205
206/*
207 * 253 multi-functional input/output ports
208 */
209
210static struct gpio_bank gpio_map_5250[] = {
211 /* first 132 gpio */
212 { "gpa0", 0, 0x000, 8, 0x700, 0x800, 0x900, 0xA00 },
213 { "gpa1", 0, 0x020, 6, 0x704, 0x808, 0x904, 0xA04 },
214 { "gpa2", 0, 0x040, 8, 0x708, 0x810, 0x908, 0xA08 },
215 { "gpb0", 0, 0x060, 5, 0x70C, 0x818, 0x90C, 0xA0C },
216 { "gpb1", 0, 0x080, 5, 0x710, 0x820, 0x910, 0xA10 },
217 { "gpb2", 0, 0x0A0, 4, 0x714, 0x828, 0x914, 0xA14 },
218 { "gpb3", 0, 0x0C0, 4, 0x718, 0x830, 0x918, 0xA18 },
219 { "gpc0", 0, 0x0E0, 7, 0x71C, 0x838, 0x91C, 0xA1C },
220 { "gpc1", 0, 0x100, 4, 0x720, 0x840, 0x920, 0xA20 },
221 { "gpc2", 0, 0x120, 7, 0x724, 0x848, 0x924, 0xA24 },
222 { "gpc3", 0, 0x140, 7, 0x728, 0x850, 0x928, 0xA28 },
223 { "gpd0", 0, 0x160, 4, 0x72C, 0x858, 0x92C, 0xA2C },
224 { "gpd1", 0, 0x180, 8, 0x730, 0x860, 0x930, 0xA30 },
225 { "gpy0", 0, 0x1A0, 6, 0, 0, 0, 0 },
226 { "gpy1", 0, 0x1C0, 4, 0, 0, 0, 0 },
227 { "gpy2", 0, 0x1E0, 6, 0, 0, 0, 0 },
228 { "gpy3", 0, 0x200, 8, 0, 0, 0, 0 },
229 { "gpy4", 0, 0x220, 8, 0, 0, 0, 0 },
230 { "gpy5", 0, 0x240, 8, 0, 0, 0, 0 },
231 { "gpy6", 0, 0x260, 8, 0, 0, 0, 0 },
232 { "gpc4", 0, 0x2E0, 7, 0x734, 0x868, 0x934, 0xA34 },
233
234 /* next 32 */
235 { "gpx0", 0, 0xC00, 8, 0xE00, 0xE80, 0xF00, 0xF40 },
236 { "gpx1", 0, 0xC20, 8, 0xE04, 0xE88, 0xF04, 0xF44 },
237 { "gpx2", 0, 0xC40, 8, 0xE08, 0xE90, 0xF08, 0xF48 },
238 { "gpx3", 0, 0xC60, 8, 0xE0C, 0xE98, 0xF0C, 0xF4C },
239
240 { "gpe0", 1, 0x000, 8, 0x700, 0x800, 0x900, 0xA00 },
241 { "gpe1", 1, 0x020, 2, 0x704, 0x808, 0x904, 0xA04 },
242 { "gpf0", 1, 0x040, 4, 0x708, 0x810, 0x908, 0xA08 },
243 { "gpf1", 1, 0x060, 4, 0x70C, 0x818, 0x90C, 0xA0C },
244 { "gpg0", 1, 0x080, 8, 0x710, 0x820, 0x910, 0xA10 },
245 { "gpg1", 1, 0x0A0, 8, 0x714, 0x828, 0x914, 0xA14 },
246 { "gpg2", 1, 0x0C0, 2, 0x718, 0x830, 0x918, 0xA18 },
247 { "gph0", 1, 0x0E0, 4, 0x71C, 0x838, 0x91C, 0xA1C },
248 { "gph1", 1, 0x100, 8, 0x720, 0x840, 0x920, 0xA20 },
249
250 { "gpv0", 2, 0x000, 8, 0x700, 0x800, 0x900, 0xA00 },
251 { "gpv1", 2, 0x020, 8, 0x704, 0x808, 0x904, 0xA04 },
252 { "gpv2", 2, 0x060, 8, 0x708, 0x810, 0x908, 0xA08 },
253 { "gpv3", 2, 0x080, 8, 0x70C, 0x818, 0x90C, 0xA0C },
254 { "gpv4", 2, 0x0C0, 2, 0x710, 0x820, 0x910, 0xA10 },
255
256 { "gpz", 3, 0x000, 7, 0x700, 0x800, 0x900, 0xA00 },
257
258 { NULL, -1, -1, -1, -1, -1, -1, -1 },
259};
260
261static struct gpio_bank gpio_map_5420[] = {
262 /* First 40 */
263 { "gpy7", 0, 0x000, 8, 0x700, 0x800, 0x900, 0xA00 },
264 { "gpx0", 0, 0xC00, 8, 0x704, 0xE80, 0xF00, 0xF40 },
265 { "gpx1", 0, 0xC20, 8, 0x708, 0xE88, 0xF04, 0xF44 },
266 { "gpx2", 0, 0xC40, 8, 0x70C, 0xE90, 0xF08, 0xF48 },
267 { "gpx3", 0, 0xC60, 8, 0x710, 0xE98, 0xF0C, 0xF4C },
268
269 /* Next 85 */
270 { "gpc0", 1, 0x000, 8, 0x700, 0x800, 0x900, 0xA00 },
271 { "gpc1", 1, 0x020, 8, 0x704, 0x808, 0x904, 0xA04 },
272 { "gpc2", 1, 0x040, 7, 0x708, 0x810, 0x908, 0xA08 },
273 { "gpc3", 1, 0x060, 4, 0x70C, 0x818, 0x90C, 0xA0C },
274 { "gpc4", 1, 0x080, 2, 0x710, 0x820, 0x910, 0xA10 },
275 { "gpd1", 1, 0x0A0, 8, 0x714, 0x828, 0x914, 0xA14 },
276 { "gpy0", 1, 0x0C0, 6, 0x718, 0x830, 0x918, 0xA18 },
277 { "gpy1", 1, 0x0E0, 4, 0x71C, 0x838, 0x91C, 0xA1C },
278 { "gpy2", 1, 0x100, 6, 0x720, 0x840, 0x920, 0xA20 },
279 { "gpy3", 1, 0x120, 8, 0x724, 0x848, 0x924, 0xA24 },
280 { "gpy4", 1, 0x140, 8, 0x728, 0x850, 0x928, 0xA28 },
281 { "gpy5", 1, 0x160, 8, 0x72C, 0x858, 0x92C, 0xA2C },
282 { "gpy6", 1, 0x180, 8, 0x730, 0x860, 0x930, 0xA30 },
283
284 /* Next 46 */
285 { "gpe0", 2, 0x000, 8, 0x700, 0x800, 0x900, 0xA00 },
286 { "gpe1", 2, 0x020, 2, 0x704, 0x808, 0x904, 0xA04 },
287 { "gpf0", 2, 0x040, 6, 0x708, 0x810, 0x908, 0xA08 },
288 { "gpf1", 2, 0x060, 8, 0x70C, 0x818, 0x90C, 0xA0C },
289 { "gpg0", 2, 0x080, 8, 0x710, 0x820, 0x910, 0xA10 },
290 { "gpg1", 2, 0x0A0, 8, 0x714, 0x828, 0x914, 0xA14 },
291 { "gpg2", 2, 0x0C0, 2, 0x718, 0x830, 0x918, 0xA18 },
292 { "gpj4", 2, 0x0E0, 4, 0x71C, 0x838, 0x91C, 0xA1C },
293
294 /* Next 54 */
295 { "gpa0", 3, 0x000, 8, 0x700, 0x800, 0x900, 0xA00 },
296 { "gpa1", 3, 0x020, 6, 0x704, 0x808, 0x904, 0xA04 },
297 { "gpa2", 3, 0x040, 8, 0x708, 0x810, 0x908, 0xA08 },
298 { "gpb0", 3, 0x060, 5, 0x70C, 0x818, 0x90C, 0xA0C },
299 { "gpb1", 3, 0x080, 5, 0x710, 0x820, 0x910, 0xA10 },
300 { "gpb2", 3, 0x0A0, 4, 0x714, 0x828, 0x914, 0xA14 },
301 { "gpb3", 3, 0x0C0, 8, 0x718, 0x830, 0x918, 0xA18 },
302 { "gpb4", 3, 0x0E0, 2, 0x71C, 0x838, 0x91C, 0xA1C },
303 { "gph0", 3, 0x100, 8, 0x720, 0x840, 0x920, 0xA20 },
304
305 /* Last 7 */
306 { "gpz", 4, 0x000, 7, 0x700, 0x800, 0x900, 0xA00 },
307
308 { NULL, -1, -1, -1, -1, -1, -1, -1 },
309};
310
311static int
312get_bank(struct pad_softc *sc, int gpio_number,
313 struct gpio_bank *bank, int *pin_shift)
314{
315 int ngpio;
316 int i;
317 int n;
318
319 n = 0;
320 for (i = 0; sc->gpio_map[i].ngpio != -1; i++) {
321 ngpio = sc->gpio_map[i].ngpio;
322
323 if ((n + ngpio) > gpio_number) {
324 *bank = sc->gpio_map[i];
325 *pin_shift = (gpio_number - n);
326 return (0);
327 };
328
329 n += ngpio;
330 };
331
332 return (-1);
333}
334
335static int
336port_intr(void *arg)
337{
338 struct port_softc *sc;
339
340 sc = arg;
341
342 return (FILTER_HANDLED);
343}
344
345static void
346ext_intr(void *arg)
347{
348 struct pad_softc *sc;
349 void (*ih) (void *);
350 void *ih_user;
351 int ngpio;
352 int found;
353 int reg;
354 int i,j;
355 int n,k;
356
357 sc = arg;
358
359 n = 0;
360 for (i = 0; sc->gpio_map[i].ngpio != -1; i++) {
361 found = 0;
362 ngpio = sc->gpio_map[i].ngpio;
363
364 if (sc->gpio_map[i].pend == 0) {
365 n += ngpio;
366 continue;
367 }
368
369 reg = READ4(sc, sc->gpio_map[i].port, sc->gpio_map[i].pend);
370
371 for (j = 0; j < ngpio; j++) {
372 if (reg & (1 << j)) {
373 found = 1;
374
375 k = (n + j);
376 if (intr_map[k].enabled == 1) {
377 ih = intr_map[k].ih;
378 ih_user = intr_map[k].ih_user;
379 ih(ih_user);
380 }
381 }
382 }
383
384 if (found) {
385 /* ACK */
386 WRITE4(sc, sc->gpio_map[i].port, sc->gpio_map[i].pend, reg);
387 }
388
389 n += ngpio;
390 }
391}
392
393int
394pad_setup_intr(int gpio_number, void (*ih)(void *), void *ih_user)
395{
396 struct interrupt_entry *entry;
397 struct pad_intr *pad_irq;
398 struct gpio_bank bank;
399 struct pad_softc *sc;
400 int pin_shift;
401 int reg;
402 int i;
403
404 sc = gpio_sc;
405
406 if (sc == NULL) {
407 device_printf(sc->dev, "Error: pad is not attached\n");
408 return (-1);
409 }
410
411 if (get_bank(sc, gpio_number, &bank, &pin_shift) != 0)
412 return (-1);
413
414 entry = NULL;
415 for (i = 0; i < N_EXT_INTS; i++)
416 if (sc->interrupt_table[i].gpio_number == gpio_number)
417 entry = &(sc->interrupt_table[i]);
418
419 if (entry == NULL) {
420 device_printf(sc->dev, "Cant find interrupt source for %d\n",
421 gpio_number);
422 return (-1);
423 }
424
425#if 0
426 printf("Request interrupt name %s\n", entry->combiner_source_name);
427#endif
428
429 pad_irq = &intr_map[gpio_number];
430 pad_irq->enabled = 1;
431 pad_irq->ih = ih;
432 pad_irq->ih_user = ih_user;
433
434 /* Setup port as external interrupt source */
435 reg = READ4(sc, bank.port, bank.con);
436 reg |= (0xf << (pin_shift * 4));
437#if 0
438 printf("writing 0x%08x to 0x%08x\n", reg, bank.con);
439#endif
440 WRITE4(sc, bank.port, bank.con, reg);
441
442 /*
443 * Configure interrupt pin
444 *
445 * 0x0 = Sets Low level
446 * 0x1 = Sets High level
447 * 0x2 = Triggers Falling edge
448 * 0x3 = Triggers Rising edge
449 * 0x4 = Triggers Both edge
450 *
451 * TODO: add parameter. For now configure as 0x0
452 */
453 reg = READ4(sc, bank.port, bank.ext_con);
454 reg &= ~(0x7 << (pin_shift * 4));
455 WRITE4(sc, bank.port, bank.ext_con, reg);
456
457 /* Unmask */
458 reg = READ4(sc, bank.port, bank.mask);
459 reg &= ~(1 << pin_shift);
460 WRITE4(sc, bank.port, bank.mask, reg);
461
462 combiner_setup_intr(entry->combiner_source_name, ext_intr, sc);
463
464 return (0);
465}
466
467static int
468pad_probe(device_t dev)
469{
470
471 if (!ofw_bus_status_okay(dev))
472 return (ENXIO);
473
474 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) {
475 device_set_desc(dev, "Exynos Pad Control");
476 return (BUS_PROBE_DEFAULT);
477 }
478
479 return (ENXIO);
480}
481
482static int
483pad_attach(device_t dev)
484{
485 struct gpio_bank bank;
486 struct pad_softc *sc;
487 int pin_shift;
488 int reg;
489 int i;
490
491 sc = device_get_softc(dev);
492
493 mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
494
495 sc->model = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
496 switch (sc->model) {
497 case EXYNOS5250:
498 sc->pad_spec = pad_spec_5250;
499 sc->gpio_map = gpio_map_5250;
500 sc->interrupt_table = interrupt_table_5250;
501 sc->gpio_npins = 253;
502 sc->nports = 4;
503 break;
504 case EXYNOS5420:
505 sc->pad_spec = pad_spec_5420;
506 sc->gpio_map = gpio_map_5420;
507 sc->interrupt_table = interrupt_table_5420;
508 sc->gpio_npins = 232;
509 sc->nports = 5;
510 break;
511 default:
512 return (-1);
513 };
514
515 if (bus_alloc_resources(dev, sc->pad_spec, sc->res)) {
516 device_printf(dev, "could not allocate resources\n");
517 return (ENXIO);
518 }
519
520 /* Memory interface */
521
522 for (i = 0; i < sc->nports; i++) {
523 sc->bst[i] = rman_get_bustag(sc->res[i]);
524 sc->bsh[i] = rman_get_bushandle(sc->res[i]);
525 };
526
527 sc->dev = dev;
528
529 gpio_sc = sc;
530
531 for (i = 0; i < sc->nports; i++) {
532 if ((bus_setup_intr(dev, sc->res[sc->nports + i],
533 INTR_TYPE_BIO | INTR_MPSAFE, port_intr,
534 NULL, sc, &sc->gpio_ih[i]))) {
535 device_printf(dev,
536 "ERROR: Unable to register interrupt handler\n");
537 return (ENXIO);
538 }
539 };
540
541 for (i = 0; i < sc->gpio_npins; i++) {
542 sc->gpio_pins[i].gp_pin = i;
543 sc->gpio_pins[i].gp_caps = DEFAULT_CAPS;
544
545 if (get_bank(sc, i, &bank, &pin_shift) != 0)
546 continue;
547
548 pin_shift *= 4;
549
550 reg = READ4(sc, bank.port, bank.con);
551 if (reg & (PIN_OUT << pin_shift))
552 sc->gpio_pins[i].gp_flags = GPIO_PIN_OUTPUT;
553 else
554 sc->gpio_pins[i].gp_flags = GPIO_PIN_INPUT;
555
556 /* TODO: add other pin statuses */
557
558 snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME,
559 "pad%d.%d", device_get_unit(dev), i);
560 }
561
562 device_add_child(dev, "gpioc", -1);
563 device_add_child(dev, "gpiobus", -1);
564
565 return (bus_generic_attach(dev));
566}
567
568static int
569pad_pin_max(device_t dev, int *maxpin)
570{
571 struct pad_softc *sc;
572
573 sc = device_get_softc(dev);
574
575 *maxpin = sc->gpio_npins - 1;
576 return (0);
577}
578
579static int
580pad_pin_getname(device_t dev, uint32_t pin, char *name)
581{
582 struct pad_softc *sc;
583 int i;
584
585 sc = device_get_softc(dev);
586 for (i = 0; i < sc->gpio_npins; i++) {
587 if (sc->gpio_pins[i].gp_pin == pin)
588 break;
589 }
590
591 if (i >= sc->gpio_npins)
592 return (EINVAL);
593
594 GPIO_LOCK(sc);
595 memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME);
596 GPIO_UNLOCK(sc);
597
598 return (0);
599}
600
601static int
602pad_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
603{
604 struct pad_softc *sc;
605 int i;
606
607 sc = device_get_softc(dev);
608 for (i = 0; i < sc->gpio_npins; i++) {
609 if (sc->gpio_pins[i].gp_pin == pin)
610 break;
611 }
612
613 if (i >= sc->gpio_npins)
614 return (EINVAL);
615
616 GPIO_LOCK(sc);
617 *caps = sc->gpio_pins[i].gp_caps;
618 GPIO_UNLOCK(sc);
619
620 return (0);
621}
622
623static int
624pad_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
625{
626 struct pad_softc *sc;
627 int i;
628
629 sc = device_get_softc(dev);
630 for (i = 0; i < sc->gpio_npins; i++) {
631 if (sc->gpio_pins[i].gp_pin == pin)
632 break;
633 }
634
635 if (i >= sc->gpio_npins)
636 return (EINVAL);
637
638 GPIO_LOCK(sc);
639 *flags = sc->gpio_pins[i].gp_flags;
640 GPIO_UNLOCK(sc);
641
642 return (0);
643}
644
645static int
646pad_pin_get(device_t dev, uint32_t pin, unsigned int *val)
647{
648 struct gpio_bank bank;
649 struct pad_softc *sc;
650 int pin_shift;
651 int i;
652
653 sc = device_get_softc(dev);
654 for (i = 0; i < sc->gpio_npins; i++) {
655 if (sc->gpio_pins[i].gp_pin == pin)
656 break;
657 }
658
659 if (i >= sc->gpio_npins)
660 return (EINVAL);
661
662 if (get_bank(sc, pin, &bank, &pin_shift) != 0)
663 return (EINVAL);
664
665 GPIO_LOCK(sc);
666 if (READ4(sc, bank.port, bank.con + 0x4) & (1 << pin_shift))
667 *val = 1;
668 else
669 *val = 0;
670 GPIO_UNLOCK(sc);
671
672 return (0);
673}
674
675static int
676pad_pin_toggle(device_t dev, uint32_t pin)
677{
678 struct gpio_bank bank;
679 struct pad_softc *sc;
680 int pin_shift;
681 int reg;
682 int i;
683
684 sc = device_get_softc(dev);
685 for (i = 0; i < sc->gpio_npins; i++) {
686 if (sc->gpio_pins[i].gp_pin == pin)
687 break;
688 }
689
690 if (i >= sc->gpio_npins)
691 return (EINVAL);
692
693 if (get_bank(sc, pin, &bank, &pin_shift) != 0)
694 return (EINVAL);
695
696 GPIO_LOCK(sc);
697 reg = READ4(sc, bank.port, bank.con + 0x4);
698 if (reg & (1 << pin_shift))
699 reg &= ~(1 << pin_shift);
700 else
701 reg |= (1 << pin_shift);
702 WRITE4(sc, bank.port, bank.con + 0x4, reg);
703 GPIO_UNLOCK(sc);
704
705 return (0);
706}
707
708
709static void
710pad_pin_configure(struct pad_softc *sc, struct gpio_pin *pin,
711 unsigned int flags)
712{
713 struct gpio_bank bank;
714 int pin_shift;
715 int reg;
716
717 GPIO_LOCK(sc);
718
719 /*
720 * Manage input/output
721 */
722 if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) {
723 pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT);
724
725 if (get_bank(sc, pin->gp_pin, &bank, &pin_shift) != 0)
726 return;
727
728 pin_shift *= 4;
729
730#if 0
731 printf("bank is 0x%08x pin_shift %d\n", bank.con, pin_shift);
732#endif
733
734 if (flags & GPIO_PIN_OUTPUT) {
735 pin->gp_flags |= GPIO_PIN_OUTPUT;
736 reg = READ4(sc, bank.port, bank.con);
737 reg &= ~(0xf << pin_shift);
738 reg |= (PIN_OUT << pin_shift);
739 WRITE4(sc, bank.port, bank.con, reg);
740 } else {
741 pin->gp_flags |= GPIO_PIN_INPUT;
742 reg = READ4(sc, bank.port, bank.con);
743 reg &= ~(0xf << pin_shift);
744 WRITE4(sc, bank.port, bank.con, reg);
745 }
746 }
747
748 GPIO_UNLOCK(sc);
749}
750
751
752static int
753pad_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
754{
755 struct pad_softc *sc;
756 int i;
757
758 sc = device_get_softc(dev);
759 for (i = 0; i < sc->gpio_npins; i++) {
760 if (sc->gpio_pins[i].gp_pin == pin)
761 break;
762 }
763
764 if (i >= sc->gpio_npins)
765 return (EINVAL);
766
34
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/bus.h>
38#include <sys/kernel.h>
39#include <sys/module.h>
40#include <sys/malloc.h>
41#include <sys/rman.h>
42#include <sys/timeet.h>
43#include <sys/timetc.h>
44#include <sys/watchdog.h>
45#include <sys/mutex.h>
46#include <sys/gpio.h>
47
48#include <dev/ofw/openfirm.h>
49#include <dev/ofw/ofw_bus.h>
50#include <dev/ofw/ofw_bus_subr.h>
51
52#include <machine/bus.h>
53#include <machine/cpu.h>
54#include <machine/intr.h>
55
56#include "gpio_if.h"
57
58#include <arm/samsung/exynos/exynos5_combiner.h>
59#include <arm/samsung/exynos/exynos5_pad.h>
60
61#define GPIO_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
62#define GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
63
64#define DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)
65
66#define MAX_PORTS 5
67#define MAX_NGPIO 253
68
69#define N_EXT_INTS 16
70
71#define EXYNOS5250 1
72#define EXYNOS5420 2
73
74#define PIN_IN 0
75#define PIN_OUT 1
76
77#define READ4(_sc, _port, _reg) \
78 bus_space_read_4(_sc->bst[_port], _sc->bsh[_port], _reg)
79#define WRITE4(_sc, _port, _reg, _val) \
80 bus_space_write_4(_sc->bst[_port], _sc->bsh[_port], _reg, _val)
81
82/*
83 * GPIO interface
84 */
85static int pad_pin_max(device_t, int *);
86static int pad_pin_getcaps(device_t, uint32_t, uint32_t *);
87static int pad_pin_getname(device_t, uint32_t, char *);
88static int pad_pin_getflags(device_t, uint32_t, uint32_t *);
89static int pad_pin_setflags(device_t, uint32_t, uint32_t);
90static int pad_pin_set(device_t, uint32_t, unsigned int);
91static int pad_pin_get(device_t, uint32_t, unsigned int *);
92static int pad_pin_toggle(device_t, uint32_t pin);
93
94struct gpio_bank {
95 char *name;
96 uint32_t port;
97 uint32_t con;
98 uint32_t ngpio;
99 uint32_t ext_con;
100 uint32_t ext_flt_con;
101 uint32_t mask;
102 uint32_t pend;
103};
104
105struct pad_softc {
106 struct resource *res[MAX_PORTS * 2];
107 bus_space_tag_t bst[MAX_PORTS];
108 bus_space_handle_t bsh[MAX_PORTS];
109 struct mtx sc_mtx;
110 int gpio_npins;
111 struct gpio_pin gpio_pins[MAX_NGPIO];
112 void *gpio_ih[MAX_PORTS];
113 device_t dev;
114 int model;
115 struct resource_spec *pad_spec;
116 struct gpio_bank *gpio_map;
117 struct interrupt_entry *interrupt_table;
118 int nports;
119};
120
121struct pad_softc *gpio_sc;
122
123static struct resource_spec pad_spec_5250[] = {
124 { SYS_RES_MEMORY, 0, RF_ACTIVE },
125 { SYS_RES_MEMORY, 1, RF_ACTIVE },
126 { SYS_RES_MEMORY, 2, RF_ACTIVE },
127 { SYS_RES_MEMORY, 3, RF_ACTIVE },
128 { SYS_RES_IRQ, 0, RF_ACTIVE },
129 { SYS_RES_IRQ, 1, RF_ACTIVE },
130 { SYS_RES_IRQ, 2, RF_ACTIVE },
131 { SYS_RES_IRQ, 3, RF_ACTIVE },
132 { -1, 0 }
133};
134
135static struct resource_spec pad_spec_5420[] = {
136 { SYS_RES_MEMORY, 0, RF_ACTIVE },
137 { SYS_RES_MEMORY, 1, RF_ACTIVE },
138 { SYS_RES_MEMORY, 2, RF_ACTIVE },
139 { SYS_RES_MEMORY, 3, RF_ACTIVE },
140 { SYS_RES_MEMORY, 4, RF_ACTIVE },
141 { SYS_RES_IRQ, 0, RF_ACTIVE },
142 { SYS_RES_IRQ, 1, RF_ACTIVE },
143 { SYS_RES_IRQ, 2, RF_ACTIVE },
144 { SYS_RES_IRQ, 3, RF_ACTIVE },
145 { SYS_RES_IRQ, 4, RF_ACTIVE },
146 { -1, 0 }
147};
148
149static struct ofw_compat_data compat_data[] = {
150 {"samsung,exynos5420-padctrl", EXYNOS5420},
151 {"samsung,exynos5250-padctrl", EXYNOS5250},
152 {NULL, 0}
153};
154
155struct pad_intr {
156 uint32_t enabled;
157 void (*ih) (void *);
158 void *ih_user;
159};
160
161static struct pad_intr intr_map[MAX_NGPIO];
162
163struct interrupt_entry {
164 int gpio_number;
165 char *combiner_source_name;
166};
167
168struct interrupt_entry interrupt_table_5250[N_EXT_INTS] = {
169 { 147, "EINT[15]" },
170 { 146, "EINT[14]" },
171 { 145, "EINT[13]" },
172 { 144, "EINT[12]" },
173 { 143, "EINT[11]" },
174 { 142, "EINT[10]" },
175 { 141, "EINT[9]" },
176 { 140, "EINT[8]" },
177 { 139, "EINT[7]" },
178 { 138, "EINT[6]" },
179 { 137, "EINT[5]" },
180 { 136, "EINT[4]" },
181 { 135, "EINT[3]" },
182 { 134, "EINT[2]" },
183 { 133, "EINT[1]" },
184 { 132, "EINT[0]" },
185};
186
187struct interrupt_entry interrupt_table_5420[N_EXT_INTS] = {
188 { 23, "EINT[15]" },
189 { 22, "EINT[14]" },
190 { 21, "EINT[13]" },
191 { 20, "EINT[12]" },
192 { 19, "EINT[11]" },
193 { 18, "EINT[10]" },
194 { 17, "EINT[9]" },
195 { 16, "EINT[8]" },
196 { 15, "EINT[7]" },
197 { 14, "EINT[6]" },
198 { 13, "EINT[5]" },
199 { 12, "EINT[4]" },
200 { 11, "EINT[3]" },
201 { 10, "EINT[2]" },
202 { 9, "EINT[1]" },
203 { 8, "EINT[0]" },
204};
205
206/*
207 * 253 multi-functional input/output ports
208 */
209
210static struct gpio_bank gpio_map_5250[] = {
211 /* first 132 gpio */
212 { "gpa0", 0, 0x000, 8, 0x700, 0x800, 0x900, 0xA00 },
213 { "gpa1", 0, 0x020, 6, 0x704, 0x808, 0x904, 0xA04 },
214 { "gpa2", 0, 0x040, 8, 0x708, 0x810, 0x908, 0xA08 },
215 { "gpb0", 0, 0x060, 5, 0x70C, 0x818, 0x90C, 0xA0C },
216 { "gpb1", 0, 0x080, 5, 0x710, 0x820, 0x910, 0xA10 },
217 { "gpb2", 0, 0x0A0, 4, 0x714, 0x828, 0x914, 0xA14 },
218 { "gpb3", 0, 0x0C0, 4, 0x718, 0x830, 0x918, 0xA18 },
219 { "gpc0", 0, 0x0E0, 7, 0x71C, 0x838, 0x91C, 0xA1C },
220 { "gpc1", 0, 0x100, 4, 0x720, 0x840, 0x920, 0xA20 },
221 { "gpc2", 0, 0x120, 7, 0x724, 0x848, 0x924, 0xA24 },
222 { "gpc3", 0, 0x140, 7, 0x728, 0x850, 0x928, 0xA28 },
223 { "gpd0", 0, 0x160, 4, 0x72C, 0x858, 0x92C, 0xA2C },
224 { "gpd1", 0, 0x180, 8, 0x730, 0x860, 0x930, 0xA30 },
225 { "gpy0", 0, 0x1A0, 6, 0, 0, 0, 0 },
226 { "gpy1", 0, 0x1C0, 4, 0, 0, 0, 0 },
227 { "gpy2", 0, 0x1E0, 6, 0, 0, 0, 0 },
228 { "gpy3", 0, 0x200, 8, 0, 0, 0, 0 },
229 { "gpy4", 0, 0x220, 8, 0, 0, 0, 0 },
230 { "gpy5", 0, 0x240, 8, 0, 0, 0, 0 },
231 { "gpy6", 0, 0x260, 8, 0, 0, 0, 0 },
232 { "gpc4", 0, 0x2E0, 7, 0x734, 0x868, 0x934, 0xA34 },
233
234 /* next 32 */
235 { "gpx0", 0, 0xC00, 8, 0xE00, 0xE80, 0xF00, 0xF40 },
236 { "gpx1", 0, 0xC20, 8, 0xE04, 0xE88, 0xF04, 0xF44 },
237 { "gpx2", 0, 0xC40, 8, 0xE08, 0xE90, 0xF08, 0xF48 },
238 { "gpx3", 0, 0xC60, 8, 0xE0C, 0xE98, 0xF0C, 0xF4C },
239
240 { "gpe0", 1, 0x000, 8, 0x700, 0x800, 0x900, 0xA00 },
241 { "gpe1", 1, 0x020, 2, 0x704, 0x808, 0x904, 0xA04 },
242 { "gpf0", 1, 0x040, 4, 0x708, 0x810, 0x908, 0xA08 },
243 { "gpf1", 1, 0x060, 4, 0x70C, 0x818, 0x90C, 0xA0C },
244 { "gpg0", 1, 0x080, 8, 0x710, 0x820, 0x910, 0xA10 },
245 { "gpg1", 1, 0x0A0, 8, 0x714, 0x828, 0x914, 0xA14 },
246 { "gpg2", 1, 0x0C0, 2, 0x718, 0x830, 0x918, 0xA18 },
247 { "gph0", 1, 0x0E0, 4, 0x71C, 0x838, 0x91C, 0xA1C },
248 { "gph1", 1, 0x100, 8, 0x720, 0x840, 0x920, 0xA20 },
249
250 { "gpv0", 2, 0x000, 8, 0x700, 0x800, 0x900, 0xA00 },
251 { "gpv1", 2, 0x020, 8, 0x704, 0x808, 0x904, 0xA04 },
252 { "gpv2", 2, 0x060, 8, 0x708, 0x810, 0x908, 0xA08 },
253 { "gpv3", 2, 0x080, 8, 0x70C, 0x818, 0x90C, 0xA0C },
254 { "gpv4", 2, 0x0C0, 2, 0x710, 0x820, 0x910, 0xA10 },
255
256 { "gpz", 3, 0x000, 7, 0x700, 0x800, 0x900, 0xA00 },
257
258 { NULL, -1, -1, -1, -1, -1, -1, -1 },
259};
260
261static struct gpio_bank gpio_map_5420[] = {
262 /* First 40 */
263 { "gpy7", 0, 0x000, 8, 0x700, 0x800, 0x900, 0xA00 },
264 { "gpx0", 0, 0xC00, 8, 0x704, 0xE80, 0xF00, 0xF40 },
265 { "gpx1", 0, 0xC20, 8, 0x708, 0xE88, 0xF04, 0xF44 },
266 { "gpx2", 0, 0xC40, 8, 0x70C, 0xE90, 0xF08, 0xF48 },
267 { "gpx3", 0, 0xC60, 8, 0x710, 0xE98, 0xF0C, 0xF4C },
268
269 /* Next 85 */
270 { "gpc0", 1, 0x000, 8, 0x700, 0x800, 0x900, 0xA00 },
271 { "gpc1", 1, 0x020, 8, 0x704, 0x808, 0x904, 0xA04 },
272 { "gpc2", 1, 0x040, 7, 0x708, 0x810, 0x908, 0xA08 },
273 { "gpc3", 1, 0x060, 4, 0x70C, 0x818, 0x90C, 0xA0C },
274 { "gpc4", 1, 0x080, 2, 0x710, 0x820, 0x910, 0xA10 },
275 { "gpd1", 1, 0x0A0, 8, 0x714, 0x828, 0x914, 0xA14 },
276 { "gpy0", 1, 0x0C0, 6, 0x718, 0x830, 0x918, 0xA18 },
277 { "gpy1", 1, 0x0E0, 4, 0x71C, 0x838, 0x91C, 0xA1C },
278 { "gpy2", 1, 0x100, 6, 0x720, 0x840, 0x920, 0xA20 },
279 { "gpy3", 1, 0x120, 8, 0x724, 0x848, 0x924, 0xA24 },
280 { "gpy4", 1, 0x140, 8, 0x728, 0x850, 0x928, 0xA28 },
281 { "gpy5", 1, 0x160, 8, 0x72C, 0x858, 0x92C, 0xA2C },
282 { "gpy6", 1, 0x180, 8, 0x730, 0x860, 0x930, 0xA30 },
283
284 /* Next 46 */
285 { "gpe0", 2, 0x000, 8, 0x700, 0x800, 0x900, 0xA00 },
286 { "gpe1", 2, 0x020, 2, 0x704, 0x808, 0x904, 0xA04 },
287 { "gpf0", 2, 0x040, 6, 0x708, 0x810, 0x908, 0xA08 },
288 { "gpf1", 2, 0x060, 8, 0x70C, 0x818, 0x90C, 0xA0C },
289 { "gpg0", 2, 0x080, 8, 0x710, 0x820, 0x910, 0xA10 },
290 { "gpg1", 2, 0x0A0, 8, 0x714, 0x828, 0x914, 0xA14 },
291 { "gpg2", 2, 0x0C0, 2, 0x718, 0x830, 0x918, 0xA18 },
292 { "gpj4", 2, 0x0E0, 4, 0x71C, 0x838, 0x91C, 0xA1C },
293
294 /* Next 54 */
295 { "gpa0", 3, 0x000, 8, 0x700, 0x800, 0x900, 0xA00 },
296 { "gpa1", 3, 0x020, 6, 0x704, 0x808, 0x904, 0xA04 },
297 { "gpa2", 3, 0x040, 8, 0x708, 0x810, 0x908, 0xA08 },
298 { "gpb0", 3, 0x060, 5, 0x70C, 0x818, 0x90C, 0xA0C },
299 { "gpb1", 3, 0x080, 5, 0x710, 0x820, 0x910, 0xA10 },
300 { "gpb2", 3, 0x0A0, 4, 0x714, 0x828, 0x914, 0xA14 },
301 { "gpb3", 3, 0x0C0, 8, 0x718, 0x830, 0x918, 0xA18 },
302 { "gpb4", 3, 0x0E0, 2, 0x71C, 0x838, 0x91C, 0xA1C },
303 { "gph0", 3, 0x100, 8, 0x720, 0x840, 0x920, 0xA20 },
304
305 /* Last 7 */
306 { "gpz", 4, 0x000, 7, 0x700, 0x800, 0x900, 0xA00 },
307
308 { NULL, -1, -1, -1, -1, -1, -1, -1 },
309};
310
311static int
312get_bank(struct pad_softc *sc, int gpio_number,
313 struct gpio_bank *bank, int *pin_shift)
314{
315 int ngpio;
316 int i;
317 int n;
318
319 n = 0;
320 for (i = 0; sc->gpio_map[i].ngpio != -1; i++) {
321 ngpio = sc->gpio_map[i].ngpio;
322
323 if ((n + ngpio) > gpio_number) {
324 *bank = sc->gpio_map[i];
325 *pin_shift = (gpio_number - n);
326 return (0);
327 };
328
329 n += ngpio;
330 };
331
332 return (-1);
333}
334
335static int
336port_intr(void *arg)
337{
338 struct port_softc *sc;
339
340 sc = arg;
341
342 return (FILTER_HANDLED);
343}
344
345static void
346ext_intr(void *arg)
347{
348 struct pad_softc *sc;
349 void (*ih) (void *);
350 void *ih_user;
351 int ngpio;
352 int found;
353 int reg;
354 int i,j;
355 int n,k;
356
357 sc = arg;
358
359 n = 0;
360 for (i = 0; sc->gpio_map[i].ngpio != -1; i++) {
361 found = 0;
362 ngpio = sc->gpio_map[i].ngpio;
363
364 if (sc->gpio_map[i].pend == 0) {
365 n += ngpio;
366 continue;
367 }
368
369 reg = READ4(sc, sc->gpio_map[i].port, sc->gpio_map[i].pend);
370
371 for (j = 0; j < ngpio; j++) {
372 if (reg & (1 << j)) {
373 found = 1;
374
375 k = (n + j);
376 if (intr_map[k].enabled == 1) {
377 ih = intr_map[k].ih;
378 ih_user = intr_map[k].ih_user;
379 ih(ih_user);
380 }
381 }
382 }
383
384 if (found) {
385 /* ACK */
386 WRITE4(sc, sc->gpio_map[i].port, sc->gpio_map[i].pend, reg);
387 }
388
389 n += ngpio;
390 }
391}
392
393int
394pad_setup_intr(int gpio_number, void (*ih)(void *), void *ih_user)
395{
396 struct interrupt_entry *entry;
397 struct pad_intr *pad_irq;
398 struct gpio_bank bank;
399 struct pad_softc *sc;
400 int pin_shift;
401 int reg;
402 int i;
403
404 sc = gpio_sc;
405
406 if (sc == NULL) {
407 device_printf(sc->dev, "Error: pad is not attached\n");
408 return (-1);
409 }
410
411 if (get_bank(sc, gpio_number, &bank, &pin_shift) != 0)
412 return (-1);
413
414 entry = NULL;
415 for (i = 0; i < N_EXT_INTS; i++)
416 if (sc->interrupt_table[i].gpio_number == gpio_number)
417 entry = &(sc->interrupt_table[i]);
418
419 if (entry == NULL) {
420 device_printf(sc->dev, "Cant find interrupt source for %d\n",
421 gpio_number);
422 return (-1);
423 }
424
425#if 0
426 printf("Request interrupt name %s\n", entry->combiner_source_name);
427#endif
428
429 pad_irq = &intr_map[gpio_number];
430 pad_irq->enabled = 1;
431 pad_irq->ih = ih;
432 pad_irq->ih_user = ih_user;
433
434 /* Setup port as external interrupt source */
435 reg = READ4(sc, bank.port, bank.con);
436 reg |= (0xf << (pin_shift * 4));
437#if 0
438 printf("writing 0x%08x to 0x%08x\n", reg, bank.con);
439#endif
440 WRITE4(sc, bank.port, bank.con, reg);
441
442 /*
443 * Configure interrupt pin
444 *
445 * 0x0 = Sets Low level
446 * 0x1 = Sets High level
447 * 0x2 = Triggers Falling edge
448 * 0x3 = Triggers Rising edge
449 * 0x4 = Triggers Both edge
450 *
451 * TODO: add parameter. For now configure as 0x0
452 */
453 reg = READ4(sc, bank.port, bank.ext_con);
454 reg &= ~(0x7 << (pin_shift * 4));
455 WRITE4(sc, bank.port, bank.ext_con, reg);
456
457 /* Unmask */
458 reg = READ4(sc, bank.port, bank.mask);
459 reg &= ~(1 << pin_shift);
460 WRITE4(sc, bank.port, bank.mask, reg);
461
462 combiner_setup_intr(entry->combiner_source_name, ext_intr, sc);
463
464 return (0);
465}
466
467static int
468pad_probe(device_t dev)
469{
470
471 if (!ofw_bus_status_okay(dev))
472 return (ENXIO);
473
474 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) {
475 device_set_desc(dev, "Exynos Pad Control");
476 return (BUS_PROBE_DEFAULT);
477 }
478
479 return (ENXIO);
480}
481
482static int
483pad_attach(device_t dev)
484{
485 struct gpio_bank bank;
486 struct pad_softc *sc;
487 int pin_shift;
488 int reg;
489 int i;
490
491 sc = device_get_softc(dev);
492
493 mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
494
495 sc->model = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
496 switch (sc->model) {
497 case EXYNOS5250:
498 sc->pad_spec = pad_spec_5250;
499 sc->gpio_map = gpio_map_5250;
500 sc->interrupt_table = interrupt_table_5250;
501 sc->gpio_npins = 253;
502 sc->nports = 4;
503 break;
504 case EXYNOS5420:
505 sc->pad_spec = pad_spec_5420;
506 sc->gpio_map = gpio_map_5420;
507 sc->interrupt_table = interrupt_table_5420;
508 sc->gpio_npins = 232;
509 sc->nports = 5;
510 break;
511 default:
512 return (-1);
513 };
514
515 if (bus_alloc_resources(dev, sc->pad_spec, sc->res)) {
516 device_printf(dev, "could not allocate resources\n");
517 return (ENXIO);
518 }
519
520 /* Memory interface */
521
522 for (i = 0; i < sc->nports; i++) {
523 sc->bst[i] = rman_get_bustag(sc->res[i]);
524 sc->bsh[i] = rman_get_bushandle(sc->res[i]);
525 };
526
527 sc->dev = dev;
528
529 gpio_sc = sc;
530
531 for (i = 0; i < sc->nports; i++) {
532 if ((bus_setup_intr(dev, sc->res[sc->nports + i],
533 INTR_TYPE_BIO | INTR_MPSAFE, port_intr,
534 NULL, sc, &sc->gpio_ih[i]))) {
535 device_printf(dev,
536 "ERROR: Unable to register interrupt handler\n");
537 return (ENXIO);
538 }
539 };
540
541 for (i = 0; i < sc->gpio_npins; i++) {
542 sc->gpio_pins[i].gp_pin = i;
543 sc->gpio_pins[i].gp_caps = DEFAULT_CAPS;
544
545 if (get_bank(sc, i, &bank, &pin_shift) != 0)
546 continue;
547
548 pin_shift *= 4;
549
550 reg = READ4(sc, bank.port, bank.con);
551 if (reg & (PIN_OUT << pin_shift))
552 sc->gpio_pins[i].gp_flags = GPIO_PIN_OUTPUT;
553 else
554 sc->gpio_pins[i].gp_flags = GPIO_PIN_INPUT;
555
556 /* TODO: add other pin statuses */
557
558 snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME,
559 "pad%d.%d", device_get_unit(dev), i);
560 }
561
562 device_add_child(dev, "gpioc", -1);
563 device_add_child(dev, "gpiobus", -1);
564
565 return (bus_generic_attach(dev));
566}
567
568static int
569pad_pin_max(device_t dev, int *maxpin)
570{
571 struct pad_softc *sc;
572
573 sc = device_get_softc(dev);
574
575 *maxpin = sc->gpio_npins - 1;
576 return (0);
577}
578
579static int
580pad_pin_getname(device_t dev, uint32_t pin, char *name)
581{
582 struct pad_softc *sc;
583 int i;
584
585 sc = device_get_softc(dev);
586 for (i = 0; i < sc->gpio_npins; i++) {
587 if (sc->gpio_pins[i].gp_pin == pin)
588 break;
589 }
590
591 if (i >= sc->gpio_npins)
592 return (EINVAL);
593
594 GPIO_LOCK(sc);
595 memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME);
596 GPIO_UNLOCK(sc);
597
598 return (0);
599}
600
601static int
602pad_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
603{
604 struct pad_softc *sc;
605 int i;
606
607 sc = device_get_softc(dev);
608 for (i = 0; i < sc->gpio_npins; i++) {
609 if (sc->gpio_pins[i].gp_pin == pin)
610 break;
611 }
612
613 if (i >= sc->gpio_npins)
614 return (EINVAL);
615
616 GPIO_LOCK(sc);
617 *caps = sc->gpio_pins[i].gp_caps;
618 GPIO_UNLOCK(sc);
619
620 return (0);
621}
622
623static int
624pad_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
625{
626 struct pad_softc *sc;
627 int i;
628
629 sc = device_get_softc(dev);
630 for (i = 0; i < sc->gpio_npins; i++) {
631 if (sc->gpio_pins[i].gp_pin == pin)
632 break;
633 }
634
635 if (i >= sc->gpio_npins)
636 return (EINVAL);
637
638 GPIO_LOCK(sc);
639 *flags = sc->gpio_pins[i].gp_flags;
640 GPIO_UNLOCK(sc);
641
642 return (0);
643}
644
645static int
646pad_pin_get(device_t dev, uint32_t pin, unsigned int *val)
647{
648 struct gpio_bank bank;
649 struct pad_softc *sc;
650 int pin_shift;
651 int i;
652
653 sc = device_get_softc(dev);
654 for (i = 0; i < sc->gpio_npins; i++) {
655 if (sc->gpio_pins[i].gp_pin == pin)
656 break;
657 }
658
659 if (i >= sc->gpio_npins)
660 return (EINVAL);
661
662 if (get_bank(sc, pin, &bank, &pin_shift) != 0)
663 return (EINVAL);
664
665 GPIO_LOCK(sc);
666 if (READ4(sc, bank.port, bank.con + 0x4) & (1 << pin_shift))
667 *val = 1;
668 else
669 *val = 0;
670 GPIO_UNLOCK(sc);
671
672 return (0);
673}
674
675static int
676pad_pin_toggle(device_t dev, uint32_t pin)
677{
678 struct gpio_bank bank;
679 struct pad_softc *sc;
680 int pin_shift;
681 int reg;
682 int i;
683
684 sc = device_get_softc(dev);
685 for (i = 0; i < sc->gpio_npins; i++) {
686 if (sc->gpio_pins[i].gp_pin == pin)
687 break;
688 }
689
690 if (i >= sc->gpio_npins)
691 return (EINVAL);
692
693 if (get_bank(sc, pin, &bank, &pin_shift) != 0)
694 return (EINVAL);
695
696 GPIO_LOCK(sc);
697 reg = READ4(sc, bank.port, bank.con + 0x4);
698 if (reg & (1 << pin_shift))
699 reg &= ~(1 << pin_shift);
700 else
701 reg |= (1 << pin_shift);
702 WRITE4(sc, bank.port, bank.con + 0x4, reg);
703 GPIO_UNLOCK(sc);
704
705 return (0);
706}
707
708
709static void
710pad_pin_configure(struct pad_softc *sc, struct gpio_pin *pin,
711 unsigned int flags)
712{
713 struct gpio_bank bank;
714 int pin_shift;
715 int reg;
716
717 GPIO_LOCK(sc);
718
719 /*
720 * Manage input/output
721 */
722 if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) {
723 pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT);
724
725 if (get_bank(sc, pin->gp_pin, &bank, &pin_shift) != 0)
726 return;
727
728 pin_shift *= 4;
729
730#if 0
731 printf("bank is 0x%08x pin_shift %d\n", bank.con, pin_shift);
732#endif
733
734 if (flags & GPIO_PIN_OUTPUT) {
735 pin->gp_flags |= GPIO_PIN_OUTPUT;
736 reg = READ4(sc, bank.port, bank.con);
737 reg &= ~(0xf << pin_shift);
738 reg |= (PIN_OUT << pin_shift);
739 WRITE4(sc, bank.port, bank.con, reg);
740 } else {
741 pin->gp_flags |= GPIO_PIN_INPUT;
742 reg = READ4(sc, bank.port, bank.con);
743 reg &= ~(0xf << pin_shift);
744 WRITE4(sc, bank.port, bank.con, reg);
745 }
746 }
747
748 GPIO_UNLOCK(sc);
749}
750
751
752static int
753pad_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
754{
755 struct pad_softc *sc;
756 int i;
757
758 sc = device_get_softc(dev);
759 for (i = 0; i < sc->gpio_npins; i++) {
760 if (sc->gpio_pins[i].gp_pin == pin)
761 break;
762 }
763
764 if (i >= sc->gpio_npins)
765 return (EINVAL);
766
767 /* Check for unwanted flags. */
768 if ((flags & sc->gpio_pins[i].gp_caps) != flags)
769 return (EINVAL);
770
771 /* Can't mix input/output together */
772 if ((flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) ==
773 (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT))
774 return (EINVAL);
775
776 pad_pin_configure(sc, &sc->gpio_pins[i], flags);
777
778 return (0);
779}
780
781static int
782pad_pin_set(device_t dev, uint32_t pin, unsigned int value)
783{
784 struct pad_softc *sc;
785 struct gpio_bank bank;
786 int pin_shift;
787 int reg;
788 int i;
789
790 sc = device_get_softc(dev);
791 for (i = 0; i < sc->gpio_npins; i++) {
792 if (sc->gpio_pins[i].gp_pin == pin)
793 break;
794 }
795
796 if (i >= sc->gpio_npins)
797 return (EINVAL);
798
799 if (get_bank(sc, pin, &bank, &pin_shift) != 0)
800 return (EINVAL);
801
802 GPIO_LOCK(sc);
803 reg = READ4(sc, bank.port, bank.con + 0x4);
804 reg &= ~(PIN_OUT << pin_shift);
805 if (value)
806 reg |= (PIN_OUT << pin_shift);
807 WRITE4(sc, bank.port, bank.con + 0x4, reg);
808 GPIO_UNLOCK(sc);
809
810 return (0);
811}
812
813static device_method_t pad_methods[] = {
814 DEVMETHOD(device_probe, pad_probe),
815 DEVMETHOD(device_attach, pad_attach),
816
817 /* GPIO protocol */
818 DEVMETHOD(gpio_pin_max, pad_pin_max),
819 DEVMETHOD(gpio_pin_getname, pad_pin_getname),
820 DEVMETHOD(gpio_pin_getcaps, pad_pin_getcaps),
821 DEVMETHOD(gpio_pin_getflags, pad_pin_getflags),
822 DEVMETHOD(gpio_pin_get, pad_pin_get),
823 DEVMETHOD(gpio_pin_toggle, pad_pin_toggle),
824 DEVMETHOD(gpio_pin_setflags, pad_pin_setflags),
825 DEVMETHOD(gpio_pin_set, pad_pin_set),
826 { 0, 0 }
827};
828
829static driver_t pad_driver = {
830 "gpio",
831 pad_methods,
832 sizeof(struct pad_softc),
833};
834
835static devclass_t pad_devclass;
836
837DRIVER_MODULE(pad, simplebus, pad_driver, pad_devclass, 0, 0);
767 pad_pin_configure(sc, &sc->gpio_pins[i], flags);
768
769 return (0);
770}
771
772static int
773pad_pin_set(device_t dev, uint32_t pin, unsigned int value)
774{
775 struct pad_softc *sc;
776 struct gpio_bank bank;
777 int pin_shift;
778 int reg;
779 int i;
780
781 sc = device_get_softc(dev);
782 for (i = 0; i < sc->gpio_npins; i++) {
783 if (sc->gpio_pins[i].gp_pin == pin)
784 break;
785 }
786
787 if (i >= sc->gpio_npins)
788 return (EINVAL);
789
790 if (get_bank(sc, pin, &bank, &pin_shift) != 0)
791 return (EINVAL);
792
793 GPIO_LOCK(sc);
794 reg = READ4(sc, bank.port, bank.con + 0x4);
795 reg &= ~(PIN_OUT << pin_shift);
796 if (value)
797 reg |= (PIN_OUT << pin_shift);
798 WRITE4(sc, bank.port, bank.con + 0x4, reg);
799 GPIO_UNLOCK(sc);
800
801 return (0);
802}
803
804static device_method_t pad_methods[] = {
805 DEVMETHOD(device_probe, pad_probe),
806 DEVMETHOD(device_attach, pad_attach),
807
808 /* GPIO protocol */
809 DEVMETHOD(gpio_pin_max, pad_pin_max),
810 DEVMETHOD(gpio_pin_getname, pad_pin_getname),
811 DEVMETHOD(gpio_pin_getcaps, pad_pin_getcaps),
812 DEVMETHOD(gpio_pin_getflags, pad_pin_getflags),
813 DEVMETHOD(gpio_pin_get, pad_pin_get),
814 DEVMETHOD(gpio_pin_toggle, pad_pin_toggle),
815 DEVMETHOD(gpio_pin_setflags, pad_pin_setflags),
816 DEVMETHOD(gpio_pin_set, pad_pin_set),
817 { 0, 0 }
818};
819
820static driver_t pad_driver = {
821 "gpio",
822 pad_methods,
823 sizeof(struct pad_softc),
824};
825
826static devclass_t pad_devclass;
827
828DRIVER_MODULE(pad, simplebus, pad_driver, pad_devclass, 0, 0);