]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/nctgpio/nctgpio.c
Upgrade to OpenSSH 7.3p1.
[FreeBSD/FreeBSD.git] / sys / dev / nctgpio / nctgpio.c
1 /*-
2  * Copyright (c) 2016 Daniel Wyatt <Daniel.Wyatt@gmail.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  * $FreeBSD$
27  *
28  */
29
30 /*
31  * Nuvoton GPIO driver.
32  *
33  */
34
35 #include <sys/cdefs.h>
36
37 #include <sys/param.h>
38 #include <sys/kernel.h>
39 #include <sys/systm.h>
40 #include <sys/bus.h>
41 #include <sys/eventhandler.h>
42 #include <sys/lock.h>
43
44 #include <sys/module.h>
45 #include <sys/rman.h>
46 #include <sys/gpio.h>
47
48 #include <isa/isavar.h>
49
50 #include <machine/bus.h>
51 #include <machine/resource.h>
52
53 #include <dev/gpio/gpiobusvar.h>
54
55 #include "gpio_if.h"
56
57 /*
58  * Global configuration registers (CR).
59  */
60 #define NCT_CR_LDN                      0x07    /* Logical Device Number */
61 #define NCT_CR_CHIP_ID                  0x20    /* Chip ID */
62 #define NCT_CR_CHIP_ID_H                0x20    /* Chip ID (high byte) */
63 #define NCT_CR_CHIP_ID_L                0x21    /* Chip ID (low byte) */
64 #define NCT_CR_OPT_1                    0x26    /* Global Options (1) */
65
66 /* Logical Device Numbers. */
67 #define NCT_LDN_GPIO                    0x07
68 #define NCT_LDN_GPIO_CFG                0x08
69 #define NCT_LDN_GPIO_MODE               0x0f
70
71 /* Logical Device 7 */
72 #define NCT_LD7_GPIO_ENABLE             0x30
73 #define NCT_LD7_GPIO0_IOR               0xe0
74 #define NCT_LD7_GPIO0_DAT               0xe1
75 #define NCT_LD7_GPIO0_INV               0xe2
76 #define NCT_LD7_GPIO0_DST               0xe3
77 #define NCT_LD7_GPIO1_IOR               0xe4
78 #define NCT_LD7_GPIO1_DAT               0xe5
79 #define NCT_LD7_GPIO1_INV               0xe6
80 #define NCT_LD7_GPIO1_DST               0xe7
81
82 /* Logical Device F */
83 #define NCT_LDF_GPIO0_OUTCFG            0xe0
84 #define NCT_LDF_GPIO1_OUTCFG            0xe1
85
86 #define NCT_EXTFUNC_ENTER               0x87
87 #define NCT_EXTFUNC_EXIT                0xaa
88
89 #define NCT_MAX_PIN                     15
90 #define NCT_IS_VALID_PIN(_p)    ((_p) >= 0 && (_p) <= NCT_MAX_PIN)
91
92 #define NCT_PIN_BIT(_p)         (1 << ((_p) % 8))
93
94 #define NCT_GPIO_CAPS   (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | \
95         GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL | \
96         GPIO_PIN_INVIN | GPIO_PIN_INVOUT)
97
98 struct nct_softc {
99         device_t                        dev;
100         device_t                        busdev;
101         struct mtx                      mtx;
102         struct resource                 *portres;
103         int                             rid;
104         struct gpio_pin                 pins[NCT_MAX_PIN + 1];
105 };
106
107 #define GPIO_LOCK_INIT(_sc)     mtx_init(&(_sc)->mtx,           \
108                 device_get_nameunit(dev), NULL, MTX_DEF)
109 #define GPIO_LOCK_DESTROY(_sc)          mtx_destroy(&(_sc)->mtx)
110 #define GPIO_LOCK(_sc)          mtx_lock(&(_sc)->mtx)
111 #define GPIO_UNLOCK(_sc)        mtx_unlock(&(_sc)->mtx)
112 #define GPIO_ASSERT_LOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_OWNED)
113 #define GPIO_ASSERT_UNLOCKED(_sc)       mtx_assert(&(_sc)->mtx, MA_NOTOWNED)
114
115 #define NCT_BARRIER_WRITE(_sc)  \
116         bus_barrier((_sc)->portres, 0, 2, BUS_SPACE_BARRIER_WRITE)
117
118 #define NCT_BARRIER_READ_WRITE(_sc)     \
119         bus_barrier((_sc)->portres, 0, 2, \
120                 BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE)
121
122 static void     ext_cfg_enter(struct nct_softc *);
123 static void     ext_cfg_exit(struct nct_softc *);
124
125 /*
126  * Potential Extended Function Enable Register addresses.
127  * Same address as EFIR.
128  */
129 uint8_t probe_addrs[] = {0x2e, 0x4e};
130
131 struct nuvoton_vendor_device_id {
132         uint16_t                chip_id;
133         const char *            descr;
134 } nct_devs[] = {
135         {
136                 .chip_id        = 0x1061,
137                 .descr          = "Nuvoton NCT5104D",
138         },
139         {
140                 .chip_id        = 0xc452,
141                 .descr          = "Nuvoton NCT5104D (PC-Engines APU)",
142         },
143 };
144
145 static void
146 write_cfg_reg_1(struct nct_softc *sc, uint8_t reg, uint8_t value)
147 {
148         GPIO_ASSERT_LOCKED(sc);
149         bus_write_1(sc->portres, 0, reg);
150         NCT_BARRIER_WRITE(sc);
151         bus_write_1(sc->portres, 1, value);
152         NCT_BARRIER_WRITE(sc);
153 }
154
155 static uint8_t
156 read_cfg_reg_1(struct nct_softc *sc, uint8_t reg)
157 {
158         uint8_t value;
159
160         GPIO_ASSERT_LOCKED(sc);
161         bus_write_1(sc->portres, 0, reg);
162         NCT_BARRIER_READ_WRITE(sc);
163         value = bus_read_1(sc->portres, 1);
164         NCT_BARRIER_READ_WRITE(sc);
165         
166         return (value);
167 }
168
169 static uint16_t
170 read_cfg_reg_2(struct nct_softc *sc, uint8_t reg)
171 {
172         uint16_t value;
173
174         value = read_cfg_reg_1(sc, reg) << 8;
175         value |= read_cfg_reg_1(sc, reg + 1);
176
177         return (value);
178 }
179
180 /*
181  * Enable extended function mode.
182  *
183  */
184 static void
185 ext_cfg_enter(struct nct_softc *sc)
186 {
187         GPIO_ASSERT_LOCKED(sc);
188         bus_write_1(sc->portres, 0, NCT_EXTFUNC_ENTER);
189         NCT_BARRIER_WRITE(sc);
190         bus_write_1(sc->portres, 0, NCT_EXTFUNC_ENTER);
191         NCT_BARRIER_WRITE(sc);
192 }
193
194 /*
195  * Disable extended function mode.
196  *
197  */
198 static void
199 ext_cfg_exit(struct nct_softc *sc)
200 {
201         GPIO_ASSERT_LOCKED(sc);
202         bus_write_1(sc->portres, 0, NCT_EXTFUNC_EXIT);
203         NCT_BARRIER_WRITE(sc);
204 }
205
206 /*
207  * Select a Logical Device.
208  */
209 static void
210 select_ldn(struct nct_softc *sc, uint8_t ldn)
211 {
212         write_cfg_reg_1(sc, NCT_CR_LDN, ldn);
213 }
214
215 /*
216  * Get the GPIO Input/Output register address
217  * for a pin.
218  */
219 static uint8_t
220 nct_ior_addr(uint32_t pin_num)
221 {
222         uint8_t addr;
223
224         addr = NCT_LD7_GPIO0_IOR;
225         if (pin_num > 7)
226                 addr = NCT_LD7_GPIO1_IOR;
227
228         return (addr);
229 }
230
231 /*
232  * Get the GPIO Data register address for a pin.
233  */
234 static uint8_t
235 nct_dat_addr(uint32_t pin_num)
236 {
237         uint8_t addr;
238
239         addr = NCT_LD7_GPIO0_DAT;
240         if (pin_num > 7)
241                 addr = NCT_LD7_GPIO1_DAT;
242
243         return (addr);
244 }
245
246 /*
247  * Get the GPIO Inversion register address
248  * for a pin.
249  */
250 static uint8_t
251 nct_inv_addr(uint32_t pin_num)
252 {
253         uint8_t addr;
254
255         addr = NCT_LD7_GPIO0_INV;
256         if (pin_num > 7)
257                 addr = NCT_LD7_GPIO1_INV;
258
259         return (addr);
260 }
261
262 /*
263  * Get the GPIO Output Configuration/Mode
264  * register address for a pin.
265  */
266 static uint8_t
267 nct_outcfg_addr(uint32_t pin_num)
268 {
269         uint8_t addr;
270
271         addr = NCT_LDF_GPIO0_OUTCFG;
272         if (pin_num > 7)
273                 addr = NCT_LDF_GPIO1_OUTCFG;
274
275         return (addr);
276 }
277
278 /*
279  * Set a pin to output mode.
280  */
281 static void
282 nct_set_pin_is_output(struct nct_softc *sc, uint32_t pin_num)
283 {
284         uint8_t reg;
285         uint8_t ior;
286
287         reg = nct_ior_addr(pin_num);
288         select_ldn(sc, NCT_LDN_GPIO);
289         ior = read_cfg_reg_1(sc, reg);
290         ior &= ~(NCT_PIN_BIT(pin_num));
291         write_cfg_reg_1(sc, reg, ior);
292 }
293
294 /*
295  * Set a pin to input mode.
296  */
297 static void
298 nct_set_pin_is_input(struct nct_softc *sc, uint32_t pin_num)
299 {
300         uint8_t reg;
301         uint8_t ior;
302
303         reg = nct_ior_addr(pin_num);
304         select_ldn(sc, NCT_LDN_GPIO);
305         ior = read_cfg_reg_1(sc, reg);
306         ior |= NCT_PIN_BIT(pin_num);
307         write_cfg_reg_1(sc, reg, ior);
308 }
309
310 /*
311  * Check whether a pin is configured as an input.
312  */
313 static bool
314 nct_pin_is_input(struct nct_softc *sc, uint32_t pin_num)
315 {
316         uint8_t reg;
317         uint8_t ior;
318
319         reg = nct_ior_addr(pin_num);
320         select_ldn(sc, NCT_LDN_GPIO);
321         ior = read_cfg_reg_1(sc, reg);
322
323         return (ior & NCT_PIN_BIT(pin_num));
324 }
325
326 /*
327  * Write a value to an output pin.
328  */
329 static void
330 nct_write_pin(struct nct_softc *sc, uint32_t pin_num, uint8_t data)
331 {
332         uint8_t reg;
333         uint8_t value;
334
335         reg = nct_dat_addr(pin_num);
336         select_ldn(sc, NCT_LDN_GPIO);
337         value = read_cfg_reg_1(sc, reg);
338         if (data)
339                 value |= NCT_PIN_BIT(pin_num);
340         else
341                 value &= ~(NCT_PIN_BIT(pin_num));
342
343         write_cfg_reg_1(sc, reg, value);
344 }
345
346 static bool
347 nct_read_pin(struct nct_softc *sc, uint32_t pin_num)
348 {
349         uint8_t reg;
350
351         reg = nct_dat_addr(pin_num);
352         select_ldn(sc, NCT_LDN_GPIO);
353
354         return (read_cfg_reg_1(sc, reg) & NCT_PIN_BIT(pin_num));
355 }
356
357 static void
358 nct_set_pin_is_inverted(struct nct_softc *sc, uint32_t pin_num)
359 {
360         uint8_t reg;
361         uint8_t inv;
362
363         reg = nct_inv_addr(pin_num);
364         select_ldn(sc, NCT_LDN_GPIO);
365         inv = read_cfg_reg_1(sc, reg);
366         inv |= (NCT_PIN_BIT(pin_num));
367         write_cfg_reg_1(sc, reg, inv);
368 }
369
370 static void
371 nct_set_pin_not_inverted(struct nct_softc *sc, uint32_t pin_num)
372 {
373         uint8_t reg;
374         uint8_t inv;
375
376         reg = nct_inv_addr(pin_num);
377         select_ldn(sc, NCT_LDN_GPIO);
378         inv = read_cfg_reg_1(sc, reg);
379         inv &= ~(NCT_PIN_BIT(pin_num));
380         write_cfg_reg_1(sc, reg, inv);
381 }
382
383 static bool
384 nct_pin_is_inverted(struct nct_softc *sc, uint32_t pin_num)
385 {
386         uint8_t reg;
387         uint8_t inv;
388
389         reg = nct_inv_addr(pin_num);
390         select_ldn(sc, NCT_LDN_GPIO);
391         inv = read_cfg_reg_1(sc, reg);
392
393         return (inv & NCT_PIN_BIT(pin_num));
394 }
395
396 static void
397 nct_set_pin_opendrain(struct nct_softc *sc, uint32_t pin_num)
398 {
399         uint8_t reg;
400         uint8_t outcfg;
401
402         reg = nct_outcfg_addr(pin_num);
403         select_ldn(sc, NCT_LDN_GPIO_MODE);
404         outcfg = read_cfg_reg_1(sc, reg);
405         outcfg |= (NCT_PIN_BIT(pin_num));
406         write_cfg_reg_1(sc, reg, outcfg);
407 }
408
409 static void
410 nct_set_pin_pushpull(struct nct_softc *sc, uint32_t pin_num)
411 {
412         uint8_t reg;
413         uint8_t outcfg;
414
415         reg = nct_outcfg_addr(pin_num);
416         select_ldn(sc, NCT_LDN_GPIO_MODE);
417         outcfg = read_cfg_reg_1(sc, reg);
418         outcfg &= ~(NCT_PIN_BIT(pin_num));
419         write_cfg_reg_1(sc, reg, outcfg);
420 }
421
422 static bool
423 nct_pin_is_opendrain(struct nct_softc *sc, uint32_t pin_num)
424 {
425         uint8_t reg;
426         uint8_t outcfg;
427
428         reg = nct_outcfg_addr(pin_num);
429         select_ldn(sc, NCT_LDN_GPIO_MODE);
430         outcfg = read_cfg_reg_1(sc, reg);
431
432         return (outcfg & NCT_PIN_BIT(pin_num));
433 }
434
435 static void
436 nct_identify(driver_t *driver, device_t parent)
437 {
438         if (device_find_child(parent, driver->name, 0) != NULL)
439                 return;
440
441         BUS_ADD_CHILD(parent, 0, driver->name, 0);
442 }
443
444 static int
445 nct_probe(device_t dev)
446 {
447         int i, j;
448         int rc;
449         struct nct_softc *sc;
450         uint16_t chipid;
451
452         /* Make sure we do not claim some ISA PNP device. */
453         if (isa_get_logicalid(dev) != 0)
454                 return (ENXIO);
455
456         sc = device_get_softc(dev);
457
458         for (i = 0; i < nitems(probe_addrs); i++) {
459                 sc->rid = 0;
460                 sc->portres = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->rid,
461                         probe_addrs[i], probe_addrs[i] + 1, 2, RF_ACTIVE);
462                 if (sc->portres == NULL)
463                         continue;
464
465                 GPIO_LOCK_INIT(sc);
466
467                 GPIO_ASSERT_UNLOCKED(sc);
468                 GPIO_LOCK(sc);
469                 ext_cfg_enter(sc);
470                 chipid = read_cfg_reg_2(sc, NCT_CR_CHIP_ID);
471                 ext_cfg_exit(sc);
472                 GPIO_UNLOCK(sc);
473
474                 GPIO_LOCK_DESTROY(sc);
475
476                 bus_release_resource(dev, SYS_RES_IOPORT, sc->rid, sc->portres);
477                 bus_delete_resource(dev, SYS_RES_IOPORT, sc->rid);
478
479                 for (j = 0; j < nitems(nct_devs); j++) {
480                         if (chipid == nct_devs[j].chip_id) {
481                                 rc = bus_set_resource(dev, SYS_RES_IOPORT, 0, probe_addrs[i], 2);
482                                 if (rc != 0) {
483                                         device_printf(dev, "bus_set_resource failed for address 0x%02X\n", probe_addrs[i]);
484                                         continue;
485                                 }
486                                 device_set_desc(dev, nct_devs[j].descr);
487                                 return (BUS_PROBE_DEFAULT);
488                         }
489                 }
490         }
491         return (ENXIO);
492 }
493
494 static int
495 nct_attach(device_t dev)
496 {
497         struct nct_softc *sc;
498         int i;
499
500         sc = device_get_softc(dev);
501
502         sc->rid = 0;
503         sc->portres = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->rid,
504                 0ul, ~0ul, 2, RF_ACTIVE);
505         if (sc->portres == NULL) {
506                 device_printf(dev, "cannot allocate ioport\n");
507                 return (ENXIO);
508         }
509
510         GPIO_LOCK_INIT(sc);
511
512         GPIO_ASSERT_UNLOCKED(sc);
513         GPIO_LOCK(sc);
514         ext_cfg_enter(sc);
515         select_ldn(sc, NCT_LDN_GPIO);
516         /* Enable gpio0 and gpio1. */
517         write_cfg_reg_1(sc, NCT_LD7_GPIO_ENABLE,
518                 read_cfg_reg_1(sc, NCT_LD7_GPIO_ENABLE) | 0x03);
519
520         for (i = 0; i <= NCT_MAX_PIN; i++) {
521                 struct gpio_pin *pin;
522
523                 pin = &sc->pins[i];
524                 pin->gp_pin = i;
525                 pin->gp_caps = NCT_GPIO_CAPS;
526                 pin->gp_flags = 0;
527
528                 snprintf(pin->gp_name, GPIOMAXNAME, "GPIO%02u", i);
529                 pin->gp_name[GPIOMAXNAME - 1] = '\0';
530
531                 if (nct_pin_is_input(sc, i))
532                         pin->gp_flags |= GPIO_PIN_INPUT;
533                 else
534                         pin->gp_flags |= GPIO_PIN_OUTPUT;
535
536                 if (nct_pin_is_opendrain(sc, i))
537                         pin->gp_flags |= GPIO_PIN_OPENDRAIN;
538                 else
539                         pin->gp_flags |= GPIO_PIN_PUSHPULL;
540
541                 if (nct_pin_is_inverted(sc, i))
542                         pin->gp_flags |= (GPIO_PIN_INVIN | GPIO_PIN_INVOUT);
543         }
544         GPIO_UNLOCK(sc);
545
546         sc->busdev = gpiobus_attach_bus(dev);
547         if (sc->busdev == NULL) {
548                 GPIO_ASSERT_UNLOCKED(sc);
549                 GPIO_LOCK(sc);
550                 ext_cfg_exit(sc);
551                 GPIO_UNLOCK(sc);
552                 bus_release_resource(dev, SYS_RES_IOPORT, sc->rid, sc->portres);
553                 GPIO_LOCK_DESTROY(sc);
554
555                 return (ENXIO);
556         }
557
558         return (0);
559 }
560
561 static int
562 nct_detach(device_t dev)
563 {
564         struct nct_softc *sc;
565
566         sc = device_get_softc(dev);
567         gpiobus_detach_bus(dev);
568
569         GPIO_ASSERT_UNLOCKED(sc);
570         GPIO_LOCK(sc);
571         ext_cfg_exit(sc);
572         GPIO_UNLOCK(sc);
573
574         /* Cleanup resources. */
575         bus_release_resource(dev, SYS_RES_IOPORT, sc->rid, sc->portres);
576
577         GPIO_LOCK_DESTROY(sc);
578
579         return (0);
580 }
581
582 static device_t
583 nct_gpio_get_bus(device_t dev)
584 {
585         struct nct_softc *sc;
586
587         sc = device_get_softc(dev);
588
589         return (sc->busdev);
590 }
591
592 static int
593 nct_gpio_pin_max(device_t dev, int *npins)
594 {
595         *npins = NCT_MAX_PIN;
596
597         return (0);
598 }
599
600 static int
601 nct_gpio_pin_set(device_t dev, uint32_t pin_num, uint32_t pin_value)
602 {
603         struct nct_softc *sc;
604
605         if (!NCT_IS_VALID_PIN(pin_num))
606                 return (EINVAL);
607
608         sc = device_get_softc(dev);
609         GPIO_ASSERT_UNLOCKED(sc);
610         GPIO_LOCK(sc);
611         nct_write_pin(sc, pin_num, pin_value);
612         GPIO_UNLOCK(sc);
613
614         return (0);
615 }
616
617 static int
618 nct_gpio_pin_get(device_t dev, uint32_t pin_num, uint32_t *pin_value)
619 {
620         struct nct_softc *sc;
621
622         if (!NCT_IS_VALID_PIN(pin_num))
623                 return (EINVAL);
624
625         sc = device_get_softc(dev);
626         GPIO_ASSERT_UNLOCKED(sc);
627         GPIO_LOCK(sc);
628         *pin_value = nct_read_pin(sc, pin_num);
629         GPIO_UNLOCK(sc);
630
631         return (0);
632 }
633
634 static int
635 nct_gpio_pin_toggle(device_t dev, uint32_t pin_num)
636 {
637         struct nct_softc *sc;
638
639         if (!NCT_IS_VALID_PIN(pin_num))
640                 return (EINVAL);
641
642         sc = device_get_softc(dev);
643         GPIO_ASSERT_UNLOCKED(sc);
644         GPIO_LOCK(sc);
645         if (nct_read_pin(sc, pin_num))
646                 nct_write_pin(sc, pin_num, 0);
647         else
648                 nct_write_pin(sc, pin_num, 1);
649
650         GPIO_UNLOCK(sc);
651
652         return (0);
653 }
654
655 static int
656 nct_gpio_pin_getcaps(device_t dev, uint32_t pin_num, uint32_t *caps)
657 {
658         struct nct_softc *sc;
659
660         if (!NCT_IS_VALID_PIN(pin_num))
661                 return (EINVAL);
662
663         sc = device_get_softc(dev);
664         GPIO_ASSERT_UNLOCKED(sc);
665         GPIO_LOCK(sc);
666         *caps = sc->pins[pin_num].gp_caps;
667         GPIO_UNLOCK(sc);
668
669         return (0);
670 }
671
672 static int
673 nct_gpio_pin_getflags(device_t dev, uint32_t pin_num, uint32_t *flags)
674 {
675         struct nct_softc *sc;
676
677         if (!NCT_IS_VALID_PIN(pin_num))
678                 return (EINVAL);
679
680         sc = device_get_softc(dev);
681         GPIO_ASSERT_UNLOCKED(sc);
682         GPIO_LOCK(sc);
683         *flags = sc->pins[pin_num].gp_flags;
684         GPIO_UNLOCK(sc);
685
686         return (0);
687 }
688
689 static int
690 nct_gpio_pin_getname(device_t dev, uint32_t pin_num, char *name)
691 {
692         struct nct_softc *sc;
693
694         if (!NCT_IS_VALID_PIN(pin_num))
695                 return (EINVAL);
696
697         sc = device_get_softc(dev);
698         GPIO_ASSERT_UNLOCKED(sc);
699         GPIO_LOCK(sc);
700         memcpy(name, sc->pins[pin_num].gp_name, GPIOMAXNAME);
701         GPIO_UNLOCK(sc);
702
703         return (0);
704 }
705
706 static int
707 nct_gpio_pin_setflags(device_t dev, uint32_t pin_num, uint32_t flags)
708 {
709         struct nct_softc *sc;
710         struct gpio_pin *pin;
711
712         if (!NCT_IS_VALID_PIN(pin_num))
713                 return (EINVAL);
714
715         sc = device_get_softc(dev);
716         pin = &sc->pins[pin_num];
717         if ((flags & pin->gp_caps) != flags)
718                 return (EINVAL);
719
720         GPIO_ASSERT_UNLOCKED(sc);
721         GPIO_LOCK(sc);
722         if (flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) {
723                 if ((flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) ==
724                         (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) {
725                                 GPIO_UNLOCK(sc);
726                                 return (EINVAL);
727                 }
728
729                 if (flags & GPIO_PIN_INPUT)
730                         nct_set_pin_is_input(sc, pin_num);
731                 else
732                         nct_set_pin_is_output(sc, pin_num);
733         }
734
735         if (flags & (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) {
736                 if (flags & GPIO_PIN_INPUT) {
737                         GPIO_UNLOCK(sc);
738                         return (EINVAL);
739                 }
740
741                 if ((flags & (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) ==
742                         (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) {
743                                 GPIO_UNLOCK(sc);
744                                 return (EINVAL);
745                 }
746
747                 if (flags & GPIO_PIN_OPENDRAIN)
748                         nct_set_pin_opendrain(sc, pin_num);
749                 else
750                         nct_set_pin_pushpull(sc, pin_num);
751         }
752
753         if (flags & (GPIO_PIN_INVIN | GPIO_PIN_INVOUT)) {
754                 if ((flags & (GPIO_PIN_INVIN | GPIO_PIN_INVOUT)) !=
755                         (GPIO_PIN_INVIN | GPIO_PIN_INVOUT)) {
756                                 GPIO_UNLOCK(sc);
757                                 return (EINVAL);
758                 }
759
760                 if (flags & GPIO_PIN_INVIN)
761                         nct_set_pin_is_inverted(sc, pin_num);
762                 else
763                         nct_set_pin_not_inverted(sc, pin_num);
764         }
765
766         pin->gp_flags = flags;
767         GPIO_UNLOCK(sc);
768
769         return (0);
770 }
771
772 static device_method_t nct_methods[] = {
773         /* Device interface */
774         DEVMETHOD(device_identify,      nct_identify),
775         DEVMETHOD(device_probe,         nct_probe),
776         DEVMETHOD(device_attach,        nct_attach),
777         DEVMETHOD(device_detach,        nct_detach),
778
779         /* GPIO */
780         DEVMETHOD(gpio_get_bus,                 nct_gpio_get_bus),
781         DEVMETHOD(gpio_pin_max,                 nct_gpio_pin_max),
782         DEVMETHOD(gpio_pin_get,                 nct_gpio_pin_get),
783         DEVMETHOD(gpio_pin_set,                 nct_gpio_pin_set),
784         DEVMETHOD(gpio_pin_toggle,              nct_gpio_pin_toggle),
785         DEVMETHOD(gpio_pin_getname,             nct_gpio_pin_getname),
786         DEVMETHOD(gpio_pin_getcaps,             nct_gpio_pin_getcaps),
787         DEVMETHOD(gpio_pin_getflags,    nct_gpio_pin_getflags),
788         DEVMETHOD(gpio_pin_setflags,    nct_gpio_pin_setflags),
789
790         DEVMETHOD_END
791 };
792
793 static driver_t nct_isa_driver = {
794         "gpio",
795         nct_methods,
796         sizeof(struct nct_softc)
797 };
798
799 static devclass_t nct_devclass;
800
801 DRIVER_MODULE(nctgpio, isa, nct_isa_driver, nct_devclass, NULL, NULL);
802 MODULE_DEPEND(nctgpio, gpiobus, 1, 1, 1);