]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - sys/arm/samsung/exynos/exynos5_pad.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / sys / arm / samsung / exynos / exynos5_pad.c
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$");
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/fdt/fdt_common.h>
49 #include <dev/ofw/openfirm.h>
50 #include <dev/ofw/ofw_bus.h>
51 #include <dev/ofw/ofw_bus_subr.h>
52
53 #include <machine/bus.h>
54 #include <machine/fdt.h>
55 #include <machine/cpu.h>
56 #include <machine/intr.h>
57
58 #include "gpio_if.h"
59
60 #include <arm/samsung/exynos/exynos5_combiner.h>
61 #include <arm/samsung/exynos/exynos5_pad.h>
62
63 #define GPIO_LOCK(_sc)          mtx_lock(&(_sc)->sc_mtx)
64 #define GPIO_UNLOCK(_sc)        mtx_unlock(&(_sc)->sc_mtx)
65
66 #define DEFAULT_CAPS    (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)
67
68 #define NPORTS  4
69 #define NGRP    40
70 #define NGPIO   253
71 #define NINTS   16
72
73 #define PIN_IN  0
74 #define PIN_OUT 1
75
76 #define READ4(_sc, _port, _reg)                                         \
77         bus_space_read_4(_sc->bst[_port], _sc->bsh[_port], _reg)
78 #define WRITE4(_sc, _port, _reg, _val)                                  \
79         bus_space_write_4(_sc->bst[_port], _sc->bsh[_port], _reg, _val)
80
81 /*
82  * GPIO interface
83  */
84 static int pad_pin_max(device_t, int *);
85 static int pad_pin_getcaps(device_t, uint32_t, uint32_t *);
86 static int pad_pin_getname(device_t, uint32_t, char *);
87 static int pad_pin_getflags(device_t, uint32_t, uint32_t *);
88 static int pad_pin_setflags(device_t, uint32_t, uint32_t);
89 static int pad_pin_set(device_t, uint32_t, unsigned int);
90 static int pad_pin_get(device_t, uint32_t, unsigned int *);
91 static int pad_pin_toggle(device_t, uint32_t pin);
92
93 struct pad_softc {
94         struct resource         *res[NPORTS+4];
95         bus_space_tag_t         bst[NPORTS];
96         bus_space_handle_t      bsh[NPORTS];
97         struct mtx              sc_mtx;
98         int                     gpio_npins;
99         struct gpio_pin         gpio_pins[NGPIO];
100         void                    *gpio_ih[NPORTS+4];
101         device_t                dev;
102 };
103
104 struct pad_softc *gpio_sc;
105
106 static struct resource_spec pad_spec[] = {
107         { SYS_RES_MEMORY,       0,      RF_ACTIVE },
108         { SYS_RES_MEMORY,       1,      RF_ACTIVE },
109         { SYS_RES_MEMORY,       2,      RF_ACTIVE },
110         { SYS_RES_MEMORY,       3,      RF_ACTIVE },
111         { SYS_RES_IRQ,          0,      RF_ACTIVE },
112         { SYS_RES_IRQ,          1,      RF_ACTIVE },
113         { SYS_RES_IRQ,          2,      RF_ACTIVE },
114         { SYS_RES_IRQ,          3,      RF_ACTIVE },
115         { -1, 0 }
116 };
117
118 struct pad_intr {
119         uint32_t        enabled;
120         void            (*ih) (void *);
121         void            *ih_user;
122 };
123
124 static struct pad_intr intr_map[NGPIO];
125
126 struct interrupt_entry {
127         int gpio_number;
128         char *combiner_source_name;
129 };
130
131 struct interrupt_entry interrupt_table[NINTS] = {
132         { 147, "EINT[15]" },
133         { 146, "EINT[14]" },
134         { 145, "EINT[13]" },
135         { 144, "EINT[12]" },
136         { 143, "EINT[11]" },
137         { 142, "EINT[10]" },
138         { 141, "EINT[9]" },
139         { 140, "EINT[8]" },
140         { 139, "EINT[7]" },
141         { 138, "EINT[6]" },
142         { 137, "EINT[5]" },
143         { 136, "EINT[4]" },
144         { 135, "EINT[3]" },
145         { 134, "EINT[2]" },
146         { 133, "EINT[1]" },
147         { 132, "EINT[0]" },
148 };
149
150 struct gpio_bank {
151         char            *name;
152         uint32_t        port;
153         uint32_t        con;
154         uint32_t        ngpio;
155         uint32_t        ext_int_grp;
156         uint32_t        ext_con;
157         uint32_t        ext_flt_con;
158         uint32_t        mask;
159         uint32_t        pend;
160 };
161
162 /*
163  * 253 multi-functional input/output ports
164  */
165
166 static struct gpio_bank gpio_map[] = {
167         /* first 132 gpio */
168         { "gpa0", 0, 0x000, 8,  1, 0x700, 0x800, 0x900, 0xA00 },
169         { "gpa1", 0, 0x020, 6,  2, 0x704, 0x808, 0x904, 0xA04 },
170         { "gpa2", 0, 0x040, 8,  3, 0x708, 0x810, 0x908, 0xA08 },
171         { "gpb0", 0, 0x060, 5,  4, 0x70C, 0x818, 0x90C, 0xA0C },
172         { "gpb1", 0, 0x080, 5,  5, 0x710, 0x820, 0x910, 0xA10 },
173         { "gpb2", 0, 0x0A0, 4,  6, 0x714, 0x828, 0x914, 0xA14 },
174         { "gpb3", 0, 0x0C0, 4,  7, 0x718, 0x830, 0x918, 0xA18 },
175         { "gpc0", 0, 0x0E0, 7,  8, 0x71C, 0x838, 0x91C, 0xA1C },
176         { "gpc1", 0, 0x100, 4,  9, 0x720, 0x840, 0x920, 0xA20 },
177         { "gpc2", 0, 0x120, 7, 10, 0x724, 0x848, 0x924, 0xA24 },
178         { "gpc3", 0, 0x140, 7, 11, 0x728, 0x850, 0x928, 0xA28 },
179         { "gpd0", 0, 0x160, 4, 12, 0x72C, 0x858, 0x92C, 0xA2C },
180         { "gpd1", 0, 0x180, 8, 13, 0x730, 0x860, 0x930, 0xA30 },
181         { "gpy0", 0, 0x1A0, 6,  0,     0,     0,     0,     0 },
182         { "gpy1", 0, 0x1C0, 4,  0,     0,     0,     0,     0 },
183         { "gpy2", 0, 0x1E0, 6,  0,     0,     0,     0,     0 },
184         { "gpy3", 0, 0x200, 8,  0,     0,     0,     0,     0 },
185         { "gpy4", 0, 0x220, 8,  0,     0,     0,     0,     0 },
186         { "gpy5", 0, 0x240, 8,  0,     0,     0,     0,     0 },
187         { "gpy6", 0, 0x260, 8,  0,     0,     0,     0,     0 },
188         { "gpc4", 0, 0x2E0, 7, 30, 0x734, 0x868, 0x934, 0xA34 },
189
190         /* next 32 */
191         { "gpx0", 0, 0xC00, 8, 40, 0xE00, 0xE80, 0xF00, 0xF40 },
192         { "gpx1", 0, 0xC20, 8, 41, 0xE04, 0xE88, 0xF04, 0xF44 },
193         { "gpx2", 0, 0xC40, 8, 42, 0xE08, 0xE90, 0xF08, 0xF48 },
194         { "gpx3", 0, 0xC60, 8, 43, 0xE0C, 0xE98, 0xF0C, 0xF4C },
195
196         { "gpe0", 1, 0x000, 8, 14, 0x700, 0x800, 0x900, 0xA00 },
197         { "gpe1", 1, 0x020, 2, 15, 0x704, 0x808, 0x904, 0xA04 },
198         { "gpf0", 1, 0x040, 4, 16, 0x708, 0x810, 0x908, 0xA08 },
199         { "gpf1", 1, 0x060, 4, 17, 0x70C, 0x818, 0x90C, 0xA0C },
200         { "gpg0", 1, 0x080, 8, 18, 0x710, 0x820, 0x910, 0xA10 },
201         { "gpg1", 1, 0x0A0, 8, 19, 0x714, 0x828, 0x914, 0xA14 },
202         { "gpg2", 1, 0x0C0, 2, 20, 0x718, 0x830, 0x918, 0xA18 },
203         { "gph0", 1, 0x0E0, 4, 21, 0x71C, 0x838, 0x91C, 0xA1C },
204         { "gph1", 1, 0x100, 8, 22, 0x720, 0x840, 0x920, 0xA20 },
205
206         { "gpv0", 2, 0x000, 8, 60, 0x700, 0x800, 0x900, 0xA00 },
207         { "gpv1", 2, 0x020, 8, 61, 0x704, 0x808, 0x904, 0xA04 },
208         { "gpv2", 2, 0x060, 8, 62, 0x708, 0x810, 0x908, 0xA08 },
209         { "gpv3", 2, 0x080, 8, 63, 0x70C, 0x818, 0x90C, 0xA0C },
210         { "gpv4", 2, 0x0C0, 2, 64, 0x710, 0x820, 0x910, 0xA10 },
211
212         { "gpz",  3, 0x000, 7, 50, 0x700, 0x800, 0x900, 0xA00 },
213 };
214
215 static int
216 get_bank(int gpio_number, struct gpio_bank *bank, int *pin_shift)
217 {
218         int ngpio;
219         int i;
220         int n;
221
222         n = 0;
223         for (i = 0; i < NGRP; i++) {
224                 ngpio = gpio_map[i].ngpio;
225
226                 if ((n + ngpio) >= gpio_number) {
227                         *bank = gpio_map[i];
228                         *pin_shift = (gpio_number - n);
229                         return (0);
230                 };
231
232                 n += ngpio;
233         };
234
235         return (-1);
236 }
237
238 static int
239 port_intr(void *arg)
240 {
241         struct port_softc *sc;
242
243         sc = arg;
244
245         return (FILTER_HANDLED);
246 }
247
248 static void
249 ext_intr(void *arg)
250 {
251         struct pad_softc *sc;
252         void (*ih) (void *);
253         void *ih_user;
254         int ngpio;
255         int found;
256         int reg;
257         int i,j;
258         int n,k;
259
260         sc = arg;
261
262         n = 0;
263         for (i = 0; i < NGRP; i++) {
264                 found = 0;
265                 ngpio = gpio_map[i].ngpio;
266
267                 if (gpio_map[i].pend == 0) {
268                         n += ngpio;
269                         continue;
270                 }
271
272                 reg = READ4(sc, gpio_map[i].port, gpio_map[i].pend);
273
274                 for (j = 0; j < ngpio; j++) {
275                         if (reg & (1 << j)) {
276                                 found = 1;
277
278                                 k = (n + j);
279                                 if (intr_map[k].enabled == 1) {
280                                         ih = intr_map[k].ih;
281                                         ih_user = intr_map[k].ih_user;
282                                         ih(ih_user);
283                                 }
284                         }
285                 }
286
287                 if (found) {
288                         /* ACK */
289                         WRITE4(sc, gpio_map[i].port, gpio_map[i].pend, reg);
290                 }
291
292                 n += ngpio;
293         }
294 }
295
296 int
297 pad_setup_intr(int gpio_number, void (*ih)(void *), void *ih_user)
298 {
299         struct interrupt_entry *entry;
300         struct pad_intr *pad_irq;
301         struct gpio_bank bank;
302         struct pad_softc *sc;
303         int pin_shift;
304         int reg;
305         int i;
306
307         sc = gpio_sc;
308
309         if (sc == NULL) {
310                 device_printf(sc->dev, "Error: pad is not attached\n");
311                 return (-1);
312         }
313
314         if (get_bank(gpio_number, &bank, &pin_shift) != 0)
315                 return (-1);
316
317         entry = NULL;
318         for (i = 0; i < NINTS; i++)
319                 if (interrupt_table[i].gpio_number == gpio_number)
320                         entry = &interrupt_table[i];
321
322         if (entry == NULL) {
323                 device_printf(sc->dev, "Cant find interrupt source for %d\n",
324                     gpio_number);
325                 return (-1);
326         }
327
328 #if 0
329         printf("Request interrupt name %s\n", entry->combiner_source_name);
330 #endif
331
332         pad_irq = &intr_map[gpio_number];
333         pad_irq->enabled = 1;
334         pad_irq->ih = ih;
335         pad_irq->ih_user = ih_user;
336
337         /* Setup port as external interrupt source */
338         reg = READ4(sc, bank.port, bank.con);
339         reg |= (0xf << (pin_shift * 4));
340 #if 0
341         printf("writing 0x%08x to 0x%08x\n", reg, bank.con);
342 #endif
343         WRITE4(sc, bank.port, bank.con, reg);
344
345         /*
346          * Configure interrupt pin
347          *
348          * 0x0 = Sets Low level
349          * 0x1 = Sets High level
350          * 0x2 = Triggers Falling edge
351          * 0x3 = Triggers Rising edge
352          * 0x4 = Triggers Both edge
353          *
354          * TODO: add parameter. For now configure as 0x0
355          */
356         reg = READ4(sc, bank.port, bank.ext_con);
357         reg &= ~(0x7 << (pin_shift * 4));
358         WRITE4(sc, bank.port, bank.ext_con, reg);
359
360         /* Unmask */
361         reg = READ4(sc, bank.port, bank.mask);
362         reg &= ~(1 << pin_shift);
363         WRITE4(sc, bank.port, bank.mask, reg);
364
365         combiner_setup_intr(entry->combiner_source_name, ext_intr, sc);
366
367         return (0);
368 }
369
370 static int
371 pad_probe(device_t dev)
372 {
373
374         if (!ofw_bus_status_okay(dev))
375                 return (ENXIO);
376
377         if (!ofw_bus_is_compatible(dev, "exynos,pad"))
378                 return (ENXIO);
379
380         device_set_desc(dev, "Exynos Pad Control");
381         return (BUS_PROBE_DEFAULT);
382 }
383
384 static int
385 pad_attach(device_t dev)
386 {
387         struct gpio_bank bank;
388         struct pad_softc *sc;
389         int pin_shift;
390         int reg;
391         int i;
392
393         sc = device_get_softc(dev);
394         mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
395
396         if (bus_alloc_resources(dev, pad_spec, sc->res)) {
397                 device_printf(dev, "could not allocate resources\n");
398                 return (ENXIO);
399         }
400
401         /* Memory interface */
402
403         for (i = 0; i < NPORTS; i++) {
404                 sc->bst[i] = rman_get_bustag(sc->res[i]);
405                 sc->bsh[i] = rman_get_bushandle(sc->res[i]);
406         };
407
408         sc->dev = dev;
409         sc->gpio_npins = NGPIO;
410
411         gpio_sc = sc;
412
413         for (i = 0; i < NPORTS; i++) {
414                 if ((bus_setup_intr(dev, sc->res[NPORTS + i],
415                             INTR_TYPE_BIO | INTR_MPSAFE, port_intr,
416                             NULL, sc, &sc->gpio_ih[i]))) {
417                         device_printf(dev,
418                             "ERROR: Unable to register interrupt handler\n");
419                         return (ENXIO);
420                 }
421         };
422
423         for (i = 0; i < sc->gpio_npins; i++) {
424                 sc->gpio_pins[i].gp_pin = i;
425                 sc->gpio_pins[i].gp_caps = DEFAULT_CAPS;
426
427                 if (get_bank(i, &bank, &pin_shift) != 0)
428                         continue;
429
430                 pin_shift *= 4;
431
432                 reg = READ4(sc, bank.port, bank.con);
433                 if (reg & (PIN_OUT << pin_shift))
434                         sc->gpio_pins[i].gp_flags = GPIO_PIN_OUTPUT;
435                 else
436                         sc->gpio_pins[i].gp_flags = GPIO_PIN_INPUT;
437
438                 /* TODO: add other pin statuses */
439
440                 snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME,
441                     "pad%d.%d", device_get_unit(dev), i);
442         }
443
444         device_add_child(dev, "gpioc", -1);
445         device_add_child(dev, "gpiobus", -1);
446
447         return (bus_generic_attach(dev));
448 }
449
450 static int
451 pad_pin_max(device_t dev, int *maxpin)
452 {
453
454         *maxpin = NGPIO - 1;
455         return (0);
456 }
457
458 static int
459 pad_pin_getname(device_t dev, uint32_t pin, char *name)
460 {
461         struct pad_softc *sc;
462         int i;
463
464         sc = device_get_softc(dev);
465         for (i = 0; i < sc->gpio_npins; i++) {
466                 if (sc->gpio_pins[i].gp_pin == pin)
467                         break;
468         }
469
470         if (i >= sc->gpio_npins)
471                 return (EINVAL);
472
473         GPIO_LOCK(sc);
474         memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME);
475         GPIO_UNLOCK(sc);
476
477         return (0);
478 }
479
480 static int
481 pad_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
482 {
483         struct pad_softc *sc;
484         int i;
485
486         sc = device_get_softc(dev);
487         for (i = 0; i < sc->gpio_npins; i++) {
488                 if (sc->gpio_pins[i].gp_pin == pin)
489                         break;
490         }
491
492         if (i >= sc->gpio_npins)
493                 return (EINVAL);
494
495         GPIO_LOCK(sc);
496         *caps = sc->gpio_pins[i].gp_caps;
497         GPIO_UNLOCK(sc);
498
499         return (0);
500 }
501
502 static int
503 pad_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
504 {
505         struct pad_softc *sc;
506         int i;
507
508         sc = device_get_softc(dev);
509         for (i = 0; i < sc->gpio_npins; i++) {
510                 if (sc->gpio_pins[i].gp_pin == pin)
511                         break;
512         }
513
514         if (i >= sc->gpio_npins)
515                 return (EINVAL);
516
517         GPIO_LOCK(sc);
518         *flags = sc->gpio_pins[i].gp_flags;
519         GPIO_UNLOCK(sc);
520
521         return (0);
522 }
523
524 static int
525 pad_pin_get(device_t dev, uint32_t pin, unsigned int *val)
526 {
527         struct gpio_bank bank;
528         struct pad_softc *sc;
529         int pin_shift;
530         int i;
531
532         sc = device_get_softc(dev);
533         for (i = 0; i < sc->gpio_npins; i++) {
534                 if (sc->gpio_pins[i].gp_pin == pin)
535                         break;
536         }
537
538         if (i >= sc->gpio_npins)
539                 return (EINVAL);
540
541         if (get_bank(pin, &bank, &pin_shift) != 0)
542                 return (EINVAL);
543
544         GPIO_LOCK(sc);
545         if (READ4(sc, bank.port, bank.con + 0x4) & (1 << pin_shift))
546                 *val = 1;
547         else
548                 *val = 0;
549         GPIO_UNLOCK(sc);
550
551         return (0);
552 }
553
554 static int
555 pad_pin_toggle(device_t dev, uint32_t pin)
556 {
557         struct gpio_bank bank;
558         struct pad_softc *sc;
559         int pin_shift;
560         int reg;
561         int i;
562
563         sc = device_get_softc(dev);
564         for (i = 0; i < sc->gpio_npins; i++) {
565                 if (sc->gpio_pins[i].gp_pin == pin)
566                         break;
567         }
568
569         if (i >= sc->gpio_npins)
570                 return (EINVAL);
571
572         if (get_bank(pin, &bank, &pin_shift) != 0)
573                 return (EINVAL);
574
575         GPIO_LOCK(sc);
576         reg = READ4(sc, bank.port, bank.con + 0x4);
577         if (reg & (1 << pin_shift))
578                 reg &= ~(1 << pin_shift);
579         else
580                 reg |= (1 << pin_shift);
581         WRITE4(sc, bank.port, bank.con + 0x4, reg);
582         GPIO_UNLOCK(sc);
583
584         return (0);
585 }
586
587
588 static void
589 pad_pin_configure(struct pad_softc *sc, struct gpio_pin *pin,
590     unsigned int flags)
591 {
592         struct gpio_bank bank;
593         int pin_shift;
594         int reg;
595
596         GPIO_LOCK(sc);
597
598         /*
599          * Manage input/output
600          */
601         if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) {
602                 pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT);
603
604                 if (get_bank(pin->gp_pin, &bank, &pin_shift) != 0)
605                         return;
606
607                 pin_shift *= 4;
608
609 #if 0
610                 printf("bank is 0x%08x pin_shift %d\n", bank.con, pin_shift);
611 #endif
612
613                 if (flags & GPIO_PIN_OUTPUT) {
614                         pin->gp_flags |= GPIO_PIN_OUTPUT;
615                         reg = READ4(sc, bank.port, bank.con);
616                         reg &= ~(0xf << pin_shift);
617                         reg |= (PIN_OUT << pin_shift);
618                         WRITE4(sc, bank.port, bank.con, reg);
619                 } else {
620                         pin->gp_flags |= GPIO_PIN_INPUT;
621                         reg = READ4(sc, bank.port, bank.con);
622                         reg &= ~(0xf << pin_shift);
623                         WRITE4(sc, bank.port, bank.con, reg);
624                 }
625         }
626
627         GPIO_UNLOCK(sc);
628 }
629
630
631 static int
632 pad_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
633 {
634         struct pad_softc *sc;
635         int i;
636
637         sc = device_get_softc(dev);
638         for (i = 0; i < sc->gpio_npins; i++) {
639                 if (sc->gpio_pins[i].gp_pin == pin)
640                         break;
641         }
642
643         if (i >= sc->gpio_npins)
644                 return (EINVAL);
645
646         pad_pin_configure(sc, &sc->gpio_pins[i], flags);
647
648         return (0);
649 }
650
651 static int
652 pad_pin_set(device_t dev, uint32_t pin, unsigned int value)
653 {
654         struct pad_softc *sc;
655         struct gpio_bank bank;
656         int pin_shift;
657         int reg;
658         int i;
659
660         sc = device_get_softc(dev);
661         for (i = 0; i < sc->gpio_npins; i++) {
662                 if (sc->gpio_pins[i].gp_pin == pin)
663                         break;
664         }
665
666         if (i >= sc->gpio_npins)
667                 return (EINVAL);
668
669         if (get_bank(pin, &bank, &pin_shift) != 0)
670                 return (EINVAL);
671
672         GPIO_LOCK(sc);
673         reg = READ4(sc, bank.port, bank.con + 0x4);
674         reg &= ~(PIN_OUT << pin_shift);
675         if (value)
676                 reg |= (PIN_OUT << pin_shift);
677         WRITE4(sc, bank.port, bank.con + 0x4, reg);
678         GPIO_UNLOCK(sc);
679
680         return (0);
681 }
682
683 static device_method_t pad_methods[] = {
684         DEVMETHOD(device_probe,         pad_probe),
685         DEVMETHOD(device_attach,        pad_attach),
686
687         /* GPIO protocol */
688         DEVMETHOD(gpio_pin_max,         pad_pin_max),
689         DEVMETHOD(gpio_pin_getname,     pad_pin_getname),
690         DEVMETHOD(gpio_pin_getcaps,     pad_pin_getcaps),
691         DEVMETHOD(gpio_pin_getflags,    pad_pin_getflags),
692         DEVMETHOD(gpio_pin_get,         pad_pin_get),
693         DEVMETHOD(gpio_pin_toggle,      pad_pin_toggle),
694         DEVMETHOD(gpio_pin_setflags,    pad_pin_setflags),
695         DEVMETHOD(gpio_pin_set,         pad_pin_set),
696         { 0, 0 }
697 };
698
699 static driver_t pad_driver = {
700         "gpio",
701         pad_methods,
702         sizeof(struct pad_softc),
703 };
704
705 static devclass_t pad_devclass;
706
707 DRIVER_MODULE(pad, simplebus, pad_driver, pad_devclass, 0, 0);