xref: /freebsd/sys/dev/nctgpio/nctgpio.c (revision 069ac184)
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  */
27 
28 /*
29  * Nuvoton GPIO driver.
30  */
31 
32 #include <sys/cdefs.h>
33 
34 #include <sys/param.h>
35 #include <sys/kernel.h>
36 #include <sys/systm.h>
37 #include <sys/bus.h>
38 #include <sys/eventhandler.h>
39 #include <sys/lock.h>
40 
41 #include <sys/module.h>
42 #include <sys/gpio.h>
43 
44 #include <machine/bus.h>
45 
46 #include <dev/gpio/gpiobusvar.h>
47 #include <dev/superio/superio.h>
48 
49 #include "gpio_if.h"
50 
51 #define NCT_PPOD_LDN 0xf /* LDN used to select Push-Pull/Open-Drain */
52 
53 /* Direct access through GPIO register table */
54 #define	NCT_IO_GSR			0 /* Group Select */
55 #define	NCT_IO_IOR			1 /* I/O */
56 #define	NCT_IO_DAT			2 /* Data */
57 #define	NCT_IO_INV			3 /* Inversion */
58 #define	NCT_IO_DST          4 /* Status */
59 
60 #define NCT_MAX_GROUP   9
61 #define NCT_MAX_PIN     75
62 
63 #define NCT_PIN_IS_VALID(_sc, _p)   ((_p) < (_sc)->npins)
64 #define NCT_PIN_GROUP(_sc, _p)      ((_sc)->pinmap[(_p)].group)
65 #define NCT_PIN_GRPNUM(_sc, _p)     ((_sc)->pinmap[(_p)].grpnum)
66 #define NCT_PIN_BIT(_sc, _p)        ((_sc)->pinmap[(_p)].bit)
67 #define NCT_PIN_BITMASK(_p)         (1 << ((_p) & 7))
68 
69 #define NCT_GPIO_CAPS	(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | \
70 	GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL | \
71 	GPIO_PIN_INVIN | GPIO_PIN_INVOUT)
72 
73 #define NCT_PREFER_INDIRECT_CHANNEL 2
74 
75 #define NCT_VERBOSE_PRINTF(dev, ...)            \
76 	do {                                        \
77 		if (__predict_false(bootverbose))       \
78 			device_printf(dev, __VA_ARGS__);    \
79 	} while (0)
80 
81 /*
82  * Note that the values are important.
83  * They match actual register offsets.
84  */
85 typedef enum {
86 	REG_IOR = 0,
87 	REG_DAT = 1,
88 	REG_INV = 2,
89 } reg_t;
90 
91 struct nct_gpio_group {
92  	uint32_t    caps;
93 	uint8_t     enable_ldn;
94 	uint8_t     enable_reg;
95 	uint8_t     enable_mask;
96 	uint8_t     data_ldn;
97 	uint8_t     iobase;
98 	uint8_t     ppod_reg; /* Push-Pull/Open-Drain */
99 	uint8_t     grpnum;
100 	uint8_t     pinbits[8];
101 	uint8_t     npins;
102 };
103 
104 struct nct_softc {
105 	device_t			dev;
106 	device_t			busdev;
107 	struct mtx			mtx;
108 	struct resource			*iores;
109 	int				iorid;
110 	int				curgrp;
111 	struct {
112 		uint8_t ior[NCT_MAX_GROUP + 1];       /* direction, 1: input 0: output */
113 		uint8_t out[NCT_MAX_GROUP + 1];       /* output value */
114 		uint8_t out_known[NCT_MAX_GROUP + 1]; /* whether out is valid */
115 		uint8_t inv[NCT_MAX_GROUP + 1];       /* inversion, 1: inverted */
116 	} cache;
117 	struct gpio_pin				pins[NCT_MAX_PIN + 1];
118 	struct nct_device			*nctdevp;
119 	int							npins; /* Total number of pins */
120 
121 	/* Lookup tables */
122 	struct {
123 		struct nct_gpio_group *group;
124 		uint8_t                grpnum;
125 		uint8_t                bit;
126 	} pinmap[NCT_MAX_PIN+1];
127 	struct nct_gpio_group *grpmap[NCT_MAX_GROUP+1];
128 };
129 
130 #define GPIO_LOCK_INIT(_sc)	mtx_init(&(_sc)->mtx,		\
131 		device_get_nameunit(dev), NULL, MTX_DEF)
132 #define GPIO_LOCK_DESTROY(_sc)		mtx_destroy(&(_sc)->mtx)
133 #define GPIO_LOCK(_sc)		mtx_lock(&(_sc)->mtx)
134 #define GPIO_UNLOCK(_sc)	mtx_unlock(&(_sc)->mtx)
135 #define GPIO_ASSERT_LOCKED(_sc)	mtx_assert(&(_sc)->mtx, MA_OWNED)
136 #define GPIO_ASSERT_UNLOCKED(_sc)	mtx_assert(&(_sc)->mtx, MA_NOTOWNED)
137 
138 #define GET_BIT(v, b)	(((v) >> (b)) & 1)
139 
140 /*
141  * For most devices there are several GPIO devices, we attach only to one of
142  * them and use the rest without attaching.
143  */
144 struct nct_device {
145 	uint16_t                  devid;
146 	int                       extid;
147 	const char               *descr;
148 	int                       ngroups;
149 	struct nct_gpio_group     groups[NCT_MAX_GROUP + 1];
150 } nct_devices[] = {
151 	{
152 		.devid   = 0xa025,
153 		.descr   = "GPIO on Winbond 83627DHG IC ver. 5",
154 		.ngroups = 5,
155 		.groups  = {
156 			{
157 				.grpnum      = 2,
158 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
159 				.enable_ldn  = 0x09,
160 				.enable_reg  = 0x30,
161 				.enable_mask = 0x01,
162 				.data_ldn    = 0x09,
163 				.ppod_reg    = 0xe0, /* FIXME Need to check for this group. */
164 				.caps        = NCT_GPIO_CAPS,
165 				.npins       = 8,
166 				.iobase      = 0xe3,
167 			},
168 			{
169 				.grpnum      = 3,
170 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
171 				.enable_ldn  = 0x09,
172 				.enable_reg  = 0x30,
173 				.enable_mask = 0x02,
174 				.data_ldn    = 0x09,
175 				.ppod_reg    = 0xe1, /* FIXME Need to check for this group. */
176 				.caps        = NCT_GPIO_CAPS,
177 				.npins       = 8,
178 				.iobase      = 0xf0,
179 			},
180 			{
181 				.grpnum      = 4,
182 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
183 				.enable_ldn  = 0x09,
184 				.enable_reg  = 0x30,
185 				.enable_mask = 0x04,
186 				.data_ldn    = 0x09,
187 				.ppod_reg    = 0xe1, /* FIXME Need to check for this group. */
188 				.caps        = NCT_GPIO_CAPS,
189 				.npins       = 8,
190 				.iobase      = 0xf4,
191 			},
192 			{
193 				.grpnum      = 5,
194 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
195 				.enable_ldn  = 0x09,
196 				.enable_reg  = 0x30,
197 				.enable_mask = 0x08,
198 				.data_ldn    = 0x09,
199 				.ppod_reg    = 0xe1, /* FIXME Need to check for this group. */
200 				.caps        = NCT_GPIO_CAPS,
201 				.npins       = 8,
202 				.iobase      = 0xe0,
203 			},
204 			{
205 				.grpnum      = 6,
206 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
207 				.enable_ldn  = 0x07,
208 				.enable_reg  = 0x30,
209 				.enable_mask = 0x01,
210 				.data_ldn    = 0x07,
211 				.ppod_reg    = 0xe1, /* FIXME Need to check for this group. */
212 				.caps        = NCT_GPIO_CAPS,
213 				.npins       = 8,
214 				.iobase      = 0xf4,
215 			},
216 		},
217 	},
218 	{
219 		.devid   = 0x1061,
220 		.descr   = "GPIO on Nuvoton NCT5104D",
221 		.ngroups = 2,
222 		.groups  = {
223 			{
224 				.grpnum      = 0,
225 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
226 				.enable_ldn  = 0x07,
227 				.enable_reg  = 0x30,
228 				.enable_mask = 0x01,
229 				.data_ldn    = 0x07,
230 				.ppod_reg    = 0xe0,
231 				.caps        = NCT_GPIO_CAPS,
232 				.npins       = 8,
233 				.iobase      = 0xe0,
234 			},
235 			{
236 				.grpnum      = 1,
237 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
238 				.enable_ldn  = 0x07,
239 				.enable_reg  = 0x30,
240 				.enable_mask = 0x02,
241 				.data_ldn    = 0x07,
242 				.ppod_reg    = 0xe1,
243 				.caps        = NCT_GPIO_CAPS,
244 				.npins       = 8,
245 				.iobase      = 0xe4,
246 			},
247 		},
248 	},
249 	{
250 		.devid   = 0xc452, /* FIXME Conflict with Nuvoton NCT6106D. See NetBSD's nct_match. */
251 		.descr   = "GPIO on Nuvoton NCT5104D (PC-Engines APU)",
252 		.ngroups = 2,
253 		.groups  = {
254 			{
255 				.grpnum      = 0,
256 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
257 				.enable_ldn  = 0x07,
258 				.enable_reg  = 0x30,
259 				.enable_mask = 0x01,
260 				.data_ldn    = 0x07,
261 				.ppod_reg    = 0xe0,
262 				.caps        = NCT_GPIO_CAPS,
263 				.npins       = 8,
264 				.iobase      = 0xe0,
265 			},
266 			{
267 				.grpnum      = 1,
268 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
269 				.enable_ldn  = 0x07,
270 				.enable_reg  = 0x30,
271 				.enable_mask = 0x02,
272 				.data_ldn    = 0x07,
273 				.ppod_reg    = 0xe1,
274 				.caps        = NCT_GPIO_CAPS,
275 				.npins       = 8,
276 				.iobase      = 0xe4,
277 			},
278 		},
279 	},
280 	{
281 		.devid   = 0xc453,
282 		.descr   = "GPIO on Nuvoton NCT5104D (PC-Engines APU3)",
283 		.ngroups = 2,
284 		.groups  = {
285 			{
286 				.grpnum      = 0,
287 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
288 				.enable_ldn  = 0x07,
289 				.enable_reg  = 0x30,
290 				.enable_mask = 0x01,
291 				.data_ldn    = 0x07,
292 				.ppod_reg    = 0xe0,
293 				.caps        = NCT_GPIO_CAPS,
294 				.npins       = 8,
295 				.iobase      = 0xe0,
296 			},
297 			{
298 				.grpnum      = 1,
299 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
300 				.enable_ldn  = 0x07,
301 				.enable_reg  = 0x30,
302 				.enable_mask = 0x02,
303 				.data_ldn    = 0x07,
304 				.ppod_reg    = 0xe1,
305 				.caps        = NCT_GPIO_CAPS,
306 				.npins       = 8,
307 				.iobase      = 0xe4,
308 			},
309 		},
310 	},
311 	{
312 		.devid  = 0xd42a,
313 		.extid  = 1,
314 		.descr  = "GPIO on Nuvoton NCT6796D-E",
315 		.ngroups = 10,
316 		.groups  = {
317 			{
318 				.grpnum      = 0,
319 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
320 				.enable_ldn  = 0x08,
321 				.enable_reg  = 0x30,
322 				.enable_mask = 0x02,
323 				.data_ldn    = 0x08,
324 				.ppod_reg    = 0xe0, /* FIXME Need to check for this group. */
325 				.caps        = NCT_GPIO_CAPS,
326 				.npins       = 8,
327 				.iobase      = 0xe0,
328 			},
329 			{
330 				.grpnum      = 1,
331 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
332 				.enable_ldn  = 0x08,
333 				.enable_reg  = 0x30,
334 				.enable_mask = 0x80,
335 				.data_ldn    = 0x08,
336 				.ppod_reg    = 0xe1, /* FIXME Need to check for this group. */
337 				.caps        = NCT_GPIO_CAPS,
338 				.npins       = 8,
339 				.iobase      = 0xf0,
340 			},
341 			{
342 				.grpnum      = 2,
343 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
344 				.enable_ldn  = 0x09,
345 				.enable_reg  = 0x30,
346 				.enable_mask = 0x01,
347 				.data_ldn    = 0x09,
348 				.ppod_reg    = 0xe1, /* FIXME Need to check for this group. */
349 				.caps        = NCT_GPIO_CAPS,
350 				.npins       = 8,
351 				.iobase      = 0xe0,
352 			},
353 			{
354 				.grpnum      = 3,
355 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6 },
356 				.enable_ldn  = 0x09,
357 				.enable_reg  = 0x30,
358 				.enable_mask = 0x02,
359 				.data_ldn    = 0x09,
360 				.ppod_reg    = 0xe1, /* FIXME Need to check for this group. */
361 				.caps        = NCT_GPIO_CAPS,
362 				.npins       = 7,
363 				.iobase      = 0xe4,
364 			},
365 			{
366 				.grpnum      = 4,
367 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
368 				.enable_ldn  = 0x09,
369 				.enable_reg  = 0x30,
370 				.enable_mask = 0x04,
371 				.data_ldn    = 0x09,
372 				.ppod_reg    = 0xe1, /* FIXME Need to check for this group. */
373 				.caps        = NCT_GPIO_CAPS,
374 				.npins       = 8,
375 				.iobase      = 0xf0, /* FIXME Page 344 say "F0~F2, E8",
376 										not "F0~F3". */
377 			},
378 			{
379 				.grpnum      = 5,
380 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
381 				.enable_ldn  = 0x09,
382 				.enable_reg  = 0x30,
383 				.enable_mask = 0x08,
384 				.data_ldn    = 0x09,
385 				.ppod_reg    = 0xe1, /* FIXME Need to check for this group. */
386 				.caps        = NCT_GPIO_CAPS,
387 				.npins       = 8,
388 				.iobase      = 0xf4,
389 			},
390 			{
391 				.grpnum      = 6,
392 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
393 				.enable_ldn  = 0x07,
394 				.enable_reg  = 0x30,
395 				.enable_mask = 0x01,
396 				.data_ldn    = 0x07,
397 				.ppod_reg    = 0xe1, /* FIXME Need to check for this group. */
398 				.caps        = NCT_GPIO_CAPS,
399 				.npins       = 8,
400 				.iobase      = 0xf4,
401 			},
402 			{
403 				.grpnum      = 7,
404 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
405 				.enable_ldn  = 0x07,
406 				.enable_reg  = 0x30,
407 				.enable_mask = 0x02,
408 				.data_ldn    = 0x07,
409 				.ppod_reg    = 0xe1, /* FIXME Need to check for this group. */
410 				.caps        = NCT_GPIO_CAPS,
411 				.npins       = 8,
412 				.iobase      = 0xe0,
413 			},
414 			{
415 				.grpnum      = 8,
416 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
417 				.enable_ldn  = 0x07,
418 				.enable_reg  = 0x30,
419 				.enable_mask = 0x04,
420 				.data_ldn    = 0x07,
421 				.ppod_reg    = 0xe1, /* FIXME Need to check for this group. */
422 				.caps        = NCT_GPIO_CAPS,
423 				.npins       = 8,
424 				.iobase      = 0xe4,
425 			},
426 			{
427 				.grpnum      = 9,
428 				.pinbits     = { 0, 1, 2, 3 },
429 				.enable_ldn  = 0x07,
430 				.enable_reg  = 0x30,
431 				.enable_mask = 0x08,
432 				.data_ldn    = 0x07,
433 				.ppod_reg    = 0xe1, /* FIXME Need to check for this group. */
434 				.caps        = NCT_GPIO_CAPS,
435 				.npins       = 4,
436 				.iobase      = 0xe8,
437 			},
438 		},
439 	},
440 	{
441 		.devid   = 0xd42a,
442 		.extid   = 2,
443 		.descr   = "GPIO on Nuvoton NCT5585D",
444 		.ngroups = 6,
445 		.groups  = {
446 			{
447 				.grpnum      = 2,
448 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6 },
449 				.enable_ldn  = 0x09,
450 				.enable_reg  = 0x30,
451 				.enable_mask = 0x01,
452 				.data_ldn    = 0x09,
453 				.ppod_reg    = 0xe1,
454 				.caps        = NCT_GPIO_CAPS,
455 				.npins       = 7,
456 				.iobase      = 0xe0,
457 			},
458 			{
459 				.grpnum      = 3,
460 				.pinbits     = { 1, 2, 3 },
461 				.enable_ldn  = 0x09,
462 				.enable_reg  = 0x30,
463 				.enable_mask = 0x02,
464 				.data_ldn    = 0x09,
465 				.ppod_reg    = 0xe2,
466 				.caps        = NCT_GPIO_CAPS,
467 				.npins       = 3,
468 				.iobase      = 0xe4,
469 			},
470 			{
471 				.grpnum      = 5,
472 				.pinbits     = { 0, 2, 6, 7 },
473 				.enable_ldn  = 0x09,
474 				.enable_reg  = 0x30,
475 				.enable_mask = 0x08,
476 				.data_ldn    = 0x09,
477 				.ppod_reg    = 0xe4,
478 				.caps        = NCT_GPIO_CAPS,
479 				.npins       = 4,
480 				.iobase      = 0xf4,
481 			},
482 			{
483 				.grpnum      = 7,
484 				.pinbits     = { 4 },
485 				.enable_ldn  = 0x07,
486 				.enable_reg  = 0x30,
487 				.enable_mask = 0x02,
488 				.data_ldn    = 0x07,
489 				.ppod_reg    = 0xe6,
490 				.caps        = NCT_GPIO_CAPS,
491 				.npins       = 1,
492 				.iobase      = 0xe0,
493 			},
494 			{
495 				.grpnum      = 8,
496 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
497 				.enable_ldn  = 0x07,
498 				.enable_reg  = 0x30,
499 				.enable_mask = 0x04,
500 				.data_ldn    = 0x07,
501 				.ppod_reg    = 0xe7,
502 				.caps        = NCT_GPIO_CAPS,
503 				.npins       = 8,
504 				.iobase      = 0xe4,
505 			},
506 			{
507 				.grpnum      = 9,
508 				.pinbits     = { 0, 2 },
509 				.enable_ldn  = 0x07,
510 				.enable_reg  = 0x30,
511 				.enable_mask = 0x08,
512 				.data_ldn    = 0x07,
513 				.ppod_reg    = 0xea,
514 				.caps        = NCT_GPIO_CAPS,
515 				.npins       = 2,
516 				.iobase      = 0xe8,
517 			},
518 		},
519 	},
520 	{
521 		.devid   = 0xc562,
522 		.descr   = "GPIO on Nuvoton NCT6779D",
523 		.ngroups = 9,
524 		.groups  = {
525 			{
526 				.grpnum      = 0,
527 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
528 				.enable_ldn  = 0x08,
529 				.enable_reg  = 0x30,
530 				.enable_mask = 0x01,
531 				.data_ldn    = 0x08,
532 				.ppod_reg    = 0xe0, /* FIXME Need to check for this group. */
533 				.caps        = NCT_GPIO_CAPS,
534 				.npins       = 8,
535 				.iobase      = 0xe0,
536 			},
537 			{
538 				.grpnum      = 1,
539 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
540 				.enable_ldn  = 0x09,
541 				.enable_reg  = 0x30,
542 				.enable_mask = 0x01,
543 				.data_ldn    = 0x08,
544 				.ppod_reg    = 0xe1, /* FIXME Need to check for this group. */
545 				.caps        = NCT_GPIO_CAPS,
546 				.npins       = 8,
547 				.iobase      = 0xf0,
548 			},
549 			{
550 				.grpnum      = 2,
551 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
552 				.enable_ldn  = 0x09,
553 				.enable_reg  = 0x30,
554 				.enable_mask = 0x01,
555 				.data_ldn    = 0x09,
556 				.ppod_reg    = 0xe1, /* FIXME Need to check for this group. */
557 				.caps        = NCT_GPIO_CAPS,
558 				.npins       = 8,
559 				.iobase      = 0xe0,
560 			},
561 			{
562 				.grpnum      = 3,
563 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6 },
564 				.enable_ldn  = 0x09,
565 				.enable_reg  = 0x30,
566 				.enable_mask = 0x02,
567 				.data_ldn    = 0x09,
568 				.ppod_reg    = 0xe1, /* FIXME Need to check for this group. */
569 				.caps        = NCT_GPIO_CAPS,
570 				.npins       = 7,
571 				.iobase      = 0xe4,
572 			},
573 			{
574 				.grpnum      = 4,
575 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
576 				.enable_ldn  = 0x09,
577 				.enable_reg  = 0x30,
578 				.enable_mask = 0x04,
579 				.data_ldn    = 0x09,
580 				.ppod_reg    = 0xe1, /* FIXME Need to check for this group. */
581 				.caps        = NCT_GPIO_CAPS,
582 				.npins       = 8,
583 				.iobase      = 0xf0,
584 			},
585 			{
586 				.grpnum      = 5,
587 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
588 				.enable_ldn  = 0x09,
589 				.enable_reg  = 0x30,
590 				.enable_mask = 0x08,
591 				.data_ldn    = 0x09,
592 				.ppod_reg    = 0xe1, /* FIXME Need to check for this group. */
593 				.caps        = NCT_GPIO_CAPS,
594 				.npins       = 8,
595 				.iobase      = 0xf4,
596 			},
597 			{
598 				.grpnum      = 6,
599 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
600 				.enable_ldn  = 0x09,
601 				.enable_reg  = 0x30,
602 				.enable_mask = 0x01,
603 				.data_ldn    = 0x07,
604 				.ppod_reg    = 0xe1, /* FIXME Need to check for this group. */
605 				.caps        = NCT_GPIO_CAPS,
606 				.npins       = 8,
607 				.iobase      = 0xf4,
608 			},
609 			{
610 				.grpnum      = 7,
611 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6 },
612 				.enable_ldn  = 0x09,
613 				.enable_reg  = 0x30,
614 				.enable_mask = 0x02,
615 				.data_ldn    = 0x07,
616 				.ppod_reg    = 0xe1, /* FIXME Need to check for this group. */
617 				.caps        = NCT_GPIO_CAPS,
618 				.npins       = 7,
619 				.iobase      = 0xe0,
620 			},
621 			{
622 				.grpnum      = 8,
623 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
624 				.enable_ldn  = 0x09,
625 				.enable_reg  = 0x30,
626 				.enable_mask = 0x04,
627 				.data_ldn    = 0x07,
628 				.ppod_reg    = 0xe1, /* FIXME Need to check for this group. */
629 				.caps        = NCT_GPIO_CAPS,
630 				.npins       = 8,
631 				.iobase      = 0xe4,
632 			},
633 		},
634 	},
635 	{
636 		.devid   = 0xd282,
637 		.descr   = "GPIO on Nuvoton NCT6112D/NCT6114D/NCT6116D",
638 		.ngroups = 9,
639 		.groups  = {
640 			{
641 				.grpnum      = 0,
642 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
643 				.enable_ldn  = 0x07,
644 				.enable_reg  = 0x30,
645 				.enable_mask = 0x01,
646 				.data_ldn    = 0x07,
647 				.ppod_reg    = 0xe0,
648 				.caps        = NCT_GPIO_CAPS,
649 				.npins       = 8,
650 				.iobase      = 0xe0,
651 			},
652 			{
653 				.grpnum      = 1,
654 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
655 				.enable_ldn  = 0x07,
656 				.enable_reg  = 0x30,
657 				.enable_mask = 0x02,
658 				.data_ldn    = 0x07,
659 				.ppod_reg    = 0xe1,
660 				.caps        = NCT_GPIO_CAPS,
661 				.npins       = 8,
662 				.iobase      = 0xe4,
663 			},
664 			{
665 				.grpnum      = 2,
666 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
667 				.enable_ldn  = 0x07,
668 				.enable_reg  = 0x30,
669 				.enable_mask = 0x04,
670 				.data_ldn    = 0x07,
671 				.ppod_reg    = 0xe1,
672 				.caps        = NCT_GPIO_CAPS,
673 				.npins       = 8,
674 				.iobase      = 0xe8,
675 			},
676 			{
677 				.grpnum      = 3,
678 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
679 				.enable_ldn  = 0x07,
680 				.enable_reg  = 0x30,
681 				.enable_mask = 0x08,
682 				.data_ldn    = 0x07,
683 				.ppod_reg    = 0xe1,
684 				.caps        = NCT_GPIO_CAPS,
685 				.npins       = 8,
686 				.iobase      = 0xec,
687 			},
688 			{
689 				.grpnum      = 4,
690 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
691 				.enable_ldn  = 0x07,
692 				.enable_reg  = 0x30,
693 				.enable_mask = 0x10,
694 				.data_ldn    = 0x07,
695 				.ppod_reg    = 0xe1,
696 				.caps        = NCT_GPIO_CAPS,
697 				.npins       = 8,
698 				.iobase      = 0xf0,
699 			},
700 			{
701 				.grpnum      = 5,
702 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
703 				.enable_ldn  = 0x07,
704 				.enable_reg  = 0x30,
705 				.enable_mask = 0x20,
706 				.data_ldn    = 0x07,
707 				.ppod_reg    = 0xe1,
708 				.caps        = NCT_GPIO_CAPS,
709 				.npins       = 8,
710 				.iobase      = 0xf4,
711 			},
712 			{
713 				.grpnum      = 6,
714 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
715 				.enable_ldn  = 0x07,
716 				.enable_reg  = 0x30,
717 				.enable_mask = 0x40,
718 				.data_ldn    = 0x07,
719 				.ppod_reg    = 0xe1,
720 				.caps        = NCT_GPIO_CAPS,
721 				.npins       = 8,
722 				.iobase      = 0xf8,
723 			},
724 			{
725 				.grpnum      = 7,
726 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
727 				.enable_ldn  = 0x07,
728 				.enable_reg  = 0x30,
729 				.enable_mask = 0x80,
730 				.data_ldn    = 0x07,
731 				.ppod_reg    = 0xe1,
732 				.caps        = NCT_GPIO_CAPS,
733 				.npins       = 8,
734 				.iobase      = 0xfc,
735 			},
736 			{
737 				.grpnum      = 8,
738 				.pinbits     = { 0, 1, 2, 3, 4, 5, 6, 7 },
739 				.enable_ldn  = 0x09,
740 				.enable_reg  = 0x30,
741 				.enable_mask = 0x01,
742 				.data_ldn    = 0x09,
743 				.ppod_reg    = 0xe1,
744 				.caps        = NCT_GPIO_CAPS,
745 				.npins       = 8,
746 				.iobase      = 0xf0,
747 			},
748 		},
749 	},
750 };
751 
752 static const char *
753 io2str(uint8_t ioport)
754 {
755 	switch (ioport) {
756 	case NCT_IO_GSR: return ("grpsel");
757 	case NCT_IO_IOR: return ("io");
758 	case NCT_IO_DAT: return ("data");
759 	case NCT_IO_INV: return ("inv");
760 	case NCT_IO_DST: return ("status");
761 	default:         return ("?");
762 	}
763 }
764 
765 static void
766 nct_io_set_group(struct nct_softc *sc, uint8_t grpnum)
767 {
768 	GPIO_ASSERT_LOCKED(sc);
769 
770 	if (grpnum == sc->curgrp)
771 		return;
772 
773 	NCT_VERBOSE_PRINTF(sc->dev, "write %s 0x%x ioport %d\n",
774 		io2str(NCT_IO_GSR), grpnum, NCT_IO_GSR);
775 	bus_write_1(sc->iores, NCT_IO_GSR, grpnum);
776 	sc->curgrp = grpnum;
777 }
778 
779 static uint8_t
780 nct_io_read(struct nct_softc *sc, uint8_t grpnum, uint8_t reg)
781 {
782 	uint8_t val;
783 
784 	nct_io_set_group(sc, grpnum);
785 
786 	val = bus_read_1(sc->iores, reg);
787 	NCT_VERBOSE_PRINTF(sc->dev, "read %s 0x%x ioport %d\n",
788 		io2str(reg), val, reg);
789 	return (val);
790 }
791 
792 static void
793 nct_io_write(struct nct_softc *sc, uint8_t grpnum, uint8_t reg, uint8_t val)
794 {
795 	nct_io_set_group(sc, grpnum);
796 
797 	NCT_VERBOSE_PRINTF(sc->dev, "write %s 0x%x ioport %d\n",
798 		io2str(reg), val, reg);
799 	bus_write_1(sc->iores, reg, val);
800 }
801 
802 static uint8_t
803 nct_get_ioreg(struct nct_softc *sc, reg_t reg, uint8_t grpnum)
804 {
805 	uint8_t iobase;
806 
807 	if (sc->iores != NULL)
808 		iobase = NCT_IO_IOR;
809 	else
810 		iobase = sc->grpmap[grpnum]->iobase;
811 	return (iobase + reg);
812 }
813 
814 static const char *
815 reg2str(reg_t reg)
816 {
817 	switch (reg) {
818 	case REG_IOR: return ("io");
819 	case REG_DAT: return ("data");
820 	case REG_INV: return ("inv");
821 	default:      return ("?");
822 	}
823 }
824 
825 static uint8_t
826 nct_read_reg(struct nct_softc *sc, reg_t reg, uint8_t grpnum)
827 {
828 	struct nct_gpio_group *gp;
829 	uint8_t                ioreg;
830 	uint8_t                val;
831 
832 	ioreg = nct_get_ioreg(sc, reg, grpnum);
833 
834 	if (sc->iores != NULL)
835 		return (nct_io_read(sc, grpnum, ioreg));
836 
837 	gp  = sc->grpmap[grpnum];
838 	val = superio_ldn_read(sc->dev, gp->data_ldn, ioreg);
839 	NCT_VERBOSE_PRINTF(sc->dev, "read %s 0x%x from group GPIO%u ioreg 0x%x\n",
840 		reg2str(reg), val, grpnum, ioreg);
841 	return (val);
842 }
843 
844 static int
845 nct_get_pin_cache(struct nct_softc *sc, uint32_t pin_num, uint8_t *cache)
846 {
847 	uint8_t bit;
848 	uint8_t group;
849 	uint8_t val;
850 
851 	KASSERT(NCT_PIN_IS_VALID(sc, pin_num), ("%s: invalid pin number %d",
852 	    __func__, pin_num));
853 
854 	group = NCT_PIN_GRPNUM(sc, pin_num);
855 	bit   = NCT_PIN_BIT(sc, pin_num);
856 	val   = cache[group];
857 	return (GET_BIT(val, bit));
858 }
859 
860 static void
861 nct_write_reg(struct nct_softc *sc, reg_t reg, uint8_t grpnum, uint8_t val)
862 {
863 	struct nct_gpio_group *gp;
864 	uint8_t                ioreg;
865 
866 	ioreg = nct_get_ioreg(sc, reg, grpnum);
867 
868 	if (sc->iores != NULL) {
869 		nct_io_write(sc, grpnum, ioreg, val);
870 		return;
871 	}
872 
873 	gp = sc->grpmap[grpnum];
874 	superio_ldn_write(sc->dev, gp->data_ldn, ioreg, val);
875 
876 	NCT_VERBOSE_PRINTF(sc->dev, "write %s 0x%x to group GPIO%u ioreg 0x%x\n",
877 		reg2str(reg), val, grpnum, ioreg);
878 }
879 
880 static void
881 nct_set_pin_reg(struct nct_softc *sc, reg_t reg, uint32_t pin_num, bool val)
882 {
883 	uint8_t *cache;
884 	uint8_t bit;
885 	uint8_t bitval;
886 	uint8_t group;
887 	uint8_t mask;
888 
889 	KASSERT(NCT_PIN_IS_VALID(sc, pin_num),
890 	    ("%s: invalid pin number %d", __func__, pin_num));
891 	KASSERT(reg == REG_IOR || reg == REG_INV,
892 	    ("%s: unsupported register %d", __func__, reg));
893 
894 	group  = NCT_PIN_GRPNUM(sc, pin_num);
895 	bit    = NCT_PIN_BIT(sc, pin_num);
896 	mask   = (uint8_t)1 << bit;
897 	bitval = (uint8_t)val << bit;
898 
899 	if (reg == REG_IOR)
900 		cache = &sc->cache.ior[group];
901 	else
902 		cache = &sc->cache.inv[group];
903 	if ((*cache & mask) == bitval)
904 		return;
905 	*cache &= ~mask;
906 	*cache |= bitval;
907 	nct_write_reg(sc, reg, group, *cache);
908 }
909 
910 /*
911  * Set a pin to input (val is true) or output (val is false) mode.
912  */
913 static void
914 nct_set_pin_input(struct nct_softc *sc, uint32_t pin_num, bool val)
915 {
916 	nct_set_pin_reg(sc, REG_IOR, pin_num, val);
917 }
918 
919 /*
920  * Check whether a pin is configured as an input.
921  */
922 static bool
923 nct_pin_is_input(struct nct_softc *sc, uint32_t pin_num)
924 {
925 	return (nct_get_pin_cache(sc, pin_num, sc->cache.ior));
926 }
927 
928 /*
929  * Set a pin to inverted (val is true) or normal (val is false) mode.
930  */
931 static void
932 nct_set_pin_inverted(struct nct_softc *sc, uint32_t pin_num, bool val)
933 {
934 	nct_set_pin_reg(sc, REG_INV, pin_num, val);
935 }
936 
937 static bool
938 nct_pin_is_inverted(struct nct_softc *sc, uint32_t pin_num)
939 {
940 	return (nct_get_pin_cache(sc, pin_num, sc->cache.inv));
941 }
942 
943 /*
944  * Write a value to an output pin.
945  * NB: the hardware remembers last output value across switching from
946  * output mode to input mode and back.
947  * Writes to a pin in input mode are not allowed here as they cannot
948  * have any effect and would corrupt the output value cache.
949  */
950 static void
951 nct_write_pin(struct nct_softc *sc, uint32_t pin_num, bool val)
952 {
953 	uint8_t bit;
954 	uint8_t group;
955 
956 	KASSERT(!nct_pin_is_input(sc, pin_num), ("attempt to write input pin"));
957 	group = NCT_PIN_GRPNUM(sc, pin_num);
958 	bit   = NCT_PIN_BIT(sc, pin_num);
959 
960 	if (GET_BIT(sc->cache.out_known[group], bit) &&
961 	    GET_BIT(sc->cache.out[group], bit) == val) {
962 		/* The pin is already in requested state. */
963 		return;
964 	}
965 	sc->cache.out_known[group] |= 1 << bit;
966 	if (val)
967 		sc->cache.out[group] |= 1 << bit;
968 	else
969 		sc->cache.out[group] &= ~(1 << bit);
970 	nct_write_reg(sc, REG_DAT, group, sc->cache.out[group]);
971 }
972 
973 static bool
974 nct_get_pin_reg(struct nct_softc *sc, reg_t reg, uint32_t pin_num)
975 {
976 	uint8_t            bit;
977 	uint8_t            group;
978 	uint8_t            val;
979 	bool               b;
980 
981 	KASSERT(NCT_PIN_IS_VALID(sc, pin_num), ("%s: invalid pin number %d",
982 			__func__, pin_num));
983 
984 	group = NCT_PIN_GRPNUM(sc, pin_num);
985 	bit   = NCT_PIN_BIT(sc, pin_num);
986 	val   = nct_read_reg(sc, reg, group);
987 	b     = GET_BIT(val, bit);
988 
989 	if (__predict_false(bootverbose)) {
990 		if (nct_pin_is_input(sc, pin_num))
991 			NCT_VERBOSE_PRINTF(sc->dev, "read %d from input pin %u<GPIO%u%u>\n",
992 				b, pin_num, group, bit);
993 		else
994 			NCT_VERBOSE_PRINTF(sc->dev,
995 				"read %d from output pin %u<GPIO%u%u>, cache miss\n",
996 				b, pin_num, group, bit);
997 	}
998 
999 	return (b);
1000 }
1001 
1002 /*
1003  * NB: state of an input pin cannot be cached, of course.
1004  * For an output we can either take the value from the cache if it's valid
1005  * or read the state from the hadrware and cache it.
1006  */
1007 static bool
1008 nct_read_pin(struct nct_softc *sc, uint32_t pin_num)
1009 {
1010 	uint8_t bit;
1011 	uint8_t group;
1012 	bool    val;
1013 
1014 	if (nct_pin_is_input(sc, pin_num)) {
1015 		return (nct_get_pin_reg(sc, REG_DAT, pin_num));
1016 	}
1017 
1018 	group = NCT_PIN_GRPNUM(sc, pin_num);
1019 	bit   = NCT_PIN_BIT(sc, pin_num);
1020 
1021 	if (GET_BIT(sc->cache.out_known[group], bit)) {
1022 		val = GET_BIT(sc->cache.out[group], bit);
1023 
1024 		NCT_VERBOSE_PRINTF(sc->dev,
1025 			"read %d from output pin %u<GPIO%u%u>, cache hit\n",
1026 			val, pin_num, group, bit);
1027 
1028 		return (val);
1029 	}
1030 
1031 	val = nct_get_pin_reg(sc, REG_DAT, pin_num);
1032 	sc->cache.out_known[group] |= 1 << bit;
1033 	if (val)
1034 		sc->cache.out[group] |= 1 << bit;
1035 	else
1036 		sc->cache.out[group] &= ~(1 << bit);
1037 	return (val);
1038 }
1039 
1040 /* FIXME Incorret for NCT5585D and probably other chips. */
1041 static uint8_t
1042 nct_ppod_reg(struct nct_softc *sc, uint32_t pin_num)
1043 {
1044 	uint8_t group = NCT_PIN_GRPNUM(sc, pin_num);
1045 
1046 	return (sc->grpmap[group]->ppod_reg);
1047 }
1048 
1049 /*
1050  * NB: PP/OD can be configured only via configuration registers.
1051  * Also, the registers are in a different logical device.
1052  * So, this is a special case.  No caching too.
1053  */
1054 static void
1055 nct_set_pin_opendrain(struct nct_softc *sc, uint32_t pin_num)
1056 {
1057 	uint8_t reg;
1058 	uint8_t outcfg;
1059 
1060 	reg = nct_ppod_reg(sc, pin_num);
1061 	outcfg = superio_ldn_read(sc->dev, NCT_PPOD_LDN, reg);
1062 	outcfg |= NCT_PIN_BITMASK(pin_num);
1063 	superio_ldn_write(sc->dev, 0xf, reg, outcfg);
1064 }
1065 
1066 static void
1067 nct_set_pin_pushpull(struct nct_softc *sc, uint32_t pin_num)
1068 {
1069 	uint8_t reg;
1070 	uint8_t outcfg;
1071 
1072 	reg = nct_ppod_reg(sc, pin_num);
1073 	outcfg = superio_ldn_read(sc->dev, NCT_PPOD_LDN, reg);
1074 	outcfg &= ~NCT_PIN_BITMASK(pin_num);
1075 	superio_ldn_write(sc->dev, 0xf, reg, outcfg);
1076 }
1077 
1078 static bool
1079 nct_pin_is_opendrain(struct nct_softc *sc, uint32_t pin_num)
1080 {
1081 	uint8_t reg;
1082 	uint8_t outcfg;
1083 
1084 	reg = nct_ppod_reg(sc, pin_num);
1085 	outcfg = superio_ldn_read(sc->dev, NCT_PPOD_LDN, reg);
1086 	return (outcfg & NCT_PIN_BITMASK(pin_num));
1087 }
1088 
1089 static struct nct_device *
1090 nct_lookup_device(device_t dev)
1091 {
1092 	struct nct_device *nctdevp;
1093 	uint16_t           devid;
1094 	int                i, extid;
1095 
1096 	devid = superio_devid(dev);
1097 	extid = superio_extid(dev);
1098 	for (i = 0, nctdevp = nct_devices; i < nitems(nct_devices); i++, nctdevp++) {
1099 		if (devid == nctdevp->devid && nctdevp->extid == extid)
1100 			return (nctdevp);
1101 	}
1102 	return (NULL);
1103 }
1104 
1105 static int
1106 nct_probe(device_t dev)
1107 {
1108 	struct nct_device *nctdevp;
1109 	uint8_t            ldn;
1110 
1111 	ldn = superio_get_ldn(dev);
1112 
1113 	if (superio_vendor(dev) != SUPERIO_VENDOR_NUVOTON) {
1114 		NCT_VERBOSE_PRINTF(dev, "ldn 0x%x not a Nuvoton device\n", ldn);
1115 		return (ENXIO);
1116 	}
1117 	if (superio_get_type(dev) != SUPERIO_DEV_GPIO) {
1118 		NCT_VERBOSE_PRINTF(dev, "ldn 0x%x not a GPIO device\n", ldn);
1119 		return (ENXIO);
1120 	}
1121 
1122 	nctdevp = nct_lookup_device(dev);
1123 	if (nctdevp == NULL) {
1124 		NCT_VERBOSE_PRINTF(dev, "ldn 0x%x not supported\n", ldn);
1125 		return (ENXIO);
1126 	}
1127 	device_set_desc(dev, nctdevp->descr);
1128 	return (BUS_PROBE_DEFAULT);
1129 }
1130 
1131 static int
1132 nct_attach(device_t dev)
1133 {
1134 	struct nct_softc *sc;
1135 	struct nct_gpio_group *gp;
1136 	uint32_t pin_num;
1137 	uint8_t v;
1138 	int flags, i, g;
1139 
1140 	sc          = device_get_softc(dev);
1141 	sc->dev     = dev;
1142 	sc->nctdevp = nct_lookup_device(dev);
1143 
1144 	flags = 0;
1145 	(void)resource_int_value(device_get_name(dev), device_get_unit(dev), "flags", &flags);
1146 
1147 	if ((flags & NCT_PREFER_INDIRECT_CHANNEL) == 0) {
1148 		uint16_t iobase;
1149 		device_t dev_8;
1150 
1151 		/*
1152 		 * As strange as it may seem, I/O port base is configured in the
1153 		 * Logical Device 8 which is primarily used for WDT, but also plays
1154 		 * a role in GPIO configuration.
1155 		 */
1156 		iobase = 0;
1157 		dev_8 = superio_find_dev(device_get_parent(dev), SUPERIO_DEV_WDT, 8);
1158 		if (dev_8 != NULL)
1159 			iobase = superio_get_iobase(dev_8);
1160 		if (iobase != 0 && iobase != 0xffff) {
1161 			int err;
1162 
1163 			NCT_VERBOSE_PRINTF(dev, "iobase %#x\n", iobase);
1164 			sc->curgrp = -1;
1165 			sc->iorid = 0;
1166 			err = bus_set_resource(dev, SYS_RES_IOPORT, sc->iorid,
1167 				iobase, 7); /* FIXME NCT6796D-E have 8 registers according to table 18.3. */
1168 			if (err == 0) {
1169 				sc->iores = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
1170 					&sc->iorid, RF_ACTIVE);
1171 				if (sc->iores == NULL) {
1172 					device_printf(dev, "can't map i/o space, "
1173 						"iobase=%#x\n", iobase);
1174 				}
1175 			} else {
1176 				device_printf(dev,
1177 					"failed to set io port resource at %#x\n", iobase);
1178 			}
1179 		}
1180 	}
1181 	NCT_VERBOSE_PRINTF(dev, "iores %p %s channel\n",
1182 		sc->iores, (sc->iores ? "direct" : "indirect"));
1183 
1184 	/* Enable GPIO groups */
1185 	for (g = 0, gp = sc->nctdevp->groups; g < sc->nctdevp->ngroups; g++, gp++) {
1186 		NCT_VERBOSE_PRINTF(dev,
1187 			"GPIO%d: %d pins, enable with mask 0x%x via ldn 0x%x reg 0x%x\n",
1188 			gp->grpnum, gp->npins, gp->enable_mask, gp->enable_ldn,
1189 			gp->enable_reg);
1190 		v = superio_ldn_read(dev, gp->enable_ldn, gp->enable_reg);
1191 		v |= gp->enable_mask;
1192 		superio_ldn_write(dev, gp->enable_ldn, gp->enable_reg, v);
1193 	}
1194 
1195 	GPIO_LOCK_INIT(sc);
1196 	GPIO_LOCK(sc);
1197 
1198 	pin_num   = 0;
1199 	sc->npins = 0;
1200 	for (g = 0, gp = sc->nctdevp->groups; g < sc->nctdevp->ngroups; g++, gp++) {
1201 
1202 		sc->grpmap[gp->grpnum] = gp;
1203 
1204 		/*
1205 		 * Caching input values is meaningless as an input can be changed at any
1206 		 * time by an external agent.  But outputs are controlled by this
1207 		 * driver, so it can cache their state.  Also, the hardware remembers
1208 		 * the output state of a pin when the pin is switched to input mode and
1209 		 * then back to output mode.  So, the cache stays valid.
1210 		 * The only problem is with pins that are in input mode at the attach
1211 		 * time.  For them the output state is not known until it is set by the
1212 		 * driver for the first time.
1213 		 * 'out' and 'out_known' bits form a tri-state output cache:
1214 		 * |-----+-----------+---------|
1215 		 * | out | out_known | cache   |
1216 		 * |-----+-----------+---------|
1217 		 * |   X |         0 | invalid |
1218 		 * |   0 |         1 |       0 |
1219 		 * |   1 |         1 |       1 |
1220 		 * |-----+-----------+---------|
1221 		 */
1222 		sc->cache.inv[gp->grpnum]       = nct_read_reg(sc, REG_INV, gp->grpnum);
1223 		sc->cache.ior[gp->grpnum]       = nct_read_reg(sc, REG_IOR, gp->grpnum);
1224 		sc->cache.out[gp->grpnum]       = nct_read_reg(sc, REG_DAT, gp->grpnum);
1225 		sc->cache.out_known[gp->grpnum] = ~sc->cache.ior[gp->grpnum];
1226 
1227 		sc->npins += gp->npins;
1228 		for (i = 0; i < gp->npins; i++, pin_num++) {
1229 			struct gpio_pin *pin;
1230 
1231 			sc->pinmap[pin_num].group  = gp;
1232 			sc->pinmap[pin_num].grpnum = gp->grpnum;
1233 			sc->pinmap[pin_num].bit    = gp->pinbits[i];
1234 
1235 			pin           = &sc->pins[pin_num];
1236 			pin->gp_pin   = pin_num;
1237 			pin->gp_caps  = gp->caps;
1238 			pin->gp_flags = 0;
1239 
1240 			snprintf(pin->gp_name, GPIOMAXNAME, "GPIO%u%u",
1241 				gp->grpnum, gp->pinbits[i]);
1242 
1243 			if (nct_pin_is_input(sc, pin_num))
1244 				pin->gp_flags |= GPIO_PIN_INPUT;
1245 			else
1246 				pin->gp_flags |= GPIO_PIN_OUTPUT;
1247 
1248 			if (nct_pin_is_opendrain(sc, pin_num))
1249 				pin->gp_flags |= GPIO_PIN_OPENDRAIN;
1250 			else
1251 				pin->gp_flags |= GPIO_PIN_PUSHPULL;
1252 
1253 			if (nct_pin_is_inverted(sc, pin_num))
1254 				pin->gp_flags |= (GPIO_PIN_INVIN | GPIO_PIN_INVOUT);
1255 		}
1256 	}
1257 	NCT_VERBOSE_PRINTF(dev, "%d pins available\n", sc->npins);
1258 
1259 	GPIO_UNLOCK(sc);
1260 
1261 	sc->busdev = gpiobus_attach_bus(dev);
1262 	if (sc->busdev == NULL) {
1263 		device_printf(dev, "failed to attach to gpiobus\n");
1264 		GPIO_LOCK_DESTROY(sc);
1265 		return (ENXIO);
1266 	}
1267 
1268 	return (0);
1269 }
1270 
1271 static int
1272 nct_detach(device_t dev)
1273 {
1274 	struct nct_softc *sc;
1275 
1276 	sc = device_get_softc(dev);
1277 	gpiobus_detach_bus(dev);
1278 
1279 	if (sc->iores != NULL)
1280 		bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->iores);
1281 	GPIO_ASSERT_UNLOCKED(sc);
1282 	GPIO_LOCK_DESTROY(sc);
1283 
1284 	return (0);
1285 }
1286 
1287 static device_t
1288 nct_gpio_get_bus(device_t dev)
1289 {
1290 	struct nct_softc *sc;
1291 
1292 	sc = device_get_softc(dev);
1293 
1294 	return (sc->busdev);
1295 }
1296 
1297 static int
1298 nct_gpio_pin_max(device_t dev, int *maxpin)
1299 {
1300 	struct nct_softc *sc;
1301 
1302 	sc      = device_get_softc(dev);
1303 	*maxpin = sc->npins - 1;
1304 	return (0);
1305 }
1306 
1307 static int
1308 nct_gpio_pin_set(device_t dev, uint32_t pin_num, uint32_t pin_value)
1309 {
1310 	struct nct_softc *sc;
1311 
1312 	sc = device_get_softc(dev);
1313 
1314 	if (!NCT_PIN_IS_VALID(sc, pin_num))
1315 		return (EINVAL);
1316 
1317 	GPIO_LOCK(sc);
1318 	if ((sc->pins[pin_num].gp_flags & GPIO_PIN_OUTPUT) == 0) {
1319 		GPIO_UNLOCK(sc);
1320 		return (EINVAL);
1321 	}
1322 	nct_write_pin(sc, pin_num, pin_value);
1323 	GPIO_UNLOCK(sc);
1324 
1325 	return (0);
1326 }
1327 
1328 static int
1329 nct_gpio_pin_get(device_t dev, uint32_t pin_num, uint32_t *pin_value)
1330 {
1331 	struct nct_softc *sc;
1332 
1333 	sc = device_get_softc(dev);
1334 
1335 	if (!NCT_PIN_IS_VALID(sc, pin_num))
1336 		return (EINVAL);
1337 
1338 	GPIO_ASSERT_UNLOCKED(sc);
1339 	GPIO_LOCK(sc);
1340 	*pin_value = nct_read_pin(sc, pin_num);
1341 	GPIO_UNLOCK(sc);
1342 
1343 	return (0);
1344 }
1345 
1346 static int
1347 nct_gpio_pin_toggle(device_t dev, uint32_t pin_num)
1348 {
1349 	struct nct_softc *sc;
1350 
1351 	sc = device_get_softc(dev);
1352 
1353 	if (!NCT_PIN_IS_VALID(sc, pin_num))
1354 		return (EINVAL);
1355 
1356 	GPIO_ASSERT_UNLOCKED(sc);
1357 	GPIO_LOCK(sc);
1358 	if ((sc->pins[pin_num].gp_flags & GPIO_PIN_OUTPUT) == 0) {
1359 		GPIO_UNLOCK(sc);
1360 		return (EINVAL);
1361 	}
1362 	if (nct_read_pin(sc, pin_num))
1363 		nct_write_pin(sc, pin_num, 0);
1364 	else
1365 		nct_write_pin(sc, pin_num, 1);
1366 
1367 	GPIO_UNLOCK(sc);
1368 
1369 	return (0);
1370 }
1371 
1372 static int
1373 nct_gpio_pin_getcaps(device_t dev, uint32_t pin_num, uint32_t *caps)
1374 {
1375 	struct nct_softc *sc;
1376 
1377 	sc = device_get_softc(dev);
1378 
1379 	if (!NCT_PIN_IS_VALID(sc, pin_num))
1380 		return (EINVAL);
1381 
1382 	GPIO_ASSERT_UNLOCKED(sc);
1383 	GPIO_LOCK(sc);
1384 	*caps = sc->pins[pin_num].gp_caps;
1385 	GPIO_UNLOCK(sc);
1386 
1387 	return (0);
1388 }
1389 
1390 static int
1391 nct_gpio_pin_getflags(device_t dev, uint32_t pin_num, uint32_t *flags)
1392 {
1393 	struct nct_softc *sc;
1394 
1395 	sc = device_get_softc(dev);
1396 
1397 	if (!NCT_PIN_IS_VALID(sc, pin_num))
1398 		return (EINVAL);
1399 
1400 	GPIO_ASSERT_UNLOCKED(sc);
1401 	GPIO_LOCK(sc);
1402 	*flags = sc->pins[pin_num].gp_flags;
1403 	GPIO_UNLOCK(sc);
1404 
1405 	return (0);
1406 }
1407 
1408 static int
1409 nct_gpio_pin_getname(device_t dev, uint32_t pin_num, char *name)
1410 {
1411 	struct nct_softc *sc;
1412 
1413 	sc = device_get_softc(dev);
1414 
1415 	if (!NCT_PIN_IS_VALID(sc, pin_num))
1416 		return (EINVAL);
1417 
1418 	GPIO_ASSERT_UNLOCKED(sc);
1419 	GPIO_LOCK(sc);
1420 	memcpy(name, sc->pins[pin_num].gp_name, GPIOMAXNAME);
1421 	GPIO_UNLOCK(sc);
1422 
1423 	return (0);
1424 }
1425 
1426 static int
1427 nct_gpio_pin_setflags(device_t dev, uint32_t pin_num, uint32_t flags)
1428 {
1429 	struct nct_softc *sc;
1430 	struct gpio_pin *pin;
1431 
1432 	sc = device_get_softc(dev);
1433 
1434 	if (!NCT_PIN_IS_VALID(sc, pin_num))
1435 		return (EINVAL);
1436 
1437 	pin = &sc->pins[pin_num];
1438 	if ((flags & pin->gp_caps) != flags)
1439 		return (EINVAL);
1440 
1441 	if ((flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) ==
1442 		(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) {
1443 			return (EINVAL);
1444 	}
1445 	if ((flags & (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) ==
1446 		(GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) {
1447 			return (EINVAL);
1448 	}
1449 	if ((flags & (GPIO_PIN_INVIN | GPIO_PIN_INVOUT)) ==
1450 		(GPIO_PIN_INVIN | GPIO_PIN_INVOUT)) {
1451 			return (EINVAL);
1452 	}
1453 
1454 	GPIO_ASSERT_UNLOCKED(sc);
1455 	GPIO_LOCK(sc);
1456 
1457 	/* input or output */
1458 	if ((flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) != 0) {
1459 		nct_set_pin_input(sc, pin_num, (flags & GPIO_PIN_INPUT) != 0);
1460 		pin->gp_flags &= ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT);
1461 		pin->gp_flags |= flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT);
1462 	}
1463 
1464 	/* invert */
1465 	if ((flags & (GPIO_PIN_INVIN | GPIO_PIN_INVOUT)) != 0) {
1466 		nct_set_pin_inverted(sc, pin_num, 1);
1467 		pin->gp_flags |= (GPIO_PIN_INVIN | GPIO_PIN_INVOUT);
1468 	} else {
1469 		nct_set_pin_inverted(sc, pin_num, 0);
1470 		pin->gp_flags &= ~(GPIO_PIN_INVIN | GPIO_PIN_INVOUT);
1471 	}
1472 
1473 	/* Open drain or push pull */
1474 	if ((flags & (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) != 0) {
1475 		if (flags & GPIO_PIN_OPENDRAIN)
1476 			nct_set_pin_opendrain(sc, pin_num);
1477 		else
1478 			nct_set_pin_pushpull(sc, pin_num);
1479 		pin->gp_flags &= ~(GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL);
1480 		pin->gp_flags |=
1481 		    flags & (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL);
1482 	}
1483 	GPIO_UNLOCK(sc);
1484 
1485 	return (0);
1486 }
1487 
1488 static device_method_t nct_methods[] = {
1489 	/* Device interface */
1490 	DEVMETHOD(device_probe,		nct_probe),
1491 	DEVMETHOD(device_attach,	nct_attach),
1492 	DEVMETHOD(device_detach,	nct_detach),
1493 
1494 	/* GPIO */
1495 	DEVMETHOD(gpio_get_bus,		nct_gpio_get_bus),
1496 	DEVMETHOD(gpio_pin_max,		nct_gpio_pin_max),
1497 	DEVMETHOD(gpio_pin_get,		nct_gpio_pin_get),
1498 	DEVMETHOD(gpio_pin_set,		nct_gpio_pin_set),
1499 	DEVMETHOD(gpio_pin_toggle,	nct_gpio_pin_toggle),
1500 	DEVMETHOD(gpio_pin_getname,	nct_gpio_pin_getname),
1501 	DEVMETHOD(gpio_pin_getcaps,	nct_gpio_pin_getcaps),
1502 	DEVMETHOD(gpio_pin_getflags,	nct_gpio_pin_getflags),
1503 	DEVMETHOD(gpio_pin_setflags,	nct_gpio_pin_setflags),
1504 
1505 	DEVMETHOD_END
1506 };
1507 
1508 static driver_t nct_driver = {
1509 	"gpio",
1510 	nct_methods,
1511 	sizeof(struct nct_softc)
1512 };
1513 
1514 DRIVER_MODULE(nctgpio, superio, nct_driver, NULL, NULL);
1515 MODULE_DEPEND(nctgpio, gpiobus, 1, 1, 1);
1516 MODULE_DEPEND(nctgpio, superio, 1, 1, 1);
1517 MODULE_VERSION(nctgpio, 1);
1518