]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/nctgpio/nctgpio.c
Add liblutok a lightweight C++ API for lua.
[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/gpio.h>
46
47 #include <machine/bus.h>
48
49 #include <dev/gpio/gpiobusvar.h>
50 #include <dev/superio/superio.h>
51
52 #include "gpio_if.h"
53
54 /* Logical Device Numbers. */
55 #define NCT_LDN_GPIO                    0x07
56 #define NCT_LDN_GPIO_MODE               0x0f
57
58 /* Logical Device 7 */
59 #define NCT_LD7_GPIO0_IOR               0xe0
60 #define NCT_LD7_GPIO0_DAT               0xe1
61 #define NCT_LD7_GPIO0_INV               0xe2
62 #define NCT_LD7_GPIO0_DST               0xe3
63 #define NCT_LD7_GPIO1_IOR               0xe4
64 #define NCT_LD7_GPIO1_DAT               0xe5
65 #define NCT_LD7_GPIO1_INV               0xe6
66 #define NCT_LD7_GPIO1_DST               0xe7
67
68 /* Logical Device F */
69 #define NCT_LDF_GPIO0_OUTCFG            0xe0
70 #define NCT_LDF_GPIO1_OUTCFG            0xe1
71
72 /* Direct I/O port access. */
73 #define NCT_IO_GSR                      0
74 #define NCT_IO_IOR                      1
75 #define NCT_IO_DAT                      2
76 #define NCT_IO_INV                      3
77
78 #define NCT_MAX_PIN                     15
79 #define NCT_IS_VALID_PIN(_p)    ((_p) >= 0 && (_p) <= NCT_MAX_PIN)
80
81 #define NCT_PIN_BIT(_p)         (1 << ((_p) & 7))
82
83 #define NCT_GPIO_CAPS   (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | \
84         GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL | \
85         GPIO_PIN_INVIN | GPIO_PIN_INVOUT)
86
87 /*
88  * Note that the values are important.
89  * They match actual register offsets.
90  */
91 typedef enum {
92         REG_IOR = 0,
93         REG_DAT = 1,
94         REG_INV = 2,
95 } reg_t;
96
97 struct nct_softc {
98         device_t                        dev;
99         device_t                        dev_f;
100         device_t                        busdev;
101         struct mtx                      mtx;
102         struct resource                 *iores;
103         int                             iorid;
104         int                             curgrp;
105         struct {
106                 /* direction, 1: pin is input */
107                 uint8_t                 ior[2];
108                 /* output value */
109                 uint8_t                 out[2];
110                 /* whether out is valid */
111                 uint8_t                 out_known[2];
112                 /* inversion, 1: pin is inverted */
113                 uint8_t                 inv[2];
114         }                               cache;
115         struct gpio_pin                 pins[NCT_MAX_PIN + 1];
116 };
117
118 #define GPIO_LOCK_INIT(_sc)     mtx_init(&(_sc)->mtx,           \
119                 device_get_nameunit(dev), NULL, MTX_DEF)
120 #define GPIO_LOCK_DESTROY(_sc)          mtx_destroy(&(_sc)->mtx)
121 #define GPIO_LOCK(_sc)          mtx_lock(&(_sc)->mtx)
122 #define GPIO_UNLOCK(_sc)        mtx_unlock(&(_sc)->mtx)
123 #define GPIO_ASSERT_LOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_OWNED)
124 #define GPIO_ASSERT_UNLOCKED(_sc)       mtx_assert(&(_sc)->mtx, MA_NOTOWNED)
125
126 struct nuvoton_vendor_device_id {
127         uint16_t                chip_id;
128         const char *            descr;
129 } nct_devs[] = {
130         {
131                 .chip_id        = 0x1061,
132                 .descr          = "Nuvoton NCT5104D",
133         },
134         {
135                 .chip_id        = 0xc452,
136                 .descr          = "Nuvoton NCT5104D (PC-Engines APU)",
137         },
138         {
139                 .chip_id        = 0xc453,
140                 .descr          = "Nuvoton NCT5104D (PC-Engines APU3)",
141         },
142 };
143
144 static void
145 nct_io_set_group(struct nct_softc *sc, int group)
146 {
147
148         GPIO_ASSERT_LOCKED(sc);
149         if (group != sc->curgrp) {
150                 bus_write_1(sc->iores, NCT_IO_GSR, group);
151                 sc->curgrp = group;
152         }
153 }
154
155 static uint8_t
156 nct_io_read(struct nct_softc *sc, int group, uint8_t reg)
157 {
158         nct_io_set_group(sc, group);
159         return (bus_read_1(sc->iores, reg));
160 }
161
162 static void
163 nct_io_write(struct nct_softc *sc, int group, uint8_t reg, uint8_t val)
164 {
165         nct_io_set_group(sc, group);
166         return (bus_write_1(sc->iores, reg, val));
167 }
168
169 static uint8_t
170 nct_get_ioreg(struct nct_softc *sc, reg_t reg, int group)
171 {
172         uint8_t ioreg;
173
174         if (sc->iores != NULL)
175                 ioreg = NCT_IO_IOR + reg;
176         else if (group == 0)
177                 ioreg = NCT_LD7_GPIO0_IOR + reg;
178         else
179                 ioreg = NCT_LD7_GPIO1_IOR + reg;
180         return (ioreg);
181 }
182
183 static uint8_t
184 nct_read_reg(struct nct_softc *sc, reg_t reg, int group)
185 {
186         uint8_t ioreg;
187         uint8_t val;
188
189         ioreg = nct_get_ioreg(sc, reg, group);
190         if (sc->iores != NULL)
191                 val = nct_io_read(sc, group, ioreg);
192         else
193                 val = superio_read(sc->dev, ioreg);
194
195         return (val);
196 }
197
198 #define GET_BIT(v, b)   (((v) >> (b)) & 1)
199 static bool
200 nct_get_pin_reg(struct nct_softc *sc, reg_t reg, uint32_t pin_num)
201 {
202         uint8_t bit;
203         uint8_t group;
204         uint8_t val;
205
206         KASSERT(NCT_IS_VALID_PIN(pin_num), ("%s: invalid pin number %d",
207             __func__, pin_num));
208
209         group = pin_num >> 3;
210         bit = pin_num & 7;
211         val = nct_read_reg(sc, reg, group);
212         return (GET_BIT(val, bit));
213 }
214
215 static int
216 nct_get_pin_cache(struct nct_softc *sc, uint32_t pin_num, uint8_t *cache)
217 {
218         uint8_t bit;
219         uint8_t group;
220         uint8_t val;
221
222         KASSERT(NCT_IS_VALID_PIN(pin_num), ("%s: invalid pin number %d",
223             __func__, pin_num));
224
225         group = pin_num >> 3;
226         bit = pin_num & 7;
227         val = cache[group];
228         return (GET_BIT(val, bit));
229 }
230
231 static void
232 nct_write_reg(struct nct_softc *sc, reg_t reg, int group, uint8_t val)
233 {
234         uint8_t ioreg;
235
236         ioreg = nct_get_ioreg(sc, reg, group);
237         if (sc->iores != NULL)
238                 nct_io_write(sc, group, ioreg, val);
239         else
240                 superio_write(sc->dev, ioreg, val);
241 }
242
243 static void
244 nct_set_pin_reg(struct nct_softc *sc, reg_t reg, uint32_t pin_num, bool val)
245 {
246         uint8_t *cache;
247         uint8_t bit;
248         uint8_t bitval;
249         uint8_t group;
250         uint8_t mask;
251
252         KASSERT(NCT_IS_VALID_PIN(pin_num),
253             ("%s: invalid pin number %d", __func__, pin_num));
254         KASSERT(reg == REG_IOR || reg == REG_INV,
255             ("%s: unsupported register %d", __func__, reg));
256
257         group = pin_num >> 3;
258         bit = pin_num & 7;
259         mask = (uint8_t)1 << bit;
260         bitval = (uint8_t)val << bit;
261
262         if (reg == REG_IOR)
263                 cache = &sc->cache.ior[group];
264         else
265                 cache = &sc->cache.inv[group];
266         if ((*cache & mask) == bitval)
267                 return;
268         *cache &= ~mask;
269         *cache |= bitval;
270         nct_write_reg(sc, reg, group, *cache);
271 }
272
273 /*
274  * Set a pin to input (val is true) or output (val is false) mode.
275  */
276 static void
277 nct_set_pin_input(struct nct_softc *sc, uint32_t pin_num, bool val)
278 {
279         nct_set_pin_reg(sc, REG_IOR, pin_num, val);
280 }
281
282 /*
283  * Check whether a pin is configured as an input.
284  */
285 static bool
286 nct_pin_is_input(struct nct_softc *sc, uint32_t pin_num)
287 {
288         return (nct_get_pin_cache(sc, pin_num, sc->cache.ior));
289 }
290
291 /*
292  * Set a pin to inverted (val is true) or normal (val is false) mode.
293  */
294 static void
295 nct_set_pin_inverted(struct nct_softc *sc, uint32_t pin_num, bool val)
296 {
297         nct_set_pin_reg(sc, REG_INV, pin_num, val);
298 }
299
300 static bool
301 nct_pin_is_inverted(struct nct_softc *sc, uint32_t pin_num)
302 {
303         return (nct_get_pin_cache(sc, pin_num, sc->cache.inv));
304 }
305
306 /*
307  * Write a value to an output pin.
308  * NB: the hardware remembers last output value across switching from
309  * output mode to input mode and back.
310  * Writes to a pin in input mode are not allowed here as they cannot
311  * have any effect and would corrupt the output value cache.
312  */
313 static void
314 nct_write_pin(struct nct_softc *sc, uint32_t pin_num, bool val)
315 {
316         uint8_t bit;
317         uint8_t group;
318
319         KASSERT(!nct_pin_is_input(sc, pin_num), ("attempt to write input pin"));
320         group = pin_num >> 3;
321         bit = pin_num & 7;
322         if (GET_BIT(sc->cache.out_known[group], bit) &&
323             GET_BIT(sc->cache.out[group], bit) == val) {
324                 /* The pin is already in requested state. */
325                 return;
326         }
327         sc->cache.out_known[group] |= 1 << bit;
328         if (val)
329                 sc->cache.out[group] |= 1 << bit;
330         else
331                 sc->cache.out[group] &= ~(1 << bit);
332         nct_write_reg(sc, REG_DAT, group, sc->cache.out[group]);
333 }
334
335 /*
336  * NB: state of an input pin cannot be cached, of course.
337  * For an output we can either take the value from the cache if it's valid
338  * or read the state from the hadrware and cache it.
339  */
340 static bool
341 nct_read_pin(struct nct_softc *sc, uint32_t pin_num)
342 {
343         uint8_t bit;
344         uint8_t group;
345         bool val;
346
347         if (nct_pin_is_input(sc, pin_num))
348                 return (nct_get_pin_reg(sc, REG_DAT, pin_num));
349
350         group = pin_num >> 3;
351         bit = pin_num & 7;
352         if (GET_BIT(sc->cache.out_known[group], bit))
353                 return (GET_BIT(sc->cache.out[group], bit));
354
355         val = nct_get_pin_reg(sc, REG_DAT, pin_num);
356         sc->cache.out_known[group] |= 1 << bit;
357         if (val)
358                 sc->cache.out[group] |= 1 << bit;
359         else
360                 sc->cache.out[group] &= ~(1 << bit);
361         return (val);
362 }
363
364 static uint8_t
365 nct_outcfg_addr(uint32_t pin_num)
366 {
367         KASSERT(NCT_IS_VALID_PIN(pin_num), ("%s: invalid pin number %d",
368             __func__, pin_num));
369         if ((pin_num >> 3) == 0)
370                 return (NCT_LDF_GPIO0_OUTCFG);
371         else
372                 return (NCT_LDF_GPIO1_OUTCFG);
373 }
374
375 /*
376  * NB: PP/OD can be configured only via configuration registers.
377  * Also, the registers are in a different logical device.
378  * So, this is a special case.  No caching too.
379  */
380 static void
381 nct_set_pin_opendrain(struct nct_softc *sc, uint32_t pin_num)
382 {
383         uint8_t reg;
384         uint8_t outcfg;
385
386         reg = nct_outcfg_addr(pin_num);
387         outcfg = superio_read(sc->dev_f, reg);
388         outcfg |= NCT_PIN_BIT(pin_num);
389         superio_write(sc->dev_f, reg, outcfg);
390 }
391
392 static void
393 nct_set_pin_pushpull(struct nct_softc *sc, uint32_t pin_num)
394 {
395         uint8_t reg;
396         uint8_t outcfg;
397
398         reg = nct_outcfg_addr(pin_num);
399         outcfg = superio_read(sc->dev_f, reg);
400         outcfg &= ~NCT_PIN_BIT(pin_num);
401         superio_write(sc->dev_f, reg, outcfg);
402 }
403
404 static bool
405 nct_pin_is_opendrain(struct nct_softc *sc, uint32_t pin_num)
406 {
407         uint8_t reg;
408         uint8_t outcfg;
409
410         reg = nct_outcfg_addr(pin_num);
411         outcfg = superio_read(sc->dev_f, reg);
412         return (outcfg & NCT_PIN_BIT(pin_num));
413 }
414
415 static int
416 nct_probe(device_t dev)
417 {
418         int j;
419         uint16_t chipid;
420
421         if (superio_vendor(dev) != SUPERIO_VENDOR_NUVOTON)
422                 return (ENXIO);
423         if (superio_get_type(dev) != SUPERIO_DEV_GPIO)
424                 return (ENXIO);
425
426         /*
427          * There are several GPIO devices, we attach only to one of them
428          * and use the rest without attaching.
429          */
430         if (superio_get_ldn(dev) != NCT_LDN_GPIO)
431                 return (ENXIO);
432
433         chipid = superio_devid(dev);
434         for (j = 0; j < nitems(nct_devs); j++) {
435                 if (chipid == nct_devs[j].chip_id) {
436                         device_set_desc(dev, "Nuvoton GPIO controller");
437                         return (BUS_PROBE_DEFAULT);
438                 }
439         }
440         return (ENXIO);
441 }
442
443 static int
444 nct_attach(device_t dev)
445 {
446         struct nct_softc *sc;
447         device_t dev_8;
448         uint16_t iobase;
449         int err;
450         int i;
451
452         sc = device_get_softc(dev);
453         sc->dev = dev;
454         sc->dev_f = superio_find_dev(device_get_parent(dev), SUPERIO_DEV_GPIO,
455             NCT_LDN_GPIO_MODE);
456         if (sc->dev_f == NULL) {
457                 device_printf(dev, "failed to find LDN F\n");
458                 return (ENXIO);
459         }
460
461         /*
462          * As strange as it may seem, I/O port base is configured in the
463          * Logical Device 8 which is primarily used for WDT, but also plays
464          * a role in GPIO configuration.
465          */
466         iobase = 0;
467         dev_8 = superio_find_dev(device_get_parent(dev), SUPERIO_DEV_WDT, 8);
468         if (dev_8 != NULL)
469                 iobase = superio_get_iobase(dev_8);
470         if (iobase != 0 && iobase != 0xffff) {
471                 sc->curgrp = -1;
472                 sc->iorid = 0;
473                 err = bus_set_resource(dev, SYS_RES_IOPORT, sc->iorid,
474                     iobase, 7);
475                 if (err == 0) {
476                         sc->iores = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
477                             &sc->iorid, RF_ACTIVE);
478                         if (sc->iores == NULL) {
479                                 device_printf(dev, "can't map i/o space, "
480                                     "iobase=0x%04x\n", iobase);
481                         }
482                 } else {
483                         device_printf(dev,
484                             "failed to set io port resource at 0x%x\n", iobase);
485                 }
486         }
487
488         /* Enable gpio0 and gpio1. */
489         superio_dev_enable(dev, 0x03);
490
491         GPIO_LOCK_INIT(sc);
492         GPIO_LOCK(sc);
493
494         sc->cache.inv[0] = nct_read_reg(sc, REG_INV, 0);
495         sc->cache.inv[1] = nct_read_reg(sc, REG_INV, 1);
496         sc->cache.ior[0] = nct_read_reg(sc, REG_IOR, 0);
497         sc->cache.ior[1] = nct_read_reg(sc, REG_IOR, 1);
498
499         /*
500          * Caching input values is meaningless as an input can be changed at any
501          * time by an external agent.  But outputs are controlled by this
502          * driver, so it can cache their state.  Also, the hardware remembers
503          * the output state of a pin when the pin is switched to input mode and
504          * then back to output mode.  So, the cache stays valid.
505          * The only problem is with pins that are in input mode at the attach
506          * time.  For them the output state is not known until it is set by the
507          * driver for the first time.
508          * 'out' and 'out_known' bits form a tri-state output cache:
509          * |-----+-----------+---------|
510          * | out | out_known | cache   |
511          * |-----+-----------+---------|
512          * |   X |         0 | invalid |
513          * |   0 |         1 |       0 |
514          * |   1 |         1 |       1 |
515          * |-----+-----------+---------|
516          */
517         sc->cache.out[0] = nct_read_reg(sc, REG_DAT, 0);
518         sc->cache.out[1] = nct_read_reg(sc, REG_DAT, 1);
519         sc->cache.out_known[0] = ~sc->cache.ior[0];
520         sc->cache.out_known[1] = ~sc->cache.ior[1];
521
522         for (i = 0; i <= NCT_MAX_PIN; i++) {
523                 struct gpio_pin *pin;
524
525                 pin = &sc->pins[i];
526                 pin->gp_pin = i;
527                 pin->gp_caps = NCT_GPIO_CAPS;
528                 pin->gp_flags = 0;
529
530                 snprintf(pin->gp_name, GPIOMAXNAME, "GPIO%02o", i);
531                 pin->gp_name[GPIOMAXNAME - 1] = '\0';
532
533                 if (nct_pin_is_input(sc, i))
534                         pin->gp_flags |= GPIO_PIN_INPUT;
535                 else
536                         pin->gp_flags |= GPIO_PIN_OUTPUT;
537
538                 if (nct_pin_is_opendrain(sc, i))
539                         pin->gp_flags |= GPIO_PIN_OPENDRAIN;
540                 else
541                         pin->gp_flags |= GPIO_PIN_PUSHPULL;
542
543                 if (nct_pin_is_inverted(sc, i))
544                         pin->gp_flags |= (GPIO_PIN_INVIN | GPIO_PIN_INVOUT);
545         }
546         GPIO_UNLOCK(sc);
547
548         sc->busdev = gpiobus_attach_bus(dev);
549         if (sc->busdev == NULL) {
550                 GPIO_LOCK_DESTROY(sc);
551                 return (ENXIO);
552         }
553
554         return (0);
555 }
556
557 static int
558 nct_detach(device_t dev)
559 {
560         struct nct_softc *sc;
561
562         sc = device_get_softc(dev);
563         gpiobus_detach_bus(dev);
564
565         if (sc->iores != NULL)
566                 bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->iores);
567         GPIO_ASSERT_UNLOCKED(sc);
568         GPIO_LOCK_DESTROY(sc);
569
570         return (0);
571 }
572
573 static device_t
574 nct_gpio_get_bus(device_t dev)
575 {
576         struct nct_softc *sc;
577
578         sc = device_get_softc(dev);
579
580         return (sc->busdev);
581 }
582
583 static int
584 nct_gpio_pin_max(device_t dev, int *npins)
585 {
586         *npins = NCT_MAX_PIN;
587
588         return (0);
589 }
590
591 static int
592 nct_gpio_pin_set(device_t dev, uint32_t pin_num, uint32_t pin_value)
593 {
594         struct nct_softc *sc;
595
596         if (!NCT_IS_VALID_PIN(pin_num))
597                 return (EINVAL);
598
599         sc = device_get_softc(dev);
600         GPIO_LOCK(sc);
601         if ((sc->pins[pin_num].gp_flags & GPIO_PIN_OUTPUT) == 0) {
602                 GPIO_UNLOCK(sc);
603                 return (EINVAL);
604         }
605         nct_write_pin(sc, pin_num, pin_value);
606         GPIO_UNLOCK(sc);
607
608         return (0);
609 }
610
611 static int
612 nct_gpio_pin_get(device_t dev, uint32_t pin_num, uint32_t *pin_value)
613 {
614         struct nct_softc *sc;
615
616         if (!NCT_IS_VALID_PIN(pin_num))
617                 return (EINVAL);
618
619         sc = device_get_softc(dev);
620         GPIO_ASSERT_UNLOCKED(sc);
621         GPIO_LOCK(sc);
622         *pin_value = nct_read_pin(sc, pin_num);
623         GPIO_UNLOCK(sc);
624
625         return (0);
626 }
627
628 static int
629 nct_gpio_pin_toggle(device_t dev, uint32_t pin_num)
630 {
631         struct nct_softc *sc;
632
633         if (!NCT_IS_VALID_PIN(pin_num))
634                 return (EINVAL);
635
636         sc = device_get_softc(dev);
637         GPIO_ASSERT_UNLOCKED(sc);
638         GPIO_LOCK(sc);
639         if ((sc->pins[pin_num].gp_flags & GPIO_PIN_OUTPUT) == 0) {
640                 GPIO_UNLOCK(sc);
641                 return (EINVAL);
642         }
643         if (nct_read_pin(sc, pin_num))
644                 nct_write_pin(sc, pin_num, 0);
645         else
646                 nct_write_pin(sc, pin_num, 1);
647
648         GPIO_UNLOCK(sc);
649
650         return (0);
651 }
652
653 static int
654 nct_gpio_pin_getcaps(device_t dev, uint32_t pin_num, uint32_t *caps)
655 {
656         struct nct_softc *sc;
657
658         if (!NCT_IS_VALID_PIN(pin_num))
659                 return (EINVAL);
660
661         sc = device_get_softc(dev);
662         GPIO_ASSERT_UNLOCKED(sc);
663         GPIO_LOCK(sc);
664         *caps = sc->pins[pin_num].gp_caps;
665         GPIO_UNLOCK(sc);
666
667         return (0);
668 }
669
670 static int
671 nct_gpio_pin_getflags(device_t dev, uint32_t pin_num, uint32_t *flags)
672 {
673         struct nct_softc *sc;
674
675         if (!NCT_IS_VALID_PIN(pin_num))
676                 return (EINVAL);
677
678         sc = device_get_softc(dev);
679         GPIO_ASSERT_UNLOCKED(sc);
680         GPIO_LOCK(sc);
681         *flags = sc->pins[pin_num].gp_flags;
682         GPIO_UNLOCK(sc);
683
684         return (0);
685 }
686
687 static int
688 nct_gpio_pin_getname(device_t dev, uint32_t pin_num, char *name)
689 {
690         struct nct_softc *sc;
691
692         if (!NCT_IS_VALID_PIN(pin_num))
693                 return (EINVAL);
694
695         sc = device_get_softc(dev);
696         GPIO_ASSERT_UNLOCKED(sc);
697         GPIO_LOCK(sc);
698         memcpy(name, sc->pins[pin_num].gp_name, GPIOMAXNAME);
699         GPIO_UNLOCK(sc);
700
701         return (0);
702 }
703
704 static int
705 nct_gpio_pin_setflags(device_t dev, uint32_t pin_num, uint32_t flags)
706 {
707         struct nct_softc *sc;
708         struct gpio_pin *pin;
709
710         if (!NCT_IS_VALID_PIN(pin_num))
711                 return (EINVAL);
712
713         sc = device_get_softc(dev);
714         pin = &sc->pins[pin_num];
715         if ((flags & pin->gp_caps) != flags)
716                 return (EINVAL);
717
718         if ((flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) ==
719                 (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) {
720                         return (EINVAL);
721         }
722         if ((flags & (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) ==
723                 (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) {
724                         return (EINVAL);
725         }
726         if ((flags & (GPIO_PIN_INVIN | GPIO_PIN_INVOUT)) ==
727                 (GPIO_PIN_INVIN | GPIO_PIN_INVOUT)) {
728                         return (EINVAL);
729         }
730
731         GPIO_ASSERT_UNLOCKED(sc);
732         GPIO_LOCK(sc);
733         if ((flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) != 0) {
734                 nct_set_pin_input(sc, pin_num, (flags & GPIO_PIN_INPUT) != 0);
735                 pin->gp_flags &= ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT);
736                 pin->gp_flags |= flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT);
737         }
738         if ((flags & (GPIO_PIN_INVIN | GPIO_PIN_INVOUT)) != 0) {
739                 nct_set_pin_inverted(sc, pin_num,
740                     (flags & GPIO_PIN_INVIN) != 0);
741                 pin->gp_flags &= ~(GPIO_PIN_INVIN | GPIO_PIN_INVOUT);
742                 pin->gp_flags |= flags & (GPIO_PIN_INVIN | GPIO_PIN_INVOUT);
743         }
744         if ((flags & (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) != 0) {
745                 if (flags & GPIO_PIN_OPENDRAIN)
746                         nct_set_pin_opendrain(sc, pin_num);
747                 else
748                         nct_set_pin_pushpull(sc, pin_num);
749                 pin->gp_flags &= ~(GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL);
750                 pin->gp_flags |=
751                     flags & (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL);
752         }
753         GPIO_UNLOCK(sc);
754
755         return (0);
756 }
757
758 static device_method_t nct_methods[] = {
759         /* Device interface */
760         DEVMETHOD(device_probe,         nct_probe),
761         DEVMETHOD(device_attach,        nct_attach),
762         DEVMETHOD(device_detach,        nct_detach),
763
764         /* GPIO */
765         DEVMETHOD(gpio_get_bus,         nct_gpio_get_bus),
766         DEVMETHOD(gpio_pin_max,         nct_gpio_pin_max),
767         DEVMETHOD(gpio_pin_get,         nct_gpio_pin_get),
768         DEVMETHOD(gpio_pin_set,         nct_gpio_pin_set),
769         DEVMETHOD(gpio_pin_toggle,      nct_gpio_pin_toggle),
770         DEVMETHOD(gpio_pin_getname,     nct_gpio_pin_getname),
771         DEVMETHOD(gpio_pin_getcaps,     nct_gpio_pin_getcaps),
772         DEVMETHOD(gpio_pin_getflags,    nct_gpio_pin_getflags),
773         DEVMETHOD(gpio_pin_setflags,    nct_gpio_pin_setflags),
774
775         DEVMETHOD_END
776 };
777
778 static driver_t nct_driver = {
779         "gpio",
780         nct_methods,
781         sizeof(struct nct_softc)
782 };
783
784 static devclass_t nct_devclass;
785
786 DRIVER_MODULE(nctgpio, superio, nct_driver, nct_devclass, NULL, NULL);
787 MODULE_DEPEND(nctgpio, gpiobus, 1, 1, 1);
788 MODULE_DEPEND(nctgpio, superio, 1, 1, 1);
789 MODULE_VERSION(nctgpio, 1);
790